Compress/Decompress NSString in objective-c (iphone) using GZIP or deflate
Asked Answered
C

4

8

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);  
Cheriecherilyn answered 10/6, 2010 at 15:34 Comment(0)
C
4

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!

Cheriecherilyn answered 7/4, 2011 at 21:44 Comment(1)
Hi, Can you provide any exact link to the framework?Pathos
B
1

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.

Benedetto answered 14/6, 2010 at 22:37 Comment(2)
Hi Quixoto, Thanks for your response. If you check edit 3 in my original post, you will see what happened after I tried some more using your advice. Thanks againCheriecherilyn
That's a reasonable set of steps, so what isn't clear is: is the transmitted string definitely Base64? (probably) What is the original encoding of the original string in Windows land? You're picking an ASCII encoding on the decode, which is unlikely to be correct. Is the data in the NSData buffer telling at all?Benedetto
A
0

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
Aunt answered 1/10, 2010 at 13:40 Comment(0)
P
0

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;

}  
Pasho answered 28/9, 2020 at 3:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.