diff options
Diffstat (limited to 'src/buffer.c')
-rw-r--r-- | src/buffer.c | 674 |
1 files changed, 674 insertions, 0 deletions
diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 00000000..0efbfed2 --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,674 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Memory buffer. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/base64.h> +#include <xmlsec/buffer.h> +#include <xmlsec/errors.h> + +/***************************************************************************** + * + * xmlSecBuffer + * + ****************************************************************************/ +static xmlSecAllocMode gAllocMode = xmlSecAllocModeDouble; +static xmlSecSize gInitialSize = 1024; + +/** + * xmlSecBufferSetDefaultAllocMode: + * @defAllocMode: the new default buffer allocation mode. + * @defInitialSize: the new default buffer minimal intial size. + * + * Sets new global default allocation mode and minimal intial size. + */ +void +xmlSecBufferSetDefaultAllocMode(xmlSecAllocMode defAllocMode, xmlSecSize defInitialSize) { + xmlSecAssert(defInitialSize > 0); + + gAllocMode = defAllocMode; + gInitialSize = defInitialSize; +} + +/** + * xmlSecBufferCreate: + * @size: the intial size. + * + * Allocates and initalizes new memory buffer with given size. + * Caller is responsible for calling #xmlSecBufferDestroy function + * to free the buffer. + * + * Returns: pointer to newly allocated buffer or NULL if an error occurs. + */ +xmlSecBufferPtr +xmlSecBufferCreate(xmlSecSize size) { + xmlSecBufferPtr buf; + int ret; + + buf = (xmlSecBufferPtr)xmlMalloc(sizeof(xmlSecBuffer)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecBuffer)=%d", sizeof(xmlSecBuffer)); + return(NULL); + } + + ret = xmlSecBufferInitialize(buf, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + xmlSecBufferDestroy(buf); + return(NULL); + } + return(buf); +} + +/** + * xmlSecBufferDestroy: + * @buf: the pointer to buffer object. + * + * Desrtoys buffer object created with #xmlSecBufferCreate function. + */ +void +xmlSecBufferDestroy(xmlSecBufferPtr buf) { + xmlSecAssert(buf != NULL); + + xmlSecBufferFinalize(buf); + xmlFree(buf); +} + +/** + * xmlSecBufferInitialize: + * @buf: the pointer to buffer object. + * @size: the initial buffer size. + * + * Initializes buffer object @buf. Caller is responsible for calling + * #xmlSecBufferFinalize function to free allocated resources. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferInitialize(xmlSecBufferPtr buf, xmlSecSize size) { + xmlSecAssert2(buf != NULL, -1); + + buf->data = NULL; + buf->size = buf->maxSize = 0; + buf->allocMode = gAllocMode; + + return(xmlSecBufferSetMaxSize(buf, size)); +} + +/** + * xmlSecBufferFinalize: + * @buf: the pointer to buffer object. + * + * Frees allocated resource for a buffer intialized with #xmlSecBufferInitialize + * function. + */ +void +xmlSecBufferFinalize(xmlSecBufferPtr buf) { + xmlSecAssert(buf != NULL); + + xmlSecBufferEmpty(buf); + if(buf->data != 0) { + xmlFree(buf->data); + } + buf->data = NULL; + buf->size = buf->maxSize = 0; +} + +/** + * xmlSecBufferEmpty: + * @buf: the pointer to buffer object. + * + * Empties the buffer. + */ +void +xmlSecBufferEmpty(xmlSecBufferPtr buf) { + xmlSecAssert(buf != NULL); + + if(buf->data != 0) { + xmlSecAssert(buf->maxSize > 0); + + memset(buf->data, 0, buf->maxSize); + } + buf->size = 0; +} + +/** + * xmlSecBufferGetData: + * @buf: the pointer to buffer object. + * + * Gets pointer to buffer's data. + * + * Returns: pointer to buffer's data. + */ +xmlSecByte* +xmlSecBufferGetData(xmlSecBufferPtr buf) { + xmlSecAssert2(buf != NULL, NULL); + + return(buf->data); +} + +/** + * xmlSecBufferSetData: + * @buf: the pointer to buffer object. + * @data: the data. + * @size: the data size. + * + * Sets the value of the buffer to @data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferSetData(xmlSecBufferPtr buf, const xmlSecByte* data, xmlSecSize size) { + int ret; + + xmlSecAssert2(buf != NULL, -1); + + xmlSecBufferEmpty(buf); + if(size > 0) { + xmlSecAssert2(data != NULL, -1); + + ret = xmlSecBufferSetMaxSize(buf, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + return(-1); + } + + memcpy(buf->data, data, size); + } + + buf->size = size; + return(0); +} + +/** + * xmlSecBufferGetSize: + * @buf: the pointer to buffer object. + * + * Gets the current buffer data size. + * + * Returns: the current data size. + */ +xmlSecSize +xmlSecBufferGetSize(xmlSecBufferPtr buf) { + xmlSecAssert2(buf != NULL, 0); + + return(buf->size); +} + +/** + * xmlSecBufferSetSize: + * @buf: the pointer to buffer object. + * @size: the new data size. + * + * Sets new buffer data size. If necessary, buffer grows to + * have at least @size bytes. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferSetSize(xmlSecBufferPtr buf, xmlSecSize size) { + int ret; + + xmlSecAssert2(buf != NULL, -1); + + ret = xmlSecBufferSetMaxSize(buf, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + return(-1); + } + + + buf->size = size; + return(0); +} + +/** + * xmlSecBufferGetMaxSize: + * @buf: the pointer to buffer object. + * + * Gets the maximum (allocated) buffer size. + * + * Returns: the maximum (allocated) buffer size. + */ +xmlSecSize +xmlSecBufferGetMaxSize(xmlSecBufferPtr buf) { + xmlSecAssert2(buf != NULL, 0); + + return(buf->maxSize); +} + +/** + * xmlSecBufferSetMaxSize: + * @buf: the pointer to buffer object. + * @size: the new maximum size. + * + * Sets new buffer maximum size. If necessary, buffer grows to + * have at least @size bytes. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferSetMaxSize(xmlSecBufferPtr buf, xmlSecSize size) { + xmlSecByte* newData; + xmlSecSize newSize = 0; + + xmlSecAssert2(buf != NULL, -1); + if(size <= buf->maxSize) { + return(0); + } + + switch(buf->allocMode) { + case xmlSecAllocModeExact: + newSize = size + 8; + break; + case xmlSecAllocModeDouble: + newSize = 2 * size + 32; + break; + } + + if(newSize < gInitialSize) { + newSize = gInitialSize; + } + + + if(buf->data != NULL) { + newData = (xmlSecByte*)xmlRealloc(buf->data, newSize); + } else { + newData = (xmlSecByte*)xmlMalloc(newSize); + } + if(newData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", newSize); + return(-1); + } + + buf->data = newData; + buf->maxSize = newSize; + + if(buf->size < buf->maxSize) { + xmlSecAssert2(buf->data != NULL, -1); + memset(buf->data + buf->size, 0, buf->maxSize - buf->size); + } + + return(0); +} + +/** + * xmlSecBufferAppend: + * @buf: the pointer to buffer object. + * @data: the data. + * @size: the data size. + * + * Appends the @data after the current data stored in the buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferAppend(xmlSecBufferPtr buf, const xmlSecByte* data, xmlSecSize size) { + int ret; + + xmlSecAssert2(buf != NULL, -1); + + if(size > 0) { + xmlSecAssert2(data != NULL, -1); + + ret = xmlSecBufferSetMaxSize(buf, buf->size + size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", buf->size + size); + return(-1); + } + + memcpy(buf->data + buf->size, data, size); + buf->size += size; + } + + return(0); +} + +/** + * xmlSecBufferPrepend: + * @buf: the pointer to buffer object. + * @data: the data. + * @size: the data size. + * + * Prepends the @data before the current data stored in the buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferPrepend(xmlSecBufferPtr buf, const xmlSecByte* data, xmlSecSize size) { + int ret; + + xmlSecAssert2(buf != NULL, -1); + + if(size > 0) { + xmlSecAssert2(data != NULL, -1); + + ret = xmlSecBufferSetMaxSize(buf, buf->size + size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", buf->size + size); + return(-1); + } + + memmove(buf->data + size, buf->data, buf->size); + memcpy(buf->data, data, size); + buf->size += size; + } + + return(0); +} + +/** + * xmlSecBufferRemoveHead: + * @buf: the pointer to buffer object. + * @size: the number of bytes to be removed. + * + * Removes @size bytes from the beginning of the current buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferRemoveHead(xmlSecBufferPtr buf, xmlSecSize size) { + xmlSecAssert2(buf != NULL, -1); + + if(size < buf->size) { + xmlSecAssert2(buf->data != NULL, -1); + + buf->size -= size; + memmove(buf->data, buf->data + size, buf->size); + } else { + buf->size = 0; + } + if(buf->size < buf->maxSize) { + xmlSecAssert2(buf->data != NULL, -1); + memset(buf->data + buf->size, 0, buf->maxSize - buf->size); + } + return(0); +} + +/** + * xmlSecBufferRemoveTail: + * @buf: the pointer to buffer object. + * @size: the number of bytes to be removed. + * + * Removes @size bytes from the end of current buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferRemoveTail(xmlSecBufferPtr buf, xmlSecSize size) { + xmlSecAssert2(buf != NULL, -1); + + if(size < buf->size) { + buf->size -= size; + } else { + buf->size = 0; + } + if(buf->size < buf->maxSize) { + xmlSecAssert2(buf->data != NULL, -1); + memset(buf->data + buf->size, 0, buf->maxSize - buf->size); + } + return(0); +} + +/** + * xmlSecBufferReadFile: + * @buf: the pointer to buffer object. + * @filename: the filename. + * + * Reads the content of the file @filename in the buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferReadFile(xmlSecBufferPtr buf, const char* filename) { + xmlSecByte buffer[1024]; + FILE* f; + int ret, len; + + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + + f = fopen(filename, "rb"); + if(f == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "fopen", + XMLSEC_ERRORS_R_IO_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + return(-1); + } + + while(1) { + len = fread(buffer, 1, sizeof(buffer), f); + if(len == 0) { + break; + }else if(len < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "fread", + XMLSEC_ERRORS_R_IO_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + fclose(f); + return(-1); + } + + ret = xmlSecBufferAppend(buf, buffer, len); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", + len); + fclose(f); + return(-1); + } + } + + fclose(f); + return(0); +} + +/** + * xmlSecBufferBase64NodeContentRead: + * @buf: the pointer to buffer object. + * @node: the pointer to node. + * + * Reads the content of the @node, base64 decodes it and stores the + * result in the buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferBase64NodeContentRead(xmlSecBufferPtr buf, xmlNodePtr node) { + xmlChar* content; + xmlSecSize size; + int ret; + + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + content = xmlNodeGetContent(node); + if(content == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* base64 decode size is less than input size */ + ret = xmlSecBufferSetMaxSize(buf, xmlStrlen(content)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + + ret = xmlSecBase64Decode(content, xmlSecBufferGetData(buf), xmlSecBufferGetMaxSize(buf)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Decode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + size = ret; + + ret = xmlSecBufferSetSize(buf, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + xmlFree(content); + return(-1); + } + xmlFree(content); + + return(0); +} + +/** + * xmlSecBufferBase64NodeContentWrite: + * @buf: the pointer to buffer object. + * @node: the pointer to a node. + * @columns: the max line size fro base64 encoded data. + * + * Sets the content of the @node to the base64 encoded buffer data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferBase64NodeContentWrite(xmlSecBufferPtr buf, xmlNodePtr node, int columns) { + xmlChar* content; + + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + content = xmlSecBase64Encode(xmlSecBufferGetData(buf), xmlSecBufferGetSize(buf), columns); + if(content == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlNodeAddContent(node, content); + xmlFree(content); + + return(0); +} + +/************************************************************************ + * + * IO buffer + * + ************************************************************************/ +static int xmlSecBufferIOWrite (xmlSecBufferPtr buf, + const xmlSecByte *data, + xmlSecSize size); +static int xmlSecBufferIOClose (xmlSecBufferPtr buf); + +/** + * xmlSecBufferCreateOutputBuffer: + * @buf: the pointer to buffer. + * + * Creates new LibXML output buffer to store data in the @buf. Caller is + * responsible for destroying @buf when processing is done. + * + * Returns: pointer to newly allocated output buffer or NULL if an error + * occurs. + */ +xmlOutputBufferPtr +xmlSecBufferCreateOutputBuffer(xmlSecBufferPtr buf) { + return(xmlOutputBufferCreateIO((xmlOutputWriteCallback)xmlSecBufferIOWrite, + (xmlOutputCloseCallback)xmlSecBufferIOClose, + buf, + NULL)); +} + +static int +xmlSecBufferIOWrite(xmlSecBufferPtr buf, const xmlSecByte *data, xmlSecSize size) { + int ret; + + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(data != NULL, -1); + + ret = xmlSecBufferAppend(buf, data, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + return(-1); + } + + return(size); +} + +static int +xmlSecBufferIOClose(xmlSecBufferPtr buf) { + xmlSecAssert2(buf != NULL, -1); + + /* just do nothing */ + return(0); +} |