/**
* 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>
* Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
*/
#include "xmlsec_globals.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <libxml2_tree.h>
#include <libxml2_globals.h>
#include "xmlsec_xmlsec.h"
#include "xmlsec_xmltree.h"
#include "xmlsec_base64.h"
#include "xmlsec_buffer.h"
#include "xmlsec_errors.h"
#include "xmlsec_error_flag.h"
//added for symbian port
#include "xmlsec_io.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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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);
if ( errno == ENOMEM )
{
xmlSecSetErrorFlag( -4 ); //KErrNoMemory
}
return(-1);
}
while(1) {
len = fread(buffer, 1, sizeof(buffer), f);
if(len == 0 && !errno) {
break;
}else if( errno ) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"fread",
XMLSEC_ERRORS_R_IO_FAILED,
"filename=%s;errno=%d",
xmlSecErrorsSafeString(filename),
errno);
if ( errno == ENOMEM )
{
xmlSecSetErrorFlag( -4 ); //KErrNoMemory
}
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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.
*/
EXPORT_C
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);
}