mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 16:50:58 +00:00
Tidied and improved logging for read from and write to file.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@14638 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
8286dec7f6
commit
72d997aa58
6 changed files with 262 additions and 100 deletions
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
||||||
|
2002-10-03 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Source/NSArray.m: Tidied init from file to ensure that everything
|
||||||
|
is released properly on failure, and we don't generate log messages
|
||||||
|
where a lower level API should be doing it. Added some documentation.
|
||||||
|
* Source/NSDictionary.m: ditto
|
||||||
|
* Source/NSString.m: ditto
|
||||||
|
* Source/NSData.m: Tidied read from and write to file,
|
||||||
|
adding lots of logging information. Also documented quite a bit.
|
||||||
|
Resolved all conflicts found with Adam's change ... generally in
|
||||||
|
favor of the most informative logging.
|
||||||
|
|
||||||
2002-10-03 Adam Fedor <fedor@gnu.org>
|
2002-10-03 Adam Fedor <fedor@gnu.org>
|
||||||
|
|
||||||
* Source/NSData.m (readContentsOfFile): Change NSDebugLog(s) to
|
* Source/NSData.m (readContentsOfFile): Change NSDebugLog(s) to
|
||||||
|
|
|
@ -545,19 +545,21 @@ static SEL rlSel;
|
||||||
* <p>If there is a failure to load the file for any reason, the receiver
|
* <p>If there is a failure to load the file for any reason, the receiver
|
||||||
* will be released and the method will return nil.
|
* will be released and the method will return nil.
|
||||||
* </p>
|
* </p>
|
||||||
|
* <p>Works by invoking [NSString-initWithContentsOfFile:] and
|
||||||
|
* [NSString-propertyList] then checking that the result is an array.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
- (id) initWithContentsOfFile: (NSString*)file
|
- (id) initWithContentsOfFile: (NSString*)file
|
||||||
{
|
{
|
||||||
NSString *myString;
|
NSString *myString;
|
||||||
NSData *someData;
|
|
||||||
|
|
||||||
someData = [[NSData allocWithZone: NSDefaultMallocZone()]
|
|
||||||
initWithContentsOfFile: file];
|
|
||||||
myString = [[NSString allocWithZone: NSDefaultMallocZone()]
|
myString = [[NSString allocWithZone: NSDefaultMallocZone()]
|
||||||
initWithData: someData encoding: NSUTF8StringEncoding];
|
initWithContentsOfFile: file];
|
||||||
RELEASE(someData);
|
if (myString == nil)
|
||||||
|
{
|
||||||
if (myString)
|
DESTROY(self);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
id result;
|
id result;
|
||||||
|
|
||||||
|
@ -574,12 +576,14 @@ static SEL rlSel;
|
||||||
if ([result isKindOfClass: NSArrayClass])
|
if ([result isKindOfClass: NSArrayClass])
|
||||||
{
|
{
|
||||||
self = [self initWithArray: result];
|
self = [self initWithArray: result];
|
||||||
return self;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NSWarnMLog(@"Contents of file '%@' does not contain an array", file);
|
||||||
|
DESTROY(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NSWarnMLog(@"Contents of file '%@' does not contain an array", file);
|
return self;
|
||||||
RELEASE(self);
|
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** <init />
|
/** <init />
|
||||||
|
|
|
@ -1248,14 +1248,20 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
|
||||||
|
|
||||||
path = [self pathForResource: @"Info-gnustep" ofType: @"plist"];
|
path = [self pathForResource: @"Info-gnustep" ofType: @"plist"];
|
||||||
if (path)
|
if (path)
|
||||||
_infoDict = [[NSDictionary alloc] initWithContentsOfFile: path];
|
{
|
||||||
|
_infoDict = [[NSDictionary alloc] initWithContentsOfFile: path];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
path = [self pathForResource: @"Info" ofType: @"plist"];
|
path = [self pathForResource: @"Info" ofType: @"plist"];
|
||||||
if (path)
|
if (path)
|
||||||
_infoDict = [[NSDictionary alloc] initWithContentsOfFile: path];
|
{
|
||||||
|
_infoDict = [[NSDictionary alloc] initWithContentsOfFile: path];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_infoDict = RETAIN([NSDictionary dictionary]);
|
{
|
||||||
|
_infoDict = RETAIN([NSDictionary dictionary]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return _infoDict;
|
return _infoDict;
|
||||||
}
|
}
|
||||||
|
|
205
Source/NSData.m
205
Source/NSData.m
|
@ -144,7 +144,7 @@ readContentsOfFile(NSString* path, void** buf, unsigned int* len, NSZone* zone)
|
||||||
if ([path getFileSystemRepresentation: thePath
|
if ([path getFileSystemRepresentation: thePath
|
||||||
maxLength: sizeof(thePath)-1] == NO)
|
maxLength: sizeof(thePath)-1] == NO)
|
||||||
{
|
{
|
||||||
NSWarnLog(@"Open (%s) attempt failed - bad path", thePath);
|
NSWarnFLog(@"Open (%s) attempt failed - bad path", thePath);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,21 +153,24 @@ readContentsOfFile(NSString* path, void** buf, unsigned int* len, NSZone* zone)
|
||||||
FILE_ATTRIBUTE_NORMAL, 0);
|
FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
if (fh == INVALID_HANDLE_VALUE)
|
if (fh == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
NSLog(@"Open (%s) attempt failed", thePath);
|
NSWarnFLog(@"Open (%s) attempt failed - %s", thePath,
|
||||||
|
GSLastErrorStr(errno));
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
fileLength = GetFileSize(fh, &high);
|
fileLength = GetFileSize(fh, &high);
|
||||||
if ((fileLength == 0xFFFFFFFF) && (GetLastError() != NO_ERROR))
|
if ((fileLength == 0xFFFFFFFF) && (GetLastError() != NO_ERROR))
|
||||||
{
|
{
|
||||||
|
NSWarnFLog(@"Failed to determine size of - %s - %s", thePath,
|
||||||
|
GSLastErrorStr(errno));
|
||||||
CloseHandle(fh);
|
CloseHandle(fh);
|
||||||
NSLog(@"Failed to determine size of - %s", thePath);
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
if (high != 0)
|
if (high != 0)
|
||||||
{
|
{
|
||||||
|
NSWarnFLog(@"File to big to handle - %s - %s", thePath,
|
||||||
|
GSLastErrorStr(errno));
|
||||||
CloseHandle(fh);
|
CloseHandle(fh);
|
||||||
NSLog(@"File too big to handle - %s", thePath);
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,26 +181,28 @@ readContentsOfFile(NSString* path, void** buf, unsigned int* len, NSZone* zone)
|
||||||
#endif
|
#endif
|
||||||
if (tmp == 0)
|
if (tmp == 0)
|
||||||
{
|
{
|
||||||
CloseHandle(fh);
|
NSWarnFLog(@"Malloc failed for file (%s) of length %d - %s",
|
||||||
NSLog(@"Malloc failed for file (%s) of length %d - %s",
|
|
||||||
thePath, fileLength, GSLastErrorStr(errno));
|
thePath, fileLength, GSLastErrorStr(errno));
|
||||||
|
CloseHandle(fh);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
if (!ReadFile(fh, tmp, fileLength, &got, 0))
|
if (!ReadFile(fh, tmp, fileLength, &got, 0))
|
||||||
{
|
{
|
||||||
if (tmp != 0)
|
if (tmp != 0)
|
||||||
{
|
{
|
||||||
|
NSWarnFLog(@"File read operation failed for %s - %s", thePath,
|
||||||
|
GSLastErrorStr(errno));
|
||||||
NSZoneFree(zone, tmp);
|
NSZoneFree(zone, tmp);
|
||||||
CloseHandle(fh);
|
CloseHandle(fh);
|
||||||
NSLog(@"File read operation failed for %s", thePath);
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (got != fileLength)
|
if (got != fileLength)
|
||||||
{
|
{
|
||||||
|
NSWarnFLog(@"File read operation short for %s - %s", thePath,
|
||||||
|
GSLastErrorStr(errno));
|
||||||
NSZoneFree(zone, tmp);
|
NSZoneFree(zone, tmp);
|
||||||
CloseHandle(fh);
|
CloseHandle(fh);
|
||||||
NSLog(@"File read operation short for %s", thePath);
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
CloseHandle(fh);
|
CloseHandle(fh);
|
||||||
|
@ -210,7 +215,7 @@ readContentsOfFile(NSString* path, void** buf, unsigned int* len, NSZone* zone)
|
||||||
|
|
||||||
if (theFile == NULL) /* We failed to open the file. */
|
if (theFile == NULL) /* We failed to open the file. */
|
||||||
{
|
{
|
||||||
NSLog(@"Open (%s) attempt failed - %s", thePath,
|
NSWarnFLog(@"Open (%s) attempt failed - %s", thePath,
|
||||||
GSLastErrorStr(errno));
|
GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
@ -221,7 +226,8 @@ readContentsOfFile(NSString* path, void** buf, unsigned int* len, NSZone* zone)
|
||||||
c = fseek(theFile, 0L, SEEK_END);
|
c = fseek(theFile, 0L, SEEK_END);
|
||||||
if (c != 0)
|
if (c != 0)
|
||||||
{
|
{
|
||||||
NSLog(@"Seek to end of file failed - %s", GSLastErrorStr(errno));
|
NSWarnFLog(@"Seek to end of file (%s) failed - %s", thePath,
|
||||||
|
GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +238,7 @@ readContentsOfFile(NSString* path, void** buf, unsigned int* len, NSZone* zone)
|
||||||
fileLength = ftell(theFile);
|
fileLength = ftell(theFile);
|
||||||
if (fileLength == -1)
|
if (fileLength == -1)
|
||||||
{
|
{
|
||||||
NSLog(@"Ftell failed - %s", GSLastErrorStr(errno));
|
NSWarnFLog(@"Ftell on %s failed - %s", thePath, GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +249,8 @@ readContentsOfFile(NSString* path, void** buf, unsigned int* len, NSZone* zone)
|
||||||
c = fseek(theFile, 0L, SEEK_SET);
|
c = fseek(theFile, 0L, SEEK_SET);
|
||||||
if (c != 0)
|
if (c != 0)
|
||||||
{
|
{
|
||||||
NSLog(@"Fseek to start of file failed - %s", GSLastErrorStr(errno));
|
NSWarnFLog(@"Fseek to start of file (%s) failed - %s",
|
||||||
|
thePath, GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,8 +283,8 @@ readContentsOfFile(NSString* path, void** buf, unsigned int* len, NSZone* zone)
|
||||||
}
|
}
|
||||||
if (tmp == 0)
|
if (tmp == 0)
|
||||||
{
|
{
|
||||||
NSLog(@"Malloc failed for file of length %d - %s",
|
NSWarnFLog(@"Malloc failed for file (%s) of length %d - %s",
|
||||||
fileLength + c, GSLastErrorStr(errno));
|
thePath, fileLength + c, GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
memcpy(tmp + fileLength, buf, c);
|
memcpy(tmp + fileLength, buf, c);
|
||||||
|
@ -293,15 +300,16 @@ readContentsOfFile(NSString* path, void** buf, unsigned int* len, NSZone* zone)
|
||||||
#endif
|
#endif
|
||||||
if (tmp == 0)
|
if (tmp == 0)
|
||||||
{
|
{
|
||||||
NSLog(@"Malloc failed for file of length %d - %s",
|
NSWarnFLog(@"Malloc failed for file (%s) of length %d - %s",
|
||||||
fileLength, GSLastErrorStr(errno));
|
thePath, fileLength, GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = fread(tmp, 1, fileLength, theFile);
|
c = fread(tmp, 1, fileLength, theFile);
|
||||||
if (c != fileLength)
|
if (c != fileLength)
|
||||||
{
|
{
|
||||||
NSLog(@"read of file contents failed - %s", GSLastErrorStr(errno));
|
NSWarnFLog(@"read of file (%s) contents failed - %s",
|
||||||
|
thePath, GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -419,6 +427,10 @@ failure:
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an autoreleased data object containing data copied from bytes
|
||||||
|
* and with the specified length. Invokes -initWithBytes:length:
|
||||||
|
*/
|
||||||
+ (id) dataWithBytes: (const void*)bytes
|
+ (id) dataWithBytes: (const void*)bytes
|
||||||
length: (unsigned int)length
|
length: (unsigned int)length
|
||||||
{
|
{
|
||||||
|
@ -429,6 +441,11 @@ failure:
|
||||||
return AUTORELEASE(d);
|
return AUTORELEASE(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an autoreleased data object encapsulating the data at bytes
|
||||||
|
* and with the specified length. Invokes
|
||||||
|
* -initWithBytesNoCopy:length:freeWhenDone: with YES
|
||||||
|
*/
|
||||||
+ (id) dataWithBytesNoCopy: (void*)bytes
|
+ (id) dataWithBytesNoCopy: (void*)bytes
|
||||||
length: (unsigned int)length
|
length: (unsigned int)length
|
||||||
{
|
{
|
||||||
|
@ -439,6 +456,11 @@ failure:
|
||||||
return AUTORELEASE(d);
|
return AUTORELEASE(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an autoreleased data object encapsulating the data at bytes
|
||||||
|
* and with the specified length. Invokes
|
||||||
|
* -initWithBytesNoCopy:length:freeWhenDone:
|
||||||
|
*/
|
||||||
+ (id) dataWithBytesNoCopy: (void*)bytes
|
+ (id) dataWithBytesNoCopy: (void*)bytes
|
||||||
length: (unsigned int)length
|
length: (unsigned int)length
|
||||||
freeWhenDone: (BOOL)shouldFree
|
freeWhenDone: (BOOL)shouldFree
|
||||||
|
@ -457,6 +479,10 @@ failure:
|
||||||
return AUTORELEASE(d);
|
return AUTORELEASE(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a data object encapsulating the contents of the specified file.
|
||||||
|
* Invokes -initWithContentsOfFile:
|
||||||
|
*/
|
||||||
+ (id) dataWithContentsOfFile: (NSString*)path
|
+ (id) dataWithContentsOfFile: (NSString*)path
|
||||||
{
|
{
|
||||||
NSData *d;
|
NSData *d;
|
||||||
|
@ -466,6 +492,11 @@ failure:
|
||||||
return AUTORELEASE(d);
|
return AUTORELEASE(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a data object encapsulating the contents of the specified
|
||||||
|
* file mapped directly into memory.
|
||||||
|
* Invokes -initWithContentsOfMappedFile:
|
||||||
|
*/
|
||||||
+ (id) dataWithContentsOfMappedFile: (NSString*)path
|
+ (id) dataWithContentsOfMappedFile: (NSString*)path
|
||||||
{
|
{
|
||||||
NSData *d;
|
NSData *d;
|
||||||
|
@ -480,6 +511,10 @@ failure:
|
||||||
return AUTORELEASE(d);
|
return AUTORELEASE(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the information at the specified url and returns an NSData
|
||||||
|
* instance encapsulating it.
|
||||||
|
*/
|
||||||
+ (id) dataWithContentsOfURL: (NSURL*)url
|
+ (id) dataWithContentsOfURL: (NSURL*)url
|
||||||
{
|
{
|
||||||
NSData *d;
|
NSData *d;
|
||||||
|
@ -488,6 +523,9 @@ failure:
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an autoreleased instance initialised by copying the contents of data.
|
||||||
|
*/
|
||||||
+ (id) dataWithData: (NSData*)data
|
+ (id) dataWithData: (NSData*)data
|
||||||
{
|
{
|
||||||
NSData *d;
|
NSData *d;
|
||||||
|
@ -497,6 +535,9 @@ failure:
|
||||||
return AUTORELEASE(d);
|
return AUTORELEASE(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new empty data object.
|
||||||
|
*/
|
||||||
+ (id) new
|
+ (id) new
|
||||||
{
|
{
|
||||||
NSData *d;
|
NSData *d;
|
||||||
|
@ -511,6 +552,11 @@ failure:
|
||||||
return [self initWithBytesNoCopy: 0 length: 0 freeWhenDone: YES];
|
return [self initWithBytesNoCopy: 0 length: 0 freeWhenDone: YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a copy of bufferSize bytes of data at aBuffer, and passes it to
|
||||||
|
* -initWithBytesNoCopy:length:freeWhenDone: with a YES argument in order
|
||||||
|
* to initialise the receiver. Returns the result.
|
||||||
|
*/
|
||||||
- (id) initWithBytes: (const void*)aBuffer
|
- (id) initWithBytes: (const void*)aBuffer
|
||||||
length: (unsigned int)bufferSize
|
length: (unsigned int)bufferSize
|
||||||
{
|
{
|
||||||
|
@ -540,6 +586,13 @@ failure:
|
||||||
}
|
}
|
||||||
|
|
||||||
/** <init /><override-subclass />
|
/** <init /><override-subclass />
|
||||||
|
* Initialises the receiver.<br />
|
||||||
|
* The value of aBuffer is a pointer to something to be stored.<br />
|
||||||
|
* The value of bufferSize is the number of bytes to use.<br />
|
||||||
|
* The value fo shouldFree specifies whether the receiver should
|
||||||
|
* attempt to free the memory pointer to by aBuffer when the receiver
|
||||||
|
* is deallocated ... ie. it says whether the receiver <em>owns</em>
|
||||||
|
* the memory.
|
||||||
*/
|
*/
|
||||||
- (id) initWithBytesNoCopy: (void*)aBuffer
|
- (id) initWithBytesNoCopy: (void*)aBuffer
|
||||||
length: (unsigned int)bufferSize
|
length: (unsigned int)bufferSize
|
||||||
|
@ -551,8 +604,8 @@ failure:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises the receiver with the contents of the specified file.<br />
|
* Initialises the receiver with the contents of the specified file.<br />
|
||||||
* Returns the resulting object.
|
* Returns the resulting object.<br />
|
||||||
* Returns nil if the file does not exist.
|
* Returns nil if the file does not exist or can not be read for some reason.
|
||||||
*/
|
*/
|
||||||
- (id) initWithContentsOfFile: (NSString*)path
|
- (id) initWithContentsOfFile: (NSString*)path
|
||||||
{
|
{
|
||||||
|
@ -567,8 +620,7 @@ failure:
|
||||||
#endif
|
#endif
|
||||||
if (readContentsOfFile(path, &fileBytes, &fileLength, zone) == NO)
|
if (readContentsOfFile(path, &fileBytes, &fileLength, zone) == NO)
|
||||||
{
|
{
|
||||||
RELEASE(self);
|
DESTROY(self);
|
||||||
self = nil;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -615,6 +667,9 @@ failure:
|
||||||
|
|
||||||
// Accessing Data
|
// Accessing Data
|
||||||
|
|
||||||
|
/** <override-subclass>
|
||||||
|
* Returns a pointer to the data encapsulated by the receiver.
|
||||||
|
*/
|
||||||
- (const void*) bytes
|
- (const void*) bytes
|
||||||
{
|
{
|
||||||
[self subclassResponsibility: _cmd];
|
[self subclassResponsibility: _cmd];
|
||||||
|
@ -667,16 +722,36 @@ failure:
|
||||||
return AUTORELEASE(str);
|
return AUTORELEASE(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the contents of the memory encapsulated by the receiver into
|
||||||
|
* the specified buffer. The buffer must be large enough to contain
|
||||||
|
* -length bytes of data ... if it isn't then a crash is likely to occur.<br />
|
||||||
|
* Invokes -getBytes:range: with the range set to the whole of the receiver.
|
||||||
|
*/
|
||||||
- (void) getBytes: (void*)buffer
|
- (void) getBytes: (void*)buffer
|
||||||
{
|
{
|
||||||
[self getBytes: buffer range: NSMakeRange(0, [self length])];
|
[self getBytes: buffer range: NSMakeRange(0, [self length])];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies length bytes of data from the memory encapsulated by the receiver
|
||||||
|
* into the specified buffer. The buffer must be large enough to contain
|
||||||
|
* length bytes of data ... if it isn't then a crash is likely to occur.<br />
|
||||||
|
* Invokes -getBytes:range: with the range set to iNSMakeRange(0, length)
|
||||||
|
*/
|
||||||
- (void) getBytes: (void*)buffer length: (unsigned int)length
|
- (void) getBytes: (void*)buffer length: (unsigned int)length
|
||||||
{
|
{
|
||||||
[self getBytes: buffer range: NSMakeRange(0, length)];
|
[self getBytes: buffer range: NSMakeRange(0, length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies data from the memory encapsulated by the receiver (in the range
|
||||||
|
* specified by aRange) into the specified buffer.<br />
|
||||||
|
* The buffer must be large enough to contain the data ... if it isn't then
|
||||||
|
* a crash is likely to occur.<br />
|
||||||
|
* If aRange specifies a range which does not entirely lie within the
|
||||||
|
* receiver, an exception is raised.
|
||||||
|
*/
|
||||||
- (void) getBytes: (void*)buffer range: (NSRange)aRange
|
- (void) getBytes: (void*)buffer range: (NSRange)aRange
|
||||||
{
|
{
|
||||||
unsigned size = [self length];
|
unsigned size = [self length];
|
||||||
|
@ -690,6 +765,12 @@ failure:
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an NSData instance encapsulating the memory from the reciever
|
||||||
|
* specified by the range aRange.<br />
|
||||||
|
* If aRange specifies a range which does not entirely lie within the
|
||||||
|
* receiver, an exception is raised.
|
||||||
|
*/
|
||||||
- (NSData*) subdataWithRange: (NSRange)aRange
|
- (NSData*) subdataWithRange: (NSRange)aRange
|
||||||
{
|
{
|
||||||
void *buffer;
|
void *buffer;
|
||||||
|
@ -747,15 +828,28 @@ failure:
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Querying a Data Object
|
/**
|
||||||
|
* Returns a boolean value indicating if the receiver and other contain
|
||||||
|
* identical data (using a byte by byte comparison). Assumes that the
|
||||||
|
* other object is an NSData instance ... may raise an exception if it isn't.
|
||||||
|
*/
|
||||||
- (BOOL) isEqualToData: (NSData*)other
|
- (BOOL) isEqualToData: (NSData*)other
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
if (other == self)
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
if ((len = [self length]) != [other length])
|
if ((len = [self length]) != [other length])
|
||||||
return NO;
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
return (memcmp([self bytes], [other bytes], len) ? NO : YES);
|
return (memcmp([self bytes], [other bytes], len) ? NO : YES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** <override-subclass>
|
||||||
|
* Returns the number of bytes of data encapsulated by the receiver.
|
||||||
|
*/
|
||||||
- (unsigned int) length
|
- (unsigned int) length
|
||||||
{
|
{
|
||||||
/* This is left to concrete subclasses to implement. */
|
/* This is left to concrete subclasses to implement. */
|
||||||
|
@ -763,9 +857,16 @@ failure:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
// Storing Data
|
* <p>Writes a copy of the data encapsulated by the receiver to a file
|
||||||
|
* at path. If the useAuxiliaryFile flag is YES, this writes to a
|
||||||
|
* temporary file and then renames that to the file at path, thus
|
||||||
|
* ensuring that path exists and does not contain partially written
|
||||||
|
* data at any point.
|
||||||
|
* </p>
|
||||||
|
* <p>On success returns YES, on failure returns NO.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
- (BOOL) writeToFile: (NSString*)path atomically: (BOOL)useAuxiliaryFile
|
- (BOOL) writeToFile: (NSString*)path atomically: (BOOL)useAuxiliaryFile
|
||||||
{
|
{
|
||||||
char thePath[BUFSIZ*2+8];
|
char thePath[BUFSIZ*2+8];
|
||||||
|
@ -783,7 +884,7 @@ failure:
|
||||||
if ([path getFileSystemRepresentation: theRealPath
|
if ([path getFileSystemRepresentation: theRealPath
|
||||||
maxLength: sizeof(theRealPath)-1] == NO)
|
maxLength: sizeof(theRealPath)-1] == NO)
|
||||||
{
|
{
|
||||||
NSWarnLog(@"Open (%s) attempt failed - bad path", theRealPath);
|
NSWarnMLog(@"Open (%s) attempt failed - bad path", theRealPath);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -795,7 +896,7 @@ failure:
|
||||||
if ([tmppath getFileSystemRepresentation: thePath
|
if ([tmppath getFileSystemRepresentation: thePath
|
||||||
maxLength: sizeof(thePath)-1] == NO)
|
maxLength: sizeof(thePath)-1] == NO)
|
||||||
{
|
{
|
||||||
NSWarnLog(@"Open (%s) attempt failed - bad path", thePath);
|
NSWarnMLog(@"Open (%s) attempt failed - bad path", thePath);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,14 +904,16 @@ failure:
|
||||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
if (fh == INVALID_HANDLE_VALUE)
|
if (fh == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
NSLog(@"Create (%s) attempt failed", thePath);
|
NSWarnMLog(@"Create (%s) attempt failed - %s", thePath,
|
||||||
|
GSLastErrorStr(errno));
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WriteFile(fh, [self bytes], [self length], &wroteBytes, 0))
|
if (!WriteFile(fh, [self bytes], [self length], &wroteBytes, 0))
|
||||||
{
|
{
|
||||||
|
NSWarnMLog(@"Write (%s) attempt failed - %s", thePath,
|
||||||
|
GSLastErrorStr(errno));
|
||||||
CloseHandle(fh);
|
CloseHandle(fh);
|
||||||
NSLog(@"Write (%s) attempt failed", thePath);
|
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
CloseHandle(fh);
|
CloseHandle(fh);
|
||||||
|
@ -826,7 +929,8 @@ failure:
|
||||||
strcat(thePath, "XXXXXX");
|
strcat(thePath, "XXXXXX");
|
||||||
if ((desc = mkstemp(thePath)) < 0)
|
if ((desc = mkstemp(thePath)) < 0)
|
||||||
{
|
{
|
||||||
NSLog(@"mkstemp (%s) failed - %s", thePath, GSLastErrorStr(errno));
|
NSWarnMLog(@"mkstemp (%s) failed - %s", thePath,
|
||||||
|
GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
mask = umask(0);
|
mask = umask(0);
|
||||||
|
@ -852,7 +956,8 @@ failure:
|
||||||
strcat(thePath, "XXXXXX");
|
strcat(thePath, "XXXXXX");
|
||||||
if (mktemp(thePath) == 0)
|
if (mktemp(thePath) == 0)
|
||||||
{
|
{
|
||||||
NSLog(@"mktemp (%s) failed - %s", thePath, GSLastErrorStr(errno));
|
NSWarnMLog(@"mktemp (%s) failed - %s", thePath,
|
||||||
|
GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -868,7 +973,7 @@ failure:
|
||||||
if (theFile == NULL) /* Something went wrong; we weren't
|
if (theFile == NULL) /* Something went wrong; we weren't
|
||||||
* even able to open the file. */
|
* even able to open the file. */
|
||||||
{
|
{
|
||||||
NSLog(@"Open (%s) failed - %s", thePath, GSLastErrorStr(errno));
|
NSWarnMLog(@"Open (%s) failed - %s", thePath, GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -880,7 +985,7 @@ failure:
|
||||||
if (c < [self length]) /* We failed to write everything for
|
if (c < [self length]) /* We failed to write everything for
|
||||||
* some reason. */
|
* some reason. */
|
||||||
{
|
{
|
||||||
NSLog(@"Fwrite (%s) failed - %s", thePath, GSLastErrorStr(errno));
|
NSWarnMLog(@"Fwrite (%s) failed - %s", thePath, GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -891,7 +996,7 @@ failure:
|
||||||
* closing the file, but we got here,
|
* closing the file, but we got here,
|
||||||
* so we need to deal with it. */
|
* so we need to deal with it. */
|
||||||
{
|
{
|
||||||
NSLog(@"Fclose (%s) failed - %s", thePath, GSLastErrorStr(errno));
|
NSWarnMLog(@"Fclose (%s) failed - %s", thePath, GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -942,7 +1047,7 @@ failure:
|
||||||
#endif
|
#endif
|
||||||
if (c != 0) /* Many things could go wrong, I guess. */
|
if (c != 0) /* Many things could go wrong, I guess. */
|
||||||
{
|
{
|
||||||
NSLog(@"Rename ('%s' to '%s') failed - %s",
|
NSWarnMLog(@"Rename ('%s' to '%s') failed - %s",
|
||||||
thePath, theRealPath, GSLastErrorStr(errno));
|
thePath, theRealPath, GSLastErrorStr(errno));
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
@ -961,7 +1066,10 @@ failure:
|
||||||
[att removeObjectForKey: NSFileDeviceIdentifier];
|
[att removeObjectForKey: NSFileDeviceIdentifier];
|
||||||
[att removeObjectForKey: NSFileType];
|
[att removeObjectForKey: NSFileType];
|
||||||
if ([mgr changeFileAttributes: att atPath: path] == NO)
|
if ([mgr changeFileAttributes: att atPath: path] == NO)
|
||||||
NSLog(@"Unable to correctly set all attributes for '%@'", path);
|
{
|
||||||
|
NSWarnMLog(@"Unable to correctly set all attributes for '%@'",
|
||||||
|
path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#ifndef __MINGW__
|
#ifndef __MINGW__
|
||||||
else if (geteuid() == 0 && [@"root" isEqualToString: NSUserName()] == NO)
|
else if (geteuid() == 0 && [@"root" isEqualToString: NSUserName()] == NO)
|
||||||
|
@ -969,7 +1077,9 @@ failure:
|
||||||
att = [NSDictionary dictionaryWithObjectsAndKeys:
|
att = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
NSFileOwnerAccountName, NSUserName(), nil];
|
NSFileOwnerAccountName, NSUserName(), nil];
|
||||||
if ([mgr changeFileAttributes: att atPath: path] == NO)
|
if ([mgr changeFileAttributes: att atPath: path] == NO)
|
||||||
NSLog(@"Unable to correctly set ownership for '%@'", path);
|
{
|
||||||
|
NSWarnMLog(@"Unable to correctly set ownership for '%@'", path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -989,6 +1099,9 @@ failure:
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a copy of the contents of the receiver to the specified URL.
|
||||||
|
*/
|
||||||
- (BOOL) writeToURL: (NSURL*)anURL atomically: (BOOL)flag
|
- (BOOL) writeToURL: (NSURL*)anURL atomically: (BOOL)flag
|
||||||
{
|
{
|
||||||
if ([anURL isFileURL] == YES)
|
if ([anURL isFileURL] == YES)
|
||||||
|
@ -2629,13 +2742,13 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
|
||||||
if ([path getFileSystemRepresentation: thePath
|
if ([path getFileSystemRepresentation: thePath
|
||||||
maxLength: sizeof(thePath)-1] == NO)
|
maxLength: sizeof(thePath)-1] == NO)
|
||||||
{
|
{
|
||||||
NSLog(@"Open (%s) attempt failed - bad path", thePath);
|
NSWarnMLog(@"Open (%s) attempt failed - bad path", thePath);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
fd = open(thePath, O_RDONLY);
|
fd = open(thePath, O_RDONLY);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
NSLog(@"[NSDataMappedFile -initWithContentsOfMappedFile:] unable to open %s - %s", thePath, GSLastErrorStr(errno));
|
NSWarnMLog(@"unable to open %s - %s", thePath, GSLastErrorStr(errno));
|
||||||
RELEASE(self);
|
RELEASE(self);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -2643,7 +2756,8 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
|
||||||
length = lseek(fd, 0, SEEK_END);
|
length = lseek(fd, 0, SEEK_END);
|
||||||
if (length < 0)
|
if (length < 0)
|
||||||
{
|
{
|
||||||
NSLog(@"[NSDataMappedFile -initWithContentsOfMappedFile:] unable to seek to eof %s - %s", thePath, GSLastErrorStr(errno));
|
NSWarnMLog(@"unable to seek to eof %s - %s",
|
||||||
|
thePath, GSLastErrorStr(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
RELEASE(self);
|
RELEASE(self);
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -2651,7 +2765,8 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
|
||||||
/* Position at start of file. */
|
/* Position at start of file. */
|
||||||
if (lseek(fd, 0, SEEK_SET) != 0)
|
if (lseek(fd, 0, SEEK_SET) != 0)
|
||||||
{
|
{
|
||||||
NSLog(@"[NSDataMappedFile -initWithContentsOfMappedFile:] unable to seek to sof %s - %s", thePath, GSLastErrorStr(errno));
|
NSWarnMLog(@"unable to seek to sof %s - %s",
|
||||||
|
thePath, GSLastErrorStr(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
RELEASE(self);
|
RELEASE(self);
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -2659,7 +2774,8 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
|
||||||
bytes = mmap(0, length, PROT_READ, MAP_SHARED, fd, 0);
|
bytes = mmap(0, length, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
if (bytes == MAP_FAILED)
|
if (bytes == MAP_FAILED)
|
||||||
{
|
{
|
||||||
NSLog(@"[NSDataMappedFile -initWithContentsOfMappedFile:] mapping failed for %s - %s", thePath, GSLastErrorStr(errno));
|
NSWarnMLog(@"mapping failed for %s - %s",
|
||||||
|
thePath, GSLastErrorStr(errno));
|
||||||
close(fd);
|
close(fd);
|
||||||
RELEASE(self);
|
RELEASE(self);
|
||||||
self = [dataMalloc allocWithZone: NSDefaultMallocZone()];
|
self = [dataMalloc allocWithZone: NSDefaultMallocZone()];
|
||||||
|
@ -2909,8 +3025,7 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
|
||||||
self = [self initWithCapacity: 0];
|
self = [self initWithCapacity: 0];
|
||||||
if (readContentsOfFile(path, &bytes, &length, zone) == NO)
|
if (readContentsOfFile(path, &bytes, &length, zone) == NO)
|
||||||
{
|
{
|
||||||
RELEASE(self);
|
DESTROY(self);
|
||||||
self = nil;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -470,24 +470,21 @@ static SEL appSel;
|
||||||
* <p>If there is a failure to load the file for any reason, the receiver
|
* <p>If there is a failure to load the file for any reason, the receiver
|
||||||
* will be released and the method will return nil.
|
* will be released and the method will return nil.
|
||||||
* </p>
|
* </p>
|
||||||
|
* <p>Works by invoking [NSString-initWithContentsOfFile:] and
|
||||||
|
* [NSString-propertyList] then checking that the result is a dictionary.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
- (id) initWithContentsOfFile: (NSString*)path
|
- (id) initWithContentsOfFile: (NSString*)path
|
||||||
{
|
{
|
||||||
NSString *myString;
|
NSString *myString;
|
||||||
NSData *someData;
|
|
||||||
|
|
||||||
someData = [[NSData allocWithZone: NSDefaultMallocZone()]
|
|
||||||
initWithContentsOfFile: path];
|
|
||||||
if (someData == nil)
|
|
||||||
{
|
|
||||||
/* NSData should have already logged an error message */
|
|
||||||
RELEASE(self);
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
myString = [[NSString allocWithZone: NSDefaultMallocZone()]
|
myString = [[NSString allocWithZone: NSDefaultMallocZone()]
|
||||||
initWithData: someData encoding: NSUTF8StringEncoding];
|
initWithContentsOfFile: path];
|
||||||
RELEASE(someData);
|
if (myString == nil)
|
||||||
if (myString)
|
{
|
||||||
|
DESTROY(self);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
id result;
|
id result;
|
||||||
|
|
||||||
|
@ -504,12 +501,15 @@ static SEL appSel;
|
||||||
if ([result isKindOfClass: NSDictionaryClass])
|
if ([result isKindOfClass: NSDictionaryClass])
|
||||||
{
|
{
|
||||||
self = [self initWithDictionary: result];
|
self = [self initWithDictionary: result];
|
||||||
return self;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NSWarnMLog(@"Contents of file '%@' does not contain a dictionary",
|
||||||
|
path);
|
||||||
|
DESTROY(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NSWarnMLog(@"Contents of file '%@' does not contain a dictionary", path);
|
return self;
|
||||||
RELEASE(self);
|
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1279,57 +1279,82 @@ handle_printf_atsign (FILE *stream,
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises the receiver with the contents of the file at path.<br />
|
||||||
|
* Invokes [NSData-initWithContentsOfFile:] to read the file, then
|
||||||
|
* examines the data to infer its encoding type, and converts the
|
||||||
|
* data to a string using -initWithData:encoding:<br />
|
||||||
|
* Releases the receiver and returns nil if the file could not be read
|
||||||
|
* and converted to a string.
|
||||||
|
*/
|
||||||
- (id) initWithContentsOfFile: (NSString*)path
|
- (id) initWithContentsOfFile: (NSString*)path
|
||||||
{
|
{
|
||||||
NSStringEncoding enc;
|
NSStringEncoding enc = _DefaultStringEncoding;
|
||||||
NSData *d = [NSDataClass dataWithContentsOfFile: path];
|
NSData *d;
|
||||||
unsigned int len = [d length];
|
unsigned int len;
|
||||||
const unichar *test;
|
const unichar *test;
|
||||||
|
|
||||||
|
d = [[NSDataClass alloc] initWithContentsOfFile: path];
|
||||||
if (d == nil)
|
if (d == nil)
|
||||||
return nil;
|
{
|
||||||
|
RELEASE(self);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
len = [d length];
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return @"";
|
{
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
test = [d bytes];
|
test = [d bytes];
|
||||||
if ((test != NULL) && (len > 1)
|
if ((test != NULL) && (len > 1))
|
||||||
&& ((test[0] == byteOrderMark) || (test[0] == byteOrderMarkSwapped)))
|
|
||||||
{
|
{
|
||||||
/* somebody set up us the BOM! */
|
if ((test[0] == byteOrderMark) || (test[0] == byteOrderMarkSwapped))
|
||||||
enc = NSUnicodeStringEncoding;
|
{
|
||||||
|
/* somebody set up us the BOM! */
|
||||||
|
enc = NSUnicodeStringEncoding;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
self = [self initWithData: d encoding: enc];
|
||||||
|
RELEASE(d);
|
||||||
|
if (self == nil)
|
||||||
{
|
{
|
||||||
enc = _DefaultStringEncoding;
|
NSWarnMLog(@"Contents of file '%@' are not string data", path);
|
||||||
}
|
}
|
||||||
return [self initWithData: d encoding: enc];
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) initWithContentsOfURL: (NSURL*)url
|
- (id) initWithContentsOfURL: (NSURL*)url
|
||||||
{
|
{
|
||||||
NSStringEncoding enc;
|
NSStringEncoding enc = _DefaultStringEncoding;
|
||||||
NSData *d = [NSDataClass dataWithContentsOfURL: url];
|
NSData *d = [NSDataClass dataWithContentsOfURL: url];
|
||||||
unsigned int len = [d length];
|
unsigned int len = [d length];
|
||||||
const unsigned char *test;
|
const unsigned char *test;
|
||||||
|
|
||||||
if (d == nil)
|
if (d == nil)
|
||||||
return nil;
|
{
|
||||||
|
NSWarnMLog(@"Contents of URL '%@' are not readable", url);
|
||||||
|
RELEASE(self);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return @"";
|
{
|
||||||
|
RELEASE(self);
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
test = [d bytes];
|
test = [d bytes];
|
||||||
if ((test != NULL) && (len > 1)
|
if ((test != NULL) && (len > 1))
|
||||||
&& ((test[0] == byteOrderMark) || (test[0] == byteOrderMarkSwapped)))
|
|
||||||
{
|
{
|
||||||
enc = NSUnicodeStringEncoding;
|
if ((test[0] == byteOrderMark) || (test[0] == byteOrderMarkSwapped))
|
||||||
|
{
|
||||||
|
enc = NSUnicodeStringEncoding;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
self = [self initWithData: d encoding: enc];
|
||||||
|
if (self == nil)
|
||||||
{
|
{
|
||||||
enc = _DefaultStringEncoding;
|
NSWarnMLog(@"Contents of URL '%@' are not string data", url);
|
||||||
}
|
}
|
||||||
return [self initWithData: d encoding: enc];
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) init
|
- (id) init
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue