1/*
2 * Copyright (c) 2011 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include "basexx.h"
25#include "CommonBaseXX.h"
26#include "ccMemory.h"
27#include "CommonBufferingPriv.h"
28#include "ccGlobals.h"
29#include <AssertMacros.h>
30
31const static encoderConstants encoderValue[] = {
32    { 16, 4, 1, 2, 0x0f }, // Base16
33    { 32, 5, 5, 8, 0x1f }, // Base32
34    { 64, 6, 3, 4, 0x3f }, // Base64
35};
36
37typedef struct _CNEncoder {
38    CoderFrame coderFrame;
39    CNEncodingDirection direction;
40    CNBufferRef base256buffer;
41    CNBufferRef baseXXbuffer;
42} CNEncoder;
43
44/*
45 * Pre-defined encoders.
46 */
47
48#define DEFAULTPAD		'='
49
50const static BaseEncoder defaultBase64 = {
51    .name = "Base64",
52    .encoding = kCNEncodingBase64,
53    .baseNum = 64,
54    .charMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
55    .padding = DEFAULTPAD,
56    .values = &encoderValue[2]
57};
58
59// RFC 4678 Base32Alphabet
60const static BaseEncoder defaultBase32 = {
61    .name = "Base32",
62    .encoding = kCNEncodingBase32,
63    .baseNum = 32,
64    .charMap = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
65    .padding = DEFAULTPAD,
66    .values = &encoderValue[1]
67};
68
69const static BaseEncoder recoveryBase32 = {
70    .name = "RecoveryBase32",
71    .encoding = kCNEncodingBase32Recovery,
72    .baseNum = 32,
73    .charMap = "ABCDEFGH8JKLMNOPQR9TUVWXYZ234567",
74    .padding = DEFAULTPAD,
75    .values = &encoderValue[1]
76};
77
78const static BaseEncoder hexBase32 = {
79    .name = "Base32Hex",
80    .encoding = kCNEncodingBase32HEX,
81    .baseNum = 32,
82    .charMap = "0123456789ABCDEFGHIJKLMNOPQRSTUV",
83    .padding = DEFAULTPAD,
84    .values = &encoderValue[1]
85};
86
87
88const static BaseEncoder defaultBase16 = {
89    .name = "Base16",
90    .encoding = kCNEncodingBase16,
91    .baseNum = 16,
92    .charMap = "0123456789ABCDEF",
93    .padding = DEFAULTPAD,
94    .values = &encoderValue[0]
95};
96
97
98/*
99    Utility functions
100 */
101
102
103static inline uint32_t baselog(CNEncoder *coderRef)
104{
105    if(coderRef && coderRef->coderFrame && coderRef->coderFrame->encoderRef && coderRef->coderFrame->encoderRef->values)
106        return coderRef->coderFrame->encoderRef->values->log;
107    else return 0;
108}
109
110static inline uint32_t basemask(CNEncoder *coderRef)
111{
112    return coderRef->coderFrame->encoderRef->values->basemask;
113}
114
115static inline uint32_t inputBlocksize(CNEncoder *coderRef)
116{
117    if(coderRef && coderRef->coderFrame && coderRef->coderFrame->encoderRef && coderRef->coderFrame->encoderRef->values)
118        return coderRef->coderFrame->encoderRef->values->inputBlocksize;
119    else return 0;
120}
121
122static inline uint32_t outputBlocksize(CNEncoder *coderRef)
123{
124    if(coderRef && coderRef->coderFrame && coderRef->coderFrame->encoderRef && coderRef->coderFrame->encoderRef->values)
125        return coderRef->coderFrame->encoderRef->values->outputBlocksize;
126    else return 0;
127}
128
129static inline uint8_t encodeToBase(CNEncoder *coderRef, uint8_t inByte)
130{
131    if(inByte < coderRef->coderFrame->encoderRef->baseNum) return coderRef->coderFrame->encoderRef->charMap[inByte];
132    return 0x80;
133}
134
135static inline uint8_t decodeFromBase(CNEncoder *coderRef, uint8_t inByte)
136{
137    return coderRef->coderFrame->reverseMap[inByte];
138}
139
140static inline size_t decodeLen(void *ctx, size_t len)
141{
142    CNEncoder *coderRef = (CNEncoder *) ctx;
143    if(0 == len) return 0;
144    return (baselog(coderRef) * len + 8 ) / 8;
145}
146
147static inline size_t encodeLen(void *ctx, size_t len)
148{
149    CNEncoder *coderRef = (CNEncoder *) ctx;
150    if(0 == len || 0 == inputBlocksize(coderRef) || 0 == outputBlocksize(coderRef)) return 0;
151    return ((len + inputBlocksize(coderRef) - 1) / inputBlocksize(coderRef)) * outputBlocksize(coderRef);
152}
153
154
155/*
156 * This takes raw data from base XX (where XX is "base") and puts it into base256 form.
157 */
158
159static int
160deCode(void *ctx, const void *in, size_t srcLen, void *out, size_t *destLen)
161{
162    uint8_t *src = (uint8_t *) in, *dest = (uint8_t *) out;
163    CNEncoder *coderRef = (CNEncoder *) ctx;
164    size_t i;
165    size_t dPos = 0;
166    int sourceBits = baselog(coderRef);
167
168    if(coderRef == NULL || coderRef->coderFrame == NULL || coderRef->coderFrame->encoderRef == NULL) return 0;
169    if((*destLen = decodeLen(coderRef, srcLen)) == 0) {
170        *dest = 0;
171        return 0;
172    }
173
174    CC_XZEROMEM(dest, *destLen);
175
176    for(i=0; i<srcLen; i++) {
177        if(src[i] != coderRef->coderFrame->encoderRef->padding) {
178            uint8_t srcByte = decodeFromBase(coderRef, src[i]);
179            int dBit = (i*sourceBits) % 8; // destination position of Leftmost Bit of source byte
180            int shiftl = (8-sourceBits) - dBit; // amount needed to shift left to get bits positioned
181            dPos = (i*sourceBits) / 8; // destination byte of leftmost bit of source byte
182
183            if(shiftl >= 0) {
184                dest[dPos] |= srcByte << shiftl;
185            } else if(shiftl < 0) {
186                int shiftr = shiftl * (-1);
187                dest[dPos] |= srcByte >> shiftr;
188                dest[dPos+1] |= srcByte << (8-shiftr);
189            }
190        }
191    }
192    *destLen = (dest[dPos+1]) ? dPos+2: dPos+1;
193    return 0;
194}
195
196/*
197 * This takes "normal" base256 encoding and puts it into baseXX (where XX is "base") raw data.
198 */
199
200static int
201enCode(void *ctx, const void *in, size_t srcLen, void *out, size_t *destLen)
202{
203    uint8_t *src = (uint8_t *) in, *dest = (uint8_t *) out;
204    CNEncoder *coderRef = (CNEncoder *) ctx;
205    size_t i;
206    int destBits = baselog(coderRef);
207    int baseShift = 8 - destBits;
208    size_t needed, dPos;
209
210    if((needed = encodeLen(coderRef, srcLen)) == 0) {
211        *destLen = 0;
212        *dest = 0;
213        return 0;
214    }
215
216    if(*destLen < needed) {
217        *destLen = needed;
218        return -1;
219    }
220
221    *destLen = needed;
222
223    CC_XZEROMEM(dest, needed);
224
225    dPos = 0;
226    for(i=0; i<srcLen; i++) {
227        int dBit = (i*8) % destBits;
228        dPos = (i*8) / destBits;
229        int shiftr = baseShift + dBit;
230
231        dest[dPos] |= (src[i] >> shiftr) & basemask(coderRef);
232        if(shiftr > destBits) {
233            shiftr = shiftr - destBits;
234            dPos++;
235            dest[dPos] |= (src[i] >> shiftr) & basemask(coderRef);
236        }
237        dest[dPos+1] |= (src[i] << (destBits - shiftr)) & basemask(coderRef);
238    }
239    dPos+=2;
240
241    for(i=0; i<dPos; i++) dest[i] = encodeToBase(coderRef, dest[i]);
242
243    for(; dPos < needed; dPos++) dest[dPos] = coderRef->coderFrame->encoderRef->padding;
244    dest[dPos] = 0;
245    return 0;
246}
247
248static void setReverseMap(CoderFrame frame)
249{
250    int i;
251    CC_XMEMSET(frame->reverseMap, 0x80, 256);
252    for(i=0; i<frame->encoderRef->baseNum; i++) {
253        int idx;
254        idx = frame->encoderRef->charMap[i];
255        frame->reverseMap[idx] = i;
256    }
257}
258
259static CoderFrame
260getCodeFrame(CNEncodings encoding)
261{
262    cc_globals_t globals = _cc_globals();
263    if(encoding > CN_STANDARD_BASE_ENCODERS) return NULL;
264    dispatch_once(&globals->basexx_init, ^{
265        for(int i=0; i<CN_STANDARD_BASE_ENCODERS; i++)
266            globals->encoderTab[i].encoderRef = NULL;
267        globals->encoderTab[kCNEncodingBase64].encoderRef = &defaultBase64;
268        globals->encoderTab[kCNEncodingBase32].encoderRef = &defaultBase32;
269        globals->encoderTab[kCNEncodingBase32Recovery].encoderRef = &recoveryBase32;
270        globals->encoderTab[kCNEncodingBase32HEX].encoderRef = &hexBase32;
271        globals->encoderTab[kCNEncodingBase16].encoderRef = &defaultBase16;
272    });
273    dispatch_once(&globals->encoderTab[encoding].encoderInit, ^{
274        globals->encoderTab[encoding].reverseMap = CC_XMALLOC(256);
275        if(globals->encoderTab[encoding].reverseMap) setReverseMap(&globals->encoderTab[encoding]);
276    });
277    if(NULL == globals->encoderTab[encoding].reverseMap) return NULL;
278    return &globals->encoderTab[encoding];
279}
280
281/*
282 Interface functions
283 */
284
285CNStatus CNEncoderCreate(CNEncodings encoding,
286                         CNEncodingDirection direction,
287                         CNEncoderRef *encoderRef)
288{
289    if(direction != kCNEncode && direction != kCNDecode) return kCNParamError;
290    if(!encoderRef) return kCNParamError;
291    *encoderRef = NULL;
292    CoderFrame codeFrame = getCodeFrame (encoding);
293    if(!codeFrame) return kCNParamError;
294
295    CNEncoder *coderRef = CC_XMALLOC(sizeof(CNEncoder));
296    if(!coderRef) return kCNMemoryFailure;
297
298    coderRef->direction = direction;
299    coderRef->coderFrame = codeFrame;
300    coderRef->base256buffer = NULL;
301    coderRef->baseXXbuffer = NULL;
302    coderRef->base256buffer = CNBufferCreate(inputBlocksize(coderRef));
303    coderRef->baseXXbuffer = CNBufferCreate(outputBlocksize(coderRef));
304    if(!coderRef->base256buffer || !coderRef->baseXXbuffer) {
305        if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer);
306        if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer);
307        CC_XFREE(coderRef, sizeof(CNEncoder));
308        return kCNMemoryFailure;
309    }
310    *encoderRef = coderRef;
311    return kCNSuccess;
312}
313
314
315CNStatus CNEncoderCreateCustom(
316                               const void *name,
317                               const uint8_t baseNum,
318                               const void *charMap,
319                               const char padChar,
320                               CNEncodingDirection direction,
321                               CNEncoderRef *encoderRef)
322{
323    if(direction != kCNEncode && direction != kCNDecode) return kCNParamError;
324    if(baseNum != 16 && baseNum != 32 && baseNum != 64) return kCNParamError;
325    if(!encoderRef || !charMap) return kCNParamError;
326    *encoderRef = NULL;
327
328    CoderFrame codeFrame = CC_XMALLOC(sizeof(BaseEncoderFrame));
329    BaseEncoderRefCustom customEncoder = CC_XMALLOC(sizeof(BaseEncoder));
330    CNEncoder *coderRef = CC_XMALLOC(sizeof(CNEncoder));
331    if(codeFrame) codeFrame->reverseMap = CC_XMALLOC(256);
332    if(coderRef) {
333        coderRef->base256buffer = NULL;
334        coderRef->baseXXbuffer = NULL;
335    }
336
337    CNStatus retval = kCNMemoryFailure;
338    if(!codeFrame || !customEncoder || !coderRef) goto errOut;
339    if(!codeFrame->reverseMap) goto errOut;
340
341    customEncoder->baseNum = baseNum;
342    customEncoder->values = &encoderValue[baseNum/32];
343    customEncoder->name = name;
344    customEncoder->charMap = charMap;
345    customEncoder->padding = padChar;
346    customEncoder->encoding = kCNEncodingCustom;
347
348    codeFrame->encoderRef = customEncoder;
349    setReverseMap(codeFrame);
350
351    coderRef->coderFrame = codeFrame;
352    coderRef->direction = direction;
353    coderRef->base256buffer = CNBufferCreate(inputBlocksize(coderRef));
354    coderRef->baseXXbuffer = CNBufferCreate(outputBlocksize(coderRef));
355    if(!coderRef->base256buffer || !coderRef->baseXXbuffer) goto errOut;
356
357    *encoderRef = coderRef;
358    return kCNSuccess;
359
360errOut:
361    if(codeFrame) {
362        if(codeFrame->reverseMap) CC_XFREE(codeFrame->reverseMap, 256);
363        CC_XFREE(codeFrame, sizeof(BaseEncoderFrame));
364    }
365
366    if(customEncoder) {
367        CC_XFREE(customEncoder, sizeof(BaseEncoder));
368    }
369
370    if(coderRef) {
371        if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer);
372        if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer);
373        CC_XFREE(coderRef, sizeof(CNEncoder));
374    }
375    return retval;
376
377}
378
379CNStatus CNEncoderRelease(CNEncoderRef *encoderRef)
380{
381    CNEncoder *coderRef = *encoderRef;
382    *encoderRef = NULL;
383    if(coderRef) {
384        CoderFrame codeFrame = coderRef->coderFrame;
385        if(codeFrame->encoderRef && kCNEncodingCustom == codeFrame->encoderRef->encoding) {
386            CC_XFREE(codeFrame->reverseMap, 256);
387            BaseEncoderRefCustom customRef = (BaseEncoderRefCustom) codeFrame->encoderRef;
388            CC_XFREE((void *) customRef, sizeof(BaseEncoder));
389        }
390        if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer);
391        if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer);
392        CC_XFREE(coderRef, sizeof(CNEncoder));
393    }
394    return kCNSuccess;
395}
396
397
398size_t
399CNEncoderGetOutputLength(CNEncoderRef encoderRef, const size_t inLen)
400{
401    CNEncoder *coderRef = encoderRef;
402    size_t retval = 0;
403
404    __Require_Quiet(NULL != coderRef, errOut);
405
406    if(coderRef->direction == kCNEncode) {
407        retval = encodeLen(coderRef, inLen + coderRef->base256buffer->bufferPos) + 1;
408    } else if(coderRef->direction == kCNDecode) {
409        retval = decodeLen(coderRef, inLen + coderRef->baseXXbuffer->bufferPos);
410    }
411
412errOut:
413    return retval;
414}
415
416
417size_t
418CNEncoderGetOutputLengthFromEncoding(CNEncodings encoding, CNEncodingDirection direction, const size_t inLen)
419{
420    size_t retval = 0;
421    CNEncoderRef coder;
422    CNStatus status;
423
424    if((status = CNEncoderCreate(encoding, direction, &coder))) return 0;
425
426    if(direction == kCNEncode) {
427        retval = encodeLen(coder, inLen) + 1;
428    } else if(direction == kCNDecode) {
429        retval = decodeLen(coder, inLen);
430    }
431
432    CNEncoderRelease(&coder);
433
434    return retval;
435}
436
437
438CNStatus
439CNEncoderUpdate(CNEncoderRef coderRef, const void *in, const size_t inLen, void *out, size_t *outLen)
440{
441    CNStatus retval = kCNParamError;
442    CNEncoder *encoderRef = coderRef;
443//    size_t outputLen, outputAvailable;
444
445
446    __Require_Quiet(NULL != coderRef, errOut);
447    __Require_Quiet(NULL != out, errOut);
448    __Require_Quiet(NULL != outLen, errOut);
449
450    if(NULL == in) {
451        if(0 == inLen) {
452            *outLen = 0;
453            return kCNSuccess;
454        }
455        return kCNParamError;
456    }
457
458//    outputAvailable = outputLen = *outLen;
459
460    if(encoderRef->direction == kCNEncode) {
461        retval = CNBufferProcessData(coderRef->base256buffer, coderRef, in, inLen, out, outLen, enCode, encodeLen);
462    } else if(encoderRef->direction == kCNDecode) {
463        retval = CNBufferProcessData(coderRef->baseXXbuffer, coderRef, in, inLen, out, outLen, deCode, decodeLen);
464    } else {
465        retval = kCNParamError;
466    }
467
468errOut:
469    return retval;
470}
471
472CNStatus
473CNEncoderFinal(CNEncoderRef coderRef, void *out, size_t *outLen)
474{
475    CNStatus retval = kCNParamError;
476    CNEncoder *encoderRef = coderRef;
477
478    __Require_Quiet(NULL != coderRef, errOut);
479    __Require_Quiet(NULL != out, errOut);
480    __Require_Quiet(NULL != outLen, errOut);
481
482    if(encoderRef->direction == kCNEncode) {
483        if((encodeLen(coderRef, coderRef->baseXXbuffer->bufferPos)+1) > *outLen) {
484            // We need room for the final '\0' on the encoded string.
485            retval = kCNBufferTooSmall;
486            goto errOut;
487        }
488        retval = CNBufferFlushData(coderRef->base256buffer, coderRef, out, outLen, enCode, encodeLen);
489        if(kCNSuccess == retval) {
490            ((uint8_t *)out)[*outLen] = 0;
491        }
492    } else if(encoderRef->direction == kCNDecode) {
493        retval = CNBufferFlushData(coderRef->baseXXbuffer, coderRef, out, outLen, deCode, decodeLen);
494    } else {
495        retval = kCNParamError;
496    }
497
498
499errOut:
500    return retval;
501
502}
503
504
505CNStatus
506CNEncoderBlocksize(CNEncodings encoding, size_t *inputSize, size_t *outputSize)
507{
508    CNEncoderRef coder;
509    CNStatus status;
510
511    __Require_Quiet(NULL != inputSize, errOut);
512    __Require_Quiet(NULL != outputSize, errOut);
513
514    if((status = CNEncoderCreate(encoding, kCNEncode, &coder))) return status;
515
516    *inputSize = inputBlocksize(coder);
517    *outputSize = outputBlocksize(coder);
518    CNEncoderRelease(&coder);
519
520    return kCNSuccess;
521errOut:
522    return kCNParamError;
523}
524
525CNStatus
526CNEncoderBlocksizeFromRef(CNEncoderRef encoderRef, size_t *inputSize, size_t *outputSize)
527{
528    __Require_Quiet(NULL != encoderRef, errOut);
529    __Require_Quiet(NULL != inputSize, errOut);
530    __Require_Quiet(NULL != outputSize, errOut);
531
532    *inputSize = inputBlocksize(encoderRef);
533    *outputSize = outputBlocksize(encoderRef);
534    return kCNSuccess;
535errOut:
536    return kCNParamError;
537}
538
539CNStatus CNEncode(CNEncodings encoding,
540                  CNEncodingDirection direction,
541                  const void *in, const size_t inLen,
542                  void *out,  size_t *outLen)
543{
544    CNStatus retval;
545    size_t outAvailable, currentlyAvailable;
546    CNEncoderRef encoder;
547    uint8_t *outPtr = out;
548
549    retval = kCNParamError;
550    __Require_Quiet(NULL != out, outReturn);
551    __Require_Quiet(NULL != outLen, outReturn);
552    __Require_Quiet(NULL != in, outReturn);
553
554    retval = CNEncoderCreate(encoding, direction, &encoder);
555    __Require_Quiet(kCNSuccess == retval, outReturn);
556
557    currentlyAvailable = outAvailable = *outLen;
558    *outLen = 0;
559
560    retval = CNEncoderUpdate(encoder, in, inLen, outPtr, &currentlyAvailable);
561    __Require_Quiet(kCNSuccess == retval, outReturn);
562
563    *outLen = currentlyAvailable;
564    outAvailable -= currentlyAvailable;
565    outPtr += currentlyAvailable;
566    currentlyAvailable = outAvailable;
567
568    retval = CNEncoderFinal(encoder, outPtr, &currentlyAvailable);
569    __Require_Quiet(kCNSuccess == retval, outReturn);
570
571    *outLen += currentlyAvailable;
572
573    retval = CNEncoderRelease(&encoder);
574
575outReturn:
576    return retval;
577
578}
579
580