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    for(i=0; i<srcLen; i++) {
226        int dBit = (i*8) % destBits;
227        dPos = (i*8) / destBits;
228        int shiftr = baseShift + dBit;
229
230        dest[dPos] |= (src[i] >> shiftr) & basemask(coderRef);
231        if(shiftr > destBits) {
232            shiftr = shiftr - destBits;
233            dPos++;
234            dest[dPos] |= (src[i] >> shiftr) & basemask(coderRef);
235        }
236        dest[dPos+1] |= (src[i] << (destBits - shiftr)) & basemask(coderRef);
237    }
238    dPos+=2;
239
240    for(i=0; i<dPos; i++) dest[i] = encodeToBase(coderRef, dest[i]);
241
242    for(; dPos < needed; dPos++) dest[dPos] = coderRef->coderFrame->encoderRef->padding;
243    dest[dPos] = 0;
244    return 0;
245}
246
247static void setReverseMap(CoderFrame frame)
248{
249    int i;
250    CC_XMEMSET(frame->reverseMap, 0x80, 256);
251    for(i=0; i<frame->encoderRef->baseNum; i++) {
252        int idx;
253        idx = frame->encoderRef->charMap[i];
254        frame->reverseMap[idx] = i;
255    }
256}
257
258static CoderFrame
259getCodeFrame(CNEncodings encoding)
260{
261    cc_globals_t globals = _cc_globals();
262    if(encoding > CN_STANDARD_BASE_ENCODERS) return NULL;
263    dispatch_once(&globals->basexx_init, ^{
264        for(int i=0; i<CN_STANDARD_BASE_ENCODERS; i++)
265            globals->encoderTab[i].encoderRef = NULL;
266        globals->encoderTab[kCNEncodingBase64].encoderRef = &defaultBase64;
267        globals->encoderTab[kCNEncodingBase32].encoderRef = &defaultBase32;
268        globals->encoderTab[kCNEncodingBase32Recovery].encoderRef = &recoveryBase32;
269        globals->encoderTab[kCNEncodingBase32HEX].encoderRef = &hexBase32;
270        globals->encoderTab[kCNEncodingBase16].encoderRef = &defaultBase16;
271    });
272    dispatch_once(&globals->encoderTab[encoding].encoderInit, ^{
273        globals->encoderTab[encoding].reverseMap = CC_XMALLOC(256);
274        if(globals->encoderTab[encoding].reverseMap) setReverseMap(&globals->encoderTab[encoding]);
275    });
276    if(NULL == globals->encoderTab[encoding].reverseMap) return NULL;
277    return &globals->encoderTab[encoding];
278}
279
280/*
281 Interface functions
282 */
283
284CNStatus CNEncoderCreate(CNEncodings encoding,
285                         CNEncodingDirection direction,
286                         CNEncoderRef *encoderRef)
287{
288    if(direction != kCNEncode && direction != kCNDecode) return kCNParamError;
289    if(!encoderRef) return kCNParamError;
290    *encoderRef = NULL;
291    CoderFrame codeFrame = getCodeFrame (encoding);
292    if(!codeFrame) return kCNParamError;
293
294    CNEncoder *coderRef = CC_XMALLOC(sizeof(CNEncoder));
295    if(!coderRef) return kCNMemoryFailure;
296
297    coderRef->direction = direction;
298    coderRef->coderFrame = codeFrame;
299    coderRef->base256buffer = NULL;
300    coderRef->baseXXbuffer = NULL;
301    coderRef->base256buffer = CNBufferCreate(inputBlocksize(coderRef));
302    coderRef->baseXXbuffer = CNBufferCreate(outputBlocksize(coderRef));
303    if(!coderRef->base256buffer || !coderRef->baseXXbuffer) {
304        if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer);
305        if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer);
306        CC_XFREE(coderRef, sizeof(CNEncoder));
307        return kCNMemoryFailure;
308    }
309    *encoderRef = coderRef;
310    return kCNSuccess;
311}
312
313
314CNStatus CNEncoderCreateCustom(
315                               const void *name,
316                               const uint8_t baseNum,
317                               const void *charMap,
318                               const char padChar,
319                               CNEncodingDirection direction,
320                               CNEncoderRef *encoderRef)
321{
322    if(direction != kCNEncode && direction != kCNDecode) return kCNParamError;
323    if(baseNum != 16 && baseNum != 32 && baseNum != 64) return kCNParamError;
324    if(!encoderRef || !charMap) return kCNParamError;
325    *encoderRef = NULL;
326
327    CoderFrame codeFrame = CC_XMALLOC(sizeof(BaseEncoderFrame));
328    BaseEncoderRefCustom customEncoder = CC_XMALLOC(sizeof(BaseEncoder));
329    CNEncoder *coderRef = CC_XMALLOC(sizeof(CNEncoder));
330    if(codeFrame) codeFrame->reverseMap = CC_XMALLOC(256);
331    if(coderRef) {
332        coderRef->base256buffer = NULL;
333        coderRef->baseXXbuffer = NULL;
334    }
335
336    CNStatus retval = kCNMemoryFailure;
337    if(!codeFrame || !customEncoder || !coderRef) goto errOut;
338    if(!codeFrame->reverseMap) goto errOut;
339
340    customEncoder->baseNum = baseNum;
341    customEncoder->values = &encoderValue[baseNum/32];
342    customEncoder->name = name;
343    customEncoder->charMap = charMap;
344    customEncoder->padding = padChar;
345    customEncoder->encoding = kCNEncodingCustom;
346
347    codeFrame->encoderRef = customEncoder;
348    setReverseMap(codeFrame);
349
350    coderRef->coderFrame = codeFrame;
351    coderRef->direction = direction;
352    coderRef->base256buffer = CNBufferCreate(inputBlocksize(coderRef));
353    coderRef->baseXXbuffer = CNBufferCreate(outputBlocksize(coderRef));
354    if(!coderRef->base256buffer || !coderRef->baseXXbuffer) goto errOut;
355
356    *encoderRef = coderRef;
357    return kCNSuccess;
358
359errOut:
360    if(codeFrame) {
361        if(codeFrame->reverseMap) CC_XFREE(codeFrame->reverseMap, 256);
362        CC_XFREE(codeFrame, sizeof(BaseEncoderFrame));
363    }
364
365    if(customEncoder) {
366        CC_XFREE(customEncoder, sizeof(BaseEncoder));
367    }
368
369    if(coderRef) {
370        if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer);
371        if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer);
372        CC_XFREE(coderRef, sizeof(CNEncoder));
373    }
374    return retval;
375
376}
377
378CNStatus CNEncoderRelease(CNEncoderRef *encoderRef)
379{
380    CNEncoder *coderRef = *encoderRef;
381    *encoderRef = NULL;
382    if(coderRef) {
383        CoderFrame codeFrame = coderRef->coderFrame;
384        if(codeFrame->encoderRef && kCNEncodingCustom == codeFrame->encoderRef->encoding) {
385            CC_XFREE(codeFrame->reverseMap, 256);
386            BaseEncoderRefCustom customRef = (BaseEncoderRefCustom) codeFrame->encoderRef;
387            CC_XFREE((void *) customRef, sizeof(BaseEncoder));
388        }
389        if(coderRef->base256buffer) CNBufferRelease(&coderRef->base256buffer);
390        if(coderRef->baseXXbuffer) CNBufferRelease(&coderRef->baseXXbuffer);
391        CC_XFREE(coderRef, sizeof(CNEncoder));
392    }
393    return kCNSuccess;
394}
395
396
397size_t
398CNEncoderGetOutputLength(CNEncoderRef encoderRef, const size_t inLen)
399{
400    CNEncoder *coderRef = encoderRef;
401    size_t retval = 0;
402
403    __Require_Quiet(NULL != coderRef, errOut);
404
405    if(coderRef->direction == kCNEncode) {
406        retval = encodeLen(coderRef, inLen + coderRef->base256buffer->bufferPos) + 1;
407    } else if(coderRef->direction == kCNDecode) {
408        retval = decodeLen(coderRef, inLen + coderRef->baseXXbuffer->bufferPos);
409    }
410
411errOut:
412    return retval;
413}
414
415
416size_t
417CNEncoderGetOutputLengthFromEncoding(CNEncodings encoding, CNEncodingDirection direction, const size_t inLen)
418{
419    size_t retval = 0;
420    CNEncoderRef coder;
421    CNStatus status;
422
423    if((status = CNEncoderCreate(encoding, direction, &coder))) return 0;
424
425    if(direction == kCNEncode) {
426        retval = encodeLen(coder, inLen) + 1;
427    } else if(direction == kCNDecode) {
428        retval = decodeLen(coder, inLen);
429    }
430
431    CNEncoderRelease(&coder);
432
433    return retval;
434}
435
436
437CNStatus
438CNEncoderUpdate(CNEncoderRef coderRef, const void *in, const size_t inLen, void *out, size_t *outLen)
439{
440    CNStatus retval = kCNParamError;
441    CNEncoder *encoderRef = coderRef;
442//    size_t outputLen, outputAvailable;
443
444
445    __Require_Quiet(NULL != coderRef, errOut);
446    __Require_Quiet(NULL != out, errOut);
447    __Require_Quiet(NULL != outLen, errOut);
448
449    if(NULL == in) {
450        if(0 == inLen) {
451            *outLen = 0;
452            return kCNSuccess;
453        }
454        return kCNParamError;
455    }
456
457//    outputAvailable = outputLen = *outLen;
458
459    if(encoderRef->direction == kCNEncode) {
460        retval = CNBufferProcessData(coderRef->base256buffer, coderRef, in, inLen, out, outLen, enCode, encodeLen);
461    } else if(encoderRef->direction == kCNDecode) {
462        retval = CNBufferProcessData(coderRef->baseXXbuffer, coderRef, in, inLen, out, outLen, deCode, decodeLen);
463    } else {
464        retval = kCNParamError;
465    }
466
467errOut:
468    return retval;
469}
470
471CNStatus
472CNEncoderFinal(CNEncoderRef coderRef, void *out, size_t *outLen)
473{
474    CNStatus retval = kCNParamError;
475    CNEncoder *encoderRef = coderRef;
476
477    __Require_Quiet(NULL != coderRef, errOut);
478    __Require_Quiet(NULL != out, errOut);
479    __Require_Quiet(NULL != outLen, errOut);
480
481    if(encoderRef->direction == kCNEncode) {
482        if((encodeLen(coderRef, coderRef->baseXXbuffer->bufferPos)+1) > *outLen) {
483            // We need room for the final '\0' on the encoded string.
484            retval = kCNBufferTooSmall;
485            goto errOut;
486        }
487        retval = CNBufferFlushData(coderRef->base256buffer, coderRef, out, outLen, enCode, encodeLen);
488        if(kCNSuccess == retval) {
489            ((uint8_t *)out)[*outLen] = 0;
490        }
491    } else if(encoderRef->direction == kCNDecode) {
492        retval = CNBufferFlushData(coderRef->baseXXbuffer, coderRef, out, outLen, deCode, decodeLen);
493    } else {
494        retval = kCNParamError;
495    }
496
497
498errOut:
499    return retval;
500
501}
502
503
504CNStatus
505CNEncoderBlocksize(CNEncodings encoding, size_t *inputSize, size_t *outputSize)
506{
507    CNEncoderRef coder;
508    CNStatus status;
509
510    __Require_Quiet(NULL != inputSize, errOut);
511    __Require_Quiet(NULL != outputSize, errOut);
512
513    if((status = CNEncoderCreate(encoding, kCNEncode, &coder))) return status;
514
515    *inputSize = inputBlocksize(coder);
516    *outputSize = outputBlocksize(coder);
517    CNEncoderRelease(&coder);
518
519    return kCNSuccess;
520errOut:
521    return kCNParamError;
522}
523
524CNStatus
525CNEncoderBlocksizeFromRef(CNEncoderRef encoderRef, size_t *inputSize, size_t *outputSize)
526{
527    __Require_Quiet(NULL != encoderRef, errOut);
528    __Require_Quiet(NULL != inputSize, errOut);
529    __Require_Quiet(NULL != outputSize, errOut);
530
531    *inputSize = inputBlocksize(encoderRef);
532    *outputSize = outputBlocksize(encoderRef);
533    return kCNSuccess;
534errOut:
535    return kCNParamError;
536}
537
538CNStatus CNEncode(CNEncodings encoding,
539                  CNEncodingDirection direction,
540                  const void *in, const size_t inLen,
541                  void *out,  size_t *outLen)
542{
543    CNStatus retval;
544    size_t outAvailable, currentlyAvailable;
545    CNEncoderRef encoder;
546    uint8_t *outPtr = out;
547
548    retval = kCNParamError;
549    __Require_Quiet(NULL != out, outReturn);
550    __Require_Quiet(NULL != outLen, outReturn);
551    __Require_Quiet(NULL != in, outReturn);
552
553    retval = CNEncoderCreate(encoding, direction, &encoder);
554    __Require_Quiet(kCNSuccess == retval, outReturn);
555
556    currentlyAvailable = outAvailable = *outLen;
557    *outLen = 0;
558
559    retval = CNEncoderUpdate(encoder, in, inLen, outPtr, &currentlyAvailable);
560    __Require_Quiet(kCNSuccess == retval, outReturn);
561
562    *outLen = currentlyAvailable;
563    outAvailable -= currentlyAvailable;
564    outPtr += currentlyAvailable;
565    currentlyAvailable = outAvailable;
566
567    retval = CNEncoderFinal(encoder, outPtr, &currentlyAvailable);
568    __Require_Quiet(kCNSuccess == retval, outReturn);
569
570    *outLen += currentlyAvailable;
571
572    retval = CNEncoderRelease(&encoder);
573
574outReturn:
575    return retval;
576
577}
578
579