Statistics
| Branch: | Revision:

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