Some background... I am writing code that interacts with javascript via a ObjC-JS bridge utilizing UIWebView's stringByEvaluatingJavaScriptFromString:. The idea is that the "brains" of the app be in JS which tells Objective-C how to behave. There are multiple benefits to this like reduced binary size, flexible updates, etc. However, there is a case where there is some Objective-C only object that the JS needs to have a reference to (JS instructs ObjC when to use/remove the object). This is being done by placing the native object in a dictionary with a unique identifier which can be passed as a string to JS (over the bridge). My problem stems with coming up with a nice identifier for said native Objective-C object.
Thus, I am trying to convert a reference to an object to a string with no luck. This is what I have:
// anObject is a custom class
NSValue *handle = [NSValue valueWithPointer:(__bridge const void *)anObject];
NSData *data = [NSData dataWithValue:handle];
NSString *stringHandle = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
The dataWithValue: function (taken from this SO post):
+ (NSData *)dataWithValue:(NSValue *)value {
NSUInteger size;
const char* encoding = [value objCType];
NSGetSizeAndAlignment(encoding, &size, NULL);
void* ptr = malloc(size);
[value getValue:ptr];
NSData* data = [NSData dataWithBytes:ptr length:size];
free(ptr);
return data;
}
Walking through it in the debugger shows me a nil value for stringHandle:
What am I doing wrong?
What you're doing wrong is trying to treat an address as if it's a UTF-8 encoded string. An address -- or any other chunk of arbitrary data -- isn't very likely to be valid UTF-8 data. (If by chance it were, it still wouldn't be the string you expect.)
If you're trying to get a string containing the pointer value, i.e., the address of the original object, that's just [NSString stringWithFormat:#"%p", anObject];
If you really need to do it from the NSValue, then replace anObject with [theValue pointerValue].
If you want to pretty-print arbitrary data, see How to convert an NSData into an NSString Hex string?
You can get a string representation by calling the NSObject method "description". You can override the "description" method in a subclass if you need.
An NSValue of a pointer will be an object holding the 4 bytes of the 32-bit pointer. It will not hold any of the data pointed to in RAM.
Related
int i = 17;
int *addressOfI = &i;
printf("the int stored at addressOfI is %d\n", *addressOfI);
The question is: If I can get the data stored in addressOfI using the * operator, why it doesn't works for type NSString? like following:
NSString *string = #"Hello world!"
printf("the NSString stored at string is %#\n", *string);
why it doesn't works for type NSString?
Because NSString is an Objective-C object and not a primitive type. The NSString * pointer actually points to a struct objc_object which provides the framework for the object system. You can probably "see" some primitive types within this framework (i.e. members of objc_object) however it's supposed to be a black box to normal developers.
The actual reason your second piece of code will crash is that the %# format specifier expects to call the description method on the object you pass in as an argument and you have dereferenced that object pointer so it's no longer a valid object pointer.
i am trying to get a substring from a parent string. parent string is mac address of device available in a dictionary. But when i try to convert it it si giving me error as below "[_NSInlineData substringFromIndex:]: unrecognized selector sent to instance".
I just want to remove some of the chars from the parent string (here it is mac address like "<0001ui3 234563>" ) and get "ui3 234563".
// This is my nsdictionary.
advertisementdata = { kCBAdvDataIsConnectable = 1; kCBAdvDataLocalName = "test123"; kCBAdvDataManufacturerData = <00029r21 6y051rt2>; kCBAdvDataServiceUUIDs = ( FFF0 ); kCBAdvDataTxPowerLevel = 0; }
// I want 9r216y051rt from kCBAdvDataManufacturerData;
NSString *str2;
str2=[advertisementData objectForKey:#"kCBAdvDataManufacturerData"];
NSString *str3;
str3=[str2 substringFromIndex:5];
// here I do not get the required 12 character string from str2 string.
get NSInlinedata error for all NSString method.
Thanks,
Note that iOS CoreBlueTooth advertisementData is binary NSData:
https://developer.apple.com/library/ios/documentation/CoreBluetooth/Reference/CBCentralManagerDelegate_Protocol/index.html#//apple_ref/doc/constant_group/Advertisement_Data_Retrieval_Keys
Documentation clearly states:
CBAdvertisementDataManufacturerDataKey
A NSData object containing the manufacturer data of a peripheral.
BTW, when you have a NSDictionary value type NSData*, you get the error by casting this NSData into a NSString*
// this is a bug!
NSString* str2=[advertisementData objectForKey:#"kCBAdvDataManufacturerData"];
To inspect the dictionary value try
NSData* advData = [advertisementData objectForKey:#"kCBAdvDataManufacturerData"];
Unfortunately, since this is binary, you need to interpret it according to the peripheral manufacturer data documentation. There is no easy way to transform this into a NSString*
Sounds like you have an NSData object, and you're trying to use an NSString method to access it. You can convert your NSData object using the callinitWithData: encoding:
Then apply the substringFromIndex call to your new NSString.
The point that you have NSInlineData and what you need is hexadecimal representation of data object.
First step should be to get a hexadecimal representation of data object's content in property list format.
NSData *datakCBAdvDataManufacturerData = [advertisementData valueForKey:#"kCBAdvDataManufacturerData"];
NSString *strmanufacturerData = datakCBAdvDataManufacturerData.description;
NSString *ChkStr = [strmanufacturerData substringWithRange:NSMakeRange(10, 8)];//depends upon your requirement.
NSLog(#"%#",ChkStr);
unsigned int outVal;
NSScanner* scanner = [NSScanner scannerWithString:ChkStr];
[scanner scanHexInt:&outVal];
NSLog(#"%#",outVal);
This outVal variable will contain value what you need.
I'm having an issue where I'm trying to create an NSString from encrypted data created by OpenSSL and I keep getting nil for the string.
The code that I'm using to encrypt and decrypt the data is taken from the following link http://saju.net.in/code/misc/openssl_aes.c.txt
Now here is the code where I'm calling to encrypt my data ("aes_init" is of course called on my application init):
//-- encrypt saved data
int textLen = str.size();
char* buff = const_cast<char*>(str.c_str());
EVP_CIPHER_CTX encryptCtx;
unsigned char *ciphertext = aes_encrypt(&encryptCtx,
reinterpret_cast<unsigned char*>(buff),
&textLen);
NSString * nsstring = [[NSString alloc] initWithBytes:reinterpret_cast<const char*>(ciphertext)
length:strlen(reinterpret_cast<const char*>(ciphertext))
encoding:NSUTF8StringEncoding];
[nsstring autorelease];
UIApplication* clientApp = [UIApplication sharedApplication];
AppController* appController = ((AppController *)clientApp.delegate);
[appController saveData:nsstring]; //--> crash at this line
I've tried different Encoding (NSASCIIStringEncoding and NSUnicodeStringEncoding) and they don't crash but the data is completely wrong after I decode.
Any ideas on how to solve this issue?
Thanks :)
Ciphertext, the output of an encryption function, should be indistinguishable from random. Meaning that any byte value can be generated, including byte values that do not map to characters. Hence it is needed to encode the ciphertext, for instance using base 64 encoding.
I'm using the following code to obfuscate a passcode for a test app of mine.
- (NSString *)obfuscate:(NSString *)string withKey:(NSString *)key
{
// Create data object from the string
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
// Get pointer to data to obfuscate
char *dataPtr = (char *) [data bytes];
// Get pointer to key data
char *keyData = (char *) [[key dataUsingEncoding:NSUTF8StringEncoding] bytes];
// Points to each char in sequence in the key
char *keyPtr = keyData;
int keyIndex = 0;
// For each character in data, xor with current value in key
for (int x = 0; x < [data length]; x++)
{
// Replace current character in data with
// current character xor'd with current key value.
// Bump each pointer to the next character
*dataPtr = *dataPtr++ ^ *keyPtr++;
// If at end of key data, reset count and
// set key pointer back to start of key value
if (++keyIndex == [key length])
keyIndex = 0, keyPtr = keyData;
}
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
This works like a charm with all strings, but i've ran into a bit of a problem comparing the following results
NSLog([[self obfuscate:#"0000", #"maki"]); //Returns 0]<W
NSLog([[self obfuscate:#"0809", #"maki"]); //Returns 0]<W
As you can see, the two strings with numbers in, while different, return the same result! Whats gone wrong in the code i've attached to result in the same result for these two numbers?
Another example:
NSLog([self obfuscate:#"8000" withKey:#"maki"]); //Returns 8U4_
NSLog([self obfuscate:#"8290" withKey:#"maki"]); //Returns 8U4_ as well
I may be misunderstanding the concept of obfuscation, but I was under the impression that each unique string returns a unique obfuscated string!
Please help me fix this bug/glitch
Source of Code: http://iosdevelopertips.com/cocoa/obfuscation-encryption-of-string-nsstring.html
The problem is your last line. You create the new string with the original, unmodified data object.
You need to create a new NSData object from the modified dataPtr bytes.
NSData *newData = [NSData dataWithBytes:dataPtr length:data.length];
return [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding];
But you have some bigger issues.
The calls to bytes returns a constant, read-only reference to the bytes in the NSData object. You should NOT be modifying that data.
The result of your XOR on the character data could, in theory, result in a byte stream that is no longer a valid UTF-8 encoded string.
The obfuscation algorithm that you have selected is based on XORing the data and the "key" values together. Generally, this is not very strong. Moreover, since XOR is symmetric, the results are very prone to producing duplicates.
Although your implementation is currently broken, fixing it would not be of much help in preventing the algorithm from producing identical results for different data: it is relatively straightforward to construct key/data pairs that produce the same obfuscated string - for example,
[self obfuscate:#"0123" withKey:#"vwxy"]
[self obfuscate:#"pqrs" withKey:#"6789"]
will produce identical results "FFJJ", even though both the strings and the keys look sufficiently different.
If you would like to "obfuscate" your strings in a cryptographically strong way, use a salted secure hash algorithm: it will produce very different results for even slightly different strings.
I'm trying to parse some HTML. I use stringWithContentsOfURL to get the HTML. I attempt to load this into a character array so I can parse it, but I crash with the EXC_BAD_ACCESS error when getCString is called. Here is the relavent code:
- (void)parseStoryWithURL:(NSURL *)storyURL
{
_paragraphs = [[NSMutableArray alloc] initWithCapacity:10];
_read = NO;
NSError* error = nil;
NSString* originalFeed = [NSString stringWithContentsOfURL:storyURL encoding:NSUTF8StringEncoding error:&error];
_i = originalFeed.length;
char* entireFeed = malloc(_i*sizeof(char));
char* current = entireFeed;
char* lagger;
char* recentChars = malloc(7);
BOOL collectRecent = NO;
BOOL paragraphStarted = NO;
BOOL paragraphEnded = NO;
int recentIndex = 0;
int paragraphSize = 0;
NSLog(#"original Feed: %#", originalFeed);
_read = [originalFeed getCString:*entireFeed maxLength:_i encoding:NSUTF8StringEncoding];
I've also tried this passing the 'current' pointer to getCString but it behaves the same. From what I've read this error is typically thrown when you try to read from deallocated memory. I'm programming for iOS 5 with memory management. The line before that I print the HTML to the log and everything is fine. Help would be appreciated. I need to get past this error so I can test/debug my HTML parsing algorithms.
PS: If someone with enough reputation is allowed to, please add "getCString" as a tag. Apparently no one uses this function :(
There are several issues with your code - you're passing the wrong pointers and not reserving enough space. Probably the easiest is to use UTF8String instead:
char *entireFeed = strdup([originalFeed UTF8String]);
At the end you'll have to free the string with free(entireFeed) though. If you don't modify it you can use
const char *entireFeed = [originalFeed UTF8String];
directly.
If you want to use getCString, you'll need to determine the length first - which has to include the termination character as well as extra space for encoded characters, so something like:
NSUInteger len = [originalFeed lengthOfBytesUsingEncoding: NSUTF8StringEncoding] + 1;
char entireFeed[len];
[originalFeed getCString:entireFeed maxLength:len encoding:NSUTF8StringEncoding];
Try explicitly malloc'ing entireFeed with a length of _i (not 100% certain of this, as NSUTF8String might also include double byte unichars or wchars) instead of the wacky char * entireFeed[_i] thing you're doing.
I can't imagine char * entireFeed[_i] is working at run-time (and instead, you're passing a NULL pointer to your getCString method).
A few strange things;
char* entireFeed[_i]; allocates an array of char*, not an array of char. I suspect you want char entireFeed[_i] or char *entireFeed = malloc(_i*sizeof(char));
getCString takes a char* as a first parameter, that is, you should send it entireFeed instead of *entireFeed.
Also, note that the (UTF-8) encoding may add bytes to the result, so allocating the buffer the exact size of the input may cause the method to return NO (buffer too small). You should really use [originalFeed UTF8String] instead.