2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "NGBase64Coding.h"
25 #import <Foundation/NSString.h>
26 #import <Foundation/NSException.h>
28 static inline BOOL isbase64(char a) {
29 if (('A' <= a) && (a <= 'Z'))
31 if (('a' <= a) && (a <= 'z'))
33 if (('0' <= a) && (a <= '9'))
35 if ((a == '+') || (a == '/'))
40 static inline int encode_base64(const char *_src, size_t _srcLen, char *_dest,
41 size_t _destSize, size_t *_destLen,
43 static inline int decode_base64(const char *_src, size_t _srcLen, char *_dest,
44 size_t _destSize, size_t *_destLen);
46 @implementation NSString(Base64Coding)
48 static Class StringClass = Nil;
49 static int NSStringMaxLineWidth = 1024;
51 - (NSString *)stringByEncodingBase64 {
54 size_t destLength = -1;
57 if ((len = [self cStringLength]) == 0)
60 destSize = (len + 2) / 3 * 4; // 3:4 conversion ratio
61 destSize += destSize / NSStringMaxLineWidth + 2; // space for newlines and '\0'
63 dest = malloc(destSize + 4);
64 if (dest == NULL) return nil;
66 NSAssert(destSize > 0, @"invalid buffer size ..");
67 NSAssert(dest, @"invalid buffer ..");
69 src = malloc(len + 4);
70 [self getCString:src];
73 if (encode_base64(src, len,
74 dest, destSize, &destLength, NSStringMaxLineWidth) == 0) {
76 return [[[NSString alloc]
77 initWithCStringNoCopy:dest
79 freeWhenDone:YES] autorelease];
83 if (dest) free((void *)dest); dest = NULL;
87 - (NSString *)stringByDecodingBase64 {
90 size_t destLength = -1;
93 if (StringClass == Nil) StringClass = [NSString class];
95 if ((len = [self cStringLength]) == 0)
98 destSize = (len / 4 + 1) * 3 + 1;
99 dest = malloc(destSize + 1);
101 NSAssert(destSize > 0, @"invalid buffer size ..");
102 NSAssert(dest, @"invalid buffer ..");
104 src = malloc(len + 4);
105 [self getCString:src];
108 if (decode_base64(src, len, dest, destSize, &destLength) == 0) {
111 if (*dest == '\0' && destLength > 0) {
112 NSLog(@"ERROR(%s): could not decode %@ as string (contains \\0 bytes)!",
113 __PRETTY_FUNCTION__, self);
115 if (dest) free(dest);
119 return [[[StringClass alloc]
120 initWithCStringNoCopy:dest
122 freeWhenDone:YES] autorelease];
126 if (dest) free(dest);
131 - (NSData *)dataByDecodingBase64 {
134 size_t destLength = -1;
137 if (StringClass == Nil) StringClass = [NSString class];
139 if ((len = [self cStringLength]) == 0)
140 return [NSData data];
142 destSize = (len / 4 + 1) * 3 + 1;
143 dest = malloc(destSize + 1);
145 NSAssert(destSize > 0, @"invalid buffer size ..");
146 NSAssert(dest, @"invalid buffer ..");
148 src = malloc(len + 4);
149 [self getCString:src];
152 if (decode_base64(src, len, dest, destSize, &destLength) == 0) {
154 return [NSData dataWithBytesNoCopy:dest length:destLength];
158 if (dest) free(dest);
162 @end /* NSString(Base64Coding) */
164 @implementation NSData(Base64Coding)
166 static int NSDataMaxLineWidth = 72;
168 - (NSData *)dataByEncodingBase64 {
171 size_t destLength = -1;
174 if ((len = [self length]) == 0)
175 return [NSData data];
177 destSize = (len + 2) / 3 * 4; // 3:4 conversion ratio
178 destSize += destSize / NSDataMaxLineWidth + 2; // space for newlines and '\0'
181 dest = malloc(destSize + 4);
183 NSAssert(destSize > 0, @"invalid buffer size ..");
184 NSAssert(dest, @"invalid buffer ..");
186 if (encode_base64([self bytes], len,
187 dest, destSize, &destLength, NSDataMaxLineWidth) == 0) {
188 return [NSData dataWithBytesNoCopy:dest length:destLength];
191 if (dest) free((void *)dest);
196 - (NSData *)dataByDecodingBase64 {
199 size_t destLength = -1;
202 if ((len = [self length]) == 0)
203 return [NSData data];
205 destSize = (len / 4 + 1) * 3 + 1;
206 dest = malloc(destSize + 4);
208 NSAssert(destSize > 0, @"invalid buffer size ..");
209 NSAssert(dest, @"invalid buffer ..");
211 if (decode_base64([self bytes], len, dest, destSize, &destLength) == 0)
212 return [NSData dataWithBytesNoCopy:dest length:destLength];
214 if (dest) free(dest);
218 - (NSString *)stringByEncodingBase64 {
222 if ((data = [self dataByEncodingBase64]) == nil)
224 s = [[NSString alloc] initWithData:data
225 encoding:[NSString defaultCStringEncoding]];
226 return [s autorelease];
228 - (NSString *)stringByDecodingBase64 {
232 if ((data = [self dataByDecodingBase64]) == nil)
234 s = [[NSString alloc] initWithData:data
235 encoding:[NSString defaultCStringEncoding]];
236 return [s autorelease];
239 @end /* NSData(Base64Coding) */
243 int NGEncodeBase64(const void *_source, unsigned _len,
244 void *_buffer, unsigned _bufferCapacity,
248 if ((_source == NULL) || (_buffer == NULL) || (_bufferCapacity == 0))
251 { // check whether buffer is big enough
253 outSize = (_len + 2) / 3 * 4; // 3:4 conversion ratio
254 outSize += (outSize / _maxLineWidth) + 2; // Space for newlines and NUL
256 if (_bufferCapacity < outSize)
260 if (encode_base64(_source, _len,
261 _buffer, _bufferCapacity, &len, _maxLineWidth) == 0) {
268 int NGDecodeBase64(const void *_source, unsigned _len,
269 void *_buffer, unsigned _bufferCapacity) {
272 if ((_source == NULL) || (_buffer == NULL) || (_bufferCapacity == 0))
275 if (((_len / 4 + 1) * 3 + 1) > _bufferCapacity)
278 if (decode_base64(_source, _len, _buffer, _bufferCapacity, &len) == 0)
284 // private implementation
286 static char base64tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
287 "abcdefghijklmnopqrstuvwxyz0123456789+/";
289 static char base64idx[128] = {
290 '\377','\377','\377','\377','\377','\377','\377','\377',
291 '\377','\377','\377','\377','\377','\377','\377','\377',
292 '\377','\377','\377','\377','\377','\377','\377','\377',
293 '\377','\377','\377','\377','\377','\377','\377','\377',
294 '\377','\377','\377','\377','\377','\377','\377','\377',
295 '\377','\377','\377', 62,'\377','\377','\377', 63,
296 52, 53, 54, 55, 56, 57, 58, 59,
297 60, 61,'\377','\377','\377','\377','\377','\377',
298 '\377', 0, 1, 2, 3, 4, 5, 6,
299 7, 8, 9, 10, 11, 12, 13, 14,
300 15, 16, 17, 18, 19, 20, 21, 22,
301 23, 24, 25,'\377','\377','\377','\377','\377',
302 '\377', 26, 27, 28, 29, 30, 31, 32,
303 33, 34, 35, 36, 37, 38, 39, 40,
304 41, 42, 43, 44, 45, 46, 47, 48,
305 49, 50, 51,'\377','\377','\377','\377','\377'
308 static inline int encode_base64(const char *_src, size_t _srcLen, char *_dest,
309 size_t _destSize, size_t *_destLen,
311 size_t inLen = _srcLen;
318 // Get three characters at a time and encode them.
319 for (i = 0; i < inLen / 3; ++i) {
320 c1 = _src[inPos++] & 0xFF;
321 c2 = _src[inPos++] & 0xFF;
322 c3 = _src[inPos++] & 0xFF;
323 out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
324 out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
325 out[outPos++] = base64tab[((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6)];
326 out[outPos++] = base64tab[c3 & 0x3F];
328 if ((outPos + 1) % (_maxLineWidth + 1) == 0)
329 out[outPos++] = '\n';
332 // Encode the remaining one or two characters.
335 //out[outPos++] = '\n';
338 c1 = _src[inPos] & 0xFF;
339 out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
340 out[outPos++] = base64tab[((c1 & 0x03) << 4)];
343 //out[outPos++] = '\n';
346 c1 = _src[inPos++] & 0xFF;
347 c2 = _src[inPos] & 0xFF;
348 out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
349 out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
350 out[outPos++] = base64tab[((c2 & 0x0F) << 2)];
352 //out[outPos++] = '\n';
360 static inline int decode_base64(const char *_src, size_t inLen, char *out,
361 size_t _destSize, size_t *_destLen)
365 register int b1, b2, b3;
366 register int a1, a2, a3, a4;
367 register size_t inPos = 0;
368 register size_t outPos = 0;
370 /* Get four input chars at a time and decode them. Ignore white space
371 * chars (CR, LF, SP, HT). If '=' is encountered, terminate input. If
372 * a char other than white space, base64 char, or '=' is encountered,
373 * flag an input error, but otherwise ignore the char.
375 while (inPos < inLen) {
376 a1 = a2 = a3 = a4 = 0;
379 while (inPos < inLen) {
380 a1 = _src[inPos++] & 0xFF;
384 else if (a1 == '=') {
388 else if (a1 != '\r' && a1 != '\n' && a1 != ' ' && a1 != '\t') {
394 while (inPos < inLen) {
395 a2 = _src[inPos++] & 0xFF;
399 else if (a2 == '=') {
403 else if (a2 != '\r' && a2 != '\n' && a2 != ' ' && a2 != '\t') {
409 while (inPos < inLen) {
410 a3 = _src[inPos++] & 0xFF;
414 else if (a3 == '=') {
418 else if (a3 != '\r' && a3 != '\n' && a3 != ' ' && a3 != '\t') {
424 while (inPos < inLen) {
425 a4 = _src[inPos++] & 0xFF;
429 else if (a4 == '=') {
433 else if (a4 != '\r' && a4 != '\n' && a4 != ' ' && a4 != '\t') {
439 if (isbase64(a1) && isbase64(a2) && isbase64(a3) && isbase64(a4)) {
440 a1 = base64idx[a1] & 0xFF;
441 a2 = base64idx[a2] & 0xFF;
442 a3 = base64idx[a3] & 0xFF;
443 a4 = base64idx[a4] & 0xFF;
444 b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
445 b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
446 b3 = ((a3 << 6) & 0xC0) | ( a4 & 0x3F);
447 out[outPos++] = (char)b1;
448 out[outPos++] = (char)b2;
449 out[outPos++] = (char)b3;
452 else if (isbase64(a1) && isbase64(a2) && isbase64(a3) && a4 == '=') {
453 a1 = base64idx[a1] & 0xFF;
454 a2 = base64idx[a2] & 0xFF;
455 a3 = base64idx[a3] & 0xFF;
456 b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
457 b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
458 out[outPos++] = (char)b1;
459 out[outPos++] = (char)b2;
463 else if (isbase64(a1) && isbase64(a2) && a3 == '=' && a4 == '=') {
464 a1 = base64idx[a1] & 0xFF;
465 a2 = base64idx[a2] & 0xFF;
466 b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
467 out[outPos++] = (char)b1;
479 return (isErr) ? -1 : 0;
482 // for static linking
484 void __link_NGBase64Coding(void) {
485 __link_NGBase64Coding();