1 /*
2  * Modification History
3  *
4  * 2001-February-11		Jason Rohrer
5  * Created.
6  *
7  * 2001-February-25		Jason Rohrer
8  * Fixed file name bugs in length and existence functions.
9  *
10  * 2001-May-11   Jason Rohrer
11  * Added a missing include.
12  *
13  * 2001-November-3   Jason Rohrer
14  * Added a function for checking if a file is a directory.
15  * Added a function for getting the child files of a directory.
16  * Added a function for getting a pathless file name.
17  *
18  * 2001-November-13   Jason Rohrer
19  * Made name length parameter optional in constructor.
20  * Made return length parameter optional in name getting functions.
21  *
22  * 2001-November-17   Jason Rohrer
23  * Added a functions for removing a file and for copying a file.
24  *
25  * 2002-March-11   Jason Rohrer
26  * Added destruction comment to getFullFileName().
27  *
28  * 2002-March-13   Jason Rohrer
29  * Changed mName to be \0-terminated to fix interaction bugs with Path.
30  * Fixed a missing delete.
31  * Added a function for creating a directory.
32  *
33  * 2002-March-31   Jason Rohrer
34  * Fixed some bad syntax.
35  *
36  * 2002-April-6    Jason Rohrer
37  * Replaced use of strdup.
38  *
39  * 2002-April-8    Jason Rohrer
40  * Fixed fopen bug.
41  *
42  * 2002-April-11    Jason Rohrer
43  * Fixed a memory leak.
44  * Fixed a casting error.
45  *
46  * 2002-June-28    Jason Rohrer
47  * Added a function for copying a file class.
48  *
49  * 2002-August-3    Jason Rohrer
50  * Added a function for getting the parent file.
51  *
52  * 2002-August-5    Jason Rohrer
53  * Used an unused error variable.
54  *
55  * 2002-September-11   Jason Rohrer
56  * Added return value to remove.
57  *
58  * 2003-January-27   Jason Rohrer
59  * Added a function for reading file contents.
60  *
61  * 2003-February-3   Jason Rohrer
62  * Added a function for writing a string to a file.
63  *
64  * 2003-March-13   Jason Rohrer
65  * Added a function for getting a child file from a directory.
66  *
67  * 2003-June-2   Jason Rohrer
68  * Fixed parent directory behavior when current file is root directory.
69  * Fixed a bug in getting child files of root directory.
70  *
71  * 2003-November-6   Jason Rohrer
72  * Added function for getting last modification time.
73  *
74  * 2003-November-10   Jason Rohrer
75  * Changed to use platform-dependent makeDirectory function.
76  *
77  * 2004-January-4   Jason Rohrer
78  * Added recursive child file functions.
79  *
80  * 2005-August-29   Jason Rohrer
81  * Fixed an uninitialized variable warning.
82  *
83  * 2010-March-6   Jason Rohrer
84  * Added versions of writeToFile readFileContents for binary data.
85  *
86  * 2010-April-23   Jason Rohrer
87  * Fixed a string length bug when line ends are Windows.
88  *
89  * 2010-May-14    Jason Rohrer
90  * String parameters as const to fix warnings.
91  */
92 
93 
94 
95 #include "minorGems/common.h"
96 
97 
98 
99 #ifndef FILE_CLASS_INCLUDED
100 #define FILE_CLASS_INCLUDED
101 
102 #include <sys/stat.h>
103 #include <stdio.h>
104 #include <string.h>
105 
106 #include <dirent.h>
107 
108 #include "Path.h"
109 
110 #include "minorGems/util/SimpleVector.h"
111 #include "minorGems/util/stringUtils.h"
112 
113 
114 
115 /**
116  * File interface.  Provides access to information about a
117  * file.
118  *
119  * @author Jason Rohrer
120  */
121 class File {
122 
123 	public:
124 
125 		/**
126 		 * Constructs a file.
127 		 *
128 		 * @param inPath the path for this file.
129 		 *   Is destroyed when this class is destroyed.
130 		 *   Pass in NULL to specify
131 		 *   no path (the current working directory).
132 		 * @param inName the name of the file to open.
133 		 *   Must be destroyed by caller if not const.
134 		 *   Copied internally.
135 		 * @param inNameLength length of the name in chars,
136 		 *   or -1 to use the c-string length of inName
137 		 *   (assuming that inName is \0-terminated).
138 		 *   Defaults to -1.
139 		 */
140 		File( Path *inPath, const char *inName, int inNameLength = -1 );
141 
142 
143 		~File();
144 
145 
146 
147 		/**
148 		 * Gets whether this file is a directory.
149 		 *
150 		 * @return true iff this file is a directory.
151 		 */
152 		char isDirectory();
153 
154 
155 
156         /**
157          * Makes a directory in the location of this file.
158          *
159          * Can only succeed if exists() is false.
160          *
161          * @return true iff directory creation succeeded.
162          */
163         char makeDirectory();
164 
165 
166 
167 		/**
168 		 * Gets the files contained in this file if it is a directory.
169          *
170 		 * @param outNumFiles pointer to where the number of
171 		 *   files will be returned.
172 		 *
173 		 * @return an array of files, or NULL if this
174 		 *    file is not a directory, is an empty directory, or doesn't exist.
175 		 *    Must be destroyed by caller if non-NULL.
176 		 */
177 		File **getChildFiles( int *outNumFiles );
178 
179 
180 
181         /**
182 		 * Gets the files contained in this file if it is a directory and
183          * recursively in subdirectories of this file.
184 		 *
185 		 * @param inDepthLimit the maximum subdirectory depth to recurse into.
186          *   If inDepthLimit is 0, then only child files in this directory
187          *   will be returned.
188 		 * @param outNumFiles pointer to where the number of
189 		 *   files will be returned.
190 		 *
191 		 * @return an array of files, or NULL if this
192 		 *    file is not a directory, is an empty directory (or a directory
193          *    containing empty subdirectories), or doesn't exist.
194 		 *    Must be destroyed by caller if non-NULL.
195 		 */
196 		File **getChildFilesRecursive( int inDepthLimit, int *outNumFiles );
197 
198 
199 
200         /**
201          * Gets a child of this directory.
202          *
203          * @param inChildFileName the name of the child file.
204          *   Must be destroyed by caller if non-const.
205          *
206          * @return the child file (even if it does not exist), or NULL if
207          *   this file is not a directory.
208          *   Must be destroyed by caller if non-NULL.
209          */
210         File *getChildFile( const char *inChildFileName );
211 
212 
213 
214         /**
215          * Gets the parent directory of this file.
216          *
217          * @return the parent directory of this file.
218          *    Must be destroyed by caller.
219          */
220         File *getParentDirectory();
221 
222 
223 
224 		/**
225 		 * Gets the length of this file.
226 		 *
227 		 * @return the length of this file in bytes.  Returns
228 		 *   0 if the file does not exist.
229 		 */
230 		long getLength();
231 
232 
233 		/**
234 		 * Gets whether a file exists.
235 		 *
236 		 * @return true if the file exists.
237 		 */
238 		char exists();
239 
240 
241 
242 		/**
243 		 * Gets the last modification time of this file.
244 		 *
245 		 * @return the modification time in seconds based on the
246          *   system clock.  Returns 0 if the file does not exist.
247 		 */
248 		unsigned long getModificationTime();
249 
250 
251 
252 		/**
253 		 * Removes this file from the disk, if it exists.
254          *
255          * @return true iff the remove succeeded, false if the removal
256          *   fails or the file does not exist.
257 		 */
258 		char remove();
259 
260 
261 
262         /**
263          * Copies this file object (does not copy the file described by
264          * this object).
265          *
266          * @return a deep copy of this file object.
267          */
268         File *copy();
269 
270 
271 
272 		/**
273 		 * Copies the contents of this file into another file.
274 		 *
275 		 * @param inDestination the file to copy this file into.
276 		 *   If it exists, it will be overwritten.
277 		 *   If it does not exist, it will be created.
278 		 *   Must be destroyed by caller.
279 		 * @param inBlockSize the block size to use when copying.
280 		 *   Defaults to blocks of 5000 bytes.
281 		 */
282 		void copy( File *inDestination, long inBlockSize = 5000 );
283 
284 
285 
286 		/**
287 		 * Gets the full-path file name sufficient
288 		 * to access this file from the current working
289 		 * directory.
290 		 *
291 		 * @param outLength pointer to where the name length, in
292 		 *   characters, will be returned.  Set to NULL to ignore
293 		 *   the output length.  Defaults to NULL.
294 		 *
295 		 * @return the full path file name for this file,
296 		 *   in platform-specific form.  Must be destroyed by caller.
297 		 *   The returned string is '\0' terminated, but this
298 		 *   extra character is not included in the length.
299 		 *   Must be destroyed by caller.
300 		 */
301 		char *getFullFileName( int *outLength = NULL );
302 
303 
304 
305 		/**
306 		 * Gets the pathless name of this file.
307 		 *
308 		 * @param outLength pointer to where the name length, in
309 		 *   characters, will be returned.  Set to NULL to ignore
310 		 *   the output length.  Defaults to NULL.
311 		 *
312 		 * @return the name of this file.  Must be destroyed by caller.
313 		 */
314 		char *getFileName( int *outLength = NULL );
315 
316 
317 
318         /**
319          * Reads the contents of this file.
320          *
321          * @return a \0-terminated string containing the file contents,
322          *   or NULL if reading the file into memory failed.
323          *   Must be destroyed by caller.
324          */
325         char *readFileContents();
326 
327 
328 
329         /**
330          * Reads the contents of this file.
331          *
332          * @param outLength pointer to where the return array length should
333          *   be returned.
334          * @param inTextMode true to open the file as text, false as binary.
335          *   Defaults to false.
336          *
337          * @return an array containing the binary file contents,
338          *   or NULL if reading the file into memory failed.
339          *   Must be destroyed by caller.
340          */
341         unsigned char *readFileContents( int *outLength,
342                                          char inTextMode = false );
343 
344 
345 
346         /**
347          * Writes a string to this file.
348          *
349          * @param inString the \0-terminated string to write.
350          *   Must be destroyed by caller if non-const.
351          *
352          * @return true if the file was written to successfully, or
353          *   false otherwise.
354          */
355         char writeToFile( const char *inString );
356 
357 
358         /**
359          * Writes a binary data to this file.
360          *
361          * @param inData the data to write.
362          *   Must be destroyed by caller if non-const.
363          * @param inLength length of inData.
364          *
365          * @return true if the file was written to successfully, or
366          *   false otherwise.
367          */
368         char writeToFile( unsigned char *inData, int inLength );
369 
370 
371 
372 	private:
373 		Path *mPath;
374 		char *mName;
375 		int mNameLength;
376 
377 
378 
379         /**
380 		 * Gets the files contained in this file if it is a directory and
381          * recursively in subdirectories of this file.
382 		 *
383 		 * @param inDepthLimit the maximum subdirectory depth to recurse into.
384          *   If inDepthLimit is 0, then only child files in this directory
385          *   will be returned.
386 		 * @param inResultVector vector to add the discovered files to.
387          *   Must be destroyed by caller.
388 		 */
389 		void getChildFilesRecursive( int inDepthLimit,
390                                      SimpleVector<File *> *inResultVector );
391 
392 
393 
394 	};
395 
396 
397 
File(Path * inPath,const char * inName,int inNameLength)398 inline File::File( Path *inPath, const char *inName, int inNameLength  )
399 	: mPath( inPath ), mNameLength( inNameLength ) {
400 
401 	if( inNameLength == -1 ) {
402 		inNameLength = strlen( inName );
403 		mNameLength = inNameLength;
404 		}
405 
406 	// copy name internally
407 	mName = stringDuplicate( inName );
408 
409 	}
410 
411 
412 
~File()413 inline File::~File() {
414 	delete [] mName;
415 
416 	if( mPath != NULL ) {
417 		delete mPath;
418 		}
419 	}
420 
421 
422 
getLength()423 inline long File::getLength() {
424 	struct stat fileInfo;
425 
426 	// get full file name
427 	int length;
428 	char *stringName = getFullFileName( &length );
429 
430 	int statError = stat( stringName, &fileInfo );
431 
432 	delete [] stringName;
433 
434 	if( statError == 0 ) {
435 		return fileInfo.st_size;
436 		}
437 	else {
438 		// file does not exist
439 		return 0;
440 		}
441 	}
442 
443 
444 
isDirectory()445 inline char File::isDirectory() {
446 	struct stat fileInfo;
447 
448 	// get full file name
449 	int length;
450 	char *stringName = getFullFileName( &length );
451 
452 	int statError = stat( stringName, &fileInfo );
453 
454 	delete [] stringName;
455 
456         if( statError == -1 ) {
457             return false;
458             }
459 	else {
460             return S_ISDIR( fileInfo.st_mode );
461             }
462 	}
463 
464 
465 
getChildFiles(int * outNumFiles)466 inline File **File::getChildFiles( int *outNumFiles ) {
467 
468 	int length;
469 	char *stringName = getFullFileName( &length );
470 
471 	DIR *directory = opendir( stringName );
472 
473 	if( directory != NULL ) {
474 
475 		SimpleVector< File* > *fileVector = new SimpleVector< File* >();
476 
477 		struct dirent *entry = readdir( directory );
478 
479 		if( entry == NULL ) {
480 			delete fileVector;
481 
482 			closedir( directory );
483 
484 			delete [] stringName;
485 
486 			*outNumFiles = 0;
487 			return NULL;
488 			}
489 
490 
491 		while( entry != NULL ) {
492 			// skip parentdir and thisdir files, if they occur
493 			if( strcmp( entry->d_name, "." ) &&
494 				strcmp( entry->d_name, ".." ) ) {
495 
496 				Path *newPath;
497 
498 				if( mPath != NULL ) {
499 					newPath = mPath->append( mName );
500 					}
501 				else {
502 
503                     if( Path::isRoot( mName ) ) {
504                         // use name as a string path
505                         newPath = new Path( mName );
506                         }
507                     else {
508                         char **folderPathArray = new char*[1];
509                         folderPathArray[0] = mName;
510 
511                         // a non-absolute path to this directory's contents
512                         int numSteps = 1;
513                         char absolute = false;
514                         newPath =
515                             new Path( folderPathArray, numSteps,
516                                       absolute );
517 
518                         delete [] folderPathArray;
519                         }
520                     }
521 
522 				// safe to pass d_name in directly because it is copied
523 				// internally by the constructor
524 
525 				fileVector->push_back(
526 					new File( newPath,
527 							  entry->d_name,
528 							  strlen( entry->d_name ) ) );
529 				}
530 
531 			entry = readdir( directory );
532 			}
533 
534 		// now we have a vector full of this directory's files
535 		int vectorSize = fileVector->size();
536 
537 		*outNumFiles = vectorSize;
538 
539 		if( vectorSize == 0 ) {
540 			delete fileVector;
541 
542 			closedir( directory );
543 
544 			delete [] stringName;
545 
546 			return NULL;
547 			}
548 		else {
549 			File **returnFiles = new File *[vectorSize];
550 			for( int i=0; i<vectorSize; i++ ) {
551 				returnFiles[i] = *( fileVector->getElement( i ) );
552 				}
553 
554 			delete fileVector;
555 
556 			closedir( directory );
557 
558 			delete [] stringName;
559 
560 			return returnFiles;
561 			}
562 		}
563 	else {
564 		delete [] stringName;
565 
566 		*outNumFiles = 0;
567 		return NULL;
568 		}
569 
570 
571 
572 	}
573 
574 
575 
getChildFilesRecursive(int inDepthLimit,int * outNumFiles)576 inline File **File::getChildFilesRecursive( int inDepthLimit,
577                                             int *outNumFiles ) {
578 
579     // create a vector for results
580     SimpleVector<File *> *resultVector = new SimpleVector<File *>();
581 
582     // call the recursive function
583     getChildFilesRecursive( inDepthLimit, resultVector );
584 
585 
586     // extract results from vector
587     File **resultArray = NULL;
588 
589     int numResults = resultVector->size();
590 
591     if( numResults > 0 ) {
592         resultArray = resultVector->getElementArray();
593         }
594 
595     delete resultVector;
596 
597 
598 
599     *outNumFiles = numResults;
600     return resultArray;
601     }
602 
603 
604 
getChildFilesRecursive(int inDepthLimit,SimpleVector<File * > * inResultVector)605 inline void File::getChildFilesRecursive(
606     int inDepthLimit,
607     SimpleVector<File *> *inResultVector ) {
608 
609     // get our child files
610     int numChildren;
611     File **childFiles = getChildFiles( &numChildren );
612 
613     if( childFiles != NULL ) {
614 
615         // for each child, add it to vector and
616         // recurse into it if it is a directory
617 
618         for( int i=0; i<numChildren; i++ ) {
619 
620             File *child = childFiles[i];
621 
622             // add it to results vector
623             inResultVector->push_back( child );
624 
625             if( child->isDirectory() ) {
626                 // skip recursion if we have hit our depth limit
627                 if( inDepthLimit > 0 ) {
628                     // recurse into this subdirectory
629                     child->getChildFilesRecursive( inDepthLimit - 1,
630                                                    inResultVector );
631                     }
632                 }
633             }
634 
635         delete [] childFiles;
636         }
637     }
638 
639 
640 
getChildFile(const char * inChildFileName)641 inline File *File::getChildFile( const char *inChildFileName ) {
642     // make sure we are a directory
643     if( !isDirectory() ) {
644         return NULL;
645         }
646 
647     // get a path to this directory
648     Path *newPath;
649 
650     if( mPath != NULL ) {
651         newPath = mPath->append( mName );
652         }
653     else {
654 
655         char **folderPathArray = new char*[1];
656         folderPathArray[0] = mName;
657 
658         // a non-absolute path to this directory's contents
659         int numSteps = 1;
660         char absolute = false;
661         newPath =
662             new Path( folderPathArray, numSteps,
663                       absolute );
664 
665         delete [] folderPathArray;
666         }
667 
668     return new File( newPath, inChildFileName );
669     }
670 
671 
672 
getParentDirectory()673 inline File *File::getParentDirectory() {
674 
675     if( mPath != NULL ) {
676 
677         char *parentName;
678 
679         Path *parentPath;
680 
681         if( strcmp( mName, ".." ) == 0 ) {
682             // already a parent dir reference
683             // append one more parent dir reference with parentName below
684             parentPath = mPath->append( ".." );
685 
686             parentName = stringDuplicate( ".." );
687             }
688         else {
689             // not a parent dir reference, so we can truncate
690             parentPath = mPath->truncate();
691 
692             parentName = mPath->getLastStep();
693             }
694 
695         File *parentFile = new File( parentPath, parentName );
696 
697         delete [] parentName;
698 
699         return parentFile;
700         }
701     else {
702         if( Path::isRoot( mName ) ) {
703             // we are already at the root
704             return new File( NULL, mName );
705             }
706         else {
707             // append parent dir symbol to path
708             char **parentPathSteps = new char*[1];
709             parentPathSteps[0] = mName;
710 
711             Path *parentPath = new Path( parentPathSteps, 1, false );
712 
713             const char *parentName = "..";
714 
715             File *parentFile = new File( parentPath, parentName );
716 
717             delete [] parentPathSteps;
718 
719             return parentFile;
720             }
721         }
722     }
723 
724 
725 
exists()726 inline char File::exists() {
727 	struct stat fileInfo;
728 
729 	// get full file name
730 	int length;
731 	char *stringName = getFullFileName( &length );
732 
733 	int statError = stat( stringName, &fileInfo );
734 
735 	delete [] stringName;
736 
737 	if( statError == 0 ) {
738 		return true;
739 		}
740 	else {
741 		// file does not exist
742 		return false;
743 		}
744 	}
745 
746 
747 
getModificationTime()748 inline unsigned long File::getModificationTime() {
749     struct stat fileInfo;
750 
751 	// get full file name
752 	int length;
753 	char *stringName = getFullFileName( &length );
754 
755 	int statError = stat( stringName, &fileInfo );
756 
757 	delete [] stringName;
758 
759 	if( statError == 0 ) {
760 		return fileInfo.st_mtime;
761 		}
762 	else {
763 		// file does not exist
764 		return 0;
765 		}
766     }
767 
768 
769 
remove()770 inline char File::remove() {
771     char returnVal = false;
772 
773     if( exists() ) {
774 		char *stringName = getFullFileName();
775 
776 		int error = ::remove( stringName );
777 
778         if( error == 0 ) {
779             returnVal = true;
780             }
781 
782 		delete [] stringName;
783 		}
784 
785     return returnVal;
786 	}
787 
788 
789 
copy()790 inline File *File::copy() {
791     Path *pathCopy = NULL;
792 
793     if( mPath != NULL ) {
794         pathCopy = mPath->copy();
795         }
796 
797     return new File( pathCopy, mName );
798     }
799 
800 
801 
copy(File * inDestination,long inBlockSize)802 inline void File::copy( File *inDestination, long inBlockSize ) {
803 	char *thisFileName = getFullFileName();
804 	char *destinationFileName = inDestination->getFullFileName();
805 
806 	FILE *thisFile = fopen( thisFileName, "rb" );
807 	FILE *destinationFile = fopen( destinationFileName, "wb" );
808 
809 	long length = getLength();
810 
811 	long bytesCopied = 0;
812 
813 	char *buffer = new char[ inBlockSize ];
814 
815 	while( bytesCopied < length ) {
816 
817 		long bytesToCopy = inBlockSize;
818 
819 		// end of file case
820 		if( length - bytesCopied < bytesToCopy ) {
821 			bytesToCopy = length - bytesCopied;
822 			}
823 
824 		fread( buffer, 1, bytesToCopy, thisFile );
825 		fwrite( buffer, 1, bytesToCopy, destinationFile );
826 
827 		bytesCopied += bytesToCopy;
828 		}
829 
830 	fclose( thisFile );
831 	fclose( destinationFile );
832 
833 	delete [] buffer;
834 	delete [] thisFileName;
835 	delete [] destinationFileName;
836 	}
837 
838 
839 
getFileName(int * outLength)840 inline char *File::getFileName( int *outLength ) {
841 	char *returnName = stringDuplicate( mName );
842 
843 	if( outLength != NULL ) {
844 		*outLength = mNameLength;
845 		}
846 
847 	return returnName;
848 	}
849 
850 
851 
getFullFileName(int * outLength)852 inline char *File::getFullFileName( int *outLength ) {
853 	int length = mNameLength;
854 
855     int pathLength = 0;
856 	char *path = NULL;
857 	if( mPath != NULL ) {
858 		path = mPath->getPathString( &pathLength );
859 
860 		length += pathLength;
861 		}
862 
863 	// extra character for '\0' termination
864 	char *returnString = new char[ length + 1 ];
865 
866 	if( path != NULL ) {
867 		memcpy( returnString, path, pathLength );
868 		memcpy( &( returnString[pathLength] ), mName, mNameLength );
869 
870 		delete [] path;
871 		}
872 	else {
873 		// no path, so copy the name directly in
874 		memcpy( returnString, mName, mNameLength );
875 		}
876 
877 	// terminate the string
878 	returnString[ length ] = '\0';
879 
880 
881 	if( outLength != NULL ) {
882 		*outLength = length;
883 		}
884 
885 	return returnString;
886 	}
887 
888 
889 
890 #include "minorGems/io/file/FileInputStream.h"
891 #include "minorGems/io/file/FileOutputStream.h"
892 
893 
894 
readFileContents()895 inline char *File::readFileContents() {
896 
897     int length;
898     // text mode!
899     unsigned char *data = readFileContents( &length, true );
900 
901     if( data == NULL ) {
902         return NULL;
903         }
904 
905     char *dataString = new char[ length + 1 ];
906 
907     memcpy( dataString, data, length );
908     dataString[ length ] = '\0';
909 
910     delete [] data;
911     return dataString;
912     }
913 
914 
915 
readFileContents(int * outLength,char inTextMode)916 inline unsigned char *File::readFileContents( int *outLength,
917                                               char inTextMode ) {
918 
919     if( exists() ) {
920         int length = getLength();
921 
922         unsigned char *returnData = new unsigned char[ length ];
923 
924         if( returnData != NULL ) {
925             FileInputStream *input = new FileInputStream( this, inTextMode );
926             int numRead = input->read( returnData, length );
927 
928             delete input;
929 
930             // in text mode, read length might not equal binary file length,
931             // due to line end conversion
932             if( numRead == length ||
933                 ( inTextMode && numRead >= 0 ) ) {
934                 *outLength = numRead;
935                 return returnData;
936                 }
937             else {
938                 delete [] returnData;
939                 return NULL;
940                 }
941             }
942         else {
943             // failed to allocate this much memory
944             return NULL;
945             }
946         }
947     else {
948         return NULL;
949         }
950 
951     }
952 
953 
954 
writeToFile(const char * inString)955 inline char File::writeToFile( const char *inString ) {
956     return writeToFile( (unsigned char *)inString, strlen( inString ) );
957     }
958 
959 
960 
writeToFile(unsigned char * inData,int inLength)961 inline char File::writeToFile( unsigned char *inData, int inLength ) {
962     FileOutputStream *output = new FileOutputStream( this );
963 
964     long numWritten = output->write( inData, inLength );
965 
966     delete output;
967 
968     if( inLength == numWritten ) {
969         return true;
970         }
971     else {
972         return false;
973         }
974 
975     }
976 
977 
978 
979 #include "Directory.h"
980 
981 
982 
makeDirectory()983 inline char File::makeDirectory() {
984     if( exists() ) {
985         return false;
986         }
987     else {
988         return Directory::makeDirectory( this );
989         }
990     }
991 
992 
993 
994 #endif
995