1//
2//  CommonBuffering.c
3//  CommonCrypto
4//
5
6#include <stdio.h>
7#include "ccMemory.h"
8#include "CommonBufferingPriv.h"
9#include <AssertMacros.h>
10
11
12CNBufferRef
13CNBufferCreate(size_t chunksize)
14{
15    CNBufferRef retval = CC_XMALLOC(sizeof(CNBuffer));
16    __Require_Quiet(NULL != retval, errOut);
17    retval->chunksize = chunksize;
18    retval->bufferPos = 0;
19    retval->buf = CC_XMALLOC(chunksize);
20    __Require_Quiet(NULL != retval->buf, errOut);
21    return retval;
22
23errOut:
24    if(retval) {
25        if(retval->buf) CC_XFREE(retval->buf, chunksize);
26        CC_XFREE(retval, sizeof(CNBuffer));
27    }
28    return NULL;
29}
30
31CNStatus
32CNBufferRelease(CNBufferRef *bufRef)
33{
34    CNBufferRef ref;
35
36    __Require_Quiet(NULL != bufRef, out);
37    ref = *bufRef;
38    if(ref->buf) CC_XFREE(ref->buf, chunksize);
39    if(ref) CC_XFREE(ref, sizeof(CNBuffer));
40out:
41    return kCNSuccess;
42}
43
44
45
46CNStatus
47CNBufferProcessData(CNBufferRef bufRef,
48                    void *ctx, const void *in, const size_t inLen, void *out, size_t *outLen,
49                    cnProcessFunction pFunc, cnSizeFunction sizeFunc)
50{
51    size_t  blocksize = bufRef->chunksize;
52    uint8_t *input = (uint8_t *) in, *output = out;
53    size_t inputLen = inLen, outputLen, inputUsing, outputAvailable;
54
55    outputAvailable = outputLen = *outLen;
56
57    if(sizeFunc(ctx, bufRef->bufferPos + inLen) > outputAvailable) return  kCNBufferTooSmall;
58    *outLen = 0;
59    if(bufRef->bufferPos > 0) {
60        inputUsing = CC_XMIN(blocksize - bufRef->bufferPos, inputLen);
61        CC_XMEMCPY(&bufRef->buf[bufRef->bufferPos], in, inputUsing);
62        bufRef->bufferPos += inputUsing;
63        if(bufRef->bufferPos < blocksize) {
64            return kCNSuccess;
65        }
66        pFunc(ctx, bufRef->buf, blocksize, output, &outputLen);
67        inputLen -= inputUsing; input += inputUsing;
68        output += outputLen; *outLen = outputLen; outputAvailable -= outputLen;
69        bufRef->bufferPos = 0;
70    }
71
72    inputUsing = inputLen - inputLen % blocksize;
73    if(inputUsing > 0) {
74        outputLen = outputAvailable;
75        pFunc(ctx, input, inputUsing, output, &outputLen);
76        inputLen -= inputUsing; input += inputUsing;
77        *outLen += outputLen;
78    }
79
80    if(inputLen > blocksize) {
81        return kCNAlignmentError;
82    } else if(inputLen > 0) {
83        CC_XMEMCPY(bufRef->buf, input, inputLen);
84        bufRef->bufferPos = inputLen;
85    }
86    return kCNSuccess;
87
88}
89
90CNStatus
91CNBufferFlushData(CNBufferRef bufRef,
92                  void *ctx, void *out, size_t *outLen,
93                  cnProcessFunction pFunc, cnSizeFunction sizeFunc)
94{
95//    size_t outputLen, outputAvailable;
96//    outputAvailable = outputLen = *outLen;
97
98    if(bufRef->bufferPos > 0) {
99        if(bufRef->bufferPos > bufRef->chunksize) return kCNAlignmentError;
100        if(sizeFunc(ctx, bufRef->bufferPos) > *outLen) return kCNBufferTooSmall;
101        pFunc(ctx, bufRef->buf, bufRef->bufferPos, out, outLen);
102    } else {
103        *outLen = 0;
104    }
105    return kCNSuccess;
106}
107
108
109
110bool
111CNBufferEmpty(CNBufferRef bufRef)
112{
113    return bufRef->bufferPos == 0;
114}
115