CocoaDev

Edit AllPages

A few useful and semi-useful methods. – DustinVoss

Added CRC32 method, found it on Google – BobInDaShadows

Added deflate method for zlib; works but not thoroughly tested; probably best suited for small blocks of data. Would appreciate feedback/code review/improvement/etc. -Seb


Added full support for gzip inflate/deflate. Mostly a copy of the zlib methods, with the proper window size change for gzip.


Does it need special linking options? – StephaneBoisson

Yes, you have to add zlib.dylib in /usr/lib to the project.

Or, specify -lz in the ‘Other Linker Flags’ section of the project -Seb

I had to add libcrypto.dylib as well – SamSoffes


I tried sticking the .h and .m files into a fresh CoreData application project and I get three warnings: “pointer targets in passing argument 1 of ‘stringWithCString:length differ in signedness” I cast the unsigned char[] pointer to a char * and the warnings went away - but I’m not sure if that will create problems in the future.

Also, I’m on 10.4.2 and haven’t yet included any other libraries in my project (like zlib.dylib mentioned above). Will I still need to do that? Do they need to get statically linked?

Thanks - BlakeSeely

—- I’ve eliminated the warning. It shouldn’t cause any problems; there is no code afterwards, which means no possibility of sign confusion. As for linking zlib, try it and see, but I bet you do have to, and I bet it is not statically linked.


http://aquaticmac.com/cocoa.php - An NSData category for AES encryption and decryption, released under the BSD license.


NSData+CocoaDevUsersAdditions.h

#import <Foundation/Foundation.h>

@interface NSData (NSDataExtension)

// Returns range [start, null byte), or (NSNotFound, 0).

// Canonical Base32 encoding/decoding.

// COBS is an encoding that eliminates 0x00.

// ZLIB

// GZIP

//CRC32

// Hash

@end


*NSData+CocoaDevUsersAdditions.m**

#import “NSData+CocoaDevUsersAdditions.h” #include #include <openssl/md5.h> #include <openssl/sha.h> #include <openssl/ripemd.h>

@implementation NSData (NSDataExtension)

// Returns range [start, null byte), or (NSNotFound, 0).

/* 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)];

}

#define FinishBlock(X)
(*code_ptr = (X),
code_ptr = dst++,
code = 0x01)

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];

}

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 = [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;

}

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];

}

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;

}

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 };

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[2method##_DIGEST_LENGTH];\ unsigned int i; \ HEComputeDigest(method) \ for(i=0; i<method##_DIGEST_LENGTH; i++) { \ digestString[2i] = __HEHexDigits[digest[i] » 4]; \ digestString[2i+1] = __HEHexDigits[digest[i] & 0x0f];\ } \ return [NSString stringWithCString:(char *)digestString length:2method##_DIGEST_LENGTH];

#define SHA1_CTX SHA_CTX #define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH

@end


Tried to use this code by dragging into xcode project libz.dyllb but it does not work or…well… it returns null data. Why?


Turn off ZeroLink, then fix the errors which result.


Done but nothing is changed, still remain null. Can you take a look to the project please? Try it: http://www.box.net/shared/ias90iom1i


Can somebody explain the differences between zip and gzip? The code above supports both. Is there an advantage to one over the other?


http://www.google.com/search?q=difference+between+zip+and+gzip

Please use the forums, this isn’t a mailing list.


Given the usage patterns of the code above, there really doesn’t seem to be a difference.


http://www.go.dlr.de/pdinfo_dv/gzip.html

Scroll down to “Note about zip vs. gzip” at the bottom of the page. Executive summary: Zip is a compressor + archive format, gzip is a compressor only.


Does anyone know the licence terms of the Additions category above or is it public domain?


stringWithCString:length: is deprecated; should it be [NSString stringWithCString:chars encoding:NSASCIIStringEncoding] ?


Yes, it should be replaced with stringWithCString:encoding:, but don’t forget to null-terminate chars in this case: char chars[charsLen] => char chars[charsLen+1]; then add chars[charsLen] = ‘\0’; before stringWithCString:encoding: – DmitryChestnykh


Couldn’t we also use [NSString alloc] initWithBytes:chars length:sizeof(chars) encoding:NSASCIIStringEncoding] autorelease] ?

This would avoid the need to do a copy.

-[[HeathBorders

Category:CocoaDevUsersAdditions