Welcome to the MacNN Forums.

If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

You are here: MacNN Forums > Software - Troubleshooting and Discussion > Developer Center > Help converting NSData to NSString

Help converting NSData to NSString
Thread Tools
Professional Poster
Join Date: Oct 2001
Location: London
Status: Offline
Reply With Quote
Nov 4, 2001, 05:58 AM
 
Hello;

I am a starter developer in cocoa and I was just writing an app to do with Internet Config on OS X and have come across the following stumbling block and was hoping someone could enlighten me.

I am hoping to write an app to discover what helper app is used for which internet protocol under mac os x. I see that OS X uses Internet Config by the com.apple.internetconfig.plist

The reference to The helper app for protocols is stored in a dictionary in this PLIST.
e.g. for FTP the co-responding key is "Helper:ftp"

"Helper:ftp" = {"ic-data" = <41726368 10496e74 65726172 63687920 352e302e 31000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 >; };

This data fed into a Hex editor results in the following :

"ArchInterarchy 5.0.1Interarchy and Its long name.

e.g. with http
"Helper:http" = {"ic-data" =<4f574542 074f6d6e 69576562 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 >;};

which gives:
"OWEBOmniWeben I try to extract this info using the following source:

...
NSData *hexData = [dataDictionary objectForKey:@"ic-data"];
helperAppName=[[NSString alloc] initWithData: hexData encoding:[NSString defaultCStringEncoding]];
NSLog (@"\nHex Datan%@", hexData);
NSLog (@"\nhelperAppNamen%@",helperAppName);
// [protocolNameTextField setStringValue:helperAppName]; - causes crash
[helperAppName dealloc];
...

I get the following from Log:

2001-11-04 11:15:37.296 internetpref[1457] Hex Data:<CFData 0x213920 [0x8016024c]>{length = 68, capacity = 68, bytes = 0x4172636810496e746572617263687920 ... 0000000000000000}

2001-11-04 11:15:37.296 internetpref[1457] helperAppName:Arch\\020Interarchy 5.0.1\\000\\000\\000\\000\\000\\000\\000\\000\\000 \\000\\000\\000\\000\\000\\000\\000\\000\\000\\000 \\000\\000\\000\\000\\000\\000\\000\\000\\000\\000 \\000\\000\\000\\000\\000\\000 \\000\\000\\000\\000\\000\\000\\000\\000\\000\\000 \\000\\000

Is it wrong to try and turn the NSData into an NSString? Am I using the wrong encoding?

p.s.

From Internet Config Documentation:

"Application Specification
The ICAppSpec is a fixed length record used to specify an application.

ICAppSpec =
record
fCreator: OSType;
name: Str63;
end;
ICAppSpecPtr = ^ICAppSpec;
ICAppSpecHandle = ^ICAppSpecPtr;

The program using this specification is expected to look up the location of the application in the desktop database. The name is provided to display to the user, and should not affect the search.
You know it makes sense. ☼ ☼ ☼ Growl.
     
Forum Regular
Join Date: Oct 2000
Location: Portland, OR USA
Status: Offline
Reply With Quote
Nov 5, 2001, 02:47 PM
 
It looks like you should be trying to convert the NSData into an ICAppSpec
rather than a string. Then you should be able to extract the string components. The specificatoin you gave looks like Pascal, whereas the types are probably C or Objective-C. Either way, you cna probably cast the NSData* into an ICAppSpec* and extract it's fields in the intended manner. Let me know if this helps.
     
Dedicated MacNNer
Join Date: Jan 2001
Location: Virginia, US
Status: Offline
Reply With Quote
Nov 5, 2001, 10:42 PM
 
The crash is because of this line:

[helperAppName dealloc];

That should be:

[helperAppName release];

Never ever call dealloc directly; it directly frees the memory. Release will free it whenever the retain count goes to 0 (i.e. no one's using the object any more). In your case, you set the string value so the text field is using it, then free it out from under the text field. The next time the text field does something with the string, boom.

The string conversion should work, although since there are lots of null characters in the data, that means there are lots of null charactes in the resulting string (the \000 stuff). If you know the data is an ASCII string and you know it's null terminated, you could do something like:

helperAppName = [NSString stringWithCString:[hexData bytes]];

(in this case, the helperAppName is autoreleased, so you don't need to release it)
     
Professional Poster
Join Date: Oct 2001
Location: London
Status: Offline
Reply With Quote
Nov 6, 2001, 07:47 AM
 
Thanks very much for your info.

I'm afraid I'm a bit in the dark here, - I'm not really familiar with C.
would this be the right sort of approach:

I should {in the header file} add the following C type definition:

  typedef struct InternetConfigApplicationSpecification
{
char creator[4];
char name[63];
} anICSpec;

and then declare anICSpec variable:

anICSpec myICSpec;

then I can {in the implementation} assign the address of the NSdata object to the address of myICSpec.

*myICSpec = *hexdata;

then I can set:

helperAppName=myICSpec.name;

Is this the right sort of thinking? or have I vastly underestimated the problem?
I'm afraid my knowledge of C and pointers is very sketchy.

or I am mis-understanding this completely?
You know it makes sense. ☼ ☼ ☼ Growl.
     
Forum Regular
Join Date: Oct 2000
Location: Portland, OR USA
Status: Offline
Reply With Quote
Nov 6, 2001, 12:58 PM
 
You have it slightly backwards, the '*' operator de-references pointers. You already have the address of the string, it's hexData (*hexData is the value of the string). You want to try something like:
<BLOCKQUOTE><font size="1"face="Geneva, Verdana, Arial">code:</font><HR><pre><font size=1 face=courier>
anICSpec *myICSpec; <font color = brown>// Create pointer to an anICSpec.</font>
myICSpec = hexData; <font color = brown>// This assigns the memory address.</font>
</font>[/code]

Then you can access the fields of myICSpec with myICSpec-&gt;field or (*myICSpec).field. Also, if I were you, I'd try to find the Carbon header that contains the type declaration so that you can be sure that it's correct because your example seems to indicate that there is a space, not a null between the cretor code and the application name.
     
Addicted to MacNN
Join Date: Mar 2000
Location: London, UK
Status: Offline
Reply With Quote
Nov 6, 2001, 01:02 PM
 
You should #import the correct headers, really. Also note that Str63 might be a pstring and not a cstring, and an OSType is actually of type long and won't be either a cstring or a pstring because it always has 4 characters.
     
Professional Poster
Join Date: Oct 2001
Location: London
Status: Offline
Reply With Quote
Nov 8, 2001, 09:22 AM
 
Thanks very much for your help.

Importing the header gave me definitions for the ICNSAppSpec struct.

It's working now, but something I Dicovered about the NSData class is that you have to get the data out of it with the getBytes: method before you can cast it in to the appropriate type.

If your are interested below is my code:


- (IBAction)getProtocolInfo id)sender
{
NSString *helperCreatorCode;
NSString *keyBuilder = @"Helper:"; // With this string we build the key for the ICData object we need.

ICAppSpec theICAppSpec;
ICAppSpecPtr theICAppSpecPointer;

OSType theOSType;
CFStringRef theCFStringRef;


keyBuilder=[keyBuilder stringByAppendingString: [[[protocolTextField stringValue] uppercaseString] lowercaseString]];
// we take the contents of the text field and make it lowercase. Then we add "helper:" beforehand.
// e.g. "FTP" becomes "helper:ftp" which is the appropriate key in the "ic-added" dictionary.

dataDictionary=[addedDictionary objectForKey:keyBuilder];


if (nil==dataDictionary)
{
[protocolNameTextField setStringValue:@"no helper"];
}
else
{
NSData *theICData = [dataDictionary objectForKey:@"ic-data"];
// this dictionary only ever has one key-data pair.
// the key always being "ic-data"

theICAppSpecPointer=&theICAppSpec;
[theICData getBytes:theICAppSpecPointer];
// make the pointer theICAppSpec point to the Address of theICData

theCFStringRef =CFStringCreateWithPascalString(NULL, theICAppSpec.name, kCFStringEncodingMacRoman);
// Carbon call to convert Pascal Strings into CFStrings

// NSLog(@"theCFStringRef, %@", theCFStringRef);
[protocolNameTextField setStringValue:theCFStringRef];
}
}

[ 11-08-2001: Message edited by: Diggory Laycock ]
You know it makes sense. ☼ ☼ ☼ Growl.
     
   
Thread Tools
Forum Links
Forum Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Top
Privacy Policy
All times are GMT -5. The time now is 09:58 PM.
All contents of these forums © 1995-2011 MacNN. All rights reserved.
Branding + Design: www.gesamtbild.com
vBulletin v.3.8.7 © 2000-2011, Jelsoft Enterprises Ltd., Content Relevant URLs by vBSEO 3.3.2