/** 
 * XML Security Library (http://www.aleksey.com/xmlsec).
 *
 * Big Numbers.
 *
 * This is free software; see Copyright file in the source
 * distribution for preciese wording.
 * 
 * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
 * Copyright (C) 2003 Cordys R&D BV, All rights reserved.
 * 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 <libxml2_tree.h>
#include <libxml2_globals.h>

#include "xmlsec_xmlsec.h"
#include "xmlsec_xmltree.h"
#include "xmlsec_base64.h"
#include "xmlsec_bn.h"
#include "xmlsec_errors.h"

/* table for converting hex digits back to bytes */
static const int xmlSecBnLookupTable[] =
{
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
    -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};

static const char xmlSecBnRevLookupTable[] = 
{ 
    '0', '1', '2', '3', '4', '5', '6', '7', 
    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 
};

/*****************************************************************************
 *
 * xmlSecBn
 *
 ****************************************************************************/
/**
 * xmlSecBnCreate:
 * @size:	the initial allocated BN size.
 *
 * Creates a new BN object. Caller is responsible for destroying it
 * by calling @xmlSecBnDestroy function.
 *
 * Returns the newly BN or a NULL if an error occurs.
 */
EXPORT_C
xmlSecBnPtr 
xmlSecBnCreate(xmlSecSize size) {
    return(xmlSecBufferCreate(size));
}

/**
 * xmlSecBnDestroy:
 * @bn:		the pointer to BN.
 *
 * Destroys @bn object created with @xmlSecBnCreate function.
 */
EXPORT_C
void 
xmlSecBnDestroy(xmlSecBnPtr bn) {
    xmlSecBufferDestroy(bn);
}

/**
 * xmlSecBnInitialize:
 * @bn:		the pointer to BN.
 * @size:	the initial allocated BN size.
 *
 * Initializes a BN object. Caller is responsible for destroying it
 * by calling @xmlSecBnFinalize function.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecBnInitialize(xmlSecBnPtr bn, xmlSecSize size) {
    return(xmlSecBufferInitialize(bn, size));
}

/**
 * xmlSecBnFinalize:
 * @bn:		the pointer to BN.
 *
 * Destroys @bn object created with @xmlSecBnInitialize function.
 */
EXPORT_C
void 
xmlSecBnFinalize(xmlSecBnPtr bn) {
    xmlSecBufferFinalize(bn);
}

/**
 * xmlSecBnGetData:
 * @bn:		the pointer to BN.
 *
 * Gets pointer to the binary @bn representation.
 * 
 * Returns pointer to binary BN data or NULL if an error occurs.
 */
EXPORT_C
xmlSecByte* 
xmlSecBnGetData(xmlSecBnPtr bn) {
    return(xmlSecBufferGetData(bn));
}

/**
 * xmlSecBnSetData:
 * @bn:		the pointer to BN.
 * @data:	the pointer to new BN binary data.
 * @size:	the size of new BN data.
 *
 * Sets the value of @bn to @data.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecBnSetData(xmlSecBnPtr bn, const xmlSecByte* data, xmlSecSize size) {
    return(xmlSecBufferSetData(bn, data, size));
}

/**
 * xmlSecBnGetSize:
 * @bn:		the pointer to BN.
 *
 * Gets the size of binary data in @bn.
 *
 * Returns the size of binary data.
 */
EXPORT_C
xmlSecSize 
xmlSecBnGetSize(xmlSecBnPtr bn) {
    return(xmlSecBufferGetSize(bn));
}

/**
 * xmlSecBnZero:
 * @bn:		the pointer to BN.
 *
 * Sets the value of @bn to zero.
 */
EXPORT_C
void 
xmlSecBnZero(xmlSecBnPtr bn) {
    xmlSecBufferEmpty(bn);
}

/**
 * xmlSecBnFromString:
 * @bn:		the pointer to BN.
 * @str:	the string with BN.
 * @base:	the base for @str.
 *
 * Reads @bn from string @str assuming it has base @base.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecBnFromString(xmlSecBnPtr bn, const xmlChar* str, xmlSecSize base) {
    xmlSecSize i, len, size;
    xmlSecByte ch;
    xmlSecByte* data;
    int positive;
    int nn;
    int ret;

    xmlSecAssert2(bn != NULL, -1);
    xmlSecAssert2(str != NULL, -1);
    xmlSecAssert2(base > 1, -1);
    xmlSecAssert2(base <= sizeof(xmlSecBnRevLookupTable), -1);

    /* trivial case */
    len = xmlStrlen(str);
    if(len == 0) {
        return(0);
    }
    
    /* The result size could not exceed the input string length
     * because each char fits inside a byte in all cases :)
     * In truth, it would be likely less than 1/2 input string length
     * because each byte is represented by 2 chars. If needed, 
     * buffer size would be increased by Mul/Add functions.
     * Finally, we can add one byte for 00 or 10 prefix.
     */
    ret = xmlSecBufferSetMaxSize(bn, xmlSecBufferGetSize(bn) + len / 2 + 1 + 1);
    if(ret < 0) {
        xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecBnRevLookupTable",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        "size=%d", len / 2 + 1);
        return (-1);
    }

    /* figure out if it is positive or negative number */
    positive = 1;
    i = 0;
    while(i < len) {
        ch = str[i++];

        /* skip spaces */
        if(isspace(ch)) {
	        continue;
        } 
        
        /* check if it is + or - */
        if(ch == '+') {
            positive = 1;
            break;
        } else if(ch == '-') {
            positive = 0;
            break;
        }

        /* otherwise, it must be start of the number */
        nn = xmlSecBnLookupTable[ch];
        if((nn >= 0) && ((xmlSecSize)nn < base)) {
            xmlSecAssert2(i > 0, -1);

            /* no sign, positive by default */
            positive = 1;
            --i; /* make sure that we will look at this character in next loop */
            break;
        } else {
	        xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        NULL,
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        "char=%c;base=%d", 
		        ch, base);
    	        return (-1);
        }
    }

    /* now parse the number itself */
    while(i < len) {
        ch = str[i++];
        if(isspace(ch)) {
	        continue;
        }

        xmlSecAssert2(ch <= sizeof(xmlSecBnLookupTable), -1);
        nn = xmlSecBnLookupTable[ch];
        if((nn < 0) || ((xmlSecSize)nn > base)) {
	        xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        NULL,
		        XMLSEC_ERRORS_R_INVALID_DATA,
		        "char=%c;base=%d", 
		        ch, base);
    	        return (-1);
        }

        ret = xmlSecBnMul(bn, base);
        if(ret < 0) {
	        xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecBnMul",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        "base=%d", base);
	        return (-1);
        }

        ret = xmlSecBnAdd(bn, nn);
        if(ret < 0) {
	        xmlSecError(XMLSEC_ERRORS_HERE,
		        NULL,
		        "xmlSecBnAdd",
		        XMLSEC_ERRORS_R_XMLSEC_FAILED,
		        "base=%d", base);
	        return (-1);
}	
    }

    /* check if we need to add 00 prefix, do this for empty bn too */
    data = xmlSecBufferGetData(bn);
    size = xmlSecBufferGetSize(bn);
    if(((size > 0) && (data[0] > 127)) || (size == 0))  {
        ch = 0;
        ret = xmlSecBufferPrepend(bn, &ch, 1);
        if(ret < 0) {
            xmlSecError(XMLSEC_ERRORS_HERE,
                NULL,
                "xmlSecBufferPrepend",
                XMLSEC_ERRORS_R_XMLSEC_FAILED,
                "base=%d", base);
            return (-1);
        }
    }

    /* do 2's compliment and add 1 to represent negative value */
    if(positive == 0) {
        data = xmlSecBufferGetData(bn);
        size = xmlSecBufferGetSize(bn);
        for(i = 0; i < size; ++i) {
            data[i] ^= 0xFF;
        }
        
        ret = xmlSecBnAdd(bn, 1);
        if(ret < 0) {
            xmlSecError(XMLSEC_ERRORS_HERE,
                NULL,
                "xmlSecBnAdd",
                XMLSEC_ERRORS_R_XMLSEC_FAILED,
                "base=%d", base);
            return (-1);
        }
    }

    return(0);
}

/**
 * xmlSecBnToString:
 * @bn:		the pointer to BN.
 * @base:	the base for returned string.
 *
 * Writes @bn to string with base @base. Caller is responsible for 
 * freeing returned string with @xmlFree.
 *
 * Returns the string represenataion if BN or a NULL if an error occurs.
 */
EXPORT_C
xmlChar* 
xmlSecBnToString(xmlSecBnPtr bn, xmlSecSize base) {
    xmlSecBn bn2;
    int positive = 1;
    xmlChar* res;
    xmlSecSize i, len, size;
    xmlSecByte* data;
    int ret;
    int nn;
    xmlChar ch;

    xmlSecAssert2(bn != NULL, NULL);
    xmlSecAssert2(base > 1, NULL);
    xmlSecAssert2(base <= sizeof(xmlSecBnRevLookupTable), NULL);


    /* copy bn */
    data = xmlSecBufferGetData(bn);
    size = xmlSecBufferGetSize(bn);
    ret = xmlSecBnInitialize(&bn2, size);
    if(ret < 0) {
        xmlSecError(XMLSEC_ERRORS_HERE,
            NULL,
            "xmlSecBnCreate",
            XMLSEC_ERRORS_R_XMLSEC_FAILED,
            "size=%d", size);
        return (NULL);
    }
    
    ret = xmlSecBnSetData(&bn2, data, size);
    if(ret < 0) {
        xmlSecError(XMLSEC_ERRORS_HERE,
            NULL,
            "xmlSecBnSetData",
            XMLSEC_ERRORS_R_XMLSEC_FAILED,
            "size=%d", size);
        xmlSecBnFinalize(&bn2);
        return (NULL);
    }

    /* check if it is a negative number or not */
    data = xmlSecBufferGetData(&bn2);
    size = xmlSecBufferGetSize(&bn2);
    if((size > 0) && (data[0] > 127)) {
        /* subtract 1 and do 2's compliment */
        ret = xmlSecBnAdd(&bn2, -1);
        if(ret < 0) {
            xmlSecError(XMLSEC_ERRORS_HERE,
                        NULL,
                        "xmlSecBnAdd",
                        XMLSEC_ERRORS_R_XMLSEC_FAILED,
                        "size=%d", size);
            xmlSecBnFinalize(&bn2);
            return (NULL);
        }
        for(i = 0; i < size; ++i) {
            data[i] ^= 0xFF;
        }

        positive = 0;
    } else {
        positive = 1;
    }

    /* Result string len is
     *	    len = log base (256) * <bn size>
     * Since the smallest base == 2 then we can get away with 
     *	    len = 8 * <bn size>
     */
    len = 8 * size + 1 + 1;
    res = (xmlChar*)xmlMalloc(len + 1);
    if(res == NULL) {
        xmlSecError(XMLSEC_ERRORS_HERE,
		            NULL,
		            NULL,
		            XMLSEC_ERRORS_R_MALLOC_FAILED,
		            "len=%d", len);
        xmlSecBnFinalize(&bn2);
        return (NULL);
    }
    memset(res, 0, len + 1);

    for(i = 0; (xmlSecBufferGetSize(&bn2) > 0) && (i < len); i++) {
        if(xmlSecBnDiv(&bn2, base, &nn) < 0) {
            xmlSecError(XMLSEC_ERRORS_HERE,
                        NULL,
                        "xmlSecBnDiv",
                        XMLSEC_ERRORS_R_XMLSEC_FAILED,
                        "base=%d", base);
            xmlFree(res);
            xmlSecBnFinalize(&bn2);
            return (NULL);
        }
        xmlSecAssert2((size_t)nn < sizeof(xmlSecBnRevLookupTable), NULL);
        res[i] = xmlSecBnRevLookupTable[nn];
    }
    xmlSecAssert2(i < len, NULL);

    /* we might have '0' at the beggining, remove it but keep one zero */
    for(len = i; (len > 1) && (res[len - 1] == '0'); len--)
        {
        };
    res[len] = '\0';

    /* add "-" for negative numbers */
    if(positive == 0) {
        res[len] = '-';
        res[++len] = '\0';
    }

    /* swap the string because we wrote it in reverse order */
    for(i = 0; i < len / 2; i++) {
        ch = res[i];
        res[i] = res[len - i - 1];
        res[len - i - 1] = ch;
    }

    xmlSecBnFinalize(&bn2);
    return(res);
}

/**
 * xmlSecBnFromHexString:
 * @bn:		the pointer to BN.
 * @str:	the string with BN.
 *
 * Reads @bn from hex string @str.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecBnFromHexString(xmlSecBnPtr bn, const xmlChar* str) {
    return(xmlSecBnFromString(bn, str, 16));
}

/**
 * xmlSecBnToHexString:
 * @bn:		the pointer to BN.
 *
 * Writes @bn to hex string. Caller is responsible for 
 * freeing returned string with @xmlFree.
 *
 * Returns the string represenataion if BN or a NULL if an error occurs.
 */
EXPORT_C
xmlChar* 
xmlSecBnToHexString(xmlSecBnPtr bn) {
    return(xmlSecBnToString(bn, 16));
}

/**
 * xmlSecBnFromDecString:
 * @bn:		the pointer to BN.
 * @str:	the string with BN.
 *
 * Reads @bn from decimal string @str.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecBnFromDecString(xmlSecBnPtr bn, const xmlChar* str) {
    return(xmlSecBnFromString(bn, str, 10));
}

/**
 * xmlSecBnToDecString:
 * @bn:		the pointer to BN.
 *
 * Writes @bn to decimal string. Caller is responsible for 
 * freeing returned string with @xmlFree.
 *
 * Returns the string represenataion if BN or a NULL if an error occurs.
 */
EXPORT_C
xmlChar* 
xmlSecBnToDecString(xmlSecBnPtr bn) {
    return(xmlSecBnToString(bn, 10));
}

/**
 * xmlSecBnMul:
 * @bn:			the pointer to BN.
 * @multiplier:		the multiplier.
 *
 * Multiplies @bn with @multiplier.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecBnMul(xmlSecBnPtr bn, int multiplier) {
    xmlSecByte* data;
    int over;
    xmlSecSize i;
    xmlSecByte ch;
    int ret;

    xmlSecAssert2(bn != NULL, -1);
    xmlSecAssert2(multiplier > 0, -1);

    if(multiplier == 1) {
	return(0);
    }

    data = xmlSecBufferGetData(bn);
    i = xmlSecBufferGetSize(bn);
    over = 0; 
    while(i > 0) {
	xmlSecAssert2(data != NULL, -1);

	over	= over + multiplier * data[--i];
	data[i]	= over % 256;
	over	= over / 256;
    }
    
    while(over > 0) {
	ch	= over % 256;
	over	= over / 256;
	
	ret = xmlSecBufferPrepend(bn, &ch, 1);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecBufferPrepend",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"size=1");
	    return (-1);
	}
    }
    
    return(0);
}

/**
 * xmlSecBnDiv:
 * @bn:		the pointer to BN.
 * @divider:	the divider
 * @mod:	the pointer for modulus result.
 *
 * Divides @bn by @divider and places modulus into @mod.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecBnDiv(xmlSecBnPtr bn, int divider, int* mod) {
    int over;
    xmlSecSize i, size;
    xmlSecByte* data;
    int ret;

    xmlSecAssert2(bn != NULL, -1);
    xmlSecAssert2(divider > 0, -1);
    xmlSecAssert2(mod != NULL, -1);

    if(divider == 1) {
	return(0);
    }

    data = xmlSecBufferGetData(bn);
    size = xmlSecBufferGetSize(bn);
    for(over = 0, i = 0; i < size; i++) {
	xmlSecAssert2(data != NULL, -1);

	over	= over * 256 + data[i];
	data[i]	= over / divider;
	over	= over % divider;
    }
    (*mod) = over;
    
    /* remove leading zeros */
    for(i = 0; i < size; i++) {
	xmlSecAssert2(data != NULL, -1);

	if(data[i] != 0) {
	    break;
	}
    }
    if(i > 0) {
	ret = xmlSecBufferRemoveHead(bn, i);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecBufferRemoveHead",
			XMLSEC_ERRORS_R_XMLSEC_FAILED,
			"size=%d", i);
	    return (-1);
	}
    }
    return(0);
}

/**
 * xmlSecBnAdd:
 * @bn:		the pointer to BN.
 * @delta:	the delta.
 *
 * Adds @delta to @bn.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecBnAdd(xmlSecBnPtr bn, int delta) {
    int over, tmp;
    xmlSecByte* data;
    xmlSecSize i;
    xmlSecByte ch;
    int ret;

    xmlSecAssert2(bn != NULL, -1);

    if(delta == 0) {
    	return(0);
    }

    data = xmlSecBufferGetData(bn);
    if(delta > 0) {
        for(over = delta, i = xmlSecBufferGetSize(bn); (i > 0) && (over > 0) ;) {
	        xmlSecAssert2(data != NULL, -1);
	
            tmp     = data[--i];
        	over   += tmp;
	        data[i]	= over % 256;
	        over	= over / 256;
        }
    
        while(over > 0) {
	        ch	= over % 256;
	        over	= over / 256;
	
        	ret = xmlSecBufferPrepend(bn, &ch, 1);
	        if(ret < 0) {
	            xmlSecError(XMLSEC_ERRORS_HERE,
			        NULL,
			        "xmlSecBufferPrepend",
			        XMLSEC_ERRORS_R_XMLSEC_FAILED,
			        "size=1");
	            return (-1);
	        }
        }
    } else {
        for(over = -delta, i = xmlSecBufferGetSize(bn); (i > 0) && (over > 0);) {
	        xmlSecAssert2(data != NULL, -1);
	
            tmp     = data[--i];
            if(tmp < over) {
                data[i]	= 0;
                over = (over - tmp) / 256;
            } else {
                data[i] = tmp - over;
                over = 0;
            }
        }
    }
    return(0);
}

/**
 * xmlSecBnReverse:
 * @bn:		the pointer to BN.
 *
 * Reverses bytes order in @bn.
 *
 * Returns 0 on success or a negative value if an error occurs.
 */
EXPORT_C
int 
xmlSecBnReverse(xmlSecBnPtr bn) {
    xmlSecByte* data;
    xmlSecSize i, j, size;
    xmlSecByte ch;

    xmlSecAssert2(bn != NULL, -1);

    data = xmlSecBufferGetData(bn);
    size = xmlSecBufferGetSize(bn);
    for(i = 0, j = size - 1; i < size / 2; ++i, --j) {
	xmlSecAssert2(data != NULL, -1);

	ch	 = data[i];
	data[i]	 = data[j];
	data[j]  = ch;
    }    

    return(0);
}

/**
 * xmlSecBnCompare:
 * @bn:		the pointer to BN.
 * @data:	the data to compare BN to.
 * @dataSize:	the @data size.
 *
 * Compares the @bn with @data.
 *
 * Returns 0 if data is equal, negative value if @bn is less or positive value if @bn
 * is greater than @data.
 */
EXPORT_C
int 
xmlSecBnCompare(xmlSecBnPtr bn, const xmlSecByte* data, xmlSecSize dataSize) {
    xmlSecByte* bnData;
    xmlSecSize bnSize;

    xmlSecAssert2(bn != NULL, -1);

    bnData = xmlSecBnGetData(bn);
    bnSize = xmlSecBnGetSize(bn);

    /* skip zeros in the beggining */
    while((dataSize > 0) && (data != 0) && (data[0] == 0)) {
	++data;
	--dataSize;
    }
    while((bnSize > 0) && (bnData != 0) && (bnData[0] == 0)) {
	++bnData;
	--bnSize;
    }

    if(((bnData == NULL) || (bnSize == 0)) && ((data == NULL) || (dataSize == 0))) {
	return(0);
    } else if((bnData == NULL) || (bnSize == 0)) {
	return(-1);
    } else if((data == NULL) || (dataSize == 0)) {
	return(1);
    } else if(bnSize < dataSize) {
	return(-1);
    } else if(bnSize > dataSize) {
	return(-1);
    } 

    xmlSecAssert2(bnData != NULL, -1);
    xmlSecAssert2(data != NULL, -1);
    xmlSecAssert2(bnSize == dataSize, -1);

    return(memcmp(bnData, data, dataSize));
}

/**
 * xmlSecBnCompareReverse:
 * @bn:		the pointer to BN.
 * @data:	the data to compare BN to.
 * @dataSize:	the @data size.
 *
 * Compares the @bn with reverse @data.
 *
 * Returns 0 if data is equal, negative value if @bn is less or positive value if @bn
 * is greater than @data.
 */
EXPORT_C
int 
xmlSecBnCompareReverse(xmlSecBnPtr bn, const xmlSecByte* data, xmlSecSize dataSize) {
    xmlSecByte* bnData;
    xmlSecSize bnSize;
    xmlSecSize i, j;

    xmlSecAssert2(bn != NULL, -1);

    bnData = xmlSecBnGetData(bn);
    bnSize = xmlSecBnGetSize(bn);

    /* skip zeros in the beggining */
    while((dataSize > 0) && (data != 0) && (data[dataSize - 1] == 0)) {
	--dataSize;
    }
    while((bnSize > 0) && (bnData != 0) && (bnData[0] == 0)) {
	++bnData;
	--bnSize;
    }

    if(((bnData == NULL) || (bnSize == 0)) && ((data == NULL) || (dataSize == 0))) {
	return(0);
    } else if((bnData == NULL) || (bnSize == 0)) {
	return(-1);
    } else if((data == NULL) || (dataSize == 0)) {
	return(1);
    } else if(bnSize < dataSize) {
	return(-1);
    } else if(bnSize > dataSize) {
	return(-1);
    } 

    xmlSecAssert2(bnData != NULL, -1);
    xmlSecAssert2(data != NULL, -1);
    xmlSecAssert2(bnSize == dataSize, -1);
    for(i = 0, j = dataSize - 1; i < dataSize; ++i, --j) {
	if(bnData[i] < data[j]) {
	    return(-1);
	} else if(data[j] < bnData[i]) {
	    return(1);
	}
    }

    return(0);
}

/**
 * xmlSecBnGetNodeValue:
 * @bn:		the pointer to BN.
 * @cur:	the poitner to an XML node.
 * @format:	the BN format.
 * @reverse:	if set then reverse read buffer after reading.
 *
 * Converts the node content from @format to @bn.
 *
 * Returns 0 on success and a negative values if an error occurs.
 */
EXPORT_C
int 
xmlSecBnGetNodeValue(xmlSecBnPtr bn, xmlNodePtr cur, xmlSecBnFormat format, int reverse) {
    xmlChar* content;
    int ret;

    xmlSecAssert2(bn != NULL, -1);
    xmlSecAssert2(cur != NULL, -1);

    switch(format) {
    case xmlSecBnBase64:
	ret = xmlSecBufferBase64NodeContentRead(bn, cur);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecBufferBase64NodeContentRead",
	    		XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
	break;
    case xmlSecBnHex:
	content = xmlNodeGetContent(cur);
	if(content == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlNodeGetContent",
	    		XMLSEC_ERRORS_R_XML_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
	ret = xmlSecBnFromHexString(bn, content);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecBnFromHexString",
	    		XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    xmlFree(content);
	    return(-1);
	}
	xmlFree(content);
	break;
    case xmlSecBnDec:
	content = xmlNodeGetContent(cur);
	if(content == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlNodeGetContent",
	    		XMLSEC_ERRORS_R_XML_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
	ret = xmlSecBnFromDecString(bn, content);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecBnFromDecString",
	    		XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    xmlFree(content);
	    return(-1);
	}
	xmlFree(content);
	break;
    }

    if(reverse != 0) {
    	ret = xmlSecBnReverse(bn);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecBnReverse",
	    		XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
    }
    return(0);
}

/**
 * xmlSecBnSetNodeValue:
 * @bn:			the pointer to BN.
 * @cur:		the poitner to an XML node.
 * @format:		the BN format.
 * @reverse:		the flag that indicates whether to reverse the buffer before writing.
 * @addLineBreaks:  	the flag; it is equal to 1 then linebreaks will be added before and after new buffer content.
 *
 * Converts the @bn and sets it to node content.
 *
 * Returns 0 on success and a negative values if an error occurs.
 */
EXPORT_C
int  
xmlSecBnSetNodeValue(xmlSecBnPtr bn, xmlNodePtr cur, xmlSecBnFormat format, int reverse, int addLineBreaks) {
    xmlChar* content;
    int ret;

    xmlSecAssert2(bn != NULL, -1);
    xmlSecAssert2(cur != NULL, -1);

    if(reverse != 0) {
    	ret = xmlSecBnReverse(bn);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecBnReverse",
	    		XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
    }

    if(addLineBreaks) {
	xmlNodeAddContent(cur, xmlSecStringCR);
    }

    switch(format) {
    case xmlSecBnBase64:
	ret = xmlSecBufferBase64NodeContentWrite(bn, cur, XMLSEC_BASE64_LINESIZE);
	if(ret < 0) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecBufferBase64NodeContentWrite",
	    		XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    return(-1);
	}
	break;
    case xmlSecBnHex:
	content = xmlSecBnToHexString(bn);
	if(content == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecBnToHexString",
	    		XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    xmlFree(content);
	    return(-1);
	}
	xmlNodeSetContent(cur, content);
	xmlFree(content);
	break;
    case xmlSecBnDec:
	content = xmlSecBnToDecString(bn);
	if(content == NULL) {
	    xmlSecError(XMLSEC_ERRORS_HERE,
			NULL,
			"xmlSecBnToDecString",
	    		XMLSEC_ERRORS_R_XMLSEC_FAILED,
			XMLSEC_ERRORS_NO_MESSAGE);
	    xmlFree(content);
	    return(-1);
	}
	xmlNodeSetContent(cur, content);
	xmlFree(content);
	break;
    }

    if(addLineBreaks) {
	xmlNodeAddContent(cur, xmlSecStringCR);
    }

    return(0);
}

/**
 * xmlSecBnBlobSetNodeValue:
 * @data:	the pointer to BN blob.
 * @dataSize:	the size of BN blob.
 * @cur:	the poitner to an XML node.
 * @format:	the BN format.
 * @reverse:	the flag that indicates whether to reverse the buffer before writing.
 * @addLineBreaks:  if the flag is equal to 1 then 
 *		linebreaks will be added before and after
 *		new buffer content.
 *
 * Converts the @blob and sets it to node content.
 *
 * Returns 0 on success and a negative values if an error occurs.
 */
EXPORT_C
int  
xmlSecBnBlobSetNodeValue(const xmlSecByte* data, xmlSecSize dataSize, 
			 xmlNodePtr cur, xmlSecBnFormat format, int reverse,
			 int addLineBreaks) {
    xmlSecBn bn;
    int ret;

    xmlSecAssert2(data != NULL, -1);
    xmlSecAssert2(cur != NULL, -1);

    ret = xmlSecBnInitialize(&bn, dataSize);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecBnInitialize",
	    	    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	return(-1);
    }

    ret = xmlSecBnSetData(&bn, data, dataSize);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecBnSetData",
	    	    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecBnFinalize(&bn);
	return(-1);
    }

    ret = xmlSecBnSetNodeValue(&bn, cur, format, reverse, addLineBreaks);
    if(ret < 0) {
	xmlSecError(XMLSEC_ERRORS_HERE,
		    NULL,
		    "xmlSecBnSetNodeValue",
	    	    XMLSEC_ERRORS_R_XMLSEC_FAILED,
		    XMLSEC_ERRORS_NO_MESSAGE);
	xmlSecBnFinalize(&bn);
	return(-1);
    }

    xmlSecBnFinalize(&bn);
    return(0);
}


