Re: NSData weirdness...
Re: NSData weirdness...
- Subject: Re: NSData weirdness...
- From: Bill Bumgarner <email@hidden>
- Date: Thu, 20 Jun 2002 23:52:40 -0400
On Thursday, June 20, 2002, at 11:24 PM, email@hidden
wrote:
Dear All,
I have written an experiment class to play around with Cocoa and
NSBundles and so on, and I have a mind numbing question about NSData
usage.
Always a good plan... play with the APIs in a sandbox that minimizes
variables before trying to use them in a real context!
Below is a Level.m file listing that is set to be my NSApp delegate (set
in Interface Builder).
// START FILE CONTENTS
... code deleted ....
// END OF FILE CONTENTS
The problem is this: the subdataWithRange: message does not seem to
work. You see the LevelData.data file in the app bundle is approx 60K in
length. But when I view the output from the NSLog() line, instead of
just the 0..100 byte range I get the entire file contents. Arghh!
First, instead of...
[[[NSBundle mainBundle] resourcePath]
stringByAppendingString:@"/LevelData.data"]
... use ...
[[NSBundle mainBundle] pathForResource: @"LevelData" ofType: @"data"]
... it is both more portable (both across platforms-- if that ever happens
again) and across versions of the OS/Foundation/Wrappers.
Now, the data problem...
-bytes returns the base address of the memory that contains the data
contained within the NSData object. Because the original NSData object
is immutable and -subdataWithRange: returns an immutable NSData instance,
the two NSData instances contain a pointer to the exact same hunk of
memory. It can't change, so why copy it?
The NSLog(@"%s", [data bytes]) is attempting to treat the contents of the
NSData object as a C-String; that is, as a NULL terminated string that
starts at the base address of the data contained within the NSData
instance.
As such, if there doesn't happen to be a NULL byte within the first 100
bytes of the data contained in the NSData object produced by
subdataWithRange: (with a range of 0,100), NSLog() will happily keep
printing characters well beyond the range of memory that is contained
within the NSData object.
Another problem was that I had mysterious info.plist type stuff appended
after the contents NSData* variable when I was using the [NSData
dataWithContentsOfFile:] message. The NSLog() method would spit out the
entire file contents (instead of the subrange) and append mumbo jumbo
like:
.... stuff deleted ...
NSData is a class cluster. That is, when you call one of the factory
methods-- like +dataWithContentsOfFile: or
+dataWithContentsOfMappedFile:-- it is very likely that you are actually
receiving instances of two different subclasses of NSData. One is
optimized for non-mapped files, the other for mapped files.
-subdataWithRange: may likely return yet a third subclass.
That it is returning a subclass is generally irrelevant to your code; it
is an NSData and treat it as such, all is well.
However, when abusing the APIs-- in this case, when trying to dump the
contents of the NSData using NSLog() on a hunk of memory that doesn't
happen to contain a NULL character-- the behavior will be undefined.
It is likely that +dataWithContentsOfFile: works in a fashion where
-subdataWithRange: makes the assumption that it really does need to copy
the data. So, when the NSData object returned by -subdatawithRange: was
created, it copied exactly the first 100 bytes.
Now, the first 100 bytes doesn't actually have a NULL character in it. So,
when you call NSLog() to print the contents of the data, NSLog() runs off
the end of the data and continues to dump whatever happens to be in memory.
In this case, there was obviously an NSString (or char *) buffer that
contained the XML representation of a property list. When you called
NSLog, it ran off the end of your data and started spewing the property
list.
In otherwords -- a buffer overrun.
Finally -- there is no magic. Think of what your code would look like if
it were "standard C".
I.e. -- total pseudo code here... haven't written this kind of stuff in
years:
unsigned char buf[100];
FILE *dataFile = fopen("LevelOne.data", "r");
fread(buf, dataFile, 100);
In the above, what would happen if you did....
fprintf(stdout, "%s", buf)
... when the first 100 bytes of LevelOne.data didn't actually contain a
NULL/'\0' character?
Same thing as the ObjC code...
b.bum
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.