Skip to content

Commit f945aa0

Browse files
committed
ADD: add base64 encoding.
1 parent 9bcec3b commit f945aa0

File tree

3 files changed

+360
-0
lines changed

3 files changed

+360
-0
lines changed

Encoding/NSData+Base64.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//
2+
// NSData+Base64.h
3+
// base64
4+
//
5+
// Created by Matt Gallagher on 2009/06/03.
6+
// Copyright 2009 Matt Gallagher. All rights reserved.
7+
//
8+
// This software is provided 'as-is', without any express or implied
9+
// warranty. In no event will the authors be held liable for any damages
10+
// arising from the use of this software. Permission is granted to anyone to
11+
// use this software for any purpose, including commercial applications, and to
12+
// alter it and redistribute it freely, subject to the following restrictions:
13+
//
14+
// 1. The origin of this software must not be misrepresented; you must not
15+
// claim that you wrote the original software. If you use this software
16+
// in a product, an acknowledgment in the product documentation would be
17+
// appreciated but is not required.
18+
// 2. Altered source versions must be plainly marked as such, and must not be
19+
// misrepresented as being the original software.
20+
// 3. This notice may not be removed or altered from any source
21+
// distribution.
22+
//
23+
24+
#import <Foundation/Foundation.h>
25+
26+
void *NewBase64Decode(
27+
const char *inputBuffer,
28+
size_t length,
29+
size_t *outputLength);
30+
31+
char *NewBase64Encode(
32+
const void *inputBuffer,
33+
size_t length,
34+
bool separateLines,
35+
size_t *outputLength);
36+
37+
@interface NSData (Base64)
38+
39+
+ (NSData *)dataFromBase64String:(NSString *)aString;
40+
- (NSString *)base64EncodedString;
41+
42+
@end

Encoding/NSData+Base64.m

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

README.markdown

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,8 @@ NSString Wrapper is a wrapper class to decorate NSString methods to java String
3030
1. VersionCompare.h Macros used for version comparison.
3131
2. MacroUtils.h Macros used for debuging and I18N.
3232
3. UIContants.h Macros used for UI.
33+
34+
####5. Encoding Utils
35+
36+
1. Base64 The author is Matt Gallagher. I got the code from <http://cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html> . The copyright info is in the header of the relevant source file.
37+

0 commit comments

Comments
 (0)