Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // NSData+zlibCompression.m
- //
- // Created by Jonathan Annett on 9/10/13.
- // Copyright (c) 2013 Sophtwhere. All rights reserved.
- //
- #import "NSData+zlibCompression.h"
- #import "NSData+Base64.h"
- #include <zlib.h>
- // turn off NSLog for this file
- #define NSLog(...)
- @implementation NSData (zlibCompression)
- - (NSData *)zlibInflate
- {
- if ([self length] == 0) return self;
- NSData *result = nil;
- @autoreleasepool {
- unsigned full_length = [self length];
- unsigned half_length = [self length] / 2;
- NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
- BOOL done = NO;
- int status;
- z_stream strm;
- strm.next_in = (Bytef *)[self bytes];
- strm.avail_in = [self length];
- strm.total_out = 0;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- if (inflateInit (&strm) != Z_OK) return nil;
- while (!done)
- {
- // Make sure we have enough room and reset the lengths.
- if (strm.total_out >= [decompressed length])
- [decompressed increaseLengthBy: half_length];
- strm.next_out = [decompressed mutableBytes] + strm.total_out;
- strm.avail_out = [decompressed length] - strm.total_out;
- // Inflate another chunk.
- status = inflate (&strm, Z_SYNC_FLUSH);
- if (status == Z_STREAM_END) done = YES;
- else if (status != Z_OK) break;
- }
- if (inflateEnd (&strm) != Z_OK) return nil;
- // Set real length.
- if (done) {
- [decompressed setLength: strm.total_out];
- result= [[NSData alloc] initWithData:decompressed];
- } else {
- result = nil;
- }
- }
- return [result autorelease];
- }
- - (NSData *)zlibDeflate
- {
- if ([self length] == 0) return self;
- NSData *result = nil;
- @autoreleasepool {
- z_stream strm;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.total_out = 0;
- strm.next_in=(Bytef *)[self bytes];
- strm.avail_in = [self length];
- // Compresssion Levels:
- // Z_NO_COMPRESSION
- // Z_BEST_SPEED
- // Z_BEST_COMPRESSION
- // Z_DEFAULT_COMPRESSION
- if (deflateInit(&strm, Z_BEST_COMPRESSION) != Z_OK) return nil;
- NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chuncks for expansion
- do {
- if (strm.total_out >= [compressed length])
- [compressed increaseLengthBy: 16384];
- strm.next_out = [compressed mutableBytes] + strm.total_out;
- strm.avail_out = [compressed length] - strm.total_out;
- deflate(&strm, Z_FINISH);
- } while (strm.avail_out == 0);
- deflateEnd(&strm);
- [compressed setLength: strm.total_out];
- NSLog(@"ZLIB: reduced data from %d bytes to %d (%1.1f%% savings)",
- self.length,
- compressed.length,
- (((float)(self.length-compressed.length))/(float)self.length * 100)
- );
- result = [[NSData alloc] initWithData:compressed];
- }
- return [result autorelease];
- }
- - (NSData *)gzipInflate
- {
- if ([self length] == 0) return self;
- unsigned full_length = [self length];
- unsigned half_length = [self length] / 2;
- NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
- BOOL done = NO;
- int status;
- z_stream strm;
- strm.next_in = (Bytef *)[self bytes];
- strm.avail_in = [self length];
- strm.total_out = 0;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- if (inflateInit2(&strm, (15+32)) != Z_OK) return nil;
- while (!done)
- {
- // Make sure we have enough room and reset the lengths.
- if (strm.total_out >= [decompressed length])
- [decompressed increaseLengthBy: half_length];
- strm.next_out = [decompressed mutableBytes] + strm.total_out;
- strm.avail_out = [decompressed length] - strm.total_out;
- // Inflate another chunk.
- status = inflate (&strm, Z_SYNC_FLUSH);
- if (status == Z_STREAM_END) done = YES;
- else if (status != Z_OK) break;
- }
- if (inflateEnd (&strm) != Z_OK) return nil;
- // Set real length.
- if (done)
- {
- [decompressed setLength: strm.total_out];
- return [NSData dataWithData: decompressed];
- }
- else return nil;
- }
- - (NSData *)gzipDeflate
- {
- if ([self length] == 0) return self;
- z_stream strm;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.total_out = 0;
- strm.next_in=(Bytef *)[self bytes];
- strm.avail_in = [self length];
- // Compresssion Levels:
- // Z_NO_COMPRESSION
- // Z_BEST_SPEED
- // Z_BEST_COMPRESSION
- // Z_DEFAULT_COMPRESSION
- if (deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil;
- NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chunks for expansion
- do {
- if (strm.total_out >= [compressed length])
- [compressed increaseLengthBy: 16384];
- strm.next_out = [compressed mutableBytes] + strm.total_out;
- strm.avail_out = [compressed length] - strm.total_out;
- deflate(&strm, Z_FINISH);
- } while (strm.avail_out == 0);
- deflateEnd(&strm);
- [compressed setLength: strm.total_out];
- NSLog(@"GZIP: reduced data from %d bytes to %d (%1.1f%% savings)",
- self.length,
- compressed.length,
- (((float)(self.length-compressed.length))/(float)self.length * 100)
- );
- return [NSData dataWithData:compressed];
- }
- -(NSData*) compress{
- if ([self length] == 0) return self;
- NSData *z = [self zlibDeflate];
- NSData *u = self;
- char method = 0;
- if (z.length < self.length) {
- method = 1;
- u = z;
- NSLog(@"using ZLIB");
- } else {
- NSLog(@"using RAW");
- }
- NSMutableData *result = [[[NSMutableData alloc] initWithBytes:&method length:1] autorelease];
- [result appendData:u];
- return result;
- }
- -(NSData*) decompress{
- if ([self length] == 0) return self;
- NSData *source = [self subdataWithRange:(NSRange){.location = 1,.length = self.length-1}];
- char *method = (char*) self.bytes;
- switch (*method) {
- case 0:
- return source;
- break;
- case 1:
- return [source zlibInflate];
- break;
- default:
- return nil;
- break;
- }
- }
- -(NSString*) base64CompressedString{
- return [[self compress] base64EncodedString];
- }
- +(NSData*) dataFromBase64CompressedString:(NSString*) b64 {
- return [[NSData dataFromBase64String:b64] decompress];
- }
- @end
- @implementation NSDictionary (b64compressed)
- -(NSString*) b64String{
- NSData *json = [NSJSONSerialization dataWithJSONObject:self options:0 error:nil];
- if (json) {
- NSData *compressed = [json compress];
- if (compressed) {
- return [compressed base64EncodedString];
- }
- }
- return nil;
- }
- +(NSDictionary*) dictionaryWithB64String:(NSString*) b64String {
- NSData *compressed = [NSData dataFromBase64String:b64String];
- if (compressed) {
- NSData *json = [compressed decompress];
- if (json) {
- NSDictionary *result = [NSJSONSerialization JSONObjectWithData:json options:0 error:nil];
- if (result) {
- if ([result isKindOfClass:[self class]]) {
- return result;
- }
- return [[self class] dictionaryWithDictionary:result];
- }
- }
- }
- return nil;
- }
- @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement