Advertisement
sophtwhere

NSData+zlibCompression.m

Oct 28th, 2013
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //
  2. //  NSData+zlibCompression.m
  3. //
  4. //  Created by Jonathan Annett on 9/10/13.
  5. //  Copyright (c) 2013 Sophtwhere. All rights reserved.
  6. //
  7.  
  8. #import "NSData+zlibCompression.h"
  9. #import "NSData+Base64.h"
  10.  
  11. #include <zlib.h>
  12.  
  13. // turn off NSLog for this file
  14. #define NSLog(...)
  15.  
  16.  
  17.  
  18.  
  19. @implementation NSData (zlibCompression)
  20.  
  21. - (NSData *)zlibInflate
  22. {
  23.  
  24.     if ([self length] == 0) return self;
  25.    
  26.     NSData *result = nil;
  27.    
  28.     @autoreleasepool {
  29.        
  30.         unsigned full_length = [self length];
  31.         unsigned half_length = [self length] / 2;
  32.        
  33.         NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
  34.         BOOL done = NO;
  35.         int status;
  36.        
  37.         z_stream strm;
  38.         strm.next_in = (Bytef *)[self bytes];
  39.         strm.avail_in = [self length];
  40.         strm.total_out = 0;
  41.         strm.zalloc = Z_NULL;
  42.         strm.zfree = Z_NULL;
  43.        
  44.         if (inflateInit (&strm) != Z_OK) return nil;
  45.        
  46.         while (!done)
  47.         {
  48.             // Make sure we have enough room and reset the lengths.
  49.             if (strm.total_out >= [decompressed length])
  50.                 [decompressed increaseLengthBy: half_length];
  51.             strm.next_out = [decompressed mutableBytes] + strm.total_out;
  52.             strm.avail_out = [decompressed length] - strm.total_out;
  53.            
  54.             // Inflate another chunk.
  55.             status = inflate (&strm, Z_SYNC_FLUSH);
  56.             if (status == Z_STREAM_END) done = YES;
  57.             else if (status != Z_OK) break;
  58.         }
  59.         if (inflateEnd (&strm) != Z_OK) return nil;
  60.        
  61.         // Set real length.
  62.         if (done) {
  63.             [decompressed setLength: strm.total_out];
  64.             result= [[NSData alloc] initWithData:decompressed];
  65.         } else {
  66.             result = nil;
  67.         }
  68.     }
  69.    
  70.     return [result autorelease];
  71. }
  72.  
  73. - (NSData *)zlibDeflate
  74. {
  75.     if ([self length] == 0) return self;
  76.  
  77.     NSData *result = nil;
  78.    
  79.     @autoreleasepool {
  80.        
  81.         z_stream strm;
  82.        
  83.         strm.zalloc = Z_NULL;
  84.         strm.zfree = Z_NULL;
  85.         strm.opaque = Z_NULL;
  86.         strm.total_out = 0;
  87.         strm.next_in=(Bytef *)[self bytes];
  88.         strm.avail_in = [self length];
  89.        
  90.         // Compresssion Levels:
  91.         //   Z_NO_COMPRESSION
  92.         //   Z_BEST_SPEED
  93.         //   Z_BEST_COMPRESSION
  94.         //   Z_DEFAULT_COMPRESSION
  95.        
  96.         if (deflateInit(&strm, Z_BEST_COMPRESSION) != Z_OK) return nil;
  97.        
  98.         NSMutableData *compressed = [NSMutableData dataWithLength:16384];  // 16K chuncks for expansion
  99.        
  100.         do {
  101.            
  102.             if (strm.total_out >= [compressed length])
  103.                 [compressed increaseLengthBy: 16384];
  104.            
  105.             strm.next_out = [compressed mutableBytes] + strm.total_out;
  106.             strm.avail_out = [compressed length] - strm.total_out;
  107.            
  108.             deflate(&strm, Z_FINISH);
  109.            
  110.         } while (strm.avail_out == 0);
  111.        
  112.         deflateEnd(&strm);
  113.        
  114.         [compressed setLength: strm.total_out];
  115.         NSLog(@"ZLIB: reduced data from %d bytes to %d (%1.1f%% savings)",
  116.               self.length,
  117.               compressed.length,
  118.               (((float)(self.length-compressed.length))/(float)self.length * 100)
  119.               );
  120.        
  121.         result = [[NSData alloc] initWithData:compressed];
  122.     }
  123.  
  124.     return [result autorelease];
  125. }
  126.  
  127. - (NSData *)gzipInflate
  128. {
  129.     if ([self length] == 0) return self;
  130.    
  131.     unsigned full_length = [self length];
  132.     unsigned half_length = [self length] / 2;
  133.    
  134.     NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
  135.     BOOL done = NO;
  136.     int status;
  137.    
  138.     z_stream strm;
  139.     strm.next_in = (Bytef *)[self bytes];
  140.     strm.avail_in = [self length];
  141.     strm.total_out = 0;
  142.     strm.zalloc = Z_NULL;
  143.     strm.zfree = Z_NULL;
  144.    
  145.     if (inflateInit2(&strm, (15+32)) != Z_OK) return nil;
  146.     while (!done)
  147.     {
  148.         // Make sure we have enough room and reset the lengths.
  149.         if (strm.total_out >= [decompressed length])
  150.             [decompressed increaseLengthBy: half_length];
  151.         strm.next_out = [decompressed mutableBytes] + strm.total_out;
  152.         strm.avail_out = [decompressed length] - strm.total_out;
  153.        
  154.         // Inflate another chunk.
  155.         status = inflate (&strm, Z_SYNC_FLUSH);
  156.         if (status == Z_STREAM_END) done = YES;
  157.         else if (status != Z_OK) break;
  158.     }
  159.     if (inflateEnd (&strm) != Z_OK) return nil;
  160.    
  161.     // Set real length.
  162.     if (done)
  163.     {
  164.         [decompressed setLength: strm.total_out];
  165.         return [NSData dataWithData: decompressed];
  166.     }
  167.     else return nil;
  168. }
  169.  
  170. - (NSData *)gzipDeflate
  171. {
  172.     if ([self length] == 0) return self;
  173.    
  174.     z_stream strm;
  175.    
  176.     strm.zalloc = Z_NULL;
  177.     strm.zfree = Z_NULL;
  178.     strm.opaque = Z_NULL;
  179.     strm.total_out = 0;
  180.     strm.next_in=(Bytef *)[self bytes];
  181.     strm.avail_in = [self length];
  182.    
  183.     // Compresssion Levels:
  184.     //   Z_NO_COMPRESSION
  185.     //   Z_BEST_SPEED
  186.     //   Z_BEST_COMPRESSION
  187.     //   Z_DEFAULT_COMPRESSION
  188.    
  189.     if (deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil;
  190.    
  191.     NSMutableData *compressed = [NSMutableData dataWithLength:16384];  // 16K chunks for expansion
  192.    
  193.     do {
  194.        
  195.         if (strm.total_out >= [compressed length])
  196.             [compressed increaseLengthBy: 16384];
  197.        
  198.         strm.next_out = [compressed mutableBytes] + strm.total_out;
  199.         strm.avail_out = [compressed length] - strm.total_out;
  200.        
  201.         deflate(&strm, Z_FINISH);
  202.        
  203.     } while (strm.avail_out == 0);
  204.    
  205.     deflateEnd(&strm);
  206.    
  207.     [compressed setLength: strm.total_out];
  208.     NSLog(@"GZIP: reduced data from %d bytes to %d (%1.1f%% savings)",
  209.           self.length,
  210.           compressed.length,
  211.           (((float)(self.length-compressed.length))/(float)self.length * 100)
  212.           );
  213.     return [NSData dataWithData:compressed];
  214. }
  215.  
  216. -(NSData*) compress{
  217.    
  218.     if ([self length] == 0) return self;
  219.    
  220.     NSData *z = [self zlibDeflate];
  221.     NSData *u = self;
  222.     char method = 0;
  223.     if (z.length < self.length) {
  224.         method = 1;
  225.         u = z;
  226.         NSLog(@"using ZLIB");
  227.     } else {
  228.         NSLog(@"using RAW");
  229.     }
  230.  
  231.     NSMutableData *result = [[[NSMutableData alloc] initWithBytes:&method length:1] autorelease];
  232.     [result appendData:u];
  233.     return result;
  234. }
  235.  
  236. -(NSData*) decompress{
  237.     if ([self length] == 0) return self;
  238.     NSData *source = [self subdataWithRange:(NSRange){.location = 1,.length = self.length-1}];
  239.     char *method = (char*) self.bytes;
  240.     switch (*method) {
  241.         case 0:
  242.             return source;
  243.             break;
  244.         case 1:
  245.             return [source zlibInflate];
  246.             break;
  247.            
  248.         default:
  249.             return nil;
  250.             break;
  251.     }
  252. }
  253.  
  254. -(NSString*) base64CompressedString{
  255.     return [[self compress] base64EncodedString];
  256. }
  257.  
  258. +(NSData*) dataFromBase64CompressedString:(NSString*) b64 {
  259.     return [[NSData dataFromBase64String:b64] decompress];
  260. }
  261. @end
  262.  
  263.  
  264. @implementation NSDictionary (b64compressed)
  265.  
  266. -(NSString*) b64String{
  267.     NSData *json = [NSJSONSerialization dataWithJSONObject:self options:0 error:nil];
  268.     if (json) {
  269.         NSData *compressed = [json compress];
  270.         if (compressed) {
  271.             return [compressed base64EncodedString];
  272.         }
  273.     }
  274.     return nil;
  275. }
  276.  
  277. +(NSDictionary*) dictionaryWithB64String:(NSString*) b64String {
  278.     NSData *compressed = [NSData dataFromBase64String:b64String];
  279.     if (compressed) {
  280.         NSData *json = [compressed decompress];
  281.         if (json) {
  282.             NSDictionary *result = [NSJSONSerialization JSONObjectWithData:json options:0 error:nil];
  283.             if (result) {
  284.                 if ([result  isKindOfClass:[self class]]) {
  285.                     return result;
  286.                 }
  287.                 return [[self class] dictionaryWithDictionary:result];
  288.             }
  289.         }
  290.     }
  291.     return nil;
  292. }
  293.  
  294. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement