//
// $Id$
//
// SPDataBase64EncodingAdditions.m
// sequel-pro
//
// Created by Rowan Beentje on March 18th, 2012
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// More info at
#import "SPDataBase64EncodingAdditions.h"
static const char _base64EncodingTable[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@implementation NSData (SPDataBase64EncodingAdditions)
/**
* Returns a base64-encoded representation of the NSData as an NSString,
* on a single line.
*/
- (NSString *)base64Encoding
{
return [self base64EncodingWithLineLength:NSNotFound];
}
/**
* Returns a base64-encoded representation of the NSData as an NSString.
* Takes an argument for the maximum output line length; supply 0 or NSNotFound
* to have the results on a single line.
*
* Derived from the MIT-licensed Quasidea Development QSUtilities implementation,
* available in its original form at https://github.com/mikeho/QSUtilities ;
* QSUtilities implementation author Mike Ho, Copyright (c) 2010 - 2011
* Quasidea Development, LLC .
*
* That implementation is itself an implementation ported from the PHP core;
* the PHP implementation is covered by the PHP license, a BSD-alike which
* is available at http://www.php.net/license/3_01.txt .
* PHP implementation author Jim Winstead , Copyright (c) 1997-2012
* The PHP Group.
*/
- (NSString *)base64EncodingWithLineLength:(NSUInteger)lineLength
{
const unsigned char *objRawData = [self bytes];
char *objPointer;
char *strResult;
// Line length details - record bool and tweak to account for 3-octet processing
BOOL hasMaxLineLength = (lineLength && lineLength != NSNotFound);
NSUInteger maxLineLengthChunks = hasMaxLineLength ? floorf(lineLength / 4) : 1;
if (!maxLineLengthChunks) maxLineLengthChunks++;
// Get the Raw Data length and ensure we actually have data
size_t intLength = [self length];
if (intLength == 0) return nil;
// Setup the String-based result placeholder and pointer within that placeholder
size_t encodedLength = ceilf((intLength + 2) / 3) * 4;
if (hasMaxLineLength) encodedLength += ceilf(encodedLength / (maxLineLengthChunks * 4)) - 1;
strResult = (char *)calloc(encodedLength, sizeof(char));
objPointer = strResult;
// Iterate through everything
NSUInteger octetsOnLine = 0;
while (intLength > 2) { // keep going until we have less than 24 bits
*objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
*objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
*objPointer++ = _base64EncodingTable[((objRawData[1] & 0x0f) << 2) + (objRawData[2] >> 6)];
*objPointer++ = _base64EncodingTable[objRawData[2] & 0x3f];
// we just handled 3 octets (24 bits) of data
objRawData += 3;
intLength -= 3;
if (hasMaxLineLength) {
octetsOnLine++;
if (octetsOnLine >= maxLineLengthChunks) {
*objPointer++ = '\n';
octetsOnLine = 0;
}
}
}
// now deal with the tail end of things
if (intLength != 0) {
*objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
if (intLength > 1) {
*objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
*objPointer++ = _base64EncodingTable[(objRawData[1] & 0x0f) << 2];
*objPointer++ = '=';
} else {
*objPointer++ = _base64EncodingTable[(objRawData[0] & 0x03) << 4];
*objPointer++ = '=';
*objPointer++ = '=';
}
}
NSString *strToReturn = [[NSString alloc] initWithBytesNoCopy:strResult length:objPointer - strResult encoding:NSASCIIStringEncoding freeWhenDone:YES];
return [strToReturn autorelease];
}
@end