// // $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