#include <stdio.h>
#include "ccMemory.h"
#include "CommonBufferingPriv.h"
#include <AssertMacros.h>
CNBufferRef
CNBufferCreate(size_t chunksize)
{
CNBufferRef retval = CC_XMALLOC(sizeof(CNBuffer));
__Require_Quiet(NULL != retval, errOut);
retval->chunksize = chunksize;
retval->bufferPos = 0;
retval->buf = CC_XMALLOC(chunksize);
__Require_Quiet(NULL != retval->buf, errOut);
return retval;
errOut:
if(retval) {
if(retval->buf) CC_XFREE(retval->buf, chunksize);
CC_XFREE(retval, sizeof(CNBuffer));
}
return NULL;
}
CNStatus
CNBufferRelease(CNBufferRef *bufRef)
{
CNBufferRef ref;
__Require_Quiet(NULL != bufRef, out);
ref = *bufRef;
if(ref->buf) CC_XFREE(ref->buf, chunksize);
if(ref) CC_XFREE(ref, sizeof(CNBuffer));
out:
return kCNSuccess;
}
CNStatus
CNBufferProcessData(CNBufferRef bufRef,
void *ctx, const void *in, const size_t inLen, void *out, size_t *outLen,
cnProcessFunction pFunc, cnSizeFunction sizeFunc)
{
size_t blocksize = bufRef->chunksize;
uint8_t *input = (uint8_t *) in, *output = out;
size_t inputLen = inLen, outputLen, inputUsing, outputAvailable;
outputAvailable = outputLen = *outLen;
if(sizeFunc(ctx, bufRef->bufferPos + inLen) > outputAvailable) return kCNBufferTooSmall;
*outLen = 0;
if(bufRef->bufferPos > 0) {
inputUsing = CC_XMIN(blocksize - bufRef->bufferPos, inputLen);
CC_XMEMCPY(&bufRef->buf[bufRef->bufferPos], in, inputUsing);
bufRef->bufferPos += inputUsing;
if(bufRef->bufferPos < blocksize) {
return kCNSuccess;
}
pFunc(ctx, bufRef->buf, blocksize, output, &outputLen);
inputLen -= inputUsing; input += inputUsing;
output += outputLen; *outLen = outputLen; outputAvailable -= outputLen;
bufRef->bufferPos = 0;
}
inputUsing = inputLen - inputLen % blocksize;
if(inputUsing > 0) {
outputLen = outputAvailable;
pFunc(ctx, input, inputUsing, output, &outputLen);
inputLen -= inputUsing; input += inputUsing;
*outLen += outputLen;
}
if(inputLen > blocksize) {
return kCNAlignmentError;
} else if(inputLen > 0) {
CC_XMEMCPY(bufRef->buf, input, inputLen);
bufRef->bufferPos = inputLen;
}
return kCNSuccess;
}
CNStatus
CNBufferFlushData(CNBufferRef bufRef,
void *ctx, void *out, size_t *outLen,
cnProcessFunction pFunc, cnSizeFunction sizeFunc)
{
if(bufRef->bufferPos > 0) {
if(bufRef->bufferPos > bufRef->chunksize) return kCNAlignmentError;
if(sizeFunc(ctx, bufRef->bufferPos) > *outLen) return kCNBufferTooSmall;
pFunc(ctx, bufRef->buf, bufRef->bufferPos, out, outLen);
} else {
*outLen = 0;
}
return kCNSuccess;
}
bool
CNBufferEmpty(CNBufferRef bufRef)
{
return bufRef->bufferPos == 0;
}