root / programs / ios / WebODF / Classes / NSData+Base64.m @ cfb53624
History | View | Annotate | Download (7.9 kB)
| 1 | // |
|---|---|
| 2 | // NSData+Base64.m |
| 3 | // base64 |
| 4 | // |
| 5 | // Created by Matt Gallagher on 2009/06/03. |
| 6 | // Copyright 2009 Matt Gallagher. All rights reserved. |
| 7 | // |
| 8 | // Permission is given to use this source code file, free of charge, in any |
| 9 | // project, commercial or otherwise, entirely at your risk, with the condition |
| 10 | // that any redistribution (in part or whole) of source code must retain |
| 11 | // this copyright and permission notice. Attribution in compiled projects is |
| 12 | // appreciated but not required. |
| 13 | // |
| 14 | |
| 15 | #import "NSData+Base64.h" |
| 16 | |
| 17 | // |
| 18 | // Mapping from 6 bit pattern to ASCII character. |
| 19 | // |
| 20 | static unsigned char base64EncodeLookup[65] = |
| 21 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| 22 | |
| 23 | // |
| 24 | // Definition for "masked-out" areas of the base64DecodeLookup mapping |
| 25 | // |
| 26 | #define xx 65 |
| 27 | |
| 28 | // |
| 29 | // Mapping from ASCII character to 6 bit pattern. |
| 30 | // |
| 31 | static unsigned char base64DecodeLookup[256] = |
| 32 | {
|
| 33 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, |
| 34 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, |
| 35 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 62, xx, xx, xx, 63, |
| 36 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, xx, xx, xx, xx, xx, xx, |
| 37 | xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
| 38 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, xx, xx, xx, xx, xx, |
| 39 | xx, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
| 40 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, xx, xx, xx, xx, xx, |
| 41 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, |
| 42 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, |
| 43 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, |
| 44 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, |
| 45 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, |
| 46 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, |
| 47 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, |
| 48 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, |
| 49 | }; |
| 50 | |
| 51 | // |
| 52 | // Fundamental sizes of the binary and base64 encode/decode units in bytes |
| 53 | // |
| 54 | #define BINARY_UNIT_SIZE 3 |
| 55 | #define BASE64_UNIT_SIZE 4 |
| 56 | |
| 57 | // |
| 58 | // NewBase64Decode |
| 59 | // |
| 60 | // Decodes the base64 ASCII string in the inputBuffer to a newly malloced |
| 61 | // output buffer. |
| 62 | // |
| 63 | // inputBuffer - the source ASCII string for the decode |
| 64 | // length - the length of the string or -1 (to specify strlen should be used) |
| 65 | // outputLength - if not-NULL, on output will contain the decoded length |
| 66 | // |
| 67 | // returns the decoded buffer. Must be free'd by caller. Length is given by |
| 68 | // outputLength. |
| 69 | // |
| 70 | void *NewBase64Decode( |
| 71 | const char *inputBuffer, |
| 72 | size_t length, |
| 73 | size_t *outputLength) |
| 74 | {
|
| 75 | if (length == -1) |
| 76 | {
|
| 77 | length = strlen(inputBuffer); |
| 78 | } |
| 79 | |
| 80 | size_t outputBufferSize = (length / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE; |
| 81 | unsigned char *outputBuffer = (unsigned char *)malloc(outputBufferSize); |
| 82 | |
| 83 | size_t i = 0; |
| 84 | size_t j = 0; |
| 85 | while (i < length) |
| 86 | {
|
| 87 | // |
| 88 | // Accumulate 4 valid characters (ignore everything else) |
| 89 | // |
| 90 | unsigned char accumulated[BASE64_UNIT_SIZE]; |
| 91 | bzero(accumulated, sizeof(unsigned char) * BASE64_UNIT_SIZE); |
| 92 | size_t accumulateIndex = 0; |
| 93 | while (i < length) |
| 94 | {
|
| 95 | unsigned char decode = base64DecodeLookup[inputBuffer[i++]]; |
| 96 | if (decode != xx) |
| 97 | {
|
| 98 | accumulated[accumulateIndex] = decode; |
| 99 | accumulateIndex++; |
| 100 | |
| 101 | if (accumulateIndex == BASE64_UNIT_SIZE) |
| 102 | {
|
| 103 | break; |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | // |
| 109 | // Store the 6 bits from each of the 4 characters as 3 bytes |
| 110 | // |
| 111 | outputBuffer[j] = (accumulated[0] << 2) | (accumulated[1] >> 4); |
| 112 | outputBuffer[j + 1] = (accumulated[1] << 4) | (accumulated[2] >> 2); |
| 113 | outputBuffer[j + 2] = (accumulated[2] << 6) | accumulated[3]; |
| 114 | j += accumulateIndex - 1; |
| 115 | } |
| 116 | |
| 117 | if (outputLength) |
| 118 | {
|
| 119 | *outputLength = j; |
| 120 | } |
| 121 | return outputBuffer; |
| 122 | } |
| 123 | |
| 124 | // |
| 125 | // NewBase64Decode |
| 126 | // |
| 127 | // Encodes the arbitrary data in the inputBuffer as base64 into a newly malloced |
| 128 | // output buffer. |
| 129 | // |
| 130 | // inputBuffer - the source data for the encode |
| 131 | // length - the length of the input in bytes |
| 132 | // separateLines - if zero, no CR/LF characters will be added. Otherwise |
| 133 | // a CR/LF pair will be added every 64 encoded chars. |
| 134 | // outputLength - if not-NULL, on output will contain the encoded length |
| 135 | // (not including terminating 0 char) |
| 136 | // |
| 137 | // returns the encoded buffer. Must be free'd by caller. Length is given by |
| 138 | // outputLength. |
| 139 | // |
| 140 | char *NewBase64Encode( |
| 141 | const void *buffer, |
| 142 | size_t length, |
| 143 | bool separateLines, |
| 144 | size_t *outputLength) |
| 145 | {
|
| 146 | const unsigned char *inputBuffer = (const unsigned char *)buffer; |
| 147 | |
| 148 | #define MAX_NUM_PADDING_CHARS 2 |
| 149 | #define OUTPUT_LINE_LENGTH 64 |
| 150 | #define INPUT_LINE_LENGTH ((OUTPUT_LINE_LENGTH / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE) |
| 151 | #define CR_LF_SIZE 0 |
| 152 | |
| 153 | // |
| 154 | // Byte accurate calculation of final buffer size |
| 155 | // |
| 156 | size_t outputBufferSize = |
| 157 | ((length / BINARY_UNIT_SIZE) |
| 158 | + ((length % BINARY_UNIT_SIZE) ? 1 : 0)) |
| 159 | * BASE64_UNIT_SIZE; |
| 160 | if (separateLines) |
| 161 | {
|
| 162 | outputBufferSize += |
| 163 | (outputBufferSize / OUTPUT_LINE_LENGTH) * CR_LF_SIZE; |
| 164 | } |
| 165 | |
| 166 | // |
| 167 | // Include space for a terminating zero |
| 168 | // |
| 169 | outputBufferSize += 1; |
| 170 | |
| 171 | // |
| 172 | // Allocate the output buffer |
| 173 | // |
| 174 | char *outputBuffer = (char *)malloc(outputBufferSize); |
| 175 | if (!outputBuffer) |
| 176 | {
|
| 177 | return NULL; |
| 178 | } |
| 179 | |
| 180 | size_t i = 0; |
| 181 | size_t j = 0; |
| 182 | const size_t lineLength = separateLines ? INPUT_LINE_LENGTH : length; |
| 183 | size_t lineEnd = lineLength; |
| 184 | |
| 185 | while (true) |
| 186 | {
|
| 187 | if (lineEnd > length) |
| 188 | {
|
| 189 | lineEnd = length; |
| 190 | } |
| 191 | |
| 192 | for (; i + BINARY_UNIT_SIZE - 1 < lineEnd; i += BINARY_UNIT_SIZE) |
| 193 | {
|
| 194 | // |
| 195 | // Inner loop: turn 48 bytes into 64 base64 characters |
| 196 | // |
| 197 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; |
| 198 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) |
| 199 | | ((inputBuffer[i + 1] & 0xF0) >> 4)]; |
| 200 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i + 1] & 0x0F) << 2) |
| 201 | | ((inputBuffer[i + 2] & 0xC0) >> 6)]; |
| 202 | outputBuffer[j++] = base64EncodeLookup[inputBuffer[i + 2] & 0x3F]; |
| 203 | } |
| 204 | |
| 205 | if (lineEnd == length) |
| 206 | {
|
| 207 | break; |
| 208 | } |
| 209 | |
| 210 | // |
| 211 | // Add the newline |
| 212 | // |
| 213 | //outputBuffer[j++] = '\r'; |
| 214 | //outputBuffer[j++] = '\n'; |
| 215 | lineEnd += lineLength; |
| 216 | } |
| 217 | |
| 218 | if (i + 1 < length) |
| 219 | {
|
| 220 | // |
| 221 | // Handle the single '=' case |
| 222 | // |
| 223 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; |
| 224 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4) |
| 225 | | ((inputBuffer[i + 1] & 0xF0) >> 4)]; |
| 226 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i + 1] & 0x0F) << 2]; |
| 227 | outputBuffer[j++] = '='; |
| 228 | } |
| 229 | else if (i < length) |
| 230 | {
|
| 231 | // |
| 232 | // Handle the double '=' case |
| 233 | // |
| 234 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2]; |
| 235 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0x03) << 4]; |
| 236 | outputBuffer[j++] = '='; |
| 237 | outputBuffer[j++] = '='; |
| 238 | } |
| 239 | outputBuffer[j] = 0; |
| 240 | |
| 241 | // |
| 242 | // Set the output length and return the buffer |
| 243 | // |
| 244 | if (outputLength) |
| 245 | {
|
| 246 | *outputLength = j; |
| 247 | } |
| 248 | return outputBuffer; |
| 249 | } |
| 250 | |
| 251 | @implementation NSData (Base64) |
| 252 | |
| 253 | // |
| 254 | // dataFromBase64String: |
| 255 | // |
| 256 | // Creates an NSData object containing the base64 decoded representation of |
| 257 | // the base64 string 'aString' |
| 258 | // |
| 259 | // Parameters: |
| 260 | // aString - the base64 string to decode |
| 261 | // |
| 262 | // returns the autoreleased NSData representation of the base64 string |
| 263 | // |
| 264 | + (NSData *)dataFromBase64String:(NSString *)aString |
| 265 | {
|
| 266 | NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding]; |
| 267 | size_t outputLength; |
| 268 | void *outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength); |
| 269 | NSData *result = [NSData dataWithBytes:outputBuffer length:outputLength]; |
| 270 | free(outputBuffer); |
| 271 | return result; |
| 272 | } |
| 273 | |
| 274 | // |
| 275 | // base64EncodedString |
| 276 | // |
| 277 | // Creates an NSString object that contains the base 64 encoding of the |
| 278 | // receiver's data. Lines are broken at 64 characters long. |
| 279 | // |
| 280 | // returns an autoreleased NSString being the base 64 representation of the |
| 281 | // receiver. |
| 282 | // |
| 283 | - (NSString *)base64EncodedString |
| 284 | {
|
| 285 | size_t outputLength; |
| 286 | char *outputBuffer = |
| 287 | NewBase64Encode([self bytes], [self length], true, &outputLength); |
| 288 | |
| 289 | NSString *result = |
| 290 | [[[NSString alloc] |
| 291 | initWithBytes:outputBuffer |
| 292 | length:outputLength |
| 293 | encoding:NSASCIIStringEncoding] |
| 294 | autorelease]; |
| 295 | free(outputBuffer); |
| 296 | return result; |
| 297 | } |
| 298 | |
| 299 | @end |