opennurbs_file_utilities.h
1 /*
2 //
3 // Copyright (c) 1993-2015 Robert McNeel & Associates. All rights reserved.
4 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
5 // McNeel & Associates.
6 //
7 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
8 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
9 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
10 //
11 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
12 //
13 ////////////////////////////////////////////////////////////////
14 */
15 
16 #if !defined(OPENNURBS_FILE_UTILITIES_INC_)
17 #define OPENNURBS_FILE_UTILITIES_INC_
18 
19 class ON_CLASS ON_FileSystem
20 {
21 private:
22  ON_FileSystem() = delete;
23  ~ON_FileSystem() = delete;
24  ON_FileSystem(const ON_FileSystem&) = delete;
25  ON_FileSystem& operator=(const ON_FileSystem&) = delete;
26 
27 public:
28  static bool PathExists(
29  const char* path
30  );
31 
32  static bool PathExists(
33  const wchar_t* path
34  );
35 
36  /*
37  Returns:
38  True if path is a directory.
39  False otherwise.
40  */
41  static bool IsDirectory(
42  const char* path
43  );
44 
45  /*
46  Returns:
47  True if path is a directory.
48  False otherwise.
49  */
50  static bool IsDirectory(
51  const wchar_t* path
52  );
53 
54  /*
55  Returns:
56  True if path is a directory where files can be written.
57  False otherwise.
58  */
59  static bool IsDirectoryWithWriteAccess(
60  const char* path
61  );
62 
63  /*
64  Returns:
65  True if path is a directory where files can be written.
66  False otherwise.
67  */
68  static bool IsDirectoryWithWriteAccess(
69  const wchar_t* path
70  );
71 
72  /*
73  Returns:
74  True if path is a file.
75  False otherwise.
76  */
77  static bool IsFile(
78  const char* path
79  );
80 
81  /*
82  Returns:
83  True if path is a file.
84  False otherwise.
85  */
86  static bool IsFile(
87  const wchar_t* path
88  );
89 
90  /*
91  Description
92  Remove a file
93  Parameters:
94  file_path - [in]
95  name of file to delete
96  Returns:
97  True if the fuke existed and was removed.
98  */
99  static bool RemoveFile(
100  const char* file_path
101  );
102 
103  /*
104  Description
105  Remove a file
106  Parameters:
107  file_path - [in]
108  name of file to delete
109  Returns:
110  True if the fuke existed and was removed.
111  */
112  static bool RemoveFile(
113  const wchar_t* file_path
114  );
115 };
116 
117 class ON_CLASS ON_FileSystemPath
118 {
119 private:
120  ON_FileSystemPath() = delete;
121  ~ON_FileSystemPath() = delete;
122  ON_FileSystemPath(const ON_FileSystemPath&) = delete;
123  ON_FileSystemPath& operator=(const ON_FileSystemPath&) = delete;
124 
125 public:
126  /*
127  Platform dependent character used to separate directory names.
128  On Windows platforms:
129  ON_FileSystemPath::DirectorySeparator = ON_wString::Backslash.
130  On UNIX (including modern Apple) platforms:
131  ON_FileSystemPath::DirectorySeparator = ON_wString::Slash.
132  */
133  static const char DirectorySeparatorAsChar;
134  static const wchar_t DirectorySeparator;
135 
136  static const char AlternateDirectorySeparatorAsChar;
137  static const wchar_t AlternateDirectorySeparator;
138 
139  static bool IsDirectorySeparator(
140  char c,
141  bool bAllowAlternate
142  );
143 
144  static bool IsDirectorySeparator(
145  wchar_t c,
146  bool bAllowAlternate
147  );
148 
149  /*
150  Description:
151  Find the locations in a path the specify the drive, directory,
152  file name and file extension.
153  Parameters:
154  path - [in]
155  path to split
156  volume - [out] (pass null if you don't need the volume)
157  If volume is not null and the path parameter begins with a
158  Windows volume specification, *volume will either be
159  the Windows volume letter followed by the trailing colon
160  or a Windows UNC \<hostname>. Otherwise volume will
161  be the empty string.
162  dir - [out] (pass null if you don't need the directory)
163  If dir is not null and the path parameter contains a
164  directory specification, then the returned value of *dir
165  will be the directory specification including the trailing
166  slash.
167  file_name_stem - [out] (pass null if you don't need the file name stem)
168  If file_name_stem is not null and the path parameter contains a
169  file name specification, then the returned value of *file_name_stem
170  will be the file name stem.
171  file_name_ext - [out] (pass null if you don't need the extension)
172  If file_name_ext is not null and the path parameter contains a
173  file name extension specification, then the returned value of
174  *file_name_ext will be the file name extension including the initial
175  '.' character.
176  Remarks:
177  This function will treat a front slash ( / ) and a back slash
178  ( \ ) as directory separators. Because this function parses
179  file names store in .3dm files and the .3dm file may have been
180  written on a Windows computer and then read on a another
181  computer, it looks for a volume specification even when the
182  operating system is not Windows.
183  This function will not return an directory that does not
184  end with a trailing slash.
185  This function will not return an empty filename and a non-empty
186  extension.
187  This function parses the path string according to these rules.
188  It does not check the actual file system to see if the answer
189  is correct.
190  See Also:
191  on_splitpath
192  */
193  static void SplitPath(
194  const char* path,
195  ON_String* volume,
196  ON_String* dir,
197  ON_String* file_name_stem,
198  ON_String* file_name_ext
199  );
200 
201  static void SplitPath(
202  const char* path,
203  ON_wString* volume,
204  ON_wString* dir,
205  ON_wString* file_name_stem,
206  ON_wString* file_name_ext
207  );
208 
209  static void SplitPath(
210  const wchar_t* path,
211  ON_wString* volume,
212  ON_wString* dir,
213  ON_wString* file_name_stem,
214  ON_wString* file_name_ext
215  );
216 
217  static void SplitPath(
218  const wchar_t* path,
219  ON_wString* volume,
220  ON_wString* dir,
221  ON_wString* file_name_stem_and_extension
222  );
223 
224  static bool FilePathHas3dmExtension(
225  const wchar_t* file_path,
226  bool bAllow3dmbakExtension
227  );
228 
229  static bool FilePathHas3dmExtension(
230  const char* file_path,
231  bool bAllow3dmbakExtension
232  );
233 
234  /*
235  Description:
236  Determine if the file_name string is a permitted file name.
237  Valid file names must be non empty, cannot have two periods in a row,
238  and cannot contain directory separators, tildes, and other
239  platform specific values.
240  Parameters:
241  file_name - [in]
242  string to test.
243  bAllPlatforms - [in]
244  If true, test name for all supported platforms.
245  Returns:
246  True if the string can be a file name.
247  */
248  static bool IsValidFileName(
249  const char* file_name,
250  bool bAllPlatforms
251  );
252 
253  /*
254  Description:
255  Determine if the file_name string is a permitted file name.
256  Valid file names must be non empty, cannot have two periods in a row,
257  and cannot contain directory separators, tildes, and other
258  platform specific values.
259  Parameters:
260  file_name - [in]
261  string to test.
262  bAllPlatforms - [in]
263  If true, test name for all supported platforms.
264  Returns:
265  True if the string can be a file name.
266  */
267  static bool IsValidFileName(
268  const wchar_t* file_name,
269  bool bAllPlatforms
270  );
271 
272  /*
273  Parameters:
274  path - [in]
275  path to split
276  Returns:
277  The volume portion of the path.
278  */
279  static const ON_wString VolumeFromPath(
280  const wchar_t* path
281  );
282 
283  /*
284  Parameters:
285  path - [in]
286  path to split
287  Returns:
288  The directory portion of the path.
289  */
290  static const ON_wString DirectoryFromPath(
291  const wchar_t* path
292  );
293 
294  /*
295  Parameters:
296  path - [in]
297  path to split
298  Returns:
299  The volume and directory portion of the path.
300  */
301  static const ON_wString VolumeAndDirectoryFromPath(
302  const wchar_t* path
303  );
304 
305  /*
306  Parameters:
307  path - [in]
308  path to split
309  bIncludeExtension - [in]
310  Returns:
311  The file name portion of the path.
312  */
313  static const ON_wString FileNameFromPath(
314  const wchar_t* path,
315  bool bIncludeExtension
316  );
317 
318  /*
319  Parameters:
320  path - [in]
321  path to split
322  Returns:
323  The file name extension portion of the path, inlcuding the leading period or "dot".
324  */
325  static const ON_wString FileNameExtensionFromPath(
326  const wchar_t* path
327  );
328 
329  /*
330  Description:
331  Condenses // to /
332  Condenses /./ to /
333  Condenses /sfsdf/../ to /
334  Sets all directory separators to directory_separator.
335  Parameters:
336  bAllowWindowsUNCHostNameOrDiskLetter - [in]
337  If bAllowWindowsUNCHostNameOrDiskLetter and the path begins with \\HostName followed by
338  a directory separator, then the initial \\ is not condensed.
339  If the path begins with X: followed by a directory separator, where "X" is a single
340  letter in the range A to Z or a to z, then the path is considered valid.
341  bDeleteWindowsUNCHostNameOrDiskLetter - [in]
342  If bAllowWindowsUNCHostNameOrDiskLetter is true and the path begins with a UNC
343  host name or disk letter followed by a directory separator, then host name or disk letter
344  is deleted. This is useful when using paths from a Windows platform on a
345  non-Windows platform.
346  directory_separator - [in]
347  If 0 == directory_separator, then the first directory separator
348  is kept when condensing occurs.
349  ON_wString::FileSystemPathSeparator is a good choice if you want
350  to use the current runtime's separator.
351  dirty_path - [in]
352  path to clean.
353  Return:
354  Cleaned path.
355  */
356  static const ON_wString CleanPath(
357  bool bTrimLeft,
358  bool bTrimRight,
359  bool bAllowWindowsUNCHostNameOrDiskLetter,
360  bool bDeleteWindowsUNCHostNameOrDiskLetter,
361  const wchar_t directory_separator,
362  const wchar_t* dirty_path
363  );
364 
365  /*
366  Parameters:
367  path - [in]
368  path to test
369  directory_separator - [in]
370  If 0 == directory_separator, then either ON_wString::FileSystemPathSeparator
371  or ON_wString::AlternateFileSystemPathSeparator is permitted as a directory
372  separator.
373  ON_wString::FileSystemPathSeparator is a good choice if you want
374  to use the current runtime's separator.
375  Returns:
376  True if path begins with ../ or ./
377  */
378  static bool IsRelativePath(
379  const wchar_t* path,
380  const wchar_t directory_separator
381  );
382 
383 
384  /*
385  Parameters:
386  path - [in]
387  path to test
388  Returns:
389  True if path begins with ../ or ..\ or ./ or .\
390  */
391  static bool IsRelativePath(
392  const wchar_t* path
393  );
394  /*
395  Description:
396  Condenses // to /
397  Condenses /./ to /
398  Condenses /sfsdf/../ to /
399  Trims left and right white space.
400  Sets all directory separators to ON_FileSystemPath::DirectorySeparator.
401  If the Platform is not windows, the UNC host names and volume letters are deleted.
402  */
403  static const ON_wString CleanPath(
404  const wchar_t* dirty_path
405  );
406 
407  /*
408  Description:
409  Get a the relative path from base_path to full_path.
410  Parameters:
411  full_path - [in]
412  base_path - [in]
413 
414  Example
415  full_path = L"c:/a/b/c/d/somefile.txt";
416  base_path = L"C:/A/B/X/Y/Z/model.3dm";
417  ON_wString::GetRelativePath(full_path,base_path) returns
418  L"../../../c/d/somefile.txt"
419 
420  Example
421  full_path = L"c:/a/b/somefile.txt";
422  base_path = L"C:/A/B/model.3dm";
423  ON_wString::GetRelativePath(full_path,base_path) returns
424  L"./somefile.txt"
425 
426  Remarks:
427  Path separators on the input can be mixed.
428  Path separators on the returned relative path are ON_wString::FileSystemPathSeparator
429  */
430  static const ON_wString RelativePath(
431  const wchar_t* full_path,
432  bool bFullPathIncludesFileName,
433  const wchar_t* base_path,
434  bool bBasePathIncludesFileName
435  );
436 
437  static const ON_wString FullPathFromRelativePath(
438  const wchar_t* base_path,
439  bool bBasePathIncludesFileName,
440  const wchar_t* relative_path
441  );
442 
443  /*
444  Returns:
445  true if the platform file system ignores case.
446  Remarks:
447  Windows and default installations of OS X 10.10.3, and default installations of the UNIX
448  terminal interface in OS X 10.10.3 and later ignore case.
449  In the case of OX X, a user can override the default setting.
450  */
451  static bool PlatformPathIgnoreCase();
452 
453  /*
454  Parameters:
455  bWithTrailingDirectorySeparator - [in]
456  true - returned path will have a trailing directory separator.
457  false - returned path will not have a trailing directory separator.
458  Returns:
459  The platform current working directory which should be the directory
460  where ON::OpenFile("fname","r") would look for a file named "fname".
461  */
462  static const ON_wString CurrentDirectory(
463  bool bWithTrailingDirectorySeparator
464  );
465 
466  /*
467  Description:
468  Removes file name from path.
469  Parameters:
470  path - [in]
471  file system path with a file name.
472  file_name - [out]
473  If file_name is not nullptr, the removed portion of path
474  is returned here.
475  Returns:
476  path with any file name removed.
477  Remarks:
478  This function uses on_wsplitpath() to decide if the path ends with characters that
479  could be a file name. It does not inspect the file system to see if the file exists.
480  */
481  static const ON_wString RemoveFileName(
482  const wchar_t* path,
483  ON_wString* file_name
484  );
485 
486  /*
487  Description:
488  Removes Windows volume name from path.
489  Parameters:
490  path - [in]
491  file system path
492  volume_name - [out]
493  If volume_name is not nullptr, the removed portion of path
494  is returned here.
495  Returns:
496  path with any volume name removed.
497  Remarks:
498  This function uses on_wsplitpath() to decide if the path begins with characters that
499  could be a volume name. It does not inspect the file system to see if the volume exists.
500  */
501  static const ON_wString RemoveVolumeName(
502  const wchar_t* path,
503  ON_wString* volume_name
504  );
505 
506  /*
507  Description:
508  Combine paths into a single valid path name. Remove internal .. and .
509  directory references. If necessary remove file names.
510  Parameters:
511  left_side - [in]
512  bLeftSideContainsFileName - [in]
513  true if left_side path ends in a file name and that
514  file name is removed and discarded.
515  right_side - [in]
516  bRightSideContainsFileName - [in]
517  true if right_side path ends in a file name.
518  If bAppendTrailingDirectorySeparator is true, that file name is removed
519  and discarded. If bAppendTrailingDirectorySeparator is false, the
520  returned path ends in that file name.
521  bAppendTrailingDirectorySeparator - [in]
522  If true, any file names are removed and a directory separator
523  is appended to the returned string.
524  Returns:
525  a path made left_side + right_side
526  Remarks:
527  This function manipulates string information.
528  This function does not look at storage media
529  to see if the paths currently exist.
530  */
531  static const ON_wString CombinePaths(
532  const wchar_t* left_side,
533  bool bLeftSideContainsFileName,
534  const wchar_t* right_side,
535  bool bRightSideContainsFileName,
536  bool bAppendTrailingDirectorySeparator
537  );
538 
539  // ids used by ON_FileSystemPath::GetPath()
540  enum class PathId : unsigned int
541  {
542  Unset = 0,
543  DesktopDirectory = 1,
544  DocumentsDirectory = 2,
545  DownloadsDirectory = 3
546  };
547 
548  /*
549  Parameters:
550  path_id - [in]
551  Specifies path to get.
552  Returns:
553  Requested path. If the path does not exist in the current context,
554  the empty string is returned.
555  */
556  static const ON_wString PlatformPath(
558  );
559 
560 
561  ON_DEPRECATED_MSG("Use ON_FileSystem::PathExists")
562  static bool PathExists(
563  const char* path
564  );
565 
566  ON_DEPRECATED_MSG("Use ON_FileSystem::PathExists")
567  static bool PathExists(
568  const wchar_t* path
569  );
570 
571  ON_DEPRECATED_MSG("Use ON_FileSystem::IsDirectory")
572  static bool IsDirectory(
573  const char* path
574  );
575 
576  ON_DEPRECATED_MSG("Use ON_FileSystem::IsDirectory")
577  static bool IsDirectory(
578  const wchar_t* path
579  );
580 
581  ON_DEPRECATED_MSG("Use ON_FileSystem::IsFile")
582  static bool IsFile(
583  const char* path
584  );
585 
586  ON_DEPRECATED_MSG("Use ON_FileSystem::IsFile")
587  static bool IsFile(
588  const wchar_t* path
589  );
590 };
591 
592 class ON_CLASS ON_FileStream
593 {
594 public:
595  /*
596  Description:
597  Portable wrapper for C runtime fopen().
598  Parameters:
599  filename - [in]
600  mode - [in]
601  Remarks:
602  Use the ON_FileStream static functions for reading, writing,
603  seeking, position finding with the FILE pointer returned
604  by this function.
605  */
606  static FILE* Open( const wchar_t* filename, const wchar_t* mode );
607 
608  /*
609  Description:
610  Portable wrapper for C runtime fopen().
611  Parameters:
612  filename - [in]
613  mode - [in]
614  Remarks:
615  Use the ON_FileStream static functions for reading, writing,
616  seeking, position finding with the FILE pointer returned
617  by this function.
618  */
619  static FILE* Open( const char* filename, const char* mode );
620 
621  /*
622  Description:
623  Portable wrapper for C runtime fclose().
624  Parameters:
625  fp - [in]
626  FILE pointer returned by ON_FileStream::Open().
627  Returns:
628  0: successful
629  -1: null fp parameter
630  != 0: fclose() failure code
631  */
632  static int Close( FILE* fp );
633 
634  /*
635  Returns:
636  True if the file is a 3dm archive.
637  */
638  static bool Is3dmFile(
639  const wchar_t* file_path,
640  bool bAllow3dmbakExtension
641  );
642 
643  /*
644  Returns:
645  True if the file is a 3dm archive.
646  */
647  static bool Is3dmFile(
648  const char* file_path,
649  bool bAllow3dmbakExtension
650  );
651 
652  /*
653  Description:
654  Open the file and seek to the location where the 3dm archive information begins.
655  Returns:
656  A file stream with the current position at the beginning of the 3dm archive.
657  nullptr if the file is not a 3dm archive.
658  */
659  static FILE* Open3dmToRead(
660  const wchar_t* file_path
661  );
662 
663  /*
664  Description:
665  Open the file and seek to the location where the 3dm archive information begins.
666  Returns:
667  A file stream with the current position at the beginning of the 3dm archive.
668  nullptr if the file is not a 3dm archive.
669  */
670  static FILE* Open3dmToRead(
671  const char* file_path
672  );
673 
674  /*
675  Description:
676  Portable wrapper for C runtime ftell().
677  Parameters:
678  fp - [in]
679  FILE pointer returned by ON_FileStream::Open().
680  Returns:
681  >= 0: current file position
682  -1: an error occured
683  */
684  static ON__INT64 CurrentPosition( FILE* fp );
685 
686  /*
687  Description:
688  Portable wrapper for C runtime fseek(fp,offset,SEEK_CUR).
689  Parameters:
690  fp - [in]
691  FILE pointer returned by ON_FileStream::Open().
692  offset - [in]
693  */
694  static bool SeekFromCurrentPosition( FILE* fp, ON__INT64 offset );
695 
696  /*
697  Description:
698  Portable wrapper for C runtime fseek(fp,offset,SEEK_SET).
699  Parameters:
700  fp - [in]
701  FILE pointer returned by ON_FileStream::Open().
702  offset - [in]
703  */
704  static bool SeekFromStart( FILE* fp, ON__INT64 offset );
705 
706  /*
707  Description:
708  Portable wrapper for C runtime fseek(fp,offset,SEEK_END).
709  Parameters:
710  fp - [in]
711  FILE pointer returned by ON_FileStream::Open().
712  offset - [in]
713  */
714  static bool SeekFromEnd( FILE* fp, ON__INT64 offset );
715 
716  /*
717  Description:
718  Portable wrapper for C runtime fseek(fp,offset,origin).
719  Parameters:
720  fp - [in]
721  FILE pointer returned by ON_FileStream::Open().
722  offset - [in]
723  origin - [in]
724  SEEK_SET (0): seek from beginning of file.
725  SEEK_CUR (1): seek from current position of file pointer.
726  SEEK_END (2): seek from end of file.
727  */
728  static bool Seek( FILE* fp, ON__INT64 offset, int orgin );
729 
730  /*
731  Description:
732  Portable wrapper for C runtime fread(buffer,1,count,fp).
733  Parameters:
734  fp - [in]
735  FILE pointer returned by ON_FileStream::Open()
736  count - [in]
737  number of bytes to read.
738  buffer - [out]
739  read bytes are stored in this buffer
740  Returns:
741  number of bytes read
742  */
743  static ON__UINT64 Read( FILE* fp, ON__UINT64 count, void* buffer );
744 
745  /*
746  Description:
747  Portable wrapper for C runtime fwrite(buffer,1,count,fp).
748  Parameters:
749  fp - [in]
750  FILE pointer returned by ON_FileStream::Open()
751  count - [in]
752  number of bytes to write
753  buffer - [in]
754  data to be written
755  Returns:
756  number of bytes written.
757  */
758  static ON__UINT64 Write( FILE* fp, ON__UINT64 count, const void* buffer );
759 
760  /*
761  Description:
762  Portable wrapper for C runtime fflush(fp).
763  Parameters:
764  fp - [in]
765  FILE pointer returned by ON_FileStream::Open().
766  Returns:
767  true if flush was successful. False if an error occured.
768  */
769  static bool Flush( FILE* fp );
770 
771  /*
772  Description:
773  Portable wrapper for C runtime fstat().
774  Parameters:
775  fp - [in]
776  FILE pointer returned by ON_FileStream::Open().
777  file_size - [out]
778  If file_size is not null, the the size of the file
779  in bytes returned here
780  file_metadata_last_modified_time - [out]
781  If file_metadata_last_modified_time is not null, then the time the
782  file's metadata (owner, permissions, ...) were last modified is returned
783  here as the number of seconds since midnight January 1, 1970.
784  file_contents_last_modified_time - [out]
785  If file_contents_last_modified_time is not null, then the time the
786  file's contents were last modified is returned here as the number of
787  seconds since midnight January 1, 1970.
788  Returns:
789  true if the query was successful. False if an error occured.
790  */
791  static bool GetFileInformation(
792  FILE* fp,
793  ON__UINT64* file_size,
794  ON__UINT64* file_metadata_last_modified_time,
795  ON__UINT64* file_contents_last_modified_time
796  );
797  static bool GetFileInformation(
798  const wchar_t* file_name,
799  ON__UINT64* file_size,
800  ON__UINT64* file_metadata_last_modified_time,
801  ON__UINT64* file_contents_last_modified_time
802  );
803  static bool GetFileInformation(
804  const char* file_name,
805  ON__UINT64* file_size,
806  ON__UINT64* file_metadata_last_modified_time,
807  ON__UINT64* file_contents_last_modified_time
808  );
809 };
810 
811 class ON_CLASS ON_ContentHash
812 {
813 public:
814  static const ON_ContentHash Unset;
815 
816 public:
817  ON_ContentHash() = default;
818  ~ON_ContentHash() = default;
819  ON_ContentHash(const ON_ContentHash&) = default;
820  ON_ContentHash& operator=(const ON_ContentHash&) = default;
821 
822  /*
823  Descripton:
824  Create an ON_ContentHash class with the specified size, hash and times.
825  Parameters:
826  sha1_name_hash - [in]
827  The SHA-1 hash of the name (typically a full path file name).
828  When the content is identified by a file name in a file system,
829  use ON_SHA1_Hash::FileSystemPathHash() to calculate this value.
830  byte_count - [in]
831  number of bytes in the content.
832  sha1_content_hash - [in]
833  The SHA-1 hash of the content (typically a buffer or file).
834  You may use ON_SHA1_Has::FileContentHash() or ON_SHA1_Hash::BufferContentHash()
835  to calculate this value.
836  hash_time - [in]
837  The time the sha1_hash was calculated in seconds since January 1, 1970 UCT.
838  If 0 is passed in, the current time is used.
839  content_last_modified_time - [in]
840  Pass 0 if not known.
841  The time the hashed information that was last modifed in seconds since January 1, 1970 UCT.
842  If content_last_modified_time > hash_time, then 0 is used.
843  Returns:
844  An ON_ContentHash with size and SHA-1 hash and times set from the parameters,
845  */
846  static ON_ContentHash Create(
847  ON_SHA1_Hash sha1_name_hash,
848  ON__UINT64 byte_count,
849  ON_SHA1_Hash sha1_content_hash,
850  ON__UINT64 hash_time,
851  ON__UINT64 content_last_modified_time
852  );
853 
854  /*
855  Descripton:
856  Create an ON_ContentHash from a memory buffer.
857  Parameters:
858  sha1_name_hash - [in]
859  A SHA-1 hash of the name associated with this content.
860  If the buffer has no name, pass ON_SHA1_Hash::ZeroDigest.
861  If the buffer has an empty name, pass ON_SHA1_Hash::EmptyContentHash.
862  buffer - [in]
863  byte_count - [in]
864  number of bytes in buffer[]
865  Returns:
866  An ON_ContentHash with size and SHA-1 hash calculated from the parameters,
867  hash time = now, and content last modified time = 0.
868  */
869  static ON_ContentHash CreateFromBuffer(
870  ON_SHA1_Hash sha1_name_hash,
871  const void* buffer,
872  size_t byte_count
873  );
874 
875  /*
876  Descripton:
877  Create an ON_ContentHash from a file stream.
878  Parameters:
879  sha1_file_name_hash - [in]
880  A SHA-1 hash of the file name associated with fp.
881  Use ON_SHA1_Has::FileSystemPathHash() to create the value.
882  If the name is not known, pass ON_SHA1_Hash::ZeroDigest.
883  fp - [in] pointer to a file opened with ON:FileOpen(...,"rb")
884  Returns:
885  An ON_ContentHash with size and SHA-1 hash and times set from the file,
886  hash time = now, and content last modifed time set from the file system
887  information returned by ON_FileStream::GetFileInformation().
888  */
889  static ON_ContentHash CreateFromFile(
890  ON_SHA1_Hash sha1_file_name_hash,
891  FILE* fp
892  );
893 
894  /*
895  Descripton:
896  Create an ON_ContentHash from a file stream.
897  Parameters:
898  filename - [in] name of file.
899  Returns:
900  An ON_ContentHash with size and SHA-1 hash and times set from the file,
901  hash time = now, and content last modifed time set from the file system
902  information returned by ON_FileStream::GetFileInformation().
903  */
904  static ON_ContentHash CreateFromFile(
905  const wchar_t* filename
906  );
907 
908  static ON_ContentHash CreateFromFile(
909  const char* filename
910  );
911 
912  /*
913  Returns:
914  True if the SHA-1 hash has been set.
915  */
916  bool IsSet() const;
917 
918  /*
919  Returns:
920  True if the SHA-1 hash is not set.
921  */
922  bool IsNotSet() const;
923 
924  /*
925  Returns:
926  Number of bytes in the content (typically a file or buffer).
927  */
928  ON__UINT64 ByteCount() const;
929 
930  /*
931  Returns:
932  Time the hash SHA-1 hash was cacluated in seconds since January 1, 1970 UCT.
933  */
934  ON__UINT64 HashCalculationTime() const;
935 
936  /*
937  Returns:
938  Time the hashed content was last modifed in seconds since January 1, 1970 UCT.
939  0 is returned if this time is not known.
940 
941  This time should be used for important decisions as a last resort.
942 
943  When hash values differ, this time may be considered to
944  which content is newer (or most recently copied).
945 
946  Unfortunately, in many cases this time is often unknown and incorrectly set.
947  For example, some file systems set the last modified time of a copy of
948  an "old" file to the time the copy was created. Thus a copy of "old" content
949  may appear to be newer than "new" content that has not been copied.
950  */
951  ON__UINT64 ContentLastModifiedTime() const;
952 
953  /*
954  Returns:
955  SHA-1 hash of the name (typically a full path file name).
956  */
957  ON_SHA1_Hash NameHash() const;
958 
959  /*
960  Returns:
961  SHA-1 hash of the content (typically a buffer or file).
962  */
963  ON_SHA1_Hash ContentHash() const;
964 
965  /*
966  Description:
967  Test a buffer to see if it has a matching size and SHA-1 hash.
968  Parameters:
969  buffer - [in]
970  byte_count - [in]
971  number of bytes in buffer[]
972  Returns:
973  True if the buffer has a matching byte_count and SHA-1 hash.
974  */
975  bool IsSameBufferContent(
976  const void* buffer,
977  size_t byte_count
978  ) const;
979 
980  /*
981  Description:
982  Test a file to see if it has a matching size and SHA-1 hash.
983  Paramters:
984  fp - [in] pointer to file opened with ON::OpenFile(...,"rb")
985  bSkipTimeCheck - [in] if true, the time of last
986  modification is not checked.
987  Returns:
988  True if the file existes, can be read, and has a matching byte_count
989  and SHA-1 hash.
990  */
991  bool IsSameFileContent(
992  FILE* fp
993  ) const;
994 
995  /*
996  Description:
997  Test a file to see if it has a matching size and SHA-1 content hash.
998  Paramters:
999  filename - [in]
1000  Returns:
1001  True if the file exists, can be read, and has a matching byte_count
1002  and SHA-1 content hash.
1003  */
1004  bool IsSameFileContent(
1005  const wchar_t* filename
1006  ) const;
1007 
1008  bool IsSameFileContent(
1009  const char* filename
1010  ) const;
1011 
1012  /// <summary>
1013  /// ON_ContentHash::Compare are the possible results of calling ON_ContentHash::CompareFile().
1014  /// </summary>
1015  enum class CompareResult : unsigned char
1016  {
1017  /// <summary>
1018  /// Not set. This value is never returned by ON_ContentHash::CheckFile().
1019  /// </summary>
1020  Unset = 0,
1021 
1022  /// <summary>
1023  /// File exists and its size and content matches the information
1024  /// used to set the content hash.
1025  /// </summary>
1026  EqualContent = 1,
1027 
1028  /// <summary>
1029  /// File exists and its size or content differs from the information
1030  /// used to set the content hash. Unable to reliably determine which
1031  /// is newer.
1032  /// </summary>
1033  DifferentContent = 2,
1034 
1035  /// <summary>
1036  /// File exists and its size or content differs from the information
1037  /// used to set the content hash. The file's laste modified time
1038  /// is older than ContentLastModifiedTime().
1039  /// </summary>
1040  DifferentContentFileIsOlder = 3,
1041 
1042  /// <summary>
1043  /// File exists and its size or content differs from the information
1044  /// used to set the content hash. The file's last modified time
1045  /// is newer than ContentLastModifiedTime().
1046  /// </summary>
1047  ContentDifferentFileIsNewer = 4,
1048 
1049  /// <summary>
1050  /// File does not exist.
1051  /// </summary>
1052  FileDoesNotExist = 5,
1053 
1054  /// <summary>
1055  /// File cannot be opened, read, or some other file system issue prevents checking.
1056  /// </summary>
1057  FileSystemFailure = 6
1058  };
1059 
1060  static ON_ContentHash::CompareResult CompareResultFromUnsigned(
1061  unsigned int compare_result_as_unsigned
1062  );
1063 
1064  /*
1065  Description:
1066  Compare the information used to set this content hash with
1067  the contents of the file.
1068  Parameters:
1069  file_path - [in]
1070  bFastCompare - [in]
1071  If bFastCompare is true and the file_path, create time, last modified time, and size
1072  exactly match the values in ON_ContentHash, then
1073  ON_ContentHash::CompareResult::EqualContent is returned
1074  without performing the expensive SHA1 test on the file's content.
1075  If bFastCompare is false, the SHA-1 hash of the file's content will be
1076  calculated and compared before ON_ContentHash::CompareResult::EqualContent
1077  is returned.
1078  Returns:
1079  Result of compare test as a ON_ContentHash::CompareResult enum.
1080  ON_ContentHash::CompareResult::DifferentContentFileIsOlder means file_path content is different and older than "this".
1081  ON_ContentHash::CompareResult::DifferentContentFileIsNewer means file_path content is different and newer than "this".
1082  */
1084  const wchar_t* file_path,
1085  bool bFastTest
1086  ) const;
1087 
1088  /*
1089  Description:
1090  Compare the byte count and SHA-1 content hash.
1091  Parameters:
1092  file_content_hash - [in]
1093  ON_ContentHash to compare against this one.
1094  Returns:
1095  Result of compare test as a ON_ContentHash::CompareResult enum.
1096  ON_ContentHash::CompareResult::DifferentContentFileIsOlder means file_content_hash is different and older than "this".
1097  ON_ContentHash::CompareResult::DifferentContentFileIsNewer means file_content_hash is different and newer than "this".
1098  */
1100  ON_ContentHash file_content_hash
1101  ) const;
1102 
1103  /*
1104  Returns:
1105  true if a and b have identical ByteCount() and SHA-1 content hash values.
1106  */
1107  static bool EqualContent(
1108  const ON_ContentHash& a,
1109  const ON_ContentHash& b
1110  );
1111 
1112  /*
1113  Returns:
1114  true if a and b have differnt ByteCount() or SHA-1 content hash values.
1115  */
1116  static bool DifferentContent(
1117  const ON_ContentHash& a,
1118  const ON_ContentHash& b
1119  );
1120 
1121 
1122  /*
1123  Description:
1124  Compares content byte count and content SHA-1
1125  */
1126  static int CompareContent(
1127  const ON_ContentHash& a,
1129  );
1130 
1131  /*
1132  Description:
1133  Compares all fields
1134  */
1135  static int Compare(
1136  const ON_ContentHash& a,
1137  const ON_ContentHash& b
1138  );
1139 
1140  /*
1141  Parameters:
1142  filename - [in]
1143  Returns:
1144  True if the file exists, has size > 0, has the same name, same size, and same last modified time
1145  than this content hash.
1146  False otherwise.
1147  Remarks:
1148  Faster than the ON_ContentHash::EqualContent() and reliable if this content
1149  hash was set on the same file system.
1150  Unreliable if the file system does not correctly set last modified times
1151  or the file was modified less than 2 seconds before the call.
1152  */
1153  bool EqualFileNameSizeAndTime(
1154  const wchar_t* filename
1155  ) const;
1156 
1157  bool Write(
1158  class ON_BinaryArchive& archive
1159  ) const;
1160 
1161  bool Read(
1162  class ON_BinaryArchive& archive
1163  );
1164 
1165  void Dump(
1166  class ON_TextLog& text_log
1167  ) const;
1168 
1169 private:
1170  // Number of bytes in the buffer or file
1171  ON__UINT64 m_byte_count = 0;
1172 
1173  // Time this hash was set (always > 0 if this ON_ContentHash is set).
1174  ON__UINT64 m_hash_time = 0; // number of seconds since Jan 1, 1970, UCT
1175 
1176  // Time the content was last modifed.
1177  // This time is often unknown, or set incorrectly.
1178  ON__UINT64 m_content_time = 0; // number of seconds since Jan 1, 1970, UCT
1179 
1180  // SHA-1 hash of the content name (file name or other assigned name)
1181  ON_SHA1_Hash m_sha1_name_hash = ON_SHA1_Hash::ZeroDigest;
1182 
1183  // SHA-1 hash of the content (buffer or file).
1184  ON_SHA1_Hash m_sha1_content_hash = ON_SHA1_Hash::ZeroDigest;
1185 };
1186 
1187 class ON_CLASS ON_FileReference
1188 {
1189 public:
1190  static const ON_FileReference Unset;
1191 
1192 #pragma region RH_C_SHARED_ENUM [ON_FileReference::Status] [Rhino.FileIO.FileReferenceStatus] [int]
1193  ///<summary>Enumerates a list of file statuses.</summary>
1194  enum class Status : unsigned int
1195  {
1196  /// <summary>
1197  /// Status of a the full path is not known.
1198  /// </summary>
1199  Unknown = 0,
1200 
1201  /// <summary>
1202  /// Full path is valid.
1203  /// </summary>
1204  FullPathValid = 1,
1205 
1206  /// <summary>
1207  /// Unable to locate file.
1208  /// </summary>
1209  FileNotFound = 2
1210  };
1211 #pragma endregion
1212 
1213  static int Compare(
1214  const ON_FileReference& a,
1215  const ON_FileReference& b
1216  );
1217 
1218  static ON_FileReference::Status StatusFromUnsigned(
1219  unsigned int full_path_status_as_unsigned
1220  );
1221 
1222  ON_FileReference() = default;
1223  ~ON_FileReference() = default;
1224  ON_FileReference(const ON_FileReference&) = default;
1225  ON_FileReference& operator=(const ON_FileReference&) = default;
1226 
1228  const wchar_t* full_path,
1229  const wchar_t* relative_path,
1230  ON_ContentHash content_hash,
1231  ON_FileReference::Status full_path_status
1232  );
1233 
1234  static ON_FileReference CreateFromFullPath(
1235  const wchar_t* full_path,
1236  bool bSetContentHash,
1237  bool bSetFullPathStatus
1238  );
1239 
1240 #pragma region RH_C_SHARED_ENUM [ON_FileReference::FindFilePreference] [Rhino.FileIO.FileFindPreference] [int]
1241  ///<summary>Defines options for file search.</summary>
1242  enum class FindFilePreference : unsigned char
1243  {
1244  ///<summary>The choice is not defined.</summary>
1245  None = 0,
1246 
1247  ///<summary>File name exists in FullPath().</summary>
1248  FullPath = 1,
1249 
1250  ///<summary>File name exists in base path + RelativePath().</summary>
1251  RelativePath = 2,
1252 
1253  ///<summary>File name exists in base path directory.</summary>
1254  BasePath = 3,
1255 
1256  ///<summary>File with mathing content exists.</summary>
1257  ContentMatch = 4,
1258 
1259  ///<summary>Most recently modifed file.</summary>
1260  MostRecent = 5
1261  };
1262 #pragma endregion
1263 
1264  /*
1265  Description:
1266  Uses the full path, relative path and parameter information to find a
1267  full path to a file that exists.
1268  Parameters:
1269  base_path - [in]
1270  If base_path and RelativePath() are not empty, then path base_path+RelativePath().
1271  If base_path is not empty, then base_path + filename is considered.
1272  bBasePathIncludesFileName - [in]
1273  True if base_path contains a file name that must be removed to get a directory path.
1274  first_choice - [in]
1275  When multiple files are found in different locations, the first_choice, second_choice,
1276  third_choice, forth_choice, and fifth_choice parameters are used to select which file
1277  is returned.
1278  second_choice - [in]
1279  When multiple files are found in different locations, the first_choice, second_choice,
1280  third_choice, forth_choice, and fifth_choice parameters are used to select which file
1281  is returned.
1282  third_choice - [in]
1283  When multiple files are found in different locations, the first_choice, second_choice,
1284  third_choice, forth_choice, and fifth_choice parameters are used to select which file
1285  is returned.
1286  forth_choice - [in]
1287  When multiple files are found in different locations, the first_choice, second_choice,
1288  third_choice, forth_choice, and fifth_choice parameters are used to select which file
1289  is returned.
1290  fifth_choice - [in]
1291  When multiple files are found in different locations, the first_choice, second_choice,
1292  third_choice, forth_choice, and fifth_choice parameters are used to select which file
1293  is returned.
1294  full_path - [out]
1295  A full path to a file that exists.
1296  If FullPath() and base_path+RelativePath() resolve to different files,
1297  the content hash information is used to select the file.
1298  Returns:
1299  If the file is found, then the returned ON_FileReference::FindFilePreference enum value
1300  indicates why it was selected.
1301  If the file is not found, then ON_FileReference::FindFilePreference::None is returned
1302  and full_path is empty.
1303  Remarks:
1304  The locations FullPath(), base_path+RelativePath(), and base_path+FileName() are tested.
1305  If multiple files are found, first_choice, second_choice, third_choice, forth_choice,
1306  and fifth_choice are used to select which file is returned.
1307  */
1309  const wchar_t* base_path,
1310  bool bBasePathIncludesFileName,
1316  ON_wString& found_file_full_path
1317  ) const;
1318 
1319  /*
1320  Description:
1321  Uses the full path, relative path and parameter information to find a
1322  full path to a file that exists.
1323  Parameters:
1324  base_path - [in]
1325  If base_path and RelativePath() are not empty, then path base_path+RelativePath().
1326  If base_path is not empty, then base_path + filename is considered.
1327  bBasePathIncludesFileName - [in]
1328  True if base_path contains a file name that must be removed to get a directory path.
1329  Returns:
1330  If the file is found, then the returned ON_FileReference::FindFilePreference enum value
1331  indicates why it was selected.
1332  If the file is not found, then ON_FileReference::FindFilePreference::None is returned
1333  and full_path is empty.
1334  Remarks:
1335  The locations FullPath(), base_path+RelativePath(), and base_path+FileName() are tested.
1336  If multiple files are found, the returned file is selected in the order
1337  relative path, full path, content match, base path and most recently modified.
1338  If you prefer a different order, use the version of ON_FileReference::FindFile
1339  with 5 ON_FileReference::FindFilePreference parameters.
1340  */
1342  const wchar_t* base_path,
1343  bool bBasePathIncludesFileName,
1344  ON_wString& found_file_full_path
1345  ) const;
1346 
1347  /*
1348  Description:
1349  The search for the file is identical to the one performed by find file.
1350  If a file is found, the full path setting in this reference is updated.
1351  */
1352  ON_FileReference::FindFilePreference FindFileAndUpdateReference(
1353  const wchar_t* base_path,
1354  bool bBasePathIncludesFileName,
1360  bool bUpdateContentHash,
1361  ON_wString& found_file_full_path
1362  );
1363 
1364  /*
1365  Description:
1366  The search for the file is identical to the one performed by find file.
1367  If a file is found, the full path setting in this reference is updated.
1368  */
1369  ON_FileReference::FindFilePreference FindFileAndUpdateReference(
1370  const wchar_t* base_path,
1371  bool bBasePathIncludesFileName,
1372  bool bUpdateContentHash,
1373  ON_wString& found_file_full_path
1374  );
1375 
1376  ON_FileReference::FindFilePreference FindFileAndUpdateReference(
1377  const wchar_t* base_path,
1378  bool bBasePathIncludesFileName,
1379  bool bUpdateContentHash
1380  );
1381 
1382  /*
1383  Returns:
1384  True if FullPath() is not empty.
1385  */
1386  bool IsSet() const;
1387 
1388  /*
1389  Returns:
1390  True if FullPath() is empty.
1391  */
1392  bool IsNotSet() const;
1393 
1394  /*
1395  Parameters:
1396  bUseArchiveBasePath - [in]
1397  If bUseArchiveBasePath is true and a file is being written, then the
1398  base path of the file being written use used as the base path to
1399  calculate the relative path.
1400  If bUseArchiveBasePath is false, then the current value of RelativePath()
1401  is saved in the archive.
1402  */
1403  bool Write(
1404  bool bUseArchiveDirectoryAsBasePath,
1405  ON_BinaryArchive& archive
1406  ) const;
1407 
1408  /*
1409  Parameters:
1410  base_path - [in]
1411  If base_path is not empty, then the relative path saved
1412  in the archive will be calculated from FullPath() and base_path.
1413  If base_path is nullptr or empty, then RelativePath() is saved in
1414  the archive.
1415  */
1416  bool Write(
1417  const wchar_t* base_path,
1418  bool bBasePathIncludesFileName,
1419  ON_BinaryArchive& archive
1420  ) const;
1421 
1422  /*
1423  Remarks:
1424  Calling Read() sets m_full_path_status = ON_FileReference::Status::Unknown,
1425  even if that was not the status when Write() was called.
1426  */
1427  bool Read(
1428  ON_BinaryArchive& archive
1429  );
1430 
1431  void Dump(
1432  class ON_TextLog& text_log
1433  ) const;
1434 
1435  unsigned int SizeOf() const;
1436 
1437  const ON_wString& FullPath() const;
1438  const wchar_t* FullPathAsPointer() const;
1439  void SetFullPath(
1440  const wchar_t* full_path,
1441  bool bSetContentHash
1442  );
1443  void SetFullPath(
1444  const char* full_path,
1445  bool bSetContentHash
1446  );
1447  void ClearFullPath();
1448 
1449  const ON_wString& RelativePath() const;
1450  const wchar_t* RelativePathAsPointer() const;
1451  void SetRelativePath(
1452  const wchar_t* relative_path
1453  );
1454  void SetRelativePath(
1455  const char* relative_path
1456  );
1457  void SetRelativePathFromBasePath(
1458  const wchar_t* base_path,
1459  bool bBasePathContainsFileName
1460  );
1461  void SetRelativePathFromBasePath(
1462  const char* base_path,
1463  bool bBasePathContainsFileName
1464  );
1465  void ClearRelativePath();
1466 
1467  /*
1468  Returns:
1469  File content hash. This value is persistent, saved in 3dm archive,
1470  and could have been calculated a long time ago on a different computer.
1471  */
1472  const ON_ContentHash& ContentHash() const;
1473  void SetContentHash(
1474  ON_ContentHash content_hash
1475  );
1476  void ClearContentHash();
1477 
1478  bool UpdateContentHash();
1479 
1480  /*
1481  Returns:
1482  Parameters:
1483  recent_time - [in]
1484  The time, in number of seconds since January 1, 1970 UTC, to use
1485  when deciding what content hashes can be considered recent.
1486  If recent_time is 0 or in the future, then the current value of
1487  ON_SecondsSinceJanOne1970UTC() is used.
1488  Typically this parameter is the value of ON_SecondsSinceJanOne1970UTC()
1489  at the beginning of a calculation durint which any referenced files will
1490  not be changed.
1491  Returns:
1492  A file content hash value calculated on or after a specified time in the current
1493  instance of the application. This value is used to detect changed files
1494  in the current instance of the application. It is cached for performance reasons.
1495  This value is never saved in 3dm files.
1496  */
1497  const ON_ContentHash& RecentContentHash(
1498  ON__UINT64 recent_time
1499  ) const;
1500 
1501  /*
1502  Returns:
1503  ON_SHA1_Hash::FileSystemPathHash(FullPath());
1504  Remarks:
1505  The value of the hash is saved in a runtime cache so
1506  using this function when comparing paths is efficient
1507  when multple compares are required.
1508  See Also:
1509  ON_NameHash::CreateFilePathHash( ON_FileReference& file_reference );
1510  */
1511  const ON_SHA1_Hash& FullPathHash() const;
1512 
1513  ON_FileReference::Status FullPathStatus() const;
1514  void SetFullPathStatus(
1515  ON_FileReference::Status full_path_status
1516  );
1517 
1518  ON_UUID EmbeddedFileId() const;
1519  void SetEmbeddedFileId(
1520  ON_UUID embedded_file_id
1521  );
1522 
1523 private:
1524  ON_wString m_full_path;
1525  ON_wString m_relative_path;
1526 
1527  // If the referenced file is saved in the model as an embedded file,
1528  // the ON_BinaryArchive read code sets m_embedded_file_id
1529  // at read time.
1530  mutable ON_UUID m_embedded_file_id = ON_nil_uuid;
1531 
1532  // file content hash. Can be calculated long ago, on a different computer,
1533  // and is saved in 3dm archived.
1534  ON_ContentHash m_content_hash; // File content hash.
1535 
1536  mutable ON_ContentHash m_recent_content_hash;
1537 
1538  // m_full_path_hash is chached runtime information. The value is not saved
1539  // in .3dm archives. It is calculated on demand.
1540  mutable ON_SHA1_Hash m_full_path_hash = ON_SHA1_Hash::EmptyContentHash; // File path hash.
1541 
1543 
1544 private:
1545  ON_FileReference::FindFilePreference Internal_FindFile(
1546  const wchar_t* base_path,
1547  bool bBasePathIncludesFileName,
1548  const ON_FileReference::FindFilePreference* file_preference,
1549  unsigned int file_preference_count,
1550  ON_wString& found_file_full_path,
1551  ON_ContentHash* found_file_content_hash
1552  ) const;
1553 };
1554 
1555 /*
1556 Description:
1557  Iterates through every item in a file system directory.
1558 */
1559 class ON_CLASS ON_FileIterator
1560 {
1561 public:
1562  ON_FileIterator() = default;
1563  ~ON_FileIterator();
1564 
1565 private:
1566  ON_FileIterator(const ON_FileIterator&) = delete;
1567  ON_FileIterator& operator=(const ON_FileIterator&) = delete;
1568 
1569 public:
1570 
1571  //////////////////////////////////////////////////////////////////////////////////
1572  //
1573  // Iteratation initialization tools
1574  //
1575  /*
1576  Description:
1577  Initialize where the search should occur.
1578  Parameters:
1579  directory_name - [in]
1580  The directory to look in.
1581  item_name_filter - [in]
1582  If this paramter is null, then the iteration
1583  includes all names in the directory.
1584  The item name to search for. This parameter can
1585  include wildcard characters, such as an
1586  asterisk (*) or a question mark (?). For example,
1587  "\rootdir\subdir\*.*" will iterate all files in
1588  the \rootdir\subdir\ directory.
1589 
1590  Returns:
1591  true:
1592  The iterator is set to the first item.
1593  false:
1594  There are no matching items.
1595 
1596  Remarks:
1597  Calling FirstItem() is eqivalent to calling Initialize() and then calling NextItem().
1598  */
1599  bool Initialize(
1600  const wchar_t* directory_name
1601  );
1602  bool Initialize(
1603  const wchar_t* directory_name,
1604  const wchar_t* item_name_filter
1605  );
1606  bool Initialize(
1607  const char* directory_name
1608  );
1609  bool Initialize(
1610  const char* directory_name,
1611  const char* item_name_filter
1612  );
1613 
1614  //////////////////////////////////////////////////////////////////////////////////
1615  //
1616  // Iteratation iteration tools
1617  //
1618 
1619  /*
1620  Description:
1621  Find the first matching item in the directory.
1622  Example:
1623  // Iterate through the files in a directory named "\rootdir\subdir"
1624  ON_FileIterator fit;
1625  fit.Initialize("\\rootdir\\subdir");
1626  for ( bool bHaveItem = fit.FirstItem(); bHaveItem; bHaveItem = fit.NextItem() )
1627  {
1628  if ( fit.CurrentFileIsDirectory() )
1629  continue;
1630  ON_String fullpath = fit.CurrentItemFullPathName();
1631  FILE* fp = ON_FileStream::Open(fullpath,"rb");
1632  if ( 0 == fp )
1633  {
1634  continue;
1635  }
1636  ...
1637  ON_FileStream::Close(fp);
1638  fp = 0;
1639  }
1640  }
1641 
1642  Returns:
1643  true:
1644  The iterator is set to the first item.
1645  false:
1646  There are no matching items.
1647  */
1648  bool FirstItem();
1649 
1650  /*
1651  Description:
1652  Find the next matching item in the directory.
1653  Returns:
1654  true:
1655  The iterator was advanced to the next item.
1656  false:
1657  There are no more matching items.
1658  */
1659  bool NextItem();
1660 
1661  /*
1662  Description:
1663  Reset this ON_FileIterator so it can be used again.
1664  */
1665  void Reset();
1666 
1667  //////////////////////////////////////////////////////////////////////////////////
1668  //
1669  // Current item query
1670  //
1671 
1672  /*
1673  Returns:
1674  Current file or directory name in the directory being iterated.
1675  Use CurrentFullPathItemName() to get the full path name.
1676  */
1677  const ON_wString CurrentItemName() const;
1678 
1679  /*
1680  Returns:
1681  The name of the directory being iterated.
1682  */
1683  const ON_wString DirectoryName() const;
1684 
1685  /*
1686  Returns:
1687  If the current item is a file, then the size of the file in bytes is returned.
1688  If the current item is a directory, then 0 is returned.
1689  */
1690  ON__UINT64 CurrentItemSize() const;
1691 
1692  /*
1693  Returns
1694  true if the current item is a directory.
1695  */
1696  bool CurrentItemIsDirectory() const;
1697 
1698  /*
1699  Returns
1700  true if the current item is a file.
1701  */
1702  bool CurrentItemIsFile() const;
1703 
1704  /*
1705  Returns
1706  true if the current file or directory is hidden.
1707  This means its name begins with a '.' or it's
1708  Windows hidden attribute is true.
1709  */
1710  bool CurrentItemIsHidden() const;
1711 
1712  const ON_wString CurrentItemFullPathName() const;
1713 
1714  /*
1715  Returns:
1716  File last modified time in seconds since January 1, 1970
1717  Remarks:
1718  The times returned by ON_FileIterator can differ from the time
1719  returned by ON_FileStream::GetFileInformation().
1720  */
1721  ON__UINT64 CurrentItemLastModifiedTime() const;
1722 
1723  /*
1724  Returns:
1725  Number of matching items iterated through.
1726  */
1727  ON__UINT64 CurrentItemCount() const;
1728 
1729 private:
1730  ON__UINT32 m_state = 0; // 0 unset, 1=initialized, 2 = itereation in progress. 3 = iteration finished.
1731  ON__UINT32 m_reserved = 0;
1732 
1733  ON_wString m_directory; // directory passed to Initialize() or FirstItem
1734  ON_wString m_item_name_filter; // item_name_filter passed to Initialize() or FirstItem
1735  ON_wString m_item_name; // Current item name.
1736 
1737  // cached full path name
1738  // m_directory + directory separator + m_item_name
1739  // (length = 0 if it is not set)
1740  mutable ON_wString m_full_path_name;
1741 
1742  ON__UINT64 m_count = 0; // number of items iterated through so far
1743  class ON_DirectoryIteratorImpl* m_impl = nullptr;
1744 };
1745 
1746 #endif
PathId
ids used by ON_FileSystemPath::GetPath()
Definition: opennurbs_file_utilities.h:511
ON_UUID is a 16 byte universally unique identifier.
Definition: opennurbs_uuid.h:32
static const ON_SHA1_Hash EmptyContentHash
Definition: opennurbs_sha1.h:23
Definition: opennurbs_sha1.h:19
Definition: opennurbs_string.h:2020
FindFilePreference
Defines options for file search.
Definition: opennurbs_file_utilities.h:1180
Definition: opennurbs_file_utilities.h:19
Definition: opennurbs_string.h:852
Definition: opennurbs_file_utilities.h:561
Definition: opennurbs_file_utilities.h:762
Status
Enumerates a list of file statuses.
Definition: opennurbs_file_utilities.h:1132
CompareResult
ON_ContentHash::Compare are the possible results of calling ON_ContentHash::CompareFile().
Definition: opennurbs_file_utilities.h:960
Definition: opennurbs_textlog.h:20
Definition: opennurbs_archive.h:1783
Status of a the full path is not known.
static const ON_SHA1_Hash ZeroDigest
Definition: opennurbs_sha1.h:22
Definition: opennurbs_file_utilities.h:109
Iterates through every item in a file system directory.
Definition: opennurbs_file_utilities.h:1480
Definition: opennurbs_file_utilities.h:1125