/*
** HDL4SE: 软件Verilog综合仿真平台
** Copyright (C) 2021-2021, raoxianhong<raoxianhong@163.net>
** LCOM: 轻量级组件对象模型
** Copyright (C) 2021-2021, raoxianhong<raoxianhong@163.net>
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice,
**   this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice,
**   this list of conditions and the following disclaimer in the documentation
**   and/or other materials provided with the distribution.
** * The name of the author may be used to endorse or promote products
**   derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
** THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
* bignumber.c
    202105201110: rxh, initial version
	202105260952:修改了接口，为verilog语言编译做准备，主要是区分了带符号和不带符号计算
*/

#include "stdlib.h" 
#include "stdio.h"
#include "object.h"
#include "string.h"
#define IMPLEMENT_GUID
#include "bignumber.h"
#undef IMPLEMENT_GUID

#define NOTIMPL printf("bignumber.c %d, %s is not implemented now\n", __LINE__, __FUNCTION__)

#define CELL_WIDTH 32
#define CELL_MASK 0xffffffff

typedef struct _sBigInteger {
	OBJECT_HEADER
	INTERFACE_DECLARE(IBigNumber)
	BIGNUMBER_VARDECLARE

	int buflen;
	int width;
	unsigned int* buf;

}sBigInteger;
 
OBJECT_FUNCDECLARE(bigint, CLSID_BIGINTEGER);
BIGNUMBER_FUNCDECLARE(bigint, CLSID_BIGINTEGER, sBigInteger);

OBJECT_FUNCIMPL(bigint, sBigInteger, CLSID_BIGINTEGER);

QUERYINTERFACE_BEGIN(bigint, CLSID_BIGINTEGER)
QUERYINTERFACE_ITEM(IID_BIGNUMBER, IBigNumber, sBigInteger)
QUERYINTERFACE_END

static const char* bigintModuleInfo()
{
	return "1.0.0-20210520.1355 Big integer library";
}

static int bigintCreate(const PARAMITEM* pParams, int paramcount, HOBJECT* pObject)
{
	sBigInteger* pobj;
	int i;
	pobj = (sBigInteger*)malloc(sizeof(sBigInteger));
	if (pobj == NULL)
		return -1;
	*pObject = 0;
	BIGNUMBER_VARINIT(pobj, CLSID_BIGINTEGER);
	INTERFACE_INIT(IBigNumber, pobj, bigint, bn);

	pobj->width = 64;
	for (i = 0; i < paramcount; i++) {
		if (pParams[i].name == PARAMID_BIGINTEGERWIDTH)
			pobj->width = pParams[i].i32value;
	}

	if (pobj->width <= 0)
		return -1;

	pobj->buflen = (pobj->width + CELL_WIDTH - 1) / CELL_WIDTH;
	if (pobj->buflen < 2)
		pobj->buflen = 2;
	pobj->buf = malloc(pobj->buflen * sizeof(unsigned int));
	if (pobj->buf == NULL)
		return -1;

	for (i = 0;i<pobj->buflen;i++)
		pobj->buf[i] = 0;

	/* 返回生成的对象 */
	OBJECT_RETURN_GEN(bigint, pobj, pObject, CLSID_BIGINTEGER);
	return EIID_OK;
}

static int actualwidth(unsigned int n)
{
	unsigned int c = 1;
	int ret = 1;
	if (n & 0x80000000)
		return CELL_WIDTH;
	while (c <= n) {
		c <<= 1;
		ret++;
	}
	return ret-1;
}

static void bigintDestroy(HOBJECT object)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	free(pobj->buf);
	free(pobj);
}

static int bigintValid(HOBJECT object)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	if (pobj == NULL)
		return 0;
	if (pobj->buflen < 2)
		return 0;
	if (pobj->buflen * CELL_WIDTH < pobj->width)
		return 0;
	if (pobj->buf == NULL)
		return 0;
	return 1;
}

static int bigint_bn_GetWidth(HOBJECT object)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	return pobj->width;
}

static int bigint_bn_SetWidth(HOBJECT object, int width, int signexpand)
{
	int i, bc, blen, sign;
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	if (width <= 0) {
		return -1;
	}
	sign = 0;
	if (signexpand) {
		bc = pobj->width / CELL_WIDTH;
		sign = pobj->buf[bc] & (1 << ((pobj->width-1) & (CELL_WIDTH-1)));
	}

	blen = (width + CELL_WIDTH - 1) / CELL_WIDTH;
	if (blen < 2)
		blen = 2;
	if (pobj->buflen < blen) {
		unsigned int * buf;
		buf = (unsigned int *)malloc(blen * (CELL_WIDTH / 8));
		if (buf == NULL)
			return -1;
		for (i = 0; i < pobj->buflen; i++)
			buf[i] = pobj->buf[i];
		pobj->buflen = blen;
		free(pobj->buf);
		pobj->buf = buf;
	}
	
	blen = width / CELL_WIDTH;
	if (blen < pobj->buflen) {
		bc = width & (CELL_WIDTH - 1);
		if (sign)
			pobj->buf[blen] |= CELL_MASK << bc;
		else
			pobj->buf[blen] &= CELL_MASK >> (CELL_WIDTH - bc);
	}
	for (i = blen+1; i < pobj->buflen; i++) {
		pobj->buf[i] = sign ? CELL_MASK : 0;
	}
	pobj->width = width;
	return 0;
}

static int bigint_bn_GetBits32(HOBJECT object, int ind32, unsigned int* pbits)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object); 
	if (ind32 < 0 || ind32 >= pobj->buflen) {
		*pbits = 0;
		return -1;
	}
	*pbits = pobj->buf[ind32];
	return 0;
}

static int bigint_bn_SetBits32(HOBJECT object, int ind32, unsigned int bits)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	if (ind32 < 0 || ind32 >= pobj->buflen)
		return -1;
	pobj->buf[ind32] = bits;
	return 0;
}

static int bigint_bn_GetBit(HOBJECT object, int indbit)
{
	sBigInteger* pobj;
	int ind32;
	pobj = (sBigInteger*)objectThis(object);
	if (indbit < 0 || indbit >= pobj->width)
		return -1;
	ind32 = indbit / 32;
	return pobj->buf[ind32] & (1 << (indbit & 31));
}

static int bigint_bn_SetBit(HOBJECT object, int indbit, int bit)
{
	sBigInteger* pobj;
	int ind32;
	pobj = (sBigInteger*)objectThis(object);
	if (indbit < 0 || indbit >= pobj->width)
		return -1;
	ind32 = indbit / 32;
	if (bit != 0)
		pobj->buf[ind32] |= (1 << (indbit & 31));
	else
		pobj->buf[ind32] &= ~(1 << (indbit & 31));
	return 0;
}


static int bigint_bn_GetInt32(HOBJECT object, int* pvalue)
{ 
	sBigInteger* pobj;
	int width;
	pobj = (sBigInteger*)objectThis(object);
	width = pobj->width;
	if (width < 32)
		bigint_bn_SetWidth(object, 32, 1);
	*(unsigned int*)pvalue = pobj->buf[0];
	if (width < 32)
		bigint_bn_SetWidth(object, width, 0);
	return 0; 
}

static int bigint_bn_GetInt64(HOBJECT object, long long* pvalue)
{
	sBigInteger* pobj;
	int width;
	pobj = (sBigInteger*)objectThis(object);
	width = pobj->width;
	if (width < 64)
		bigint_bn_SetWidth(object, 64, 1);
	((unsigned int *)pvalue)[0] = pobj->buf[0];
	((unsigned int *)pvalue)[1] = pobj->buf[1];
	if (width < 64)
		bigint_bn_SetWidth(object, width, 0);
	return 0;
}

static int bigint_bn_GetUint32(HOBJECT object, unsigned int* pvalue)
{
	sBigInteger* pobj;
	int width;
	pobj = (sBigInteger*)objectThis(object);
	width = pobj->width;
	if (width < 32)
		bigint_bn_SetWidth(object, 32, 0);
	*(unsigned int*)pvalue = pobj->buf[0];
	if (width < 32)
		bigint_bn_SetWidth(object, width, 0);
	return 0;
}

static int bigint_bn_GetUint64(HOBJECT object, unsigned long long* pvalue)
{
	sBigInteger* pobj;
	int width;
	pobj = (sBigInteger*)objectThis(object);
	width = pobj->width;
	if (width < 64)
		bigint_bn_SetWidth(object, 64, 0);
	((unsigned int*)pvalue)[0] = pobj->buf[0];
	((unsigned int*)pvalue)[1] = pobj->buf[1];
	if (width < 64)
		bigint_bn_SetWidth(object, width, 0);

	return 0;
}

static int bigint_bn_GetStr(HOBJECT object, int base, char* str, int buflen)
{ 
	int i;
	int bc, ac;
	char fmt[10];
	char buf[10];
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	str[0] = 0;
	bc = bigint_bn_GetWidth(object);
	if (bc == 0) {
		strcpy(str, "0");
		return 0;
	}
	sprintf(str, "%d'h", bc);
	i = ((bc + (CELL_WIDTH-1)) / CELL_WIDTH) - 1;
	ac = actualwidth(pobj->buf[i]);
	ac = (ac + 7) / 8;
	sprintf(fmt, "%%%dx_", ac);
	sprintf(buf, fmt, pobj->buf[i]);
	strcat(str, buf);
	for (i = ((bc + (CELL_WIDTH-1)) / CELL_WIDTH)-2; i >= 0; i--) {
		sprintf(buf, "%08x", pobj->buf[i]);
		strcat(str, buf);
		if (i > 0)
			strcat(str, "_");
	}
	return 0; 
}

static int bigint_bn_AssignInt32(HOBJECT object, int value)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	pobj->buf[0] = *(unsigned int*)&value;
	bigint_bn_SetWidth(object, pobj->width, 1);
	return 0;
}

static int bigint_bn_AssignInt64(HOBJECT object, long long value)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	pobj->buf[0] = (*(unsigned long long*)(&value)) & CELL_MASK;
	pobj->buf[1] = ((*(unsigned long long*)(&value)) >> CELL_WIDTH) & CELL_MASK;
	bigint_bn_SetWidth(object, pobj->width, 1);
	return 0;
}

static int bigint_bn_AssignUint32(HOBJECT object, unsigned int value)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	pobj->buf[0] = *(unsigned int*)&value;
	bigint_bn_SetWidth(object, pobj->width, 0);
	return 0;
}

static int bigint_bn_AssignUint64(HOBJECT object, unsigned long long value)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	pobj->buf[0] = (*(unsigned long long*)(&value)) & CELL_MASK;
	pobj->buf[1] = ((*(unsigned long long*)(&value)) >> CELL_WIDTH) & CELL_MASK;
	bigint_bn_SetWidth(object, pobj->width, 0);
	return 0;
}

enum TOKEN_STATE {
	TOKEN_INITIAL,
	TOKEN_NUM,
	TOKEN_BASE,
	TOKEN_BIN,
	TOKEN_OCT,
	TOKEN_DEC,
	TOKEN_HEX
};

#define MAXNUMWIDTH (1 << 30)

static int bigint_bn_AssignStr(HOBJECT object, const char* str, const char **nstr, int autowidth)
{ 
	int width, objwidth, sign;
	enum TOKEN_STATE state;
	const char* strt = str;
	int numvalid = 0;
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	width = -1;
	objwidth = pobj->width;
	if (autowidth == 0 && objwidth <= 0)
		return -1;
	if (autowidth)
		bigint_bn_SetWidth(object, 64, 0);
	state = TOKEN_INITIAL;
	sign = 0;
	while (*strt != 0) {
		int ch = *strt;
		switch (state) {
		case TOKEN_INITIAL: {
			if (ch == '\'') {
				state = TOKEN_BASE;
			}
			else if (ch >= '0' && ch <= '9') {
				bigint_bn_AssignInt32(object, ch - '0');
				numvalid = 1;
				state = TOKEN_NUM;
			}
		} break;
		case TOKEN_NUM: {
			if (ch >= '0' && ch <= '9') {
				if (pobj->buf[pobj->buflen - 1] > (1 << 27)) {
					int w;
					w = pobj->width * 2;
					if (w > MAXNUMWIDTH) {
						w = MAXNUMWIDTH;
					}
					if (0 != bigint_bn_SetWidth(object, w, 0)) {
						return -1;
					}
				}
				bigint_bn_MulInt32(object, object, 10);
				bigint_bn_AddInt32(object, object, ch - '0');
			}
			else if (ch == '\'') {
				int i;
				for (i = pobj->buflen - 1; i > 0; i--) {
					if (pobj->buf[i] != 0) {
						/* too large width of a number */
						width = MAXNUMWIDTH;
						break;
					}
				}
				if (width == -1) {
					if (pobj->buf[0] > MAXNUMWIDTH) {
						width = MAXNUMWIDTH;
					}
					else {
						width = pobj->buf[0];
					}
				}
				state = TOKEN_BASE;
				if (width == 0)
					width = -1;
				else
				if (0 != bigint_bn_SetWidth(object, width, 0)) {
					return -1;
				}
				numvalid = 0;
			}
			else {
				goto lastnum;
			}
		}break;
		case TOKEN_BASE: {
			if (ch == 's' || ch == 'S') {
				sign = 1;
			}
			else if (ch == 'b' || ch == 'B') {
				bigint_bn_AssignInt32(object, 0);
				state = TOKEN_BIN;
			}
			else if (ch == 'h' || ch == 'H') {
				bigint_bn_AssignInt32(object, 0);
				state = TOKEN_HEX;
			}
			else if (ch == 'o' || ch == 'O') {
				bigint_bn_AssignInt32(object, 0);
				state = TOKEN_OCT;
			}
			else if (ch == 'd' || ch == 'D') {
				bigint_bn_AssignInt32(object, 0);
				state = TOKEN_DEC;
			}
			else if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {

			}
			else {
				return -1;
			}
		}break;
		case TOKEN_BIN: {
			if (ch == '0' || ch == '1') {
				if (autowidth && (width == -1)) {
					if (pobj->buf[pobj->buflen - 1] > (1 << 27)) {
						int w;
						w = pobj->width * 2;
						if (w > MAXNUMWIDTH) {
							w = MAXNUMWIDTH;
						}
						if (0 != bigint_bn_SetWidth(object, w, 0))
							return -1;
					}
				}
				bigint_bn_MulInt32(object, object, 2);
				bigint_bn_AddInt32(object, object, ch - '0');
				numvalid = 1;
			}
			else if (ch == '_') {
			}
			else {
				goto lastnum;
			}
		}break;
		case TOKEN_OCT: {
			if (ch >= '0' && ch <= '7') {
				if (autowidth && (width == -1)) {
					if (pobj->buf[pobj->buflen - 1] > (1 << 27)) {
						int w;
						w = pobj->width * 2;
						if (w > MAXNUMWIDTH) {
							w = MAXNUMWIDTH;
						}
						if (0 != bigint_bn_SetWidth(object, w, 0))
							return -1;
					}
				}
				bigint_bn_MulInt32(object, object, 8);
				bigint_bn_AddInt32(object, object, ch - '0');
				numvalid = 1;
			}
			else if (ch == '_') {
			}
			else {
				goto lastnum;
			}
		}break;
		case TOKEN_DEC: {
			if (ch >= '0' && ch <= '9') {
				if (autowidth && (width == -1)) {
					if (pobj->buf[pobj->buflen - 1] > (1 << 27)) {
						int w;
						w = pobj->width * 2;
						if (w > MAXNUMWIDTH) {
							w = MAXNUMWIDTH;
						}
						if (0 != bigint_bn_SetWidth(object, w, 0))
							return -1;
					}
				}
				bigint_bn_MulInt32(object, object, 10);
				bigint_bn_AddInt32(object, object, ch - '0');
				numvalid = 1;
			}
			else {
				goto lastnum;
			}
		}break;
		case TOKEN_HEX: {
			if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
				numvalid = 1;
				if (autowidth && (width == -1)) {
					if (pobj->buf[pobj->buflen - 1] > (1 << 27)) {
						int w;
						w = pobj->width * 2;
						if (w > MAXNUMWIDTH) {
							w = MAXNUMWIDTH;
						}
						if (0 != bigint_bn_SetWidth(object, w, 0))
							return -1;
					}
				}
				bigint_bn_MulInt32(object, object, 16);
				if (ch > '0' && ch <= '9')
					bigint_bn_AddInt32(object, object, ch - '0');
				else if (ch >= 'a' && ch <= 'f')
					bigint_bn_AddInt32(object, object, ch - 'a' + 10);
				else if (ch >= 'A' && ch <= 'F')
					bigint_bn_AddInt32(object, object, ch - 'A' + 10);
			}
			else if (ch == '_') {
			}
			else {
				goto lastnum;
			}

		}break;
		}
		strt++;
	}
	if (numvalid == 0)
		return -1;
lastnum:
	if (nstr != NULL)
		*nstr = strt;
	if (autowidth && (width == -1)) {
		int i;
		width = 0;
		for (i = pobj->buflen - 1; i >= 0; i--) {
			if (pobj->buf[i] != 0) {
				width = actualwidth(pobj->buf[i]);
				width += i * CELL_WIDTH;
				break;
			}
		}
		if (width == 0)
			width = 1;
		if (sign == 0)
			width++;
	}
	else {
		width = objwidth;
	}
	bigint_bn_SetWidth(object, width, sign);
	return 0;
}

static int bigint_bn_Clone(HOBJECT object, HOBJECT src)
{ 
	sBigInteger* pobj;
	IBigNumber** numsrc;
	int i;
	int width;
	int buflen;
	pobj = (sBigInteger*)objectThis(object);
	if (EIID_OK != objectQueryInterface(src, IID_BIGNUMBER, (void**)&numsrc))
		return -1;
	width = objectCall0(numsrc, GetWidth);
	if (width <= 0) {
		objectRelease(numsrc);
		return -1;
	}
	buflen = (width + CELL_WIDTH - 1) / CELL_WIDTH;
	if (buflen < 2)
		buflen = 2;
	if (pobj->buflen < buflen) {
		unsigned int* buf;
		buf = (unsigned int*)malloc(buflen * (CELL_WIDTH / 8));
		if (buf == NULL) {
			objectRelease(numsrc);
			return -2;
		}
		free(pobj->buf);
		pobj->buf = buf;
	}
	pobj->buflen = buflen;
	pobj->width = width;
	for (i = 0; i < pobj->buflen; i++) {
		objectCall2(numsrc, GetBits32, i, &pobj->buf[i]);
	}
	objectRelease(numsrc);
	return 0;
}

static int bigint_bn_CloneSubBits(HOBJECT object, HOBJECT src, int from, int width, int signexpand)
{
	if (from < 0 || width <= 0)
		return -1;
	bigint_bn_SetWidth(object, width, 0);
	if (signexpand)
		bigint_bn_SAR(object, src, from);
	else
		bigint_bn_SHR(object, src, from);
	bigint_bn_SetWidth(object, width, signexpand);
	return 0;
}

static int bigint_bn_Assign(HOBJECT object, HOBJECT src)
{
	int width;
	width = bigint_bn_GetWidth(object);
	bigint_bn_Clone(object, src);
	bigint_bn_SetWidth(object, width, 1);
	return 0;
}

static int bigint_bn_AssignSubBits(HOBJECT object, HOBJECT src, int from, int width)
{
	int objwidth;
	objwidth = bigint_bn_GetWidth(object);
	bigint_bn_CloneSubBits(object, src, from, width, 1);
	bigint_bn_SetWidth(object, objwidth, 1);
	return 0;
}

static int bigint_bn_AssignU(HOBJECT object, HOBJECT src)
{
	int width;
	width = bigint_bn_GetWidth(object);
	bigint_bn_Clone(object, src);
	bigint_bn_SetWidth(object, width, 0);
	return 0;
}

static int bigint_bn_AssignSubBitsU(HOBJECT object, HOBJECT src, int from, int width)
{
	int objwidth;
	objwidth = bigint_bn_GetWidth(object);
	bigint_bn_CloneSubBits(object, src, from, width, 0);
	bigint_bn_SetWidth(object, objwidth, 0);
	return 0;
}

static int bigint_bn_AddInt32(HOBJECT object, HOBJECT src, int value)
{ 
	unsigned long long temp;
	int ind;
	unsigned int v, vs, widthsrc;
	sBigInteger* pobj;
	IBigNumber** numsrc;
	pobj = (sBigInteger*)objectThis(object);
	if (EIID_OK != objectQueryInterface(src, IID_BIGNUMBER, (void**)&numsrc))
		return -1;
	widthsrc = objectCall0(numsrc, GetWidth);
	objectCall2(numsrc, SetWidth, widthsrc, 1);
	bigint_bn_SetWidth(object, pobj->width, 1);
	objectCall2(numsrc, GetBits32, 0, &vs);
	temp = vs;
	temp += *(unsigned int*)&value;
	pobj->buf[0] = temp & CELL_MASK;
	temp >>= CELL_WIDTH;
	ind = 1;
	v = 0;
	if (value < 0)
		v = CELL_MASK;
	while (ind < pobj->buflen) {
		temp += v;
		if (0 != objectCall2(numsrc, GetBits32, ind, &vs))
			vs = CELL_MASK;
		temp += vs;
		pobj->buf[ind] = temp & CELL_MASK;
		temp >>= CELL_WIDTH;
		ind++;
	}
	return 0;
}

static int bigint_bn_SubInt32(HOBJECT object, HOBJECT src, int value)
{
	return bigint_bn_AddInt32(object, src, -value);
}

static int bigint_bn_MulInt32(HOBJECT object, HOBJECT src, int value)
{
	IBigNumber ** temp;
	temp = bigintegerCreate(32);
	bigint_bn_AssignInt32(temp, value);
	bigint_bn_Mul(object, src, temp);
	objectRelease(temp);
	return 0;
}

static int bigint_bn_DivInt32(HOBJECT object, HOBJECT src, int value)
{
	IBigNumber** temp;
	temp = bigintegerCreate(32);
	bigint_bn_AssignInt32(temp, value);
	bigint_bn_Div(object, src, temp);
	objectRelease(temp);
	return 0;
}

static int bigint_bn_ModInt32(HOBJECT object, HOBJECT src, int value)
{
	IBigNumber** temp;
	temp = bigintegerCreate(32);
	bigint_bn_AssignInt32(temp, value);
	bigint_bn_Mod(object, src, temp);
	objectRelease(temp);
	return 0;
}

static int bigint_bn_AddUint32(HOBJECT object, HOBJECT src, unsigned int value)
{
	unsigned long long temp;
	int ind;
	unsigned int vs, widthsrc;
	sBigInteger* pobj;
	IBigNumber** numsrc;
	pobj = (sBigInteger*)objectThis(object);
	if (EIID_OK != objectQueryInterface(src, IID_BIGNUMBER, (void**)&numsrc))
		return -1;
	widthsrc = objectCall0(numsrc, GetWidth);
	objectCall2(numsrc, SetWidth, widthsrc, 0);
	bigint_bn_SetWidth(object, pobj->width, 0);
	objectCall2(numsrc, GetBits32, 0, &vs);
	temp = vs;
	temp += *(unsigned int*)&value;
	pobj->buf[0] = temp & CELL_MASK;
	temp >>= CELL_WIDTH;
	ind = 1;
	while (ind < pobj->buflen) {
		if (0 != objectCall2(numsrc, GetBits32, ind, &vs))
			vs = 0;
		temp += vs;
		pobj->buf[ind] = temp & CELL_MASK;
		temp >>= CELL_WIDTH;
		ind++;
	}
	return 0;
}

static int bigint_bn_SubUint32(HOBJECT object, HOBJECT src, unsigned int value)
{
	bigint_bn_AssignUint32(object, value);
	bigint_bn_Neg(object, object);
	bigint_bn_AddU(object, object, src);
	return 0;
}

static int bigint_bn_MulUint32(HOBJECT object, HOBJECT src, unsigned int value)
{
	IBigNumber** temp;
	temp = bigintegerCreate(32);
	bigint_bn_AssignUint32(temp, value);
	bigint_bn_MulU(object, src, temp);
	objectRelease(temp);
	return 0;
}

static int bigint_bn_DivUint32(HOBJECT object, HOBJECT src, unsigned int value)
{
	IBigNumber** temp;
	temp = bigintegerCreate(32);
	bigint_bn_AssignUint32(temp, value);
	bigint_bn_DivU(object, src, temp);
	objectRelease(temp);
	return 0;
}

static int bigint_bn_ModUint32(HOBJECT object, HOBJECT src, unsigned int value)
{
	IBigNumber** temp;
	temp = bigintegerCreate(32);
	bigint_bn_AssignUint32(temp, value);
	bigint_bn_ModU(object, src, temp);
	objectRelease(temp);
	return 0;
}

static int bigint_bn_AddFunc(HOBJECT object, HOBJECT src0, HOBJECT src1, int signexpand)
{ 
	unsigned long long temp;
	sBigInteger* pobj;
	IBigNumber** psrc0;
	IBigNumber** psrc1;
	int widthobj, widthsrc0, widthsrc1;
	int i;
	pobj = (sBigInteger*)objectThis(object);
	if (EIID_OK != objectQueryInterface(src0, IID_BIGNUMBER, (void**)&psrc0)) {
		return -1;
	}
	if (EIID_OK != objectQueryInterface(src1, IID_BIGNUMBER, (void**)&psrc1)) {
		objectRelease(psrc0);
		return -1;
	}
	widthobj = pobj->width;
	widthsrc0 = objectCall0(psrc0, GetWidth);
	widthsrc1 = objectCall0(psrc1, GetWidth);
	if (widthsrc0 < widthobj) {
		objectCall2(psrc0, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc0, SetWidth, widthsrc0, signexpand);
	}
	if (widthsrc1 < widthobj) {
		objectCall2(psrc1, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc1, SetWidth, widthsrc1, signexpand);
	}
	temp = 0;
	for (i = 0; i < pobj->buflen; i++) {
		unsigned int src0value, src1value;
		objectCall2(psrc0, GetBits32, i, &src0value);
		objectCall2(psrc1, GetBits32, i, &src1value);
		temp += src0value;
		temp += src1value;
		pobj->buf[i] = temp & CELL_MASK;
		temp >>= CELL_WIDTH;
	}
	bigint_bn_SetWidth(object, widthobj, 1);
	if (widthsrc0 < widthobj) {
		objectCall2(psrc0, SetWidth, widthsrc0, 0);
	}
	if (widthsrc1 < widthobj) {
		objectCall2(psrc1, SetWidth, widthsrc1, 0);
	}
	objectRelease(psrc0);
	objectRelease(psrc1);
	return 0;
}

static int bigint_bn_Add(HOBJECT object, HOBJECT src0, HOBJECT src1)
{
	return bigint_bn_AddFunc(object, src0, src1, 1);
}

static int bigint_bn_Sub(HOBJECT object, HOBJECT src0, HOBJECT src1)
{ 
	if (EIID_OK != bigint_bn_Neg(object, src1))
		return -1;
	return bigint_bn_Add(object, src0, object);
}

static int bigint_bn_MulFunc(HOBJECT object, HOBJECT src0, HOBJECT src1, int signexpand)
{ 
	sBigInteger* pobj;
	IBigNumber** psrc0;
	IBigNumber** psrc1;
	unsigned int* buf;
	int widthobj, widthsrc0, widthsrc1;
	int i, j;
	pobj = (sBigInteger*)objectThis(object);
	if (EIID_OK != objectQueryInterface(src0, IID_BIGNUMBER, (void**)&psrc0)) {
		return -1;
	}
	if (EIID_OK != objectQueryInterface(src1, IID_BIGNUMBER, (void**)&psrc1)) {
		objectRelease(psrc0);
		return -1;
	} 
	widthobj = pobj->width;
	widthsrc0 = objectCall0(psrc0, GetWidth);
	widthsrc1 = objectCall0(psrc1, GetWidth);
	if (widthsrc0 < widthobj) {
		objectCall2(psrc0, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc0, SetWidth, widthsrc0, signexpand);
	}
	if (widthsrc1 < widthobj) {
		objectCall2(psrc1, SetWidth, widthobj, signexpand);
	} 
	else {
		objectCall2(psrc1, SetWidth, widthsrc1, signexpand);
	}
	pobj->buflen = (pobj->width + CELL_WIDTH - 1) / CELL_WIDTH;
	if (pobj->buflen < 2)
		pobj->buflen = 2;
	buf = (unsigned int*)malloc(pobj->buflen * CELL_WIDTH / 8);
	if (buf == NULL) {
		objectRelease(psrc0);
		objectRelease(psrc1);
		return -1;
	}

	for (i = 0; i < pobj->buflen; i++)
		buf[i] = 0;
	for (i = 0; i < pobj->buflen; i++) {
		unsigned long long addin;
		unsigned long long m0, m1;
		unsigned int m0s, m1s;
		addin = 0;
		objectCall2(psrc0, GetBits32, i, &m0s);
		m0 = m0s;
		for (j = 0; j < pobj->buflen - i; j++) {
			objectCall2(psrc1, GetBits32, j, &m1s);
			m1 = m1s;
			m1 = m0 * m1 + addin + buf[i+j];
			buf[i + j] = m1 & CELL_MASK;
			addin = m1 >> CELL_WIDTH;
		}
	}
	free(pobj->buf);
	pobj->buf = buf;
	bigint_bn_SetWidth(object, widthobj, 1);
	if (widthsrc0 < widthobj) {
		objectCall2(psrc0, SetWidth, widthsrc0, 1);
	}
	if (widthsrc1 < widthobj) {
		objectCall2(psrc1, SetWidth, widthsrc1, 1);
	}
	objectRelease(psrc0);
	objectRelease(psrc1);
	return 0;
}

static int bigint_bn_Mul(HOBJECT object, HOBJECT src0, HOBJECT src1)
{
	return bigint_bn_MulFunc(object, src0, src1, 1);
}

static int bigint_bn_Div(HOBJECT object, HOBJECT src0, HOBJECT src1)
{ 
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	NOTIMPL;
	return 0;
}

static int bigint_bn_Mod(HOBJECT object, HOBJECT src0, HOBJECT src1)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	NOTIMPL;
	return 0;
}

static int bigint_bn_AddU(HOBJECT object, HOBJECT src0, HOBJECT src1)
{
	return bigint_bn_AddFunc(object, src0, src1, 0);
}

static int bigint_bn_SubU(HOBJECT object, HOBJECT src0, HOBJECT src1)
{
	if (EIID_OK != bigint_bn_Neg(object, src1))
		return -1;
	return bigint_bn_AddU(object, src0, object);
}

static int bigint_bn_MulU(HOBJECT object, HOBJECT src0, HOBJECT src1)
{
	return bigint_bn_MulFunc(object, src0, src1, 0);
}

static int bigint_bn_DivU(HOBJECT object, HOBJECT src0, HOBJECT src1)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	NOTIMPL;
	return 0;
}

static int bigint_bn_ModU(HOBJECT object, HOBJECT src0, HOBJECT src1)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	NOTIMPL;
	return 0;
}

static int bigint_bn_Neg(HOBJECT object, HOBJECT src)
{
	/* 反码加一 */
	bigint_bn_Not(object, src);
	bigint_bn_AddInt32(object, object, 1);
	return 0;
}

static int bigint_bn_Abs(HOBJECT object, HOBJECT src)
{
	return 0;
}

static int bigint_bn_IsGT(HOBJECT object, HOBJECT src)
{
	return 0;
}

static int bigint_bn_IsGE(HOBJECT object, HOBJECT src)
{
	return 0;
}

static int bigint_bn_IsLT(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	sBigInteger* psrc;
	int i;
	int bc, sign, signsrc;

	pobj = (sBigInteger*)objectThis(object);
	if (!objectIsClass(src, CLSID_BIGINTEGER)) {
		return 0;
	}
	psrc = (sBigInteger*)objectThis(src);
	bc = pobj->width / CELL_WIDTH;
	sign = pobj->buf[bc] & (1 << ((pobj->width - 1) & (CELL_WIDTH - 1)));
	bc = psrc->width / CELL_WIDTH;
	signsrc = psrc->buf[bc] & (1 << ((psrc->width - 1) & (CELL_WIDTH - 1)));
	if (sign == 0 && signsrc != 0) {
		return 0;
	}
	else if (sign != 0 && signsrc == 0) {
		return 1;
	}

	bc = pobj->buflen;
	if (bc < psrc->buflen)
		bc = psrc->buflen;
	for (i = bc - 1; i >= pobj->buflen; i--) {
		if (sign != 0) {
			if (psrc->buf[i] != 0xffffffff)
				return 0;
		}
		else {
			if (psrc->buf[0] != 0)
				return 1;
		}
	}
	for (; i >= psrc->buflen; i--) {
		if (sign != 0) {
			if (pobj->buf[i] != 0xffffffff)
				return 1;
		}
		else {
			if (pobj->buf[0] != 0)
				return 0;
		}
	}
	for (; i >= 0; i--) {
		if (sign != 0) {
			if (pobj->buf[i] > psrc->buf[i])
				return 1;
			else if (pobj->buf[i] < psrc->buf[i])
				return 0;
		}
		else {
			if (pobj->buf[i] < psrc->buf[i])
				return 1;
			if (pobj->buf[i] > psrc->buf[i])
				return 0;
		}
	}
	return 0;
}

static int bigint_bn_IsLE(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	sBigInteger* psrc;
	int i;
	int bc, sign, signsrc;

	pobj = (sBigInteger*)objectThis(object);
	if (!objectIsClass(src, CLSID_BIGINTEGER)) {
		return 0;
	}
	psrc = (sBigInteger*)objectThis(src);
	bc = pobj->width / CELL_WIDTH;
	sign = pobj->buf[bc] & (1 << ((pobj->width - 1) & (CELL_WIDTH - 1)));
	bc = psrc->width / CELL_WIDTH;
	signsrc = psrc->buf[bc] & (1 << ((psrc->width - 1) & (CELL_WIDTH - 1)));
	if (sign == 0 && signsrc != 0) {
		return 0;
	}
	else if (sign != 0 && signsrc == 0) {
		return 1;
	}

	bc = pobj->buflen;
	if (bc < psrc->buflen)
		bc = psrc->buflen;
	for (i = bc - 1; i >= pobj->buflen; i--) {
		if (sign != 0) {
			if (psrc->buf[i] != 0xffffffff)
				return 0;
		}
		else {
			if (psrc->buf[0] != 0)
				return 1;
		}
	}
	for (; i >= psrc->buflen; i--) {
		if (sign != 0) {
			if (pobj->buf[i] != 0xffffffff)
				return 1;
		}
		else {
			if (pobj->buf[0] != 0)
				return 0;
		}
	}
	for (; i >= 0; i--) {
		if (sign != 0) {
			if (pobj->buf[i] > psrc->buf[i])
				return 1;
			else if (pobj->buf[i] < psrc->buf[i])
				return 0;
		}
		else {
			if (pobj->buf[i] < psrc->buf[i])
				return 1;
			if (pobj->buf[i] > psrc->buf[i])
				return 0;
		}
	}
	return 1;
}

static int bigint_bn_IsEQ(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	sBigInteger* psrc;
	int i;
	int bc, sign, signsrc;
	pobj = (sBigInteger*)objectThis(object);
	if (!objectIsClass(src, CLSID_BIGINTEGER)) {
		return 0;
	}
	psrc = (sBigInteger*)objectThis(src);
	bc = pobj->width / CELL_WIDTH;
	sign = pobj->buf[bc] & (1 << ((pobj->width - 1) & (CELL_WIDTH - 1)));
	bc = psrc->width / CELL_WIDTH;
	signsrc = psrc->buf[bc] & (1 << ((psrc->width - 1) & (CELL_WIDTH - 1)));
	if (sign != signsrc) {
		return 0;
	}
	for (i = 0; i < pobj->buflen && i < psrc->buflen; i++) {
		if (pobj->buf[i] != psrc->buf[i])
			return 0;
	}
	for (; i < pobj->buflen; i++) {
		if (sign == 0 && pobj->buf[i] != 0)
			return 0;
		else if (sign != 0 && pobj->buf[i] != CELL_MASK)
			return 0;
	}
	for (; i < psrc->buflen; i++) {
		if (sign == 0 && psrc->buf[i] != 0)
			return 0;
		else if (sign != 0 && psrc->buf[i] != CELL_MASK)
			return 0;
	}
	return 1;
}


static int bigint_bn_IsNE(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	sBigInteger* psrc;
	int i;
	int bc, sign, signsrc;
	pobj = (sBigInteger*)objectThis(object);
	if (!objectIsClass(src, CLSID_BIGINTEGER)) {
		return 0;
	}
	psrc = (sBigInteger*)objectThis(src);
	bc = pobj->width / CELL_WIDTH;
	sign = pobj->buf[bc] & (1 << ((pobj->width - 1) & (CELL_WIDTH - 1)));
	bc = psrc->width / CELL_WIDTH;
	signsrc = psrc->buf[bc] & (1 << ((psrc->width - 1) & (CELL_WIDTH - 1)));
	if (sign != signsrc) {
		return 0;
	}
	for (i = 0; i < pobj->buflen && i < psrc->buflen; i++) {
		if (pobj->buf[i] != psrc->buf[i])
			return 0;
	}
	for (; i < pobj->buflen; i++) {
		if (sign == 0 && pobj->buf[i] != 0)
			return 0;
		else if (sign != 0 && pobj->buf[i] != CELL_MASK)
			return 0;
	}
	for (; i < psrc->buflen; i++) {
		if (sign == 0 && psrc->buf[i] != 0)
			return 0;
		else if (sign != 0 && psrc->buf[i] != CELL_MASK)
			return 0;
	}
	return 1;
}


static int bigint_bn_IsGTU(HOBJECT object, HOBJECT src)
{
	return 0;
}

static int bigint_bn_IsGEU(HOBJECT object, HOBJECT src)
{
	return 0;
}

static int bigint_bn_IsLTU(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	sBigInteger* psrc;
	int i;
	int bc, sign, signsrc;

	pobj = (sBigInteger*)objectThis(object);
	if (!objectIsClass(src, CLSID_BIGINTEGER)) {
		return 0;
	}
	psrc = (sBigInteger*)objectThis(src);
	bc = pobj->width / CELL_WIDTH;
	sign = pobj->buf[bc] & (1 << ((pobj->width - 1) & (CELL_WIDTH - 1)));
	bc = psrc->width / CELL_WIDTH;
	signsrc = psrc->buf[bc] & (1 << ((psrc->width - 1) & (CELL_WIDTH - 1)));
	if (sign == 0 && signsrc != 0) {
		return 0;
	}
	else if (sign != 0 && signsrc == 0) {
		return 1;
	}

	bc = pobj->buflen;
	if (bc < psrc->buflen)
		bc = psrc->buflen;
	for (i = bc - 1; i >= pobj->buflen; i--) {
		if (sign != 0) {
			if (psrc->buf[i] != 0xffffffff)
				return 0;
		}
		else {
			if (psrc->buf[0] != 0)
				return 1;
		}
	}
	for (; i >= psrc->buflen; i--) {
		if (sign != 0) {
			if (pobj->buf[i] != 0xffffffff)
				return 1;
		}
		else {
			if (pobj->buf[0] != 0)
				return 0;
		}
	}
	for (; i >= 0; i--) {
		if (sign != 0) {
			if (pobj->buf[i] > psrc->buf[i])
				return 1;
			else if (pobj->buf[i] < psrc->buf[i])
				return 0;
		}
		else {
			if (pobj->buf[i] < psrc->buf[i])
				return 1;
			if (pobj->buf[i] > psrc->buf[i])
				return 0;
		}
	}
	return 0;
}

static int bigint_bn_IsLEU(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	sBigInteger* psrc;
	int i;
	int bc, sign, signsrc;

	pobj = (sBigInteger*)objectThis(object);
	if (!objectIsClass(src, CLSID_BIGINTEGER)) {
		return 0;
	}
	psrc = (sBigInteger*)objectThis(src);
	bc = pobj->width / CELL_WIDTH;
	sign = pobj->buf[bc] & (1 << ((pobj->width - 1) & (CELL_WIDTH - 1)));
	bc = psrc->width / CELL_WIDTH;
	signsrc = psrc->buf[bc] & (1 << ((psrc->width - 1) & (CELL_WIDTH - 1)));
	if (sign == 0 && signsrc != 0) {
		return 0;
	}
	else if (sign != 0 && signsrc == 0) {
		return 1;
	}

	bc = pobj->buflen;
	if (bc < psrc->buflen)
		bc = psrc->buflen;
	for (i = bc - 1; i >= pobj->buflen; i--) {
		if (sign != 0) {
			if (psrc->buf[i] != 0xffffffff)
				return 0;
		}
		else {
			if (psrc->buf[0] != 0)
				return 1;
		}
	}
	for (; i >= psrc->buflen; i--) {
		if (sign != 0) {
			if (pobj->buf[i] != 0xffffffff)
				return 1;
		}
		else {
			if (pobj->buf[0] != 0)
				return 0;
		}
	}
	for (; i >= 0; i--) {
		if (sign != 0) {
			if (pobj->buf[i] > psrc->buf[i])
				return 1;
			else if (pobj->buf[i] < psrc->buf[i])
				return 0;
		}
		else {
			if (pobj->buf[i] < psrc->buf[i])
				return 1;
			if (pobj->buf[i] > psrc->buf[i])
				return 0;
		}
	}
	return 1;
}

static int bigint_bn_IsEQU(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	sBigInteger* psrc;
	int i;
	int bc, sign, signsrc;
	pobj = (sBigInteger*)objectThis(object);
	if (!objectIsClass(src, CLSID_BIGINTEGER)) {
		return 0;
	}
	psrc = (sBigInteger*)objectThis(src);
	bc = pobj->width / CELL_WIDTH;
	sign = pobj->buf[bc] & (1 << ((pobj->width - 1) & (CELL_WIDTH - 1)));
	bc = psrc->width / CELL_WIDTH;
	signsrc = psrc->buf[bc] & (1 << ((psrc->width - 1) & (CELL_WIDTH - 1)));
	if (sign != signsrc) {
		return 0;
	}
	for (i = 0; i < pobj->buflen && i < psrc->buflen; i++) {
		if (pobj->buf[i] != psrc->buf[i])
			return 0;
	}
	for (; i < pobj->buflen; i++) {
		if (sign == 0 && pobj->buf[i] != 0)
			return 0;
		else if (sign != 0 && pobj->buf[i] != CELL_MASK)
			return 0;
	}
	for (; i < psrc->buflen; i++) {
		if (sign == 0 && psrc->buf[i] != 0)
			return 0;
		else if (sign != 0 && psrc->buf[i] != CELL_MASK)
			return 0;
	}
	return 1;
}


static int bigint_bn_IsNEU(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	sBigInteger* psrc;
	int i;
	int bc, sign, signsrc;
	pobj = (sBigInteger*)objectThis(object);
	if (!objectIsClass(src, CLSID_BIGINTEGER)) {
		return 0;
	}
	psrc = (sBigInteger*)objectThis(src);
	bc = pobj->width / CELL_WIDTH;
	sign = pobj->buf[bc] & (1 << ((pobj->width - 1) & (CELL_WIDTH - 1)));
	bc = psrc->width / CELL_WIDTH;
	signsrc = psrc->buf[bc] & (1 << ((psrc->width - 1) & (CELL_WIDTH - 1)));
	if (sign != signsrc) {
		return 0;
	}
	for (i = 0; i < pobj->buflen && i < psrc->buflen; i++) {
		if (pobj->buf[i] != psrc->buf[i])
			return 0;
	}
	for (; i < pobj->buflen; i++) {
		if (sign == 0 && pobj->buf[i] != 0)
			return 0;
		else if (sign != 0 && pobj->buf[i] != CELL_MASK)
			return 0;
	}
	for (; i < psrc->buflen; i++) {
		if (sign == 0 && psrc->buf[i] != 0)
			return 0;
		else if (sign != 0 && psrc->buf[i] != CELL_MASK)
			return 0;
	}
	return 1;
}

static int bigint_bn_IsZero(HOBJECT object)
{
	sBigInteger* pobj;
	int i;
	pobj = (sBigInteger*)objectThis(object);
	for (i = 0; i < pobj->buflen; i++)
		if (pobj->buf[i] != 0)
			return 0;
	return 1;
}

static int bigint_bn_IsNotZero(HOBJECT object)
{
	sBigInteger* pobj;
	int i;
	pobj = (sBigInteger*)objectThis(object);
	for (i = 0; i < pobj->buflen; i++)
		if (pobj->buf[i] != 0)
			return 0;
	return 1;
}

static int bigint_bn_IsNeg(HOBJECT object)
{
	sBigInteger* pobj;
	int bc, sign;
	pobj = (sBigInteger*)objectThis(object);
	bc = pobj->width / CELL_WIDTH;
	sign = pobj->buf[bc] & (1 << ((pobj->width - 1) & (CELL_WIDTH - 1)));
	return sign ? 1 : 0;
}

static int bigint_bn_AndL(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	sBigInteger* psrc;
	int i;
	pobj = (sBigInteger*)objectThis(object);
	if (!objectIsClass(src, CLSID_BIGINTEGER)) {
		return -1;
	}
	psrc = (sBigInteger*)objectThis(src);
	for (i = 0; i < pobj->buflen && i < psrc->buflen; i++) {
		pobj->buf[i] &= psrc->buf[i];
	}
	for (; i < pobj->buflen; i++) {
		pobj->buf[i] = 0;
	}
	return 0;
}

static int bigint_bn_OrL(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	sBigInteger* psrc;
	int i;
	pobj = (sBigInteger*)objectThis(object);
	if (!objectIsClass(src, CLSID_BIGINTEGER)) {
		return -1;
	}
	psrc = (sBigInteger*)objectThis(src);
	for (i = 0; i < pobj->buflen && i < psrc->buflen; i++) {
		pobj->buf[i] |= psrc->buf[i];
	}
	return 0;
}

static int bigint_bn_NotL(HOBJECT object)
{
	sBigInteger* pobj;

	return 0;
}

static int bigint_bn_And(HOBJECT object, HOBJECT src0, HOBJECT src1)
{
	int signexpand = 1;
	sBigInteger* pobj;
	IBigNumber** psrc0;
	IBigNumber** psrc1;
	int widthobj, widthsrc0, widthsrc1;
	int i;
	pobj = (sBigInteger*)objectThis(object);
	if (EIID_OK != objectQueryInterface(src0, IID_BIGNUMBER, (void**)&psrc0)) {
		return -1;
	}
	if (EIID_OK != objectQueryInterface(src1, IID_BIGNUMBER, (void**)&psrc1)) {
		objectRelease(psrc0);
		return -1;
	}
	widthobj = pobj->width;
	widthsrc0 = objectCall0(psrc0, GetWidth);
	widthsrc1 = objectCall0(psrc1, GetWidth);
	if (widthsrc0 < widthobj) {
		objectCall2(psrc0, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc0, SetWidth, widthsrc0, signexpand);
	}
	if (widthsrc1 < widthobj) {
		objectCall2(psrc1, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc1, SetWidth, widthsrc1, signexpand);
	}
	for (i = 0; i < pobj->buflen; i++) {
		unsigned int src0value, src1value;
		objectCall2(psrc0, GetBits32, i, &src0value);
		objectCall2(psrc1, GetBits32, i, &src1value);
		pobj->buf[i] = src0value & src1value;
	}
	bigint_bn_SetWidth(object, widthobj, 1);
	if (widthsrc0 < widthobj) {
		objectCall2(psrc0, SetWidth, widthsrc0, 0);
	}
	if (widthsrc1 < widthobj) {
		objectCall2(psrc1, SetWidth, widthsrc1, 0);
	}
	objectRelease(psrc0);
	objectRelease(psrc1);
	return 0;

}

static int bigint_bn_Or(HOBJECT object, HOBJECT src0, HOBJECT src1)
{
	int signexpand = 1;
	sBigInteger* pobj;
	IBigNumber** psrc0;
	IBigNumber** psrc1;
	int widthobj, widthsrc0, widthsrc1;
	int i;
	pobj = (sBigInteger*)objectThis(object);
	if (EIID_OK != objectQueryInterface(src0, IID_BIGNUMBER, (void**)&psrc0)) {
		return -1;
	}
	if (EIID_OK != objectQueryInterface(src1, IID_BIGNUMBER, (void**)&psrc1)) {
		objectRelease(psrc0);
		return -1;
	}
	widthobj = pobj->width;
	widthsrc0 = objectCall0(psrc0, GetWidth);
	widthsrc1 = objectCall0(psrc1, GetWidth);
	if (widthsrc0 < widthobj) {
		objectCall2(psrc0, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc0, SetWidth, widthsrc0, signexpand);
	}
	if (widthsrc1 < widthobj) {
		objectCall2(psrc1, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc1, SetWidth, widthsrc1, signexpand);
	}
	for (i = 0; i < pobj->buflen; i++) {
		unsigned int src0value, src1value;
		objectCall2(psrc0, GetBits32, i, &src0value);
		objectCall2(psrc1, GetBits32, i, &src1value);
		pobj->buf[i] = src0value | src1value;
	}
	bigint_bn_SetWidth(object, widthobj, 1);
	if (widthsrc0 < widthobj) {
		objectCall2(psrc0, SetWidth, widthsrc0, 0);
	}
	if (widthsrc1 < widthobj) {
		objectCall2(psrc1, SetWidth, widthsrc1, 0);
	}
	objectRelease(psrc0);
	objectRelease(psrc1);
	return 0;
}

static int bigint_bn_Xor(HOBJECT object, HOBJECT src0, HOBJECT src1)
{
	int signexpand = 1;
	sBigInteger* pobj;
	IBigNumber** psrc0;
	IBigNumber** psrc1;
	int widthobj, widthsrc0, widthsrc1;
	int i;
	pobj = (sBigInteger*)objectThis(object);
	if (EIID_OK != objectQueryInterface(src0, IID_BIGNUMBER, (void**)&psrc0)) {
		return -1;
	}
	if (EIID_OK != objectQueryInterface(src1, IID_BIGNUMBER, (void**)&psrc1)) {
		objectRelease(psrc0);
		return -1;
	}
	widthobj = pobj->width;
	widthsrc0 = objectCall0(psrc0, GetWidth);
	widthsrc1 = objectCall0(psrc1, GetWidth);
	if (widthsrc0 < widthobj) {
		objectCall2(psrc0, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc0, SetWidth, widthsrc0, signexpand);
	}
	if (widthsrc1 < widthobj) {
		objectCall2(psrc1, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc1, SetWidth, widthsrc1, signexpand);
	}
	for (i = 0; i < pobj->buflen; i++) {
		unsigned int src0value, src1value;
		objectCall2(psrc0, GetBits32, i, &src0value);
		objectCall2(psrc1, GetBits32, i, &src1value);
		pobj->buf[i] = src0value ^ src1value;
	}
	bigint_bn_SetWidth(object, widthobj, 1);
	if (widthsrc0 < widthobj) {
		objectCall2(psrc0, SetWidth, widthsrc0, 0);
	}
	if (widthsrc1 < widthobj) {
		objectCall2(psrc1, SetWidth, widthsrc1, 0);
	}
	objectRelease(psrc0);
	objectRelease(psrc1);
	return 0;
}

static int bigint_bn_Not(HOBJECT object, HOBJECT src)
{
	int signexpand = 1;
	sBigInteger* pobj;
	IBigNumber** psrc;
	int widthobj, widthsrc;
	int i;
	pobj = (sBigInteger*)objectThis(object);
	if (EIID_OK != objectQueryInterface(src, IID_BIGNUMBER, (void**)&psrc)) {
		return -1;
	}
	widthobj = pobj->width;
	widthsrc = objectCall0(psrc, GetWidth);
	if (widthsrc < widthobj) {
		objectCall2(psrc, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc, SetWidth, widthsrc, signexpand);
	}
	for (i = 0; i < pobj->buflen; i++) {
		unsigned int srcvalue;
		objectCall2(psrc, GetBits32, i, &srcvalue);
		pobj->buf[i] = ~srcvalue;
	}
	bigint_bn_SetWidth(object, widthobj, 1);
	if (widthsrc < widthobj) {
		objectCall2(psrc, SetWidth, widthsrc, 0);
	}
	objectRelease(psrc);
	return 0;
}

static int bigint_bn_uAnd(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	NOTIMPL;
	return 0;
}

static int bigint_bn_uAndNot(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	NOTIMPL;
	return 0;
}

static int bigint_bn_uOr(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	NOTIMPL;
	return 0;
}

static int bigint_bn_uOrNot(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	NOTIMPL;
	return 0;
}

static int bigint_bn_uXor(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	NOTIMPL;
	return 0;
}

static int bigint_bn_uXorNot(HOBJECT object, HOBJECT src)
{
	sBigInteger* pobj;
	pobj = (sBigInteger*)objectThis(object);
	NOTIMPL;
	return 0;
}

static int bigint_bn_SHL(HOBJECT object, HOBJECT src, int bits)
{ 
	sBigInteger* pobj;
	int signexpand = 1;
	IBigNumber** psrc;
	int widthobj, widthsrc;
	int ifrom, ito, i;
	unsigned long long current, next;

	if (bits == 0)
		return 0;

	if (bits < 0)
		return bigint_bn_SHR(object, src, -bits);

	pobj = (sBigInteger*)objectThis(object);
	if (EIID_OK != objectQueryInterface(src, IID_BIGNUMBER, (void**)&psrc)) {
		return -1;
	}
	widthobj = pobj->width;
	widthsrc = objectCall0(psrc, GetWidth);
	if (widthsrc < widthobj) {
		objectCall2(psrc, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc, SetWidth, widthsrc, signexpand);
	}

	ito = bits / CELL_WIDTH;
	bits -= ito * CELL_WIDTH;
	ifrom = 0;
	for (i = pobj->buflen-1; i>=0; i--) {
		current = 0;
		if (i >= ito) {
			unsigned int srcvalue;
			objectCall2(psrc, GetBits32, i-ito, &srcvalue);
			current = srcvalue;
			current <<= CELL_WIDTH;
		}
		if (i >= ito+1) {
			unsigned int srcvalue;
			objectCall2(psrc, GetBits32, i - ito - 1, &srcvalue);
			next = srcvalue;
			current |= next;
		}
		current >>= CELL_WIDTH - bits;
		pobj->buf[i] = (unsigned int)(current & CELL_MASK);
	}
	return 0;
}

static int bigint_bn_SHR(HOBJECT object, HOBJECT src, int bits)
{
	sBigInteger* pobj;
	int signexpand = 0;
	IBigNumber** psrc;
	unsigned int srcvalue;
	int widthobj, widthsrc;
	int bc;
	int ifrom, ito, i, zerolen;
	unsigned long long current, next;
	pobj = (sBigInteger*)objectThis(object);
	if (bits == 0)
		return 0;
	if (bits < 0)
		return bigint_bn_SHL(object, src, -bits);
	if (EIID_OK != objectQueryInterface(src, IID_BIGNUMBER, (void**)&psrc)) {
		return -1;
	}
	widthobj = pobj->width;
	widthsrc = objectCall0(psrc, GetWidth);
	if (widthsrc < widthobj) {
		objectCall2(psrc, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc, SetWidth, widthsrc, signexpand);
	}
	ito = 0;
	ifrom = bits / CELL_WIDTH;
	if (bits >= widthsrc) {
		for (i = 0;i<pobj->buflen;i++)
			pobj->buf[i] = signexpand?CELL_MASK:0;
		return 0;
	}
	bits -= ifrom * CELL_WIDTH;
	if (ifrom+1 < pobj->buflen) {
		objectCall2(psrc, GetBits32, ifrom + 1, &srcvalue);
		current = srcvalue;
		current <<= CELL_WIDTH;
	}
	else {
		current = 0;
	}
	objectCall2(psrc, GetBits32, ifrom, &srcvalue);
	current |= srcvalue;
	current >>= bits;
	for (i = ifrom + 1; i < pobj->buflen-1; i++) {
		pobj->buf[ito++] = (unsigned int)(current & CELL_MASK);
		current >>= CELL_WIDTH;
		objectCall2(psrc, GetBits32, ifrom, &srcvalue);
		next = srcvalue;
		next <<= CELL_WIDTH-bits;
		current |= next;
	}
	pobj->buf[ito++] = (unsigned int)(current & CELL_MASK);
	while (ito < pobj->buflen)
		pobj->buf[ito++] = 0;
	return 0;
}

static int bigint_bn_SAL(HOBJECT object, HOBJECT src, int bits)
{
	return bigint_bn_SHL(object, src, bits);
}

static int bigint_bn_SAR(HOBJECT object, HOBJECT src, int bits)
{
	sBigInteger* pobj;
	int signexpand = 1;
	IBigNumber** psrc;
	unsigned int srcvalue;
	int widthobj, widthsrc;
	int bc, sign;
	int ifrom, ito, i, zerolen;
	unsigned long long current, next;
	pobj = (sBigInteger*)objectThis(object);
	if (bits == 0)
		return 0;
	if (bits < 0)
		return bigint_bn_SHL(object, src, -bits);
	if (EIID_OK != objectQueryInterface(src, IID_BIGNUMBER, (void**)&psrc)) {
		return -1;
	}
	widthobj = pobj->width;
	widthsrc = objectCall0(psrc, GetWidth);
	if (widthsrc < widthobj) {
		objectCall2(psrc, SetWidth, widthobj, signexpand);
	}
	else {
		objectCall2(psrc, SetWidth, widthsrc, signexpand);
	}
	bc = pobj->width / CELL_WIDTH;
	objectCall2(psrc, GetBits32, bc, &srcvalue);
	sign = srcvalue & (1 << ((pobj->width-1) & (CELL_WIDTH - 1)));
	ito = 0;
	ifrom = bits / CELL_WIDTH;
	if (ifrom >= pobj->buflen) {
		for (i = 0;i<pobj->buflen;i++)
			pobj->buf[i] = sign ? CELL_MASK : 0;
		return 0;
	}
	bits -= ifrom * CELL_WIDTH;
	if (ifrom + 1 < pobj->buflen) {
		objectCall2(psrc, GetBits32, ifrom+1, &srcvalue);
		current = srcvalue;
		current <<= CELL_WIDTH;
	}
	else {
		current = 0;
	}
	objectCall2(psrc, GetBits32, ifrom, &srcvalue);
	current |= srcvalue;
	current >>= bits;
	for (i = ifrom + 1; i < pobj->buflen - 1; i++) {
		pobj->buf[ito++] = (unsigned int)(current & CELL_MASK);
		current >>= CELL_WIDTH;
		objectCall2(psrc, GetBits32, i + 1, &srcvalue);
		next = srcvalue;
		next <<= CELL_WIDTH - bits;
		current |= next;
	}
	next = sign ? CELL_MASK : 0;
	next <<= CELL_WIDTH - bits;
	current |= next;
	pobj->buf[ito++] = (unsigned int)(current & CELL_MASK);
	while (ito < pobj->buflen)
		pobj->buf[ito++] = sign ? CELL_MASK : 0;
	return 0;
}

IBigNumber** bigintegerCreate(int width)
{
	int ret;
	IBigNumber** bn;
	PARAMITEM param;
	A_u_t_o_registor_bigint();
	param.name = PARAMID_BIGINTEGERWIDTH;
	param.i32value = width;
	ret = objectCreateEx(CLSID_BIGINTEGER, &param, 1, IID_BIGNUMBER, (const void**)&bn);
	return bn;
}
