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
22 #include "NGBase64Coding.h"
24 #import <Foundation/NSString.h>
25 #import <Foundation/NSException.h>
27 static inline BOOL isbase64(char a) {
28 if (('A' <= a) && (a <= 'Z'))
30 if (('a' <= a) && (a <= 'z'))
32 if (('0' <= a) && (a <= '9'))
34 if ((a == '+') || (a == '/'))
39 static inline int encode_base64(const char *_src, size_t _srcLen, char *_dest,
40 size_t _destSize, size_t *_destLen,
42 static inline int decode_base64(const char *_src, size_t _srcLen, char *_dest,
43 size_t _destSize, size_t *_destLen);
45 @implementation NSString(Base64Coding)
47 static Class StringClass = Nil;
48 static int NSStringMaxLineWidth = 1024;
50 - (NSString *)stringByEncodingBase64 {
53 size_t destLength = -1;
56 if ((len = [self cStringLength]) == 0)
59 destSize = (len + 2) / 3 * 4; // 3:4 conversion ratio
60 destSize += destSize / NSStringMaxLineWidth + 2; // space for newlines and '\0'
62 dest = malloc(destSize + 4);
63 if (dest == NULL) return nil;
65 NSAssert(destSize > 0, @"invalid buffer size ..");
66 NSAssert(dest, @"invalid buffer ..");
68 src = malloc(len + 4);
69 [self getCString:src];
72 if (encode_base64(src, len,
73 dest, destSize, &destLength, NSStringMaxLineWidth) == 0) {
75 return [[[NSString alloc]
76 initWithCStringNoCopy:dest
78 freeWhenDone:YES] autorelease];
82 if (dest) free((void *)dest); dest = NULL;
86 - (NSString *)stringByDecodingBase64 {
89 size_t destLength = -1;
92 if (StringClass == Nil) StringClass = [NSString class];
94 if ((len = [self cStringLength]) == 0)
97 destSize = (len / 4 + 1) * 3 + 1;
98 dest = malloc(destSize + 1);
100 NSAssert(destSize > 0, @"invalid buffer size ..");
101 NSAssert(dest, @"invalid buffer ..");
103 src = malloc(len + 4);
104 [self getCString:src];
107 if (decode_base64(src, len, dest, destSize, &destLength) == 0) {
110 if (*dest == '\0' && destLength > 0) {
111 NSLog(@"ERROR(%s): could not decode %@ as string (contains \\0 bytes)!",
112 __PRETTY_FUNCTION__, self);
114 if (dest) free(dest);
118 return [[[StringClass alloc]
119 initWithCStringNoCopy:dest
121 freeWhenDone:YES] autorelease];
125 if (dest) free(dest);
130 - (NSData *)dataByDecodingBase64 {
133 size_t destLength = -1;
136 if (StringClass == Nil) StringClass = [NSString class];
138 if ((len = [self cStringLength]) == 0)
139 return [NSData data];
141 destSize = (len / 4 + 1) * 3 + 1;
142 dest = malloc(destSize + 1);
144 NSAssert(destSize > 0, @"invalid buffer size ..");
145 NSAssert(dest, @"invalid buffer ..");
147 src = malloc(len + 4);
148 [self getCString:src];
151 if (decode_base64(src, len, dest, destSize, &destLength) == 0) {
153 return [NSData dataWithBytesNoCopy:dest length:destLength];
157 if (dest) free(dest);
161 @end /* NSString(Base64Coding) */
163 @implementation NSData(Base64Coding)
165 static int NSDataMaxLineWidth = 72;
167 - (NSData *)dataByEncodingBase64 {
170 size_t destLength = -1;
173 if ((len = [self length]) == 0)
174 return [NSData data];
176 destSize = (len + 2) / 3 * 4; // 3:4 conversion ratio
177 destSize += destSize / NSDataMaxLineWidth + 2; // space for newlines and '\0'
180 dest = malloc(destSize + 4);
182 NSAssert(destSize > 0, @"invalid buffer size ..");
183 NSAssert(dest, @"invalid buffer ..");
185 if (encode_base64([self bytes], len,
186 dest, destSize, &destLength, NSDataMaxLineWidth) == 0) {
187 return [NSData dataWithBytesNoCopy:dest length:destLength];
190 if (dest) free((void *)dest);
195 - (NSData *)dataByDecodingBase64 {
198 size_t destLength = -1;
201 if ((len = [self length]) == 0)
202 return [NSData data];
204 destSize = (len / 4 + 1) * 3 + 1;
205 dest = malloc(destSize + 4);
207 NSAssert(destSize > 0, @"invalid buffer size ..");
208 NSAssert(dest, @"invalid buffer ..");
210 if (decode_base64([self bytes], len, dest, destSize, &destLength) == 0)
211 return [NSData dataWithBytesNoCopy:dest length:destLength];
213 if (dest) free(dest);
217 - (NSString *)stringByEncodingBase64 {
221 if ((data = [self dataByEncodingBase64]) == nil)
223 s = [[NSString alloc] initWithData:data
224 encoding:[NSString defaultCStringEncoding]];
225 return [s autorelease];
227 - (NSString *)stringByDecodingBase64 {
231 if ((data = [self dataByDecodingBase64]) == nil)
233 s = [[NSString alloc] initWithData:data
234 encoding:[NSString defaultCStringEncoding]];
235 return [s autorelease];
238 @end /* NSData(Base64Coding) */
242 int NGEncodeBase64(const void *_source, unsigned _len,
243 void *_buffer, unsigned _bufferCapacity,
247 if ((_source == NULL) || (_buffer == NULL) || (_bufferCapacity == 0))
250 { // check whether buffer is big enough
252 outSize = (_len + 2) / 3 * 4; // 3:4 conversion ratio
253 outSize += (outSize / _maxLineWidth) + 2; // Space for newlines and NUL
255 if (_bufferCapacity < outSize)
259 if (encode_base64(_source, _len,
260 _buffer, _bufferCapacity, &len, _maxLineWidth) == 0) {
267 int NGDecodeBase64(const void *_source, unsigned _len,
268 void *_buffer, unsigned _bufferCapacity) {
271 if ((_source == NULL) || (_buffer == NULL) || (_bufferCapacity == 0))
274 if (((_len / 4 + 1) * 3 + 1) > _bufferCapacity)
277 if (decode_base64(_source, _len, _buffer, _bufferCapacity, &len) == 0)
283 // private implementation
285 static char base64tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
286 "abcdefghijklmnopqrstuvwxyz0123456789+/";
288 static char base64idx[128] = {
289 '\377','\377','\377','\377','\377','\377','\377','\377',
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', 62,'\377','\377','\377', 63,
295 52, 53, 54, 55, 56, 57, 58, 59,
296 60, 61,'\377','\377','\377','\377','\377','\377',
297 '\377', 0, 1, 2, 3, 4, 5, 6,
298 7, 8, 9, 10, 11, 12, 13, 14,
299 15, 16, 17, 18, 19, 20, 21, 22,
300 23, 24, 25,'\377','\377','\377','\377','\377',
301 '\377', 26, 27, 28, 29, 30, 31, 32,
302 33, 34, 35, 36, 37, 38, 39, 40,
303 41, 42, 43, 44, 45, 46, 47, 48,
304 49, 50, 51,'\377','\377','\377','\377','\377'
307 static inline int encode_base64(const char *_src, size_t _srcLen, char *_dest,
308 size_t _destSize, size_t *_destLen,
310 size_t inLen = _srcLen;
317 // Get three characters at a time and encode them.
318 for (i = 0; i < inLen / 3; ++i) {
319 c1 = _src[inPos++] & 0xFF;
320 c2 = _src[inPos++] & 0xFF;
321 c3 = _src[inPos++] & 0xFF;
322 out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
323 out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
324 out[outPos++] = base64tab[((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6)];
325 out[outPos++] = base64tab[c3 & 0x3F];
327 if ((outPos + 1) % (_maxLineWidth + 1) == 0)
328 out[outPos++] = '\n';
331 // Encode the remaining one or two characters.
334 //out[outPos++] = '\n';
337 c1 = _src[inPos] & 0xFF;
338 out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
339 out[outPos++] = base64tab[((c1 & 0x03) << 4)];
342 //out[outPos++] = '\n';
345 c1 = _src[inPos++] & 0xFF;
346 c2 = _src[inPos] & 0xFF;
347 out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
348 out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
349 out[outPos++] = base64tab[((c2 & 0x0F) << 2)];
351 //out[outPos++] = '\n';
359 static inline int decode_base64(const char *_src, size_t inLen, char *out,
360 size_t _destSize, size_t *_destLen)
364 register int b1, b2, b3;
365 register int a1, a2, a3, a4;
366 register size_t inPos = 0;
367 register size_t outPos = 0;
369 /* Get four input chars at a time and decode them. Ignore white space
370 * chars (CR, LF, SP, HT). If '=' is encountered, terminate input. If
371 * a char other than white space, base64 char, or '=' is encountered,
372 * flag an input error, but otherwise ignore the char.
374 while (inPos < inLen) {
375 a1 = a2 = a3 = a4 = 0;
378 while (inPos < inLen) {
379 a1 = _src[inPos++] & 0xFF;
383 else if (a1 == '=') {
387 else if (a1 != '\r' && a1 != '\n' && a1 != ' ' && a1 != '\t') {
393 while (inPos < inLen) {
394 a2 = _src[inPos++] & 0xFF;
398 else if (a2 == '=') {
402 else if (a2 != '\r' && a2 != '\n' && a2 != ' ' && a2 != '\t') {
408 while (inPos < inLen) {
409 a3 = _src[inPos++] & 0xFF;
413 else if (a3 == '=') {
417 else if (a3 != '\r' && a3 != '\n' && a3 != ' ' && a3 != '\t') {
423 while (inPos < inLen) {
424 a4 = _src[inPos++] & 0xFF;
428 else if (a4 == '=') {
432 else if (a4 != '\r' && a4 != '\n' && a4 != ' ' && a4 != '\t') {
438 if (isbase64(a1) && isbase64(a2) && isbase64(a3) && isbase64(a4)) {
439 a1 = base64idx[a1] & 0xFF;
440 a2 = base64idx[a2] & 0xFF;
441 a3 = base64idx[a3] & 0xFF;
442 a4 = base64idx[a4] & 0xFF;
443 b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
444 b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
445 b3 = ((a3 << 6) & 0xC0) | ( a4 & 0x3F);
446 out[outPos++] = (char)b1;
447 out[outPos++] = (char)b2;
448 out[outPos++] = (char)b3;
451 else if (isbase64(a1) && isbase64(a2) && isbase64(a3) && a4 == '=') {
452 a1 = base64idx[a1] & 0xFF;
453 a2 = base64idx[a2] & 0xFF;
454 a3 = base64idx[a3] & 0xFF;
455 b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
456 b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
457 out[outPos++] = (char)b1;
458 out[outPos++] = (char)b2;
462 else if (isbase64(a1) && isbase64(a2) && a3 == '=' && a4 == '=') {
463 a1 = base64idx[a1] & 0xFF;
464 a2 = base64idx[a2] & 0xFF;
465 b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
466 out[outPos++] = (char)b1;
478 return (isErr) ? -1 : 0;
481 // for static linking
483 void __link_NGBase64Coding(void) {
484 __link_NGBase64Coding();