123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- //
- // Base64.m
- //
- // Version 1.1
- //
- // 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 "Base64.h"
- #import <Availability.h>
- #if !__has_feature(objc_arc)
- #error This library requires automatic reference counting
- #endif
- @implementation NSData (Base64)
- + (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++] = '=';
- }
- if (outputLength >= 4)
- {
- //truncate data to match actual output length
- outputBytes = realloc(outputBytes, outputLength);
- return [[NSString alloc] initWithBytesNoCopy:outputBytes
- length:outputLength
- encoding:NSASCIIStringEncoding
- freeWhenDone:YES];
- }
- else if (outputBytes)
- {
- free(outputBytes);
- }
- return nil;
- }
- - (NSString *)base64EncodedString
- {
- return [self base64EncodedStringWithWrapWidth:0];
- }
- @end
- @implementation NSString (Base64)
- + (NSString *)stringWithBase64EncodedString:(NSString *)string
- {
- NSData *data = [NSData dataWithBase64EncodedString:string];
- if (data)
- {
- return [[self alloc] initWithData:data encoding:NSUTF8StringEncoding];
- }
- return nil;
- }
- - (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth
- {
- NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
- return [data base64EncodedStringWithWrapWidth:wrapWidth];
- }
- - (NSString *)base64EncodedString
- {
- NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
- return [data base64EncodedString];
- }
- - (NSString *)base64DecodedString
- {
- return [NSString stringWithBase64EncodedString:self];
- }
- - (NSData *)base64DecodedData
- {
- return [NSData dataWithBase64EncodedString:self];
- }
- @end
|