git.fiddlerwoaroof.com
Source/NSData_HMext.m
0c532ca4
 //  NSData_HMext.m
 //
 //  Created by John Wiseman on 9/6/05.
 //  Copyright 2005 John Wiseman.
 //
 //  Licensed under the MIT license--see the accompanying LICENSE.txt
 //  file.
 
 
2fbaf64c
 #import "NSData_HMext.h"
0c532ca4
 #import "DebugLog.h"
 
 
 // Reads up to maxLen bytes from a file into a buffer.  The
 // buffer is allocated and returned in buf, while the number of
 // bytes read is returned in len.
 //
 // More or less taken from GnuStep's implementation of NSData.
 
2fbaf64c
 static BOOL readContentsOfFile(NSString* path, void** buf, size_t maxLen, size_t* len, NSZone* zone)
0c532ca4
 {
0223e6a6
     const char	*thePath = 0;
     FILE		*theFile = 0;
     void		*tmp = 0;
2fbaf64c
     size_t			c;
     size_t		fileLength;
0223e6a6
     
     thePath = [path fileSystemRepresentation];
     if (thePath == 0)
0c532ca4
     {
0223e6a6
         //      NSWarnFLog(@"Open (%@) attempt failed - bad path", path);
         return NO;
0c532ca4
     }
0223e6a6
     
     theFile = fopen(thePath, "rb");
     
     if (theFile == 0)		/* We failed to open the file. */
0c532ca4
     {
0223e6a6
         //      NSWarnFLog(@"Open (%@) attempt failed - %s", path,
         //      GSLastErrorStr(errno));
         goto failure;
0c532ca4
     }
0223e6a6
     
     /*
      *	Seek to the end of the file.
      */
     c = fseek(theFile, 0L, SEEK_END);
     if (c != 0)
0c532ca4
     {
0223e6a6
         //      NSWarnFLog(@"Seek to end of file (%@) failed - %s", path,
         //      GSLastErrorStr(errno));
         goto failure;
0c532ca4
     }
0223e6a6
     
     /*
      *	Determine the length of the file (having seeked to the end of the
      *	file) by calling ftell().
      */
     fileLength = ftell(theFile);
     if (fileLength == -1)
0c532ca4
     {
0223e6a6
         //      NSWarnFLog(@"Ftell on %@ failed - %s", path,
         //      GSLastErrorStr(errno));
         goto failure;
0c532ca4
     }
0223e6a6
     
     /*
      *	Rewind the file pointer to the beginning, preparing to read in
      *	the file.
      */
     c = fseek(theFile, 0L, SEEK_SET);
     if (c != 0)
0c532ca4
     {
0223e6a6
         //      NSWarnFLog(@"Fseek to start of file (%@) failed - %s", path,
         //      GSLastErrorStr(errno));
         goto failure;
0c532ca4
     }
0223e6a6
     
     if (fileLength == 0)
0c532ca4
     {
0223e6a6
         unsigned char	buf[BUFSIZ];
2fbaf64c
         size_t bytesToRead = maxLen;
0223e6a6
         /*
          * Special case ... a file of length zero may be a named pipe or some
          * file in the /proc filesystem, which will return us data if we read
          * from it ... so we try reading as much as we can, up to the specified
          * limit.
          */
         while ((c = fread(buf, 1, (bytesToRead < BUFSIZ) ? bytesToRead : BUFSIZ, theFile)) != 0)
         {
             if (tmp == 0)
             {
                 tmp = NSZoneMalloc(zone, c);
             }
             else
             {
                 tmp = NSZoneRealloc(zone, tmp, fileLength + c);
             }
             if (tmp == 0)
             {
                 //	      NSLog(@"Malloc failed for file (%@) of length %d - %s", path,
                 //		fileLength + c, GSLastErrorStr(errno));
                 goto failure;
             }
             memcpy(tmp + fileLength, buf, c);
             fileLength += c;
             bytesToRead -= c;
         }
         if (fileLength == maxLen)
         {
             DebugLog(DEBUG_LEVEL_DEBUG, @"Truncated indexing of %s to %d bytes", thePath, maxLen);
         }
0c532ca4
     }
0223e6a6
     else
0c532ca4
     {
0223e6a6
         if (fileLength > maxLen)
         {
             fileLength = maxLen;
             DebugLog(DEBUG_LEVEL_DEBUG, @"Truncated indexing of %s to %d bytes", thePath, maxLen);
         }
         tmp = NSZoneMalloc(zone, fileLength);
         if (tmp == 0)
         {
             //	  NSLog(@"Malloc failed for file (%@) of length %d - %s", path,
             //	  fileLength, GSLastErrorStr(errno));
             goto failure;
         }
         
         c = fread(tmp, 1, fileLength, theFile);
         if (c != (int)fileLength)
         {
             //	  NSWarnFLog(@"read of file (%@) contents failed - %s", path,
             //	  GSLastErrorStr(errno));
             goto failure;
         }
0c532ca4
     }
0223e6a6
     
     *buf = tmp;
     *len = fileLength;
     fclose(theFile);
     return YES;
     
     /*
      *	Just in case the failure action needs to be changed.
      */
0c532ca4
 failure:
0223e6a6
     if (tmp != 0)
0c532ca4
     {
0223e6a6
         NSZoneFree(zone, tmp);
0c532ca4
     }
0223e6a6
     if (theFile != 0)
     {
         fclose(theFile);
     }
     return NO;
0c532ca4
 }
 
 @implementation NSData (NSData_Extensions)
 
 
 /**
  * Returns a data object encapsulating the contents of the specified file
  * (but only up to the first theMaxSize bytes of the file).
  * Invokes -initWithContentsOfFile:
  *
  * Based on GnuStep's -[NSData dataWithContentsOfFile].
  */
 + (id) dataWithContentsOfFile: (NSString*)path maxSize:(int)theMaxSize error:(NSError**)error
 {
0223e6a6
     NSData	*d;
     
     d = [NSData allocWithZone: NSDefaultMallocZone()];
     d = [d initWithContentsOfFile: path maxSize:theMaxSize error:error];
     return [d autorelease];
0c532ca4
 }
 
 
 /**
  * Initializes the receiver with up to theMaxSize bytes of the specified file.
  * Returns the resulting object.
  * Returns nil if the file does not exist or can not be read for some reason,
  * in which case error information will (probably) be returned as well.
  *
  * Based on GnuStep's -[NSData initWithContentsOfFile].
  */
 - (id) initWithContentsOfFile: (NSString*)path maxSize:(int)theMaxSize error:(NSError**)error
 {
0223e6a6
     void		*fileBytes = NULL;
2fbaf64c
     size_t	fileLength = 0;
0223e6a6
     NSZone	*zone;
     
     zone = NSDefaultMallocZone();
     if (readContentsOfFile(path, &fileBytes, theMaxSize, &fileLength, zone) == NO)
0c532ca4
     {
0223e6a6
         if (error)
         {
             NSNumber *errorCode = [NSNumber numberWithInt:errno];
2fbaf64c
             NSString *errorDescription = [NSString stringWithCString:strerror(errno) encoding:NSUTF8StringEncoding];
0223e6a6
             NSString* errorPath = path;
             NSMutableDictionary *errorAttribs = [NSMutableDictionary dictionaryWithCapacity:2];
             [errorAttribs setObject:errorCode forKey:@"Errno"];
             [errorAttribs setObject:errorDescription forKey:@"Description"];
             [errorAttribs setObject:errorPath forKey:@"Path"];
             *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:errorAttribs];
         }
         [self dealloc];
         return nil;
0c532ca4
     }
0223e6a6
     else
0c532ca4
     {
0223e6a6
         self = [self initWithBytesNoCopy:fileBytes length:fileLength freeWhenDone:YES];
0c532ca4
     }
0223e6a6
     return self;
0c532ca4
 }
 
 @end