I have a web-service running on Windows Azure which returns JSON that I consume in my iPhone app.
Unfortunately, Windows Azure doesn't seem to support the compression of dynamic responses yet (long story) so I decided to get around it by returning an uncompressed JSON package, which contains a compressed (using GZIP) string.
e.g
{"Error":null,"IsCompressed":true,"Success":true,"Value":"vWsAAB+LCAAAAAAAB..etc.."}
... where value is the compressed string of a complex object represented in JSON.
This was really easy to implement on the server, but for the life of me I can't figure out how to decompress a gzipped NSString into an uncompressed NSString, all the examples I can find for zlib etc are dealing with files etc.
Can anyone give me any clues on how to do this? (I'd also be happy for a solution that used deflate as I could change the server-side implementation to use deflate too).
Thanks!!
Steven
Edit 1: Aaah, I see that ASIHTTPRequest is using the following function in it's source code:
//uncompress gzipped data with zlib
+ (NSData *)uncompressZippedData:(NSData*)compressedData;
... and I'm aware that I can convert NSString to NSData, so I'll see if this leads me anywhere!
Edit 2: Unfortunately, the method described in Edit 1 didn't lead me anywhere.
Edit 3: Following the advice below regarding base64 encoding/decoding, I came up with the following code. The encodedGzippedString is as you can guess, a string "Hello, my name is Steven Elliott" which is gzipped and then converted to a base64 string. Unfortunately, the result that prints using NSLog is just blank.
NSString *encodedGzippedString = #"GgAAAB+LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee++997o7nU4n99//P1xmZAFs9s5K2smeIYCqyB8/fnwfPyK+uE6X2SJPiyZ93eaX+TI9Lcuiatvx/wOwYc0HGgAAAA==";
NSData *decodedGzippedData = [NSData dataFromBase64String:encodedGzippedString];
NSData* unGzippedJsonData = [ASIHTTPRequest uncompressZippedData:decodedGzippedData];
NSString* unGzippedJsonString = [[NSString alloc] initWithData:unGzippedJsonData encoding:NSASCIIStringEncoding];
NSLog(#"Result: %#", unGzippedJsonString);
After all this time, I finally found a solution to this problem!
None of the answers above helped me, as promising as they all looked. In the end, I was able to compress the string on the server with gzip using the chilkat framework for .net ... and then decompress it on the iphone using the chilkat framework for iOS (not yet released, but available if you email the guy directly).
The chilkat framework made this super easy to do so big thumbs up to the developer!
Your "compressed" string is not raw GZIP'd data, it's in some encoding that allows those bytes to be stored in a string-- looks like base-64 or something like it. To get an NSData out of this, you'll need to decode it into the NSData.
If it's really base-64, check out this blog post an accompanying code:
http://cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html
which will do what you want.
Once you have an NSData object, the ASIHTTPRequest method will probably do as you like.
This worked for me:
from a string gzipeed, then base64 encoded
to un-gzipped string (all utf8).
#import "base64.h"
#import "NSData+Compression.h"
...
+(NSString *)gunzipBase64StrToStr:(NSString *)stringValue {
//now we decode from Base64
Byte inputData[[stringValue lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];//prepare a Byte[]
[[stringValue dataUsingEncoding:NSUTF8StringEncoding] getBytes:inputData];//get the pointer of the data
size_t inputDataSize = (size_t)[stringValue length];
size_t outputDataSize = EstimateBas64DecodedDataSize(inputDataSize);//calculate the decoded data size
Byte outputData[outputDataSize];//prepare a Byte[] for the decoded data
Base64DecodeData(inputData, inputDataSize, outputData, &outputDataSize);//decode the data
NSData *theData = [[NSData alloc] initWithBytes:outputData length:outputDataSize];//create a NSData object from the decoded data
//NSLog(#"DATA: %# \n",[theData description]);
//And now we gunzip:
theData=[theData gzipInflate];//make bigger==gunzip
return [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding];
}
#end
I needed to compress data on the iPhone using Objective-c and decompress on PHP. Here is what I used in XCode 11.5 and iOS 12.4:
iOS Objective-c Compression Decompression Test
Include libcompression.tbd in the Build Phases -> Link Binary With Library. Then include the header.
#include "compression.h"
NSLog(#"START META DATA COMPRESSION");
NSString *testString = #"THIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TEST";
NSData *theData = [testString dataUsingEncoding:NSUTF8StringEncoding];
size_t src_size = theData.length;
uint8_t *src_buffer = (uint8_t*)[theData bytes];
size_t dst_size = src_size+4096;
uint8_t *dst_buffer = (uint8_t*)malloc(dst_size);
dst_size = compression_encode_buffer(dst_buffer, dst_size, src_buffer, src_size, NULL, COMPRESSION_ZLIB);
NSLog(#"originalsize:%zu compressed:%zu", src_size, dst_size);
NSData *dataData = [NSData dataWithBytes:dst_buffer length:sizeof(dst_buffer)];
NSString *compressedDataBase64String = [dataData base64EncodedStringWithOptions:0];
NSLog(#"Compressed Data %#", compressedDataBase64String);
NSLog(#"START META DATA DECOMPRESSION");
src_size = compression_decode_buffer(src_buffer, src_size, dst_buffer, dst_size, NULL, COMPRESSION_ZLIB);
NSData *decompressed = [[NSData alloc] initWithBytes:src_buffer length:src_size];
NSString *decTestString;
decTestString = [[NSString alloc] initWithData:decompressed encoding:NSASCIIStringEncoding];
NSLog(#"DECOMPRESSED DATA %#", decTestString);
free(dst_buffer);
On the PHP side I used the following function to decompress the data:
function decompressString($compressed_string) {
//NEED RAW GZINFLATE FOR COMPATIBILITY WITH IOS COMPRESSION_ZLIB WITH IETF RFC 1951
$full_string = gzinflate($compressed_string);
return $full_string;
}
Related
I am looking to convert a signature that is captured from the user.
I have the following
NSData *imageData = UIImagePNGRepresentation(drawImage.image);
NSUInteger len = [imageData length];
byteData = (Byte*)malloc(len);
memcpy(byteData, [imageData bytes], len);
Which I saw from a similar question, My problem is I can't use byteData anywhere, it shoots back a Bad_access error. E Am I converting it properly to a byte Array? If I output imageData to console i get
<89504e47 0d0a1a0a 0000000d 49484452 00000140 0000016f 08060000 003b6a12 49000020 00494441 547801ed 9d07b464 4599c71d 494a5219 5832c210 84251d19 51118519 755d0c18 402489a0 b206c015 44443d0a a8e82a8a 804a7005 040cc0c2 022eac89 a30c02a3 4bf02c41 24391266 605601c9 9267ffff 377d39df f474bfd7 affb7657 75d7afce f9dead9b eaabfa7d f7febb6e ddf0a62c 58b0e079 24084000 02251278 7e898da6 cd108000 044c0001 e4388000 048a2580 00161b7a 1a0e0108 20801c03 108040b1 0410c062 434fc321 00010490 63000210 28960002 586ce869 38042080 00720c40 0002c512 40008b0d 3d0d8700 0410408e 010840a0 58020860 b1a1a7e1 10800002 c8310001 08144b00 012c36f4 341c0210 40003906 20008162 092080c5 869e8643 00020820 c7000420 502c0104 b0d8d0d3 70084000 01e41880 00048a25 8000161b 7a1a0e01 0820801c 03108040 b10410c0 62434fc3 21000104 90630002 10289600 02586ce8 69380420 8000720c 400002c5 1240008b 0d3d0d87 00041040 8e010840 a0580208 60b1a1a7 e1108000 02c83100 0108144b 00012c36 f4341c02 10400039 06200081 62092080 c5869e86 43000208 20c70004 20502c01 04b0d8d etc..
To convert data to string use:
[NSString stringWithCString: encoding:];
[NSString stringWithUTF8String:];
If you want to send it via HTTP use the second one. And make sure it is zero-terminated:
byteData = (Byte*)calloc(len+1, sizeof(Byte));
Solved it. Problem was i was encoding it with the format. I need to do a base64 Encoding. The following the site was was where the answer for the base64 encoder is http://www.cocoadev.com/index.pl?BaseSixtyFour
I'm looking for an example demonstrating how I can encode and then decode the same string using UTF-8. Encode and then Decode means I want to implement the methods in 2 areas where one can encode it and another is able to decode it.
I have seen the API but I didn't get much success:
stringWithCString:encoding:
stringWithUTF8String:
stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc;
EDITED
I have the string øæ-test-2.txt which I am encoding as follows:
char *s = "øæ-test-2.txt";
NSString *enc = [NSString stringWithCString:s encoding:NSASCIIStringEncoding];
but am getting øæ-test-2.txt as output.
Now I want to get back the original string back i.e. øæ-test-2.txt
EDITED
I am getting øæ-test-2.txt from server and I need øæ-test-2.txt by decoding it. I am able to get the output from the link : http://www.cafewebmaster.com/online_tools/utf_decode
Please try to use the link and you will understand my concern.
It would be highly appreciated if anyone can give some hint, tutorial or point me in the right direction.
Regards
To turn an NSString object into a UTF8 C-string, use UTF8String
char *utf8string = [#"A string with ümläuts" UTF8String];
To turn a UTF8 C-string into an NSString object, use stringWithUTF8String: or initWithUTF8String:
NSString *string = [NSString stringWithUTF8String:utf8string];
Note that NSString objects are implemented as UTF-16, so you can't really have a "UTF-8 NSString" (and the encoding should be treated as an implementation detail, anyway).
Instead of
char *utf8string = [#"A string with ümläuts" UTF8String];
This should be
const char *utf8string = [#"A string with ümläuts" UTF8String];
Otherwise you have an incompatible type issue.
I'm new to this, so here goes..
I'm having a problem with displaying images in uitableview, that are downloaded from a mysql database. Here's what I'm doing:
converting images using UIImagePNGRepresentation.
uploading to MYSQL database via webservice.
So far so good..
The images are downloaded from MYSQL using JSON.
NSDictionary used to create array of image data from JSON String.
[UIImage imageWithData:[imageArray objectAtIndex:indexpath.row]] fails with error: [NSCFString bytes]: unrecongnised selector sent to instance.
I can understand why this is happening, but don't know how to resolve it. The imageWithData is expecting NSData object, but I've converted the string to NSData with no success.
Any help will be greatly appreciated.
Are you converting to and from data properly?
To data:
NSData* theData;
theData = [theNSString dataUsingEncoding:NSASCIIStringEncoding];
To string:
NSString* theNSString;
theNSString = [[NSString alloc] initWithData:theData encoding:NSASCIIStringEncoding];
Thanks for your response.
Yes I was doing the conversion to/from data, as you stated, the only difference being that I was using NSUTF8StringEncoding rather than NSASCIIStringEncoding.
I've tried it with NSASCIIStringEncoding, but the results is the same. It seems that the converted data is different to that stored on the database.
The data from the JSON string (NSData to NSString) is:
<89504e47 0d0a1a0a 0000000d 49484452 00000087 0000005a 08020000 001d25d2 ac000020 00494441 54780174 bd7778dc e775e73b bdf78e19 f40e1004 c002764a ec942cdb b12ccb55 b6e3123b 8e539e44 cecd3ad7 bbc9c6eb f4dc2789 b3297e9c 4d1cc5b1 2dc9b264 4bb22a25 52ec0401 16f45e07 184ceff3 ....
However, the conversion back to NSData gives the following data:
<3c383935 30346534 37203064 30613161 30612030 30303030 30306420 34393438 34343532 20303030 30303038 37203030 30303030 35612030 38303230 30303020 30303164 32356432 20616330 30303032 30203030 34393434 34312035 34373830.....
This may be the same, but [UIImage imageWithData:theData] returns null image.
NSXMLParserInvalidCharacterError # 9
This is the error I get when I hit a weird character (like quotes copied and pasted from word to the web form, that end up in the feed). The feed I am using is not giving an encoding, and their is no hope for me to get them to change that. This is all I get in the header:
< ?xml version="1.0"?>
< rss version="2.0">
What can I do about illegal characters when parsing feeds? Do I sweep the data prior to the parse? Is there something I am missing in the API? Has anyone dealt with this issue?
NSString *dataString = [[[NSString alloc] initWithData:webData encoding:NSASCIIStringEncoding] autorelease];
NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
Fixed my problems...
The NSString -initWithData:encoding: method returns nil if it fails, so you can try one encoding after another until you find one that converts. This doesn't guarantee that you'll convert all the characters correctly, but if your feed source isn't sending you correctly encoded XML, then you'll probably have to live with it.
The basic idea is:
// try the most likely encoding
NSString xmlString = [[NSString alloc] initWithData:xmlData
encoding:NSUTF8StringEncoding];
if (xmlString == nil) {
// try the next likely encoding
xmlString = [[NSString alloc] initWithData:xmlData
encoding:NSWindowsCP1252StringEncoding];
}
if (xmlString == nil) {
// etc...
}
To be generic and robust, you could do the following until successful:
1.) Try the encoding specified in the Content-Type header of the HTTP response (if any)
2.) Check the start of the response data for a byte order mark and if found, try the indicated encoding
3.) Look at the first two bytes; if you find a whitespace character or '<' paired with a nul/zero character, try UTF-16 (similarly, you can check the first four bytes to see if you have UTF-32)
4.) Scan the start of the data looking for the <?xml ... ?> processing instruction and look for encoding='something' inside it; try that encoding.
5.) Try some common encodings. Definitely check Windows Latin-1, Mac Roman, and ISO Latin-1 if your data source is in English.
6.) If none of the above work, you could try removing all bytes greater than 127 (or substitute '?' or another ASCII character) and convert the data using the ASCII encoding.
If you don't have an NSString by this point, you should fail. If you do have an NSString, you should look for the encoding declaration in the <?xml ... ?> processing instruction (if you didn't already in step 4). If it's there, you should convert the NSString back to NSData using that encoding; if it's not there, you should convert back using UTF-8 encoding.
Also, the CFStringConvertIANACharSetNameToEncoding() and CFStringConvertEncodingToNSStringEncoding() functions can help get the NSStringEncoding that goes with the encoding name form the Content-Type header or the <?xml ... ?> processing instruction.
You can also remove that encoding line from xml like this:
int length = str.length >100 ? 100:str.length;
NSString*mystr= [str stringByReplacingOccurrencesOfString:#"encoding=\".*?\""
withString:#""
options:NSRegularExpressionSearch
range:NSMakeRange(0, length)];
im trying to get a call to amazon web service and im stuck on getting the signature, looked at this but i still have a question on it.
using this example what is the
NSData *keyData;
NSData *clearTextData
? what do i need to pass for these two values?
/*
inputs:
NSData *keyData;
NSData *clearTextData
*/
uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0};
CCHmacContext hmacContext;
CCHmacInit(&hmacContext, kCCHmacAlgSHA1, keyData.bytes, keyData.length);
CCHmacUpdate(&hmacContext, clearTextData.bytes, clearTextData.length);
CCHmacFinal(&hmacContext, digest);
NSData *out = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]
I just spent like 4 hours Googling and looking for ways to calculate an unkeyed SHA1 on the iPhone that would match the results of the sha1() function in php. Here was the result:
#import <CommonCrypto/CommonDigest.h>
NSString *hashkey = <your data here>;
// PHP uses ASCII encoding, not UTF
const char *s = [hashkey cStringUsingEncoding:NSASCIIStringEncoding];
NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
// This is the destination
uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0};
// This one function does an unkeyed SHA1 hash of your hash data
CC_SHA1(keyData.bytes, keyData.length, digest);
// Now convert to NSData structure to make it usable again
NSData *out = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
// description converts to hex but puts <> around it and spaces every 4 bytes
NSString *hash = [out description];
hash = [hash stringByReplacingOccurrencesOfString:#" " withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#"<" withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#">" withString:#""];
// hash is now a string with just the 40char hash value in it
Hopefully this will help others who are struggling with SHA1 on the iPhone
If you are calling the Amazon web service too look up prices or product details, your Amazon web service key will be disabled and your app will stop working.
Look at the terms of service of the Amazon Web Services, use by mobile clients is strictly disallowed:
https://affiliate-program.amazon.com/gp/advertising/api/detail/agreement.html
I found this out the hard way when my own application had my AWS key disabled in a production app. I had read the TOS, but it was not really there as you can see by the link above to some other obscure detail of use. You wouldn't think the affiliate program would have anything to do with the API, but it does.
You can find details of other apps blocked at this TechCrunch article:
http://www.techcrunch.com/2009/07/07/amazon-killing-mobile-apps-that-use-its-data/
Just giving you a heads up and hopefully saving you a lot of work.
// This is my code used in my Twitter connection, and working well for me.
// KeithF's code was a big help!
//
// This is a category added to NSData.
#implementation NSData (EOUtil)
- (NSData*)dataByHmacSHA1EncryptingWithKey:(NSData*)key
{
void* buffer = malloc(CC_SHA1_DIGEST_LENGTH);
CCHmac(kCCHmacAlgSHA1, [key bytes], [key length], [self bytes], [self length], buffer);
return [NSData dataWithBytesNoCopy:buffer length:CC_SHA1_DIGEST_LENGTH freeWhenDone:YES];
}
#end
Take a look at CocoaCryptoHashing for the SHA1 encoding
I posted one solution to this here, that returns the Base64 encoded data that AWS requests.
Apple's iOS developer library has provided an excellent sample titled CryptoExercise which includes a simple function:
- (NSData *)getHashBytes:(NSData *)plainText" to get a SHA-1 hash.
You can see this
maybe it helps you.