#include  <stdio.h>
#include  <string.h>
#include  <stdlib.h>
#include  "GeneType.h"
#include  "PyBasic.h"
#include  "ciku.h"

#define	   UDCMEM_ALIGN	   128
UdcMemAll  udcAll;

JINT	Hzcode2244ToYjcode(JINT nHzcode);
JINT	JwordNCmp(JWORD* pwSrc1, JWORD* pwSrc2, JINT nNum);

VOID	SetUdcfh(UdCikuHeader *pUdcfh);
VOID	SetSpecHzData(JWORD* pwSpecHz, JINT nMaxLen);
VOID	SetUdcIndex(UdcIndex *pUdci);
VOID	CreateUdCikuFile();

JINT	ReadUdcData(CHAR* szUdcName);
JINT	WriteUdcData(CHAR* szUdcName, JINT nTimeStamp);
JINT	AddUdc(JWORD* pwHz2244, JINT nLen);
JINT	DelUdc(JWORD* pwHz2244, JINT nLen);
JINT	PureUdc(VOID);

/*
**  Read out all those data in System Ciku file to pCkAll.
*/
JINT ReadUdcData(CHAR* szUdcName)
{
	FILE*	pfUdc;
	JINT	i, k, nTmp;
	JINT	nFileSize;

	pfUdc = fopen(szUdcName, "rb");
	if (pfUdc == NULL)
	{
		fprintf(stderr, "Failed to fopen() UserDefinedCiku File: %s\n", szUdcName);
		return FALSE;
	}

	fseek(pfUdc, 0, SEEK_SET);
	if ((JINT)fread (&(udcAll.udcfh), 1, sizeof(UdCikuHeader), pfUdc) != sizeof(UdCikuHeader) )
	{
		fprintf(stderr, "Failed to fread() UdCiku Header.\n");
		fclose(pfUdc);
		return FALSE;
	}

	/* Check Magic Word in Header */
	if ((udcAll.udcfh.nMagicDescHi != 0x35303539) || (udcAll.udcfh.nMagicDescLow != 0x34333442))
	{
		fprintf(stderr, "This is not a valid UdCiku File.\n");
		fclose(pfUdc);
		return FALSE;
	}
	nFileSize = udcAll.udcfh.nFileSize;

	fseek(pfUdc, 0, SEEK_END);
	if (nFileSize != ftell(pfUdc))
	{
		fprintf(stderr, "File UdCiku was demaged.\n");
		fclose(pfUdc);
		return FALSE;
	}

	/* Read in UdcIndex Data */
	nTmp = udcAll.udcfh.nIdxUdcPos;
	fseek(pfUdc, nTmp, SEEK_SET);
	if ((JINT)fread (&(udcAll.udci), 1, sizeof(UdcIndex), pfUdc) != sizeof(UdcIndex))
	{
		fprintf(stderr, "Failed to fread() UdCiku UdcIndex.\n");
		fclose(pfUdc);
		return FALSE;
	}

	/* Alloc Memory for SpecHz, and fill these data to it */
	nTmp = udcAll.udcfh.nSizeSpecHz;   /* In BYTE */
	udcAll.pwUdcSh = (JWORD*)malloc(nTmp);
	if (udcAll.pwUdcSh == NULL)
	{
		fprintf(stderr, "Failed to malloc() for pwUdcSh.\n");
		fclose(pfUdc);
		return FALSE;
	}

	nTmp = (udcAll.udcfh.nSizeSpecHz) / sizeof(JWORD);   /* In JWORD */
	fseek(pfUdc, udcAll.udcfh.nSpecHzStartPos, SEEK_SET);
	if ((JINT)fread (udcAll.pwUdcSh, sizeof(JWORD), nTmp, pfUdc) != nTmp )
	{
		fprintf(stderr, "Failed to fread() UdCiku File.\n");
		fclose(pfUdc);
		return FALSE;
	}

	/* Alloc Memory for pwUdc28[NUM_YINJIE], align each with UDCMEM_ALIGN BYTE (64 JWORD) */
	for (i = 0; i < NUM_YINJIE; i++)
	{
		/* Get the Actual Size to nTmp and upper align it to UDCMEM_ALIGN */
		nTmp = udcAll.udci.nYjOff[i + 1] - udcAll.udci.nYjOff[i];
		nTmp = ((nTmp + UDCMEM_ALIGN) / UDCMEM_ALIGN) * UDCMEM_ALIGN;
		udcAll.pwUdc28[i] = (JWORD*)malloc(nTmp);
	}

	/* Is there any failure in Memory Allocation? If no, Init it to 0x0000 */
	for (i = 0; i < NUM_YINJIE; i++)
	{
		if (udcAll.pwUdc28[i] == NULL)
		{
			for(k = 0; k < NUM_YINJIE; k++)
			{
				free (udcAll.pwUdc28[i]);
				udcAll.pwUdc28[i] = NULL;
			}
			fprintf(stderr, "Failed in Alloc Mem for pwUdc28. %d\n", i);
			return FALSE;
		}

		nTmp = udcAll.udci.nYjOff[i + 1] - udcAll.udci.nYjOff[i];
		nTmp = ((nTmp + UDCMEM_ALIGN) / UDCMEM_ALIGN) * UDCMEM_ALIGN;
		for (k = 0; k < (nTmp / 2); k++)
			udcAll.pwUdc28[i][k] = 0x0000;
	}

	/* Read in pwUdc28 data */
	nTmp = udcAll.udci.nStartPos;
	fseek(pfUdc, nTmp, SEEK_SET);

	for(i = 0; i < NUM_YINJIE; i++)
	{
		nTmp = (udcAll.udci.nYjOff[i + 1] - udcAll.udci.nYjOff[i]) / sizeof(JWORD);
		if ((JINT)fread (udcAll.pwUdc28[i], sizeof(JWORD), nTmp, pfUdc) != nTmp)
		{
			fprintf(stderr, "Failed to fread() UdCiku pwUdc28.\n");
			fclose(pfUdc);
			return FALSE;
		}
	}

	fclose(pfUdc);
	return TRUE;
}


JINT WriteUdcData(CHAR* szUdcName, JINT nTimeStamp)
{
	FILE*	pfUdc;
	JINT	i, nTmp;
	JINT	nFileSize;

	udcAll.udcfh.nLatestTime  = nTimeStamp;

	nFileSize = sizeof(UdCikuHeader) + sizeof(UdcIndex) +
		    udcAll.udcfh.nSizeSpecHz + udcAll.udci.nYjOff[NUM_YINJIE];
	udcAll.udcfh.nFileSize	  = nFileSize;
	udcAll.udci.nStartPos	  = sizeof(UdCikuHeader) + sizeof(UdcIndex) + udcAll.udcfh.nSizeSpecHz;
	udcAll.udci.nEndPos	  = sizeof(UdCikuHeader) + sizeof(UdcIndex) +
		    udcAll.udcfh.nSizeSpecHz + udcAll.udci.nYjOff[NUM_YINJIE];

	/* Write These data back to file */
	pfUdc = fopen(szUdcName, "wb");
	if (pfUdc == NULL)
	{
		fprintf(stderr, "Failed to Open UdCiku File to Write.\n");
		return FALSE;
	}

	if ((JINT)fwrite (&(udcAll.udcfh), 1, sizeof(UdCikuHeader), pfUdc) != sizeof(UdCikuHeader) )
	{
		fprintf(stderr, "Failed to fwrite() Ud Ciku File11.\n");
		return FALSE;
	}

	if ((JINT)fwrite (&(udcAll.udci),  1, sizeof(UdcIndex), pfUdc) != sizeof(UdcIndex) )
	{
		fprintf(stderr, "Failed to fwrite() Ud Ciku File22.\n");
		return FALSE;
	}

	nTmp = (udcAll.udcfh.nSizeSpecHz) / sizeof(JWORD);
	if ((JINT)fwrite (udcAll.pwUdcSh, sizeof(JWORD), nTmp, pfUdc) != nTmp )
	{
		fprintf(stderr, "Failed to fwrite() Ud Ciku File33.\n");
		return FALSE;
	}

	for(i = 0; i < NUM_YINJIE; i++)
	{
		nTmp = (udcAll.udci.nYjOff[i + 1] - udcAll.udci.nYjOff[i]) / sizeof(JWORD);
		if ((JINT)fwrite (udcAll.pwUdc28[i], sizeof(JWORD), nTmp, pfUdc) != nTmp )
		{
			fprintf(stderr, "Failed to fwrite() Ud Ciku File44.\n");
			return FALSE;
		}
	}

	fclose(pfUdc);
	return TRUE;
}


/*
**  Add an User Defined Cizu to structure udcAll.pwUdc28[i] AND
**  realloc the related size of udcAll.udci.nYjOff[]
**  nLen is in JWORD.
*/
JINT AddUdc(JWORD* pwHz2244, JINT nLen)
{
	JINT	i, nTmp1, nTmp2;
	JINT	nCurSize;
	JINT	nFreqLen, nTmpLen;
	JINT	nFirstYj;

	if (nLen <= 1)
		return FALSE;

	nFirstYj = Hzcode2244ToYjcode(pwHz2244[0]);
	if (nFirstYj == 0xFFFF)
	{
		fprintf(stderr, "Error in AddUdc.\n");
		return FALSE;
	}

	/*
	**  STEP1: Is it necessary to realloc() for this Yinjie's space?
	*/
	nCurSize = udcAll.udci.nYjOff[nFirstYj + 1] - udcAll.udci.nYjOff[nFirstYj];    /* In BYTE */
	nTmp1	 = ((nCurSize + UDCMEM_ALIGN) / UDCMEM_ALIGN) * UDCMEM_ALIGN;
	nTmp2	 = ((nCurSize + ((nLen + 1) * sizeof(JWORD)) + UDCMEM_ALIGN) / UDCMEM_ALIGN) * UDCMEM_ALIGN;
	if (nTmp2 > nTmp1)
	{
		udcAll.pwUdc28[nFirstYj] = (JWORD*)realloc(udcAll.pwUdc28[nFirstYj], nTmp2);
		if (udcAll.pwUdc28[nFirstYj] == NULL)
		{
			fprintf(stderr, "Failed to realloc() in AddUdc().\n");
			return FALSE;
		}
		for(i = 0; i < (UDCMEM_ALIGN) / 2; i++)
			udcAll.pwUdc28[nFirstYj][nTmp1 + i] = 0x0000;
	}

	/*
	** STEP2:  Reduce the Frequence of other Udc for FUTURE FUNCTION: DiscardUdc().
	** Notice: Cannot DiscardUdc() here, that will make the LOGIC confusion.
	*/
	/* NO i++ in this FOR sentence */
	for (i = 0; i < nCurSize / 2; )
	{
		nFreqLen = (JINT)udcAll.pwUdc28[nFirstYj][i];
		nTmpLen	 = (nFreqLen & 0x0007) + 2;
		if (nFreqLen >= 0x0010)
			udcAll.pwUdc28[nFirstYj][i] -= 8;
		i += (nTmpLen + 1);
	}

	/*
	** STEP3:  Append this pwHz2244 just after pwUdc28[nFirstYj][nCurSize / 2]
	** Set the Frequence of this pwHz2244 to the Highest: 11111xxx.
	** xxx from 000 to 111, indicates length from 2 to 9
	*/
	nFreqLen = 0x00F8 + (nLen - 2);
	udcAll.pwUdc28[nFirstYj][nCurSize / 2] = (JWORD)nFreqLen;
	for (i = 0; i < nLen; i++)
		udcAll.pwUdc28[nFirstYj][(nCurSize / 2) + 1 + i] = pwHz2244[i];

	/*
	** STEP4:  Adjust udcAll.udci.nYjOff[nFirstYj + 1] to nYjOff[NUM_YINJIE]
	*/
	for (i = nFirstYj; i < NUM_YINJIE; i++)
		udcAll.udci.nYjOff[i + 1] += 2 * (nLen + 1);

	return TRUE;
}


/*
**  Del an User Defined Cizu to structure udcAll.pwUdc28[i] AND
**  realloc the related size of udcAll.udci.nYjOff[]
**  If cannot find this Udc, just return FALSE.
*/
JINT DelUdc(JWORD* pwHz2244, JINT nLen)
{
	JINT	i, k, nTmp1, nTmp2;
	JINT	nCurSize;
	JINT	nFreqLen, nTmpLen;
	JINT	nFirstYj;
	JINT	nFindFlag;

	if (nLen <= 1)
		return FALSE;

	nFirstYj = Hzcode2244ToYjcode(pwHz2244[0]);
	if (nFirstYj == 0xFFFF)
	{
		fprintf(stderr, "Error in DelUdc.\n");
		return FALSE;
	}

	/*
	**  STEP1: Find this pwHz2244, Forward other Udcdata to (nLen + 1) JWORD.
	*/
	nFindFlag = FALSE;
	nCurSize  = udcAll.udci.nYjOff[nFirstYj + 1] - udcAll.udci.nYjOff[nFirstYj];	/* In BYTE */

	/* NO i++ in this FOR sentence */
	for (i = 0; i < nCurSize / 2; )
	{
		nFreqLen = (JINT)udcAll.pwUdc28[nFirstYj][i];
		nTmpLen	 = (nFreqLen & 0x0007) + 2;
		/* DON'T exchange the sequence of two judgement in the following IF sentence */
		if ((nTmpLen == nLen) && (JwordNCmp(pwHz2244, &(udcAll.pwUdc28[nFirstYj][i + 1]), nTmpLen) == 0))
		{
			nFindFlag = TRUE;
			for (k = i; k < (nCurSize / 2) - (nTmpLen + 1); k++)
				udcAll.pwUdc28[nFirstYj][k] = udcAll.pwUdc28[nFirstYj][k + nTmpLen + 1];
			for (k = (nCurSize / 2) - (nTmpLen + 1); k < nCurSize / 2; k++)
				udcAll.pwUdc28[nFirstYj][k] = 0x0000;

			break;	      /* BREAK OUT FOR_i sentence */
		}
		i += (nTmpLen + 1);
	}

	if (nFindFlag == FALSE)
	{
		fprintf (stderr, "Failed to find given Udcizu in DelUdc().\n");
		return FALSE;
	}

	/*
	**  STEP2: Is it necessary to realloc() for this Yinjie's space?
	*/
	nTmp1	  = ((nCurSize + UDCMEM_ALIGN) / UDCMEM_ALIGN) * UDCMEM_ALIGN;
	nTmp2	  = ((nCurSize - ((nLen + 1) * sizeof(JWORD)) + UDCMEM_ALIGN) / UDCMEM_ALIGN) * UDCMEM_ALIGN;
	if (nTmp2 < nTmp1)
	{
		udcAll.pwUdc28[nFirstYj] = (JWORD*)realloc(udcAll.pwUdc28[nFirstYj], nTmp2);
		if (udcAll.pwUdc28[nFirstYj] == NULL)
		{
			fprintf(stderr, "Failed to realloc() in DelUdc().\n");
			return FALSE;
		}
	}

	/*
	** STEP3:  Adjust udcAll.udci.nYjOff[nFirstYj + 1] to nYjOff[NUM_YINJIE]
	*/
	for (i = nFirstYj; i < NUM_YINJIE; i++)
		udcAll.udci.nYjOff[i + 1] -= 2 * (nLen + 1);

	return TRUE;
}


/*
**  Pure (Discard or Clean) these rarely used Udc in UdCiku.
**  BEST WAY to use:
**	     CALL this function just before the SAVING UDC operation!!!
*/
JINT PureUdc(VOID)
{
	JINT	i, k, nYj, nTmp1, nTmp2;
	JINT	nCurSize;
	JINT	nTmpFreq, nTmpLen;
	JINT	nPuredSize;

	JINT	nPureNum;
	nPureNum = 0;

	for (nYj = 0; nYj < NUM_YINJIE; nYj++)
	{
		nCurSize   = udcAll.udci.nYjOff[nYj + 1] - udcAll.udci.nYjOff[nYj];	 /* In BYTE */
		nTmp1	   = ((nCurSize + UDCMEM_ALIGN) / UDCMEM_ALIGN) * UDCMEM_ALIGN;	 /* Old Buf Size */

		nPuredSize = 0;
		/* NO i++ in this FOR sentence */
		for (i = 0; i < nCurSize / 2; )
		{
			nTmpFreq = (JUINT)udcAll.pwUdc28[nYj][i] & 0x00F8;
			nTmpLen	 = (udcAll.pwUdc28[nYj][i] & 0x0007) + 2;

			if (nTmpFreq != 0x0008)	    /* Lowest Frequence */
			{
				for (k = i; k < (nCurSize / 2) - (nTmpLen + 1); k++)
					udcAll.pwUdc28[nYj][k] = udcAll.pwUdc28[nYj][k + nTmpLen + 1];
				for (k = (nCurSize / 2) - (nTmpLen + 1); k < nCurSize / 2; k++)
					udcAll.pwUdc28[nYj][k] = 0x0000;

				nPureNum   += 1;
				nCurSize   -= 2 * (nTmpLen + 1);
				nPuredSize += 2 * (nTmpLen + 1);
			}
			else	/* If an Udcizu is already deleted, DON'T CHANGE i HERE!! MXL */
				i += (nTmpLen + 1);
		}

		/* Adjust udcAll.udci.nYjOff[nFirstYj + 1] to nYjOff[NUM_YINJIE] */
		for (k = nYj; k < NUM_YINJIE; k++)
			udcAll.udci.nYjOff[k + 1] -= nPuredSize;

		/* Is it necessary to resize the buffer allocated for udcAll.pwUdc28[nYj] ? */
		nTmp2	  = ((nCurSize + UDCMEM_ALIGN) / UDCMEM_ALIGN) * UDCMEM_ALIGN;	/* New Buf Size */
		if (nTmp2 < nTmp1)
		{
			udcAll.pwUdc28[nYj] = (JWORD*)realloc(udcAll.pwUdc28[nYj], nTmp2);
			if (udcAll.pwUdc28[nYj] == NULL)
			{
				fprintf(stderr, "Failed to realloc() in PureUdc().\n");
				return FALSE;
			}
		}
	}

#ifdef _DEBUG
	fprintf (stderr, "PureNum is %d\n", nPureNum);
#endif

	return TRUE;
}


/*
**  Create UdFileHeader.
**  Data Sequence:
**
**  UdCikuHeader(UDCMEM_ALIGN) + UdcIndex (1676) + SpecHzData (2048 = 1024 * sizeof(JWORD)) + Ud2~8CizuData
**
**  Notice: In Memory, Ud2~8CizuData is not same as in disk file. They are realloced.
*/
VOID SetUdcfh(UdCikuHeader *pUdcfh)
{
	JINT	i, nLen;
	CHAR   szName[] = " SUN TDC P.R.C. 用户拼音词库 1.0";
	CHAR   szCopyright[] = "版权所有(C) 太阳计算机系统(中国)有限公司 1997_11";

	for (i = 0; i < 32; i++)
		pUdcfh->szName[i]      = '\0';
	for (i = 0; i < 48; i++)
		pUdcfh->szCopyright[i] = '\0';

	pUdcfh->nMagicDescHi	= 0x35303539;
	pUdcfh->nMagicDescLow	= 0x34333442;
	pUdcfh->nSize		= sizeof(UdCikuHeader);
	pUdcfh->nFileSize	= 0;

	nLen = strlen(szName);
	for (i = 0; i < nLen; i++)
		pUdcfh->szName[i]      = szName[i];

	nLen = strlen(szCopyright);
	for (i = 0; i < nLen; i++)
		pUdcfh->szCopyright[i] = szCopyright[i];

	pUdcfh->nVersion	= 0x00010000;		/* Version 1.0 */
	pUdcfh->nLatestTime	= 0;

	pUdcfh->nSpecHzStartPos = 0;
	pUdcfh->nSizeSpecHz	= 0;		 /* 2 KiloBytes for all spec Hanzi, each seperated by a 0x0000(JWORD) */
	pUdcfh->nIdxUdcPos	= 0;		 /* Index Position of User defined 2 ~ 8 Hanzi Cizu */

	pUdcfh->nReserve1	= 0;
	pUdcfh->nReserve2	= 0;
	pUdcfh->nReserve3	= 0;

	printf("Sizeof structure UdCikuHeader is %d\n", sizeof(UdCikuHeader));
}

/*
**  Here: nMaxLen in JWORD.
**  Data Sequence of pwSpecHz ==>
**		     0HHHHHHHHHH00HHHHH0H00000HHHH
*/
VOID SetSpecHzData(JWORD* pwSpecHz, JINT nMaxLen)
{
	JINT	nHzcode, nYjcode;
	JINT	i, k, m, nLen, nOff;

	JWORD	wSpecYjHanzi[NUM_YINJIE][6];
	JINT	nSpecCount[NUM_YINJIE];

/*	UCHAR	szTmp[20], nTmpYj, nFlag; */

	UCHAR	 szSpecHz[400] =
	"之节或子出也能对大百太且用及过无才开到于下不来占此小学少最虽叫只因加边同由则几必然名多反后年可长秒向第并前半间曾好会全个从化给比让说以各有为门要人经是的了而你我他与其就和在这那每某本总如被更但将仅应该很都性上中内外分原";
/*    1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 */

	memset(wSpecYjHanzi, 0x00, sizeof(JWORD) * NUM_YINJIE * 6);
	memset(nSpecCount,   0x00, sizeof(JINT) * NUM_YINJIE);

	/* 是0xCAC7 不0xB2BB */
	nLen = strlen((CHAR*)szSpecHz);
	for (i = 0; (i < nLen / 2) && (i < nMaxLen); i++)
	{
		nHzcode = (szSpecHz[2 * i] << 8) + szSpecHz[2 * i + 1];
		nYjcode = Hzcode2244ToYjcode(nHzcode);

		wSpecYjHanzi[nYjcode][nSpecCount[nYjcode]] = (JWORD)nHzcode;
		nSpecCount[nYjcode]++;
	}

	k = 0;
	for (i = 0; i < NUM_YINJIE; i++)
	{
		pwSpecHz[k++] = 0x0000;
		for (m = 0; m < nSpecCount[i]; m++)
			pwSpecHz[k++] = wSpecYjHanzi[i][m];
	}
}


VOID SetUdcIndex(UdcIndex *pUdci)
{
	JINT	i, k;
	JINT	nM28Len[NUM_YINJIE];

	pUdci->nSize	  = sizeof(UdcIndex);
	pUdci->nStartPos  = 0;				/* To be added by a BaseOffset */

	for (i = 0; i < (NUM_YINJIE + 1); i++)
		pUdci->nYjOff[i]  = 0;

	/* Assume that there is a FreqLen(JWORD), and a 0xBBBB(换) and 0xCCCC (烫) */
	for (i = 0; i < NUM_YINJIE; i++)
		nM28Len[i] = 0;

	for (i = 0; i < NUM_YINJIE; i++)
		for (k = i; k < NUM_YINJIE; k++)
			pUdci->nYjOff[k + 1] += nM28Len[i];

	pUdci->nEndPos	   = pUdci->nYjOff[NUM_YINJIE];	   /* To be added by a BaseOffset */
}


VOID CreateUdCikuFile()
{
	JINT	i, nTmp;
	JINT	nFileSize;
	JWORD	wSpecHz[1024];
	FILE*	pfUdCiku;
	JWORD*	pwUdCizu[NUM_YINJIE];

	UdCikuHeader	  udcfh;
	UdcIndex	  udci;

	SetUdcfh(&udcfh);

	memset(wSpecHz, '\0', 1024 * sizeof(JWORD));
	SetSpecHzData(wSpecHz, 1024);
	SetUdcIndex(&udci);

	nFileSize = sizeof(UdCikuHeader) + sizeof(UdcIndex) + (1024 * sizeof(JWORD)) + udci.nEndPos;
	udcfh.nFileSize	      = nFileSize;
	fprintf (stderr, "File Size of UdCiku.dat should be %d 0x%X\n", nFileSize, nFileSize);

	udcfh.nSpecHzStartPos  = sizeof(UdCikuHeader) + sizeof(UdcIndex);
	udcfh.nSizeSpecHz      = 1024 * sizeof(JWORD);	     /* 2 KiloBytes for all spec Hanzi, each seperated by a 0x0000(JWORD) */
	udcfh.nIdxUdcPos       = sizeof(UdCikuHeader);	     /* Index Position of User defined 2 ~ 8 Hanzi Cizu */

	udci.nStartPos	      += sizeof(UdCikuHeader) + sizeof(UdcIndex) + (1024 * sizeof(JWORD));
	udci.nEndPos	      += sizeof(UdCikuHeader) + sizeof(UdcIndex) + (1024 * sizeof(JWORD));

	pfUdCiku = fopen("UdCiku.dat", "wb");
	if (pfUdCiku == NULL)
	{
		fprintf (stderr, "Failed to Create User Defined Ciku [UdCiku.dat]\n");
		exit (FALSE);
	}

	/* Alloc for each Yinjie 64 * 2 bytes space to contain User Defined Cizu */
	for (i = 0; i < NUM_YINJIE; i++)
	{
		pwUdCizu[i] = (JWORD*)malloc(64 * sizeof(JWORD));
		if (pwUdCizu == NULL)
		{
			printf("Failed to alloc mem in CreateUdCikuFile().\n");
			exit (FALSE);
		}
	}

	/* WriteData to file */
	if ((JINT)fwrite (&udcfh, 1, sizeof(UdCikuHeader), pfUdCiku) != sizeof(UdCikuHeader) )
	{
		fprintf(stderr, "Failed to fwrite() Ud Ciku File11.\n");
		exit (FALSE);
	}

	if ((JINT)fwrite (&udci,  1, sizeof(UdcIndex), pfUdCiku) != sizeof(UdcIndex) )
	{
		fprintf(stderr, "Failed to fwrite() Ud Ciku File22.\n");
		exit (FALSE);
	}

	if ((JINT)fwrite (wSpecHz,  sizeof(JWORD), 1024, pfUdCiku) != 1024 )
	{
		fprintf(stderr, "Failed to fwrite() Ud Ciku File33.\n");
		exit (FALSE);
	}

	for(i = 0; i < NUM_YINJIE; i++)
	{
		nTmp = (udci.nYjOff[i + 1] - udci.nYjOff[i]) / 2;
		if ((JINT)fwrite (pwUdCizu[i], sizeof(JWORD), nTmp, pfUdCiku) != nTmp )
		{
			fprintf(stderr, "Failed to fwrite() Ud Ciku File44.\n");
			exit (FALSE);
		}
	}

	fclose(pfUdCiku);

	for(i = 0; i < NUM_YINJIE; i++)
		free (pwUdCizu[i]);

}


/*
**  This Function similar to strncmp() in standard ANSI library.
**  RETURN:  0	      pwSrc1 == pwSrc2
**	    -1	      pwSrc1 <	pwSrc2
**	     1	      pwSrc1 >	pwSrc2
**
**  Notice: because Jword hava no StringZero characteristics,
**	    SO, must give a proper nNum value!!!
**	    nNum is in JWORD, not in BYTE!!
*/
JINT JwordNCmp(JWORD* pwSrc1, JWORD* pwSrc2, JINT nNum)
{
	JINT	i;
	JINT	nRet;

	nRet = 0;
	for(i = 0; (i < nNum) && (nRet == 0); i++)
	{
		if(pwSrc1[i] > pwSrc2[i])
		{
			nRet = 1;
			break;
		}
		else if(pwSrc1[i] < pwSrc2[i])
		{
			nRet = -1;
			break;
		}
	}

	return nRet;
}


