/*
Copyright 1990-2003 Sun Microsystems, Inc. All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions: The above copyright notice and this
permission notice shall be included in all copies or substantial
portions of the Software.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.


Except as contained in this notice, the names of The Open Group and/or
Sun Microsystems, Inc. shall not be used in advertising or otherwise to
promote the sale, use or other dealings in this Software without prior
written authorization from The Open Group and/or Sun Microsystems,
Inc., as applicable.


X Window System is a trademark of The Open Group

OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
logo, LBX, X Window System, and Xinerama are trademarks of the Open
Group. All other trademarks and registered trademarks mentioned herein
are the property of their respective owners. No right, title or
interest in or to any trademark, service mark, logo or trade name of
Sun Microsystems, Inc. or its licensors is granted.

*/

#include  <stdio.h>
#include  <string.h>
#include  <stdlib.h>
#include  "GeneType.h"
#include  "PyStatic.h"
#include  "PyBig5.h"
#include  "Ciku.h"

#define    UDCMEM_ALIGN    128
UdcMemAll  udcAll;

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 = Big5HzcodeToYjcode(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 = Big5HzcodeToYjcode(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 = Big5HzcodeToYjcode(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 ZyUdCiku.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("ZyUdCiku.dat", "wb");
	if (pfUdCiku == NULL)
	{
		fprintf (stderr, "Failed to Create User Defined Ciku [ZyUdCiku.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;
}


