Is there a compression API available for use on the iPhone? We're building some RESTful web services for our iPhone app to talk to, but we want to compress at least some of the conversations for efficiency.
I don't care what the format (ZIP, LHA, whatever) is, and it does not need to be secure.
Some respondents have pointed out that the server can compress its output, and the iPhone can consume that. The scenario we have is exactly the reverse. We'll be POSTing compressed content to the web service. We're not concerned with compression going the other way.
There is no built-in iOS feature that allows you to compress a video. However, iPhone users can adjust the size of video recordings in their camera settings before recording. Using a third-party app like Video Compress will allow you to reduce the file size of a video after recording it.
Compressing the songs on a CD further into 256kbps AAC "iTunes Plus" format cuts the data down to just one-fifth of the size of CD audio, or as little as three percent of the original 192kHz recordings.
Simply put, file compression (or data compression) is the act of reducing the size of a file while preserving the original data. Doing so allows the file to take up less space on a storage device, in addition to making it easier to transfer over the internet or otherwise.
If you store the data for the conversations in an NSData object, the folks at the CocoaDev wiki have posted an NSData category that adds gzip and zlib compression / decompression as simple methods. These have worked well for me in my iPhone application.
As the above link has gone dead while the CocoaDev wiki is being moved to a new host, I've reproduced this category in its entirety below.
Interface:
@interface NSData (NSDataExtension) // Returns range [start, null byte), or (NSNotFound, 0). - (NSRange) rangeOfNullTerminatedBytesFrom:(int)start; // Canonical Base32 encoding/decoding. + (NSData *) dataWithBase32String:(NSString *)base32; - (NSString *) base32String; // COBS is an encoding that eliminates 0x00. - (NSData *) encodeCOBS; - (NSData *) decodeCOBS; // ZLIB - (NSData *) zlibInflate; - (NSData *) zlibDeflate; // GZIP - (NSData *) gzipInflate; - (NSData *) gzipDeflate; //CRC32 - (unsigned int)crc32; // Hash - (NSData*) md5Digest; - (NSString*) md5DigestString; - (NSData*) sha1Digest; - (NSString*) sha1DigestString; - (NSData*) ripemd160Digest; - (NSString*) ripemd160DigestString; @end
Implementation:
#import "NSData+CocoaDevUsersAdditions.h" #include <zlib.h> #include <openssl/md5.h> #include <openssl/sha.h> #include <openssl/ripemd.h> @implementation NSData (NSDataExtension) // Returns range [start, null byte), or (NSNotFound, 0). - (NSRange) rangeOfNullTerminatedBytesFrom:(int)start { const Byte *pdata = [self bytes]; int len = [self length]; if (start < len) { const Byte *end = memchr (pdata + start, 0x00, len - start); if (end != NULL) return NSMakeRange (start, end - (pdata + start)); } return NSMakeRange (NSNotFound, 0); } + (NSData *) dataWithBase32String:(NSString *)encoded { /* First valid character that can be indexed in decode lookup table */ static int charDigitsBase = '2'; /* Lookup table used to decode() characters in encoded strings */ static int charDigits[] = { 26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1 // 23456789:;<=>? ,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14 // @ABCDEFGHIJKLMNO ,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1 // PQRSTUVWXYZ[\]^_ ,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14 // `abcdefghijklmno ,15,16,17,18,19,20,21,22,23,24,25 // pqrstuvwxyz }; if (! [encoded canBeConvertedToEncoding:NSASCIIStringEncoding]) return nil; const char *chars = [encoded cStringUsingEncoding:NSASCIIStringEncoding]; // avoids using characterAtIndex. int charsLen = [encoded lengthOfBytesUsingEncoding:NSASCIIStringEncoding]; // Note that the code below could detect non canonical Base32 length within the loop. However canonical Base32 length can be tested before entering the loop. // A canonical Base32 length modulo 8 cannot be: // 1 (aborts discarding 5 bits at STEP n=0 which produces no byte), // 3 (aborts discarding 7 bits at STEP n=2 which produces no byte), // 6 (aborts discarding 6 bits at STEP n=1 which produces no byte). switch (charsLen & 7) { // test the length of last subblock case 1: // 5 bits in subblock: 0 useful bits but 5 discarded case 3: // 15 bits in subblock: 8 useful bits but 7 discarded case 6: // 30 bits in subblock: 24 useful bits but 6 discarded return nil; // non-canonical length } int charDigitsLen = sizeof(charDigits); int bytesLen = (charsLen * 5) >> 3; Byte bytes[bytesLen]; int bytesOffset = 0, charsOffset = 0; // Also the code below does test that other discarded bits // (1 to 4 bits at end) are effectively 0. while (charsLen > 0) { int digit, lastDigit; // STEP n = 0: Read the 1st Char in a 8-Chars subblock // Leave 5 bits, asserting there's another encoding Char if ((digit = (int)chars[charsOffset] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) return nil; // invalid character lastDigit = digit << 3; // STEP n = 5: Read the 2nd Char in a 8-Chars subblock // Insert 3 bits, leave 2 bits, possibly trailing if no more Char if ((digit = (int)chars[charsOffset + 1] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) return nil; // invalid character bytes[bytesOffset] = (Byte)((digit >> 2) | lastDigit); lastDigit = (digit & 3) << 6; if (charsLen == 2) { if (lastDigit != 0) return nil; // non-canonical end break; // discard the 2 trailing null bits } // STEP n = 2: Read the 3rd Char in a 8-Chars subblock // Leave 7 bits, asserting there's another encoding Char if ((digit = (int)chars[charsOffset + 2] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) return nil; // invalid character lastDigit |= (Byte)(digit << 1); // STEP n = 7: Read the 4th Char in a 8-chars Subblock // Insert 1 bit, leave 4 bits, possibly trailing if no more Char if ((digit = (int)chars[charsOffset + 3] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) return nil; // invalid character bytes[bytesOffset + 1] = (Byte)((digit >> 4) | lastDigit); lastDigit = (Byte)((digit & 15) << 4); if (charsLen == 4) { if (lastDigit != 0) return nil; // non-canonical end break; // discard the 4 trailing null bits } // STEP n = 4: Read the 5th Char in a 8-Chars subblock // Insert 4 bits, leave 1 bit, possibly trailing if no more Char if ((digit = (int)chars[charsOffset + 4] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) return nil; // invalid character bytes[bytesOffset + 2] = (Byte)((digit >> 1) | lastDigit); lastDigit = (Byte)((digit & 1) << 7); if (charsLen == 5) { if (lastDigit != 0) return nil; // non-canonical end break; // discard the 1 trailing null bit } // STEP n = 1: Read the 6th Char in a 8-Chars subblock // Leave 6 bits, asserting there's another encoding Char if ((digit = (int)chars[charsOffset + 5] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) return nil; // invalid character lastDigit |= (Byte)(digit << 2); // STEP n = 6: Read the 7th Char in a 8-Chars subblock // Insert 2 bits, leave 3 bits, possibly trailing if no more Char if ((digit = (int)chars[charsOffset + 6] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) return nil; // invalid character bytes[bytesOffset + 3] = (Byte)((digit >> 3) | lastDigit); lastDigit = (Byte)((digit & 7) << 5); if (charsLen == 7) { if (lastDigit != 0) return nil; // non-canonical end break; // discard the 3 trailing null bits } // STEP n = 3: Read the 8th Char in a 8-Chars subblock // Insert 5 bits, leave 0 bit, next encoding Char may not exist if ((digit = (int)chars[charsOffset + 7] - charDigitsBase) < 0 || digit >= charDigitsLen || (digit = charDigits[digit]) == -1) return nil; // invalid character bytes[bytesOffset + 4] = (Byte)(digit | lastDigit); //// This point is always reached for chars.length multiple of 8 charsOffset += 8; bytesOffset += 5; charsLen -= 8; } // On loop exit, discard the n trailing null bits return [NSData dataWithBytes:bytes length:sizeof(bytes)]; } - (NSString *) base32String { /* Lookup table used to canonically encode() groups of data bits */ static char canonicalChars[] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M' // 00..12 ,'N','O','P','Q','R','S','T','U','V','W','X','Y','Z' // 13..25 ,'2','3','4','5','6','7' // 26..31 }; const Byte *bytes = [self bytes]; int bytesOffset = 0, bytesLen = [self length]; int charsOffset = 0, charsLen = ((bytesLen << 3) + 4) / 5; char chars[charsLen]; while (bytesLen != 0) { int digit, lastDigit; // INVARIANTS FOR EACH STEP n in [0..5[; digit in [0..31[; // The remaining n bits are already aligned on top positions // of the 5 least bits of digit, the other bits are 0. ////// STEP n = 0: insert new 5 bits, leave 3 bits digit = bytes[bytesOffset] & 255; chars[charsOffset] = canonicalChars[digit >> 3]; lastDigit = (digit & 7) << 2; if (bytesLen == 1) { // put the last 3 bits chars[charsOffset + 1] = canonicalChars[lastDigit]; break; } ////// STEP n = 3: insert 2 new bits, then 5 bits, leave 1 bit digit = bytes[bytesOffset + 1] & 255; chars[charsOffset + 1] = canonicalChars[(digit >> 6) | lastDigit]; chars[charsOffset + 2] = canonicalChars[(digit >> 1) & 31]; lastDigit = (digit & 1) << 4; if (bytesLen == 2) { // put the last 1 bit chars[charsOffset + 3] = canonicalChars[lastDigit]; break; } ////// STEP n = 1: insert 4 new bits, leave 4 bit digit = bytes[bytesOffset + 2] & 255; chars[charsOffset + 3] = canonicalChars[(digit >> 4) | lastDigit]; lastDigit = (digit & 15) << 1; if (bytesLen == 3) { // put the last 1 bits chars[charsOffset + 4] = canonicalChars[lastDigit]; break; } ////// STEP n = 4: insert 1 new bit, then 5 bits, leave 2 bits digit = bytes[bytesOffset + 3] & 255; chars[charsOffset + 4] = canonicalChars[(digit >> 7) | lastDigit]; chars[charsOffset + 5] = canonicalChars[(digit >> 2) & 31]; lastDigit = (digit & 3) << 3; if (bytesLen == 4) { // put the last 2 bits chars[charsOffset + 6] = canonicalChars[lastDigit]; break; } ////// STEP n = 2: insert 3 new bits, then 5 bits, leave 0 bit digit = bytes[bytesOffset + 4] & 255; chars[charsOffset + 6] = canonicalChars[(digit >> 5) | lastDigit]; chars[charsOffset + 7] = canonicalChars[digit & 31]; //// This point is always reached for bytes.length multiple of 5 bytesOffset += 5; charsOffset += 8; bytesLen -= 5; } return [NSString stringWithCString:chars length:sizeof(chars)]; } #define FinishBlock(X) \ (*code_ptr = (X), \ code_ptr = dst++, \ code = 0x01) - (NSData *) encodeCOBS { if ([self length] == 0) return self; NSMutableData *encoded = [NSMutableData dataWithLength:([self length] + [self length] / 254 + 1)]; unsigned char *dst = [encoded mutableBytes]; const unsigned char *ptr = [self bytes]; unsigned long length = [self length]; const unsigned char *end = ptr + length; unsigned char *code_ptr = dst++; unsigned char code = 0x01; while (ptr < end) { if (*ptr == 0) FinishBlock(code); else { *dst++ = *ptr; code++; if (code == 0xFF) FinishBlock(code); } ptr++; } FinishBlock(code); [encoded setLength:((Byte *)dst - (Byte *)[encoded mutableBytes])]; return [NSData dataWithData:encoded]; } - (NSData *) decodeCOBS { if ([self length] == 0) return self; const Byte *ptr = [self bytes]; unsigned length = [self length]; NSMutableData *decoded = [NSMutableData dataWithLength:length]; Byte *dst = [decoded mutableBytes]; Byte *basedst = dst; const unsigned char *end = ptr + length; while (ptr < end) { int i, code = *ptr++; for (i=1; i<code; i++) *dst++ = *ptr++; if (code < 0xFF) *dst++ = 0; } [decoded setLength:(dst - basedst)]; return [NSData dataWithData:decoded]; } - (NSData *)zlibInflate { 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 (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]; return [NSData dataWithData: decompressed]; } else return nil; } - (NSData *)zlibDeflate { 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 (deflateInit(&strm, Z_DEFAULT_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]; return [NSData dataWithData: compressed]; } - (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_DEFAULT_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]; return [NSData dataWithData:compressed]; } // --------------------------------CRC32------------------------------- static const unsigned long crc32table[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; - (unsigned int)crc32 { unsigned int crcval; unsigned int x, y; const void *bytes; unsigned int max; bytes = [self bytes]; max = [self length]; crcval = 0xffffffff; for (x = 0, y = max; x < y; x++) { crcval = ((crcval >> 8) & 0x00ffffff) ^ crc32table[(crcval ^ (*((unsigned char *)bytes + x))) & 0xff]; } return crcval ^ 0xffffffff; } // Hash function, by [[DamienBob]] #define HEComputeDigest(method) \ method##_CTX ctx; \ unsigned char digest[method##_DIGEST_LENGTH]; \ method##_Init(&ctx); \ method##_Update(&ctx, [self bytes], [self length]); \ method##_Final(digest, &ctx); #define HEComputeDigestNSData(method) \ HEComputeDigest(method) \ return [NSData dataWithBytes:digest length:method##_DIGEST_LENGTH]; #define HEComputeDigestNSString(method) \ static char __HEHexDigits[] = "0123456789abcdef"; \ unsigned char digestString[2*method##_DIGEST_LENGTH];\ unsigned int i; \ HEComputeDigest(method) \ for(i=0; i<method##_DIGEST_LENGTH; i++) { \ digestString[2*i] = __HEHexDigits[digest[i] >> 4]; \ digestString[2*i+1] = __HEHexDigits[digest[i] & 0x0f];\ } \ return [NSString stringWithCString:(char *)digestString length:2*method##_DIGEST_LENGTH]; #define SHA1_CTX SHA_CTX #define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH - (NSData*) md5Digest { HEComputeDigestNSData(MD5); } - (NSString*) md5DigestString { HEComputeDigestNSString(MD5); } - (NSData*) sha1Digest { HEComputeDigestNSData(SHA1); } - (NSString*) sha1DigestString { HEComputeDigestNSString(SHA1); } - (NSData*) ripemd160Digest { HEComputeDigestNSData(RIPEMD160); } - (NSString*) ripemd160DigestString { HEComputeDigestNSString(RIPEMD160); } @end
zlib and bzip2 are available. And you can always add others, as long as they'll (generally) compile under OS X.
bzip2 is a better choice for smallest file sizes, but requires much more CPU power to compress and decompress.
Also, since you're talking to a web service, you may not have to do much. NSURLRequest accepts gzip encoding transparently in server responses.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With