// // NSData+Base64.m // // Version 1.0.2 // // Created by Nick Lockwood on 12/01/2012. // Copyright (C) 2012 Charcoal Design // // Distributed under the permissive zlib License // Get the latest version from here: // // https://github.com/nicklockwood/Base64 // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source distribution. // #import "NSData+Base64.h" @implementation NSData (Base64) - (NSData*)formatWithData:(NSData*)data{ if (data && [data length]>76) { }return data; } + (NSData *)dataWithBase64EncodedString:(NSString *)string { const char lookup[] = { 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 62, 99, 99, 99, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 99, 99, 99, 99, 99, 99, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 99, 99, 99, 99, 99, 99, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 99, 99, 99, 99, 99 }; NSData *inputData = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; long long inputLength = [inputData length]; const unsigned char *inputBytes = [inputData bytes]; long long maxOutputLength = (inputLength / 4 + 1) * 3; NSMutableData *outputData = [NSMutableData dataWithLength:maxOutputLength]; unsigned char *outputBytes = (unsigned char *)[outputData mutableBytes]; int accumulator = 0; long long outputLength = 0; unsigned char accumulated[] = {0, 0, 0, 0}; for (long long i = 0; i < inputLength; i++) { unsigned char decoded = lookup[inputBytes[i] & 0x7F]; if (decoded != 99) { accumulated[accumulator] = decoded; if (accumulator == 3) { outputBytes[outputLength++] = (accumulated[0] << 2) | (accumulated[1] >> 4); outputBytes[outputLength++] = (accumulated[1] << 4) | (accumulated[2] >> 2); outputBytes[outputLength++] = (accumulated[2] << 6) | accumulated[3]; } accumulator = (accumulator + 1) % 4; } } //handle left-over data if (accumulator > 0) outputBytes[outputLength] = (accumulated[0] << 2) | (accumulated[1] >> 4); if (accumulator > 1) outputBytes[++outputLength] = (accumulated[1] << 4) | (accumulated[2] >> 2); if (accumulator > 2) outputLength++; //truncate data to match actual output length outputData.length = outputLength; return outputLength? outputData: nil; } - (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth { //ensure wrapWidth is a multiple of 4 wrapWidth = (wrapWidth / 4) * 4; const char lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; long long inputLength = [self length]; const unsigned char *inputBytes = [self bytes]; long long maxOutputLength = (inputLength / 3 + 1) * 4; maxOutputLength += wrapWidth? (maxOutputLength / wrapWidth) * 2: 0; unsigned char *outputBytes = (unsigned char *)malloc(maxOutputLength); long long i; long long outputLength = 0; for (i = 0; i < inputLength - 2; i += 3) { outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)]; outputBytes[outputLength++] = lookup[((inputBytes[i + 1] & 0x0F) << 2) | ((inputBytes[i + 2] & 0xC0) >> 6)]; outputBytes[outputLength++] = lookup[inputBytes[i + 2] & 0x3F]; //add line break if (wrapWidth && (outputLength + 2) % (wrapWidth + 2) == 0) { outputBytes[outputLength++] = '\r'; outputBytes[outputLength++] = '\n'; } } //handle left-over data if (i == inputLength - 2) { // = terminator outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)]; outputBytes[outputLength++] = lookup[(inputBytes[i + 1] & 0x0F) << 2]; outputBytes[outputLength++] = '='; } else if (i == inputLength - 1) { // == terminator outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; outputBytes[outputLength++] = lookup[(inputBytes[i] & 0x03) << 4]; outputBytes[outputLength++] = '='; outputBytes[outputLength++] = '='; } //truncate data to match actual output length outputBytes = realloc(outputBytes, outputLength); NSString *result = [[NSString alloc] initWithBytesNoCopy:outputBytes length:outputLength encoding:NSASCIIStringEncoding freeWhenDone:YES]; #if !__has_feature(objc_arc) [result autorelease]; #endif return (outputLength >= 4)? result: nil; } - (NSString *)base64EncodedString { return [self base64EncodedStringWithWrapWidth:0]; } @end