Compare NSData with byte sequence? - ios

Note: in other questions they compare a value stored in NSData objects, not its bytes.
I want to perform something like this:
NSData *d = ...;
if (d == "fff1") {
...
}
The only solution I have found:
NSData *d = ...;
NSString *str = [NSString withFormat:#"%#", d];
if ([str isEqualToString:#"<fff1>"] {
...
}
But I don't like that I need to add extra surrounding backets in comparison. Are there better solutions?

For purpose of comparing raw data you use memcmp:
NSData *dataA;
void *someBuffer;
if(memcmp([dataA bytes], someBuffer, dataA.length) == 0) ; //they are the same
Note you should watch that length is not too large for any of the buffers.
EDIT: added NSData procedure:
Or better yet you could convert your string to NSData and do the comparison on the NSData:
NSData *d = ...;
if([d isEqualToData:[NSData dataWithBytes:"fff1" length:sizeof("fff1")]]) {
}

Related

JSon returning Integer values into array

I have successfully realized the interaction with json and returning successfully all the required entities. But i have one field that will be returned as an integer. I want to do the simplest thing and access an element of the array , which is an integer , and compare it with another integer. No matter what i do it doesn't work out : this is my code so far :
NSString *strURL2 = [NSString stringWithFormat:#"MyURL"];
NSData *dataURL2 = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL2]];
NSString *strResult2 = [[NSString alloc] initWithData:dataURL2 encoding:NSUTF8StringEncoding];
NSDictionary *json2 = [strResult2 JSONValue];
userExists = [json2 valueForKeyPath:#"userId"];
Where userExists is an array, and the values stored in it are NOT strings , they are Int.
Any help?!
NSString *strURL2 = [NSString stringWithFormat:#"MyURL"];
NSData *dataURL2 = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL2]];
NSString *strResult2 = [[NSString alloc] initWithData:dataURL2 encoding:NSUTF8StringEncoding];
NSDictionary *json2 = [strResult2 JSONValue];
Now if you want to add the integer to the array (has to be NSMutableArray of course) userExists, you do it like so:
[userExists addObject:[[json2 objectForKey:#"userId"] integerValue]]
If your intention was to compare the returned integer with an integer in the array at index i then you do it like so:
if([userExists objectAtIndex:i] == [[json2 objectForKey:#"userId"] integerValue]) {
....
}

How to get a certain bytes length subString from a NSString

Such as I have a NSString is str = #"我就是测试一下" or str = #"我" . And I want to restrict a certain byte length. such as byteLength = 10.
I know the subSrtring is not the str.length=10 How to get a certain bytes length subString from a NSString, thank you
you can use dataUsingEncoding method to get a NSData from NSString. And then use length and bytes property to get the byte length or bytes
Then if the NSData's length > your certain length you should use + (id)dataWithBytes:(const void *)bytes length:(NSUInteger)length; method to get the certain length byte NSData you should be careful that the return NSData may be can not decode by NSString
At last you can use - (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding; method to get the result NSString you want
And you can use the code below:
- (NSString *)fetchStringWithOriginalString:(NSString *)originalString withByteLength:(NSUInteger)length
{
NSData* originalData=[originalString dataUsingEncoding:NSUTF8StringEncoding];
const char *originalBytes = originalData.bytes;
//make sure to use a loop to get a not nil string.
//because your certain length data may be not decode by NSString
for (NSUInteger i = length; i > 0; i--) {
#autoreleasepool {
NSData *data = [NSData dataWithBytes:originalBytes length:i];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (string) {
return string;
}
}
}
return #"";
}
you can call the above method like this :
NSString* originalString= #"我就是测试一下";
NSString *string = [self fetchStringWithOriginalString:originalString withByteLength:10];
NSData* stringData=[string dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"10 bytes string : %# ; it only %i bytes",string,stringData.length);
The Result :
Be careful:
the - (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding; may be return nil
As apple said:the - (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding; Return:
An NSString object initialized by converting the bytes in data into
Unicode characters using encoding. The returned object may be
different from the original receiver. Returns nil if the
initialization fails for some reason (for example if data does not
represent valid data for encoding).
So you should use a for loop to get a nearest length data which can decode by NSSting
Use
[str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]
I think this should work:
NSUInteger bytes = [incomingText lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
if (bytes > MAX_TEXT_BYTES) {
int length = [incomingText length];
int cutoffIndex = (int)(MAX_TEXT_BYTES * (length / bytes));
return [incomingText substringToIndex:cutoffIndex];
}

Struct to NSData between Mac and iOS

I have been working on this problem for a while, I have an app running on the mac, it has co-ordinate data stored in a struct like this:
struct xyz {
float x;
float y;
float z;
};
struct xy {
float x;
float y;
};
struct object {
struct xyz *myXYZ;
struct xy *myXY;
};
This all works as expected, then I add the struct into NSData like so:
struct object anInitialTestStruct;
NSMutableData *myTestDataOut = [NSMutableData dataWithBytes:&anInitialTestStruct length:64 freeWhenDone:NO];
BOOL good = [myTestDataOut writeToFile:[NSString stringWithFormat:#"%#/filename.dat", docsDirectory] atomically:YES];
This works as expected, I get a file and looks like there is data in it (for reference I have used pointers and malloc for the anInitialTestStruct but still don't get the desired result)
Now on the iphone, I copy the file into the project, and do this:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"filename" ofType:#"dat"];
NSData *myVecNSData = [[NSData alloc] initWithContentsOfFile:filePath options:NSDataReadingUncached error:&error];
if ( error ) {
NSLog(#"%#", error);
}
I don't get the correct data back. Interestingly if I run the initWithContents method on the mac and read the file in there it appears to be ok.
So I'm thinking there is something different on the iphone / mac way it deals with the filesystem.... I've tried encoding the data using NSKeyedArchiver, but I get an exception stating "incomprehensible archive....."
For case of your "object" structure you have to store "xy" and "xyz" structures separately, for example in a dictionary:
struct object anInitialTestStruct;
NSDictionary *structureDataAsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[NSMutableData dataWithBytes:anInitialTestStruct.myXY length:sizeof(xy)], #"xy key",
[NSMutableData dataWithBytes:anInitialTestStruct.myXYZ length:sizeof(xyz)], #"xyz key",
nil];
NSData *myTestDataOut = [NSKeyedArchiver archivedDataWithRootObject:structureDataAsDictionary];
BOOL good = [myTestDataOut writeToFile:[NSString stringWithFormat:#"%#/filename.dat", docsDirectory] atomically:YES];
and decoding is something like this:
struct object anInitialTestStruct;
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"filename" ofType:#"dat"];
NSData *myVecNSData = [[NSData alloc] initWithContentsOfFile:filePath options:NSDataReadingUncached error:&error];
if ( error ) {
NSLog(#"%#", error);
}
// retrieving dictionary from NSData
NSDictionary *structureDataAsDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:myVecNSData];
// allocating memory for myXY and myXYZ fields
anInitialTestStruct.myXY = (xy*)malloc(sizeof(xy));
if (anInitialTestStruct.myXY == NULL) {
// error handling
}
anInitialTestStruct.myXYZ = (xyz*)malloc(sizeof(xyz));
if (anInitialTestStruct.myXYZ == NULL) {
// error handling
}
// filling myXY and myXYZ fields with read data
[[structureDataAsDictionary objectForKey:#"xy key"] getBytes:anInitialTestStruct.myXY];
[[structureDataAsDictionary objectForKey:#"xyz key"] getBytes:anInitialTestStruct.myXYZ];
You might have truble encoding your pointers see here
"Pointers
You can’t encode a pointer and get back something useful at decode time. You have to encode the information to which the pointer is pointing. This is true in non-keyed coding as well. ..."

How to convert NData populated with hex values to NSString

I have a NSdata object that is populated with a bunch of information thats formated in hex.. I am trying to convert it into its proper string representation but am struggling to have any success.
One thing I have tried is to simply put it into a NSString and then NSLog it with a special character identifier thingy.. forgot the word (%02x), However to do this I am encoding it to NSUTF16.. which i dont want to do.. I mearly want to see exactly whats the data I am getting looks like as a NSString.
The reason I am doing this is because I am having some issues with my encoding later on in my code and im not sure if its because the data I am receiving is incorrect or me stuffing it up at some point when I am handling it.
Any help would be appreciated.
You can get a string representation of your NSData like so:
NSData *data = (your data)
NSString *string = [NSString stringWithCString:[data bytes] encoding:NSUTF8StringEncoding];
Does that answer your question?
Maybe I haven't understood, but something like this:
NSData *yourData;
NSLog(#"%#", [yourData description]);
doesn't fit your need?
Give this a try -
-(NSString*)hexToString:(NSData*)data{
NSString *hexString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
if (([hexString length] % 2) != 0)
return nil;
NSMutableString *string = [NSMutableString string];
for (NSInteger i = 0; i < [hexString length]; i += 2) {
NSString *hex = [hexString substringWithRange:NSMakeRange(i, 2)];
NSInteger decimalValue = 0;
sscanf([hex UTF8String], "%x", &decimalValue);
[string appendFormat:#"%d", decimalValue];
}
return string;
}

Decoding the scanned barcode value to int value

When I scan the barcode and I get some value if it is Equal=2 then I need to display with == and if it is Equal=3 then I need to display with = and if the value is 4 then invalid.
But Scanned Barcode are of integer value -- when decode using NSASCII it is displaying only till value 127 after that it is showing invalid results. Eg: if my Barcode value = 9699 the result value=jem then my added result value=jem= actualstring value=%åasc value id only showing 37
Here is my code:
- (void) readerView:(ZBarReaderView *)view didReadSymbols:(ZBarSymbolSet *)syms fromImage:(UIImage *)img
{
// do something useful with results -- cool thing is that you get access to the image too
for (ZBarSymbol *symbol in syms) {
[resultsBox setText:symbol.data];
if ([resultsBox.text length] == 2) {
addedresult.text = [resultsBox.text stringByAppendingString:#"=="];
} else if ([resultsBox.text length] == 3) {
addedresult.text = [resultsBox.text stringByAppendingString:#"="];
} if ([resultsBox.text length] >= 4) {
addedresult.text = #"Invalid";
}
[Base64 initialize];
NSString *myString = [[NSString alloc]initWithString:addedresult.text];
NSData * data = [Base64 decode:myString];
NSString * actualString = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"%#",actualString);
labeltext.text= actualString;
int asc = [actualString characterAtIndex:0];
label.text = [NSString stringWithFormat:#"%d", asc];
[actualString release];
break;
}
}
Since someone revived this question's comments, i'll revive this entire post.
You shouldn't go through NSData to create an NSString from something you already have, and you're probably losing something along the way. Go directly to NSString using stringWithFormat. Also, ASCII will come back and byte you later, if you have a choice, use UTF8.
NSString *actualStringUTF8 = [NSString stringWithFormat:#"%#",[addedresult.text urlEncodeUsingEncoding:NSUTF8StringEncoding]];
NSString *actualStringASCII = [NSString stringWithFormat:#"%#",[addedresult.text urlEncodeUsingEncoding:NSUTF8StringEncoding]];
NSLog(#"%#",actualStringUTF8);
NSLog(#"%c",[actualStringUTF8 UTF8String]); //This is a const char*
Secondly, I looked into the SDK and it says symbol.data is already an NSString*. Depending on what you want, you may not need to do anything. If you do end up needing to change encoding, make sure you understand why you need to (one good reason is "the rest of the application uses NS****StringEncoding").
Also make sure you compare strings the correct "Objective-C" way:
[actualString isEqualToString: testString];
NOT actualString == testString;

Resources