/*
Copyright 1990-2001 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 "PYIM.h"

/* Jword.c */
JINT    GbkHz2244ToYjSM(JINT nHzcode);
JINT    GbkHz2244ToYj(JINT nHzcode);
UCHAR*  RecovDyz2244(UCHAR *szDyz2244);
VOID    Jword2Uchar(JWORD* pwJword, UCHAR* szUch, JINT nMaxLen);
VOID    JwordNCpy(JWORD* pwDst, JWORD* pwSrc, JINT nLen);
JINT    JwordNCmp(JWORD* pwSrc1, JWORD* pwSrc2, JINT nNum);
JINT    JwordValidLen(JWORD* pwJwordArray, JINT nMaxLen);
JINT    JwordHanziLen(JWORD* pwJwordArray, JINT nMaxLen);

VOID    ProcUdCizu(SesGuiElement* pSge);
VOID    UniformSlctHz(SesGuiElement* pSge);
JINT    GetNSelect(JINT nXrd, JINT nTotalStep, JWORD* pwSlctHz, JWORD* pwUdcUnit);
VOID    AdjustFreq(JWORD* pwHz2244, JINT nLenThis);
JINT    IsCizuExist(JWORD* pwHz2244, JINT nLenThis);
VOID    JwordInfo(JWORD* pwJwordArray, JINT nMaxLen);

VOID    WarpByte(VOID* pv, JINT n);
VOID    WarpIndex(ShIndex* pInt419);
VOID    WarpCikuHeader(CikuHeader* pCh);

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);
VOID    FreeUdcData();
VOID    InitStructUc(UdcCandi* puc);

JINT    HasNonLinkHz(JWORD* pwSlctHz, JINT nTotalSteps);
JINT    IsXrdNonLinkHz(JINT nXrd, JWORD* pwSlctHz, JINT nTotalSteps);
JINT    IsXrdPreLinkHz(JINT nXrd, JWORD* pwSlctHz, JINT nTotalSteps);
JINT    IsXrdSufLinkHz(JINT nXrd, JWORD* pwSlctHz, JINT nTotalSteps);
JINT    TypeOfNSelect (JINT nXrd, JWORD* pwSlctHz, JINT nTotalSteps);

/* Type Value of function TypeOfNSelect() return */
#define SLCT_TYPE_INVALID     0        /* Invalid Selection */
#define SLCT_TYPE_NONLINK     1        /* One of Non Link Hanzi */
#define SLCT_TYPE_PRELINK     2        /* One of Pre Link Hanzi */
#define SLCT_TYPE_SUFLINK     3        /* One of Suf Link Hanzi */
#define SLCT_TYPE_NORMHZ      4        /* Normal Single Hanzi */
#define SLCT_TYPE_TWOHZ       5        /* Two Hanzi */
#define SLCT_TYPE_THREEHZ     6        /* Three Hanzi */
#define SLCT_TYPE_MFOURHZ     7        /* >= 4 Hanzi */

UdcMemAll  udcAll;

/***************************************************************************************
	
NONLINKHZ[2 * NUM_NONLINKHZ + 2] =  <以下单字为: 前后均不可联的字, 在分词时作用类同标点符号>
"是的了不也而你我他与它她其就和或";
  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

PRELINKHZ[2 * NUM_PRELINKHZ + 2] = <以下单字为: 只可与前联, 不可与后联>
"们性员子上下中内外化者家儿年月日时分秒街路村";
  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

SUFLINKHZ[2 * NUM_SUFLINKHZ + 2] = <以下单字为: 只可与后联, 不可与前联>
"不在这从到那哪第各每某本总当由如以为被使更且指于但将可应会该此全很都近约";
  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
  
***************************************************************************************/

/*
**  Uniform pwSlctHz first, find these User Defined Cizu, and add them to UdCizu.dat.
**  Call AddUdCizu(JWORD* pwHz2244, JINT nLen) to add this Cizu.
*/
VOID ProcUdCizu(SesGuiElement* pSge)
{
	JINT    i, j, k, m, w;
	JINT    nOrgStep, nUnifStep;
	JWORD   wTmp[10], wTmpBak[20];
	JINT    nTmpLen, nHzNum;
	JINT    nTypeSlct[8];              /* Max Length of User defined Cizu is 8 */

	nOrgStep   = pSge->nSlctSteps;
	/* Uniform pwSlctHz */
	UniformSlctHz(pSge);
	nUnifStep  = pSge->nSlctSteps;
	
	/* NOT JwordValidLen() Here. Don't count 0x0009 */
	nHzNum     = JwordHanziLen(pSge->pwSlctHz, UTWO);
	
	assert(nUnifStep != 0);
	
	/*
	**  以下 IF...ELSE... 逻辑中有重叠的情况, 为清晰起见, 分别列出. 
	**  如果归一为一个选择, 则立即返回.
	*/
	if (nUnifStep <= 1)
		return;
	
	if ((nOrgStep == nHzNum) && (nHzNum <= 8) && (nUnifStep > 1))
	{
		memset (wTmp, '\0', 10 * sizeof(JWORD));
		nTmpLen  = 0;
		for (i = 0; i < nUnifStep; i++)
			nTmpLen += GetNSelect(i, nUnifStep, pSge->pwSlctHz, &(wTmp[nTmpLen]));

		AddUdc (wTmp, nHzNum);
		return;
	}
	
	/*
	**  All condition OF  nHzNum <= 4, except that ((nHzNum == 4) && (HasNonLinkHz))
	**                AND nHzNum > 5, except nUnifStep is not two small.
	**  在不被归一为单个词组的情况下=> 双字和三字一定构成词，
	**                                 没有NONLINKHZ的四字也一定被定义为词.
	**                                 5 ~ 8字时,如果其中最多只有一个双字词, 即, 没有三字的情况, 
	**                                           其他均为单字, 且不是NONLINKHZ, 也被定义为词. 
	**  否则, 进入后面的处理过程.
	*/
	if ( (nHzNum <= 3)                                                           || 
	     ((nHzNum == 4)  && (!HasNonLinkHz(pSge->pwSlctHz, pSge->nSlctSteps)))   || 
	     (((nHzNum >= 5) && (nHzNum <= 8))&& (nOrgStep >= (nHzNum - 1)) && 
	     (nUnifStep >= (nHzNum - 1)) && (!HasNonLinkHz(pSge->pwSlctHz, pSge->nSlctSteps)))
	   )
	{
		memset (wTmp, '\0', 10 * sizeof(JWORD));
		nTmpLen  = 0;
		for (i = 0; i < nUnifStep; i++)
			nTmpLen += GetNSelect(i, nUnifStep, pSge->pwSlctHz, &(wTmp[nTmpLen]));
	
		AddUdc (wTmp, nHzNum);
		return;
	}

	/*
	**  此处处理包括: 四字中有NONLINKHZ的情况,
	**                5 ~ 8字中有多个双字词, 或有三字词的情况, 或有NONLINKHZ的情况, 
	**                以及在更长的其他所有情况.
	**
	**  NONLINKHZ  PRELINKHZ  SUFLINKHZ  NORMLINKHZ
	**  HZ2CIZU    HZ3CIZU    HZ48CIZU
	**  处理办法:     STEP1: 首先取最长8个字, 或者以NONLINKHZ分开, 或者以大于等于四字的已有词分开.
	**                       规定: PRELINKHZ不可与前面的四字以上已有词联结, SUFLINKHZ不可与后面的
	**                             四字以上已有词联结, 即, 划分出的任何单元中, 任何单字的前后四字
	**                             以上已有词或NONLINKHZ.
	**                       如果第一个为PRELINK, 则继续跳过, 如果第一个为SUFLINK, 则一定取下一个,
	**                             除非下一个为四字以上已有词, 否则双双跳过.
	**                STEP2: 从前往后进行处理, 如果第一个是单字, 第二个为双字或三字已有词, 则
	**  #define NUM_NONLINKHZ   16
	**  #define NUM_PRELINKHZ   22
	**  #define NUM_SUFLINKHZ   36
	*/
	for (i = 0; i < nUnifStep;  )
	{
		/* Get maximum 8 types of the following selections */
		for (j = 0; j < 8; j++)
			nTypeSlct[j] = TypeOfNSelect (i + j, pSge->pwSlctHz, nUnifStep);
			
		/* >= 4 Phrase or NonLinkHz */
		if ((nTypeSlct[0] == SLCT_TYPE_MFOURHZ) || (nTypeSlct[0] == SLCT_TYPE_NONLINK))
		{
			i++;
			continue;
		}
		
		else if ((nTypeSlct[0] == SLCT_TYPE_PRELINK) || (nTypeSlct[0] == SLCT_TYPE_SUFLINK) 
			|| (nTypeSlct[0] == SLCT_TYPE_NORMHZ))
		{
			m = k = 1;      /* Count for single Hanzi */
			for (j = 1; j < 8; j++)
			{
				if ((nTypeSlct[j] == SLCT_TYPE_PRELINK) || (nTypeSlct[j] == SLCT_TYPE_SUFLINK) 
					|| (nTypeSlct[j] == SLCT_TYPE_NORMHZ))
				{
					m++;
					k++;
				}
				else
				{
					if (nTypeSlct[j - 1] == SLCT_TYPE_SUFLINK)
					{
						if (k > 0)
							k--;
					}
					break;
				}
			}
		
			/* Only a single Hanzi before other */
			if (m == 1)      /* Both (k == 0) || (k == 1) */
			{
				if ((nTypeSlct[1] == SLCT_TYPE_TWOHZ) || (nTypeSlct[1] == SLCT_TYPE_THREEHZ))
				{
					memset (wTmp, '\0', 10 * sizeof(JWORD));
					nTmpLen  = 0;
					nTmpLen += GetNSelect(i, nUnifStep, pSge->pwSlctHz, &(wTmp[nTmpLen]));
					nTmpLen += GetNSelect(i + 1, nUnifStep, pSge->pwSlctHz, &(wTmp[nTmpLen]));
					
					AddUdc (wTmp, nTmpLen);
				}
				
				i++;
				continue;
			}
			
			/* Multiple Single Hanzi Connected!! Concentrated them into a single Phrase */
			memset (wTmp, '\0', 10 * sizeof(JWORD));
			nTmpLen  = 0;
			for (j = i; j < (i + k); j++)
				nTmpLen += GetNSelect(j, nUnifStep, pSge->pwSlctHz, &(wTmp[nTmpLen]));
			
			AddUdc (wTmp, nTmpLen);
			i += k;
			continue;
		}
		else if ((nTypeSlct[0] == SLCT_TYPE_TWOHZ) || (nTypeSlct[0] == SLCT_TYPE_THREEHZ))
		{
			if (nTypeSlct[1] == SLCT_TYPE_PRELINK)
			{
				memset (wTmp, '\0', 10 * sizeof(JWORD));
				nTmpLen  = 0;
				nTmpLen += GetNSelect(i, nUnifStep, pSge->pwSlctHz, &(wTmp[nTmpLen]));
				nTmpLen += GetNSelect(i + 1, nUnifStep, pSge->pwSlctHz, &(wTmp[nTmpLen]));

				AddUdc (wTmp, nTmpLen);

				i += 2;
				continue;
			}
			else if (nTypeSlct[1] == SLCT_TYPE_NORMHZ)
			{
				memset (wTmp, '\0', 10 * sizeof(JWORD));
				nTmpLen  = 0;
				nTmpLen += GetNSelect(i, nUnifStep, pSge->pwSlctHz, &(wTmp[nTmpLen]));
				nTmpLen += GetNSelect(i + 1, nUnifStep, pSge->pwSlctHz, &(wTmp[nTmpLen]));

				AddUdc (wTmp, nTmpLen);

				i++;
				continue;
			}
			else
			{
				i++;
				continue;
			}
		}
		else
		{
			i++;
			continue;
		}
	}
	
	return;
}


/*
**  Adjust pSge->pwSlctHz and pSge->nSlctSteps to make seperated selected Hanzi
**  to be a single Hanzi. For example, "中", "国", "人" was uniformed as "中国人".
**  Atfer this uniformation, CALL AdjustFreq("中国人") also.
**  pSge->nSlctSteps was adjusted also.
**  pSge->pwSlctHz was seperated by 0x0009 still.
**         ________
**        /  <-----\
**                   ______  _____
**                  / <----\/ <---\
**        OO O OOO OOOO O O OOO OO O  ( Random pwSlctHz )
**
*/
VOID UniformSlctHz(SesGuiElement* pSge)
{
	JINT    nOrgStep;
	JWORD   wTmpAllSlct[UTWO];
	JINT    nUnifPos, nUnifStep;
	JWORD   wCombCizu[20], wThisCizu[10];
	JINT    nTmpLen;
	JINT    nEndPos;
	JINT    i, j, k;
	
	memset (wTmpAllSlct,  '\0', UTWO * sizeof(JWORD));
	memset (wCombCizu,    '\0', 20 * sizeof(JWORD));
	memset (wThisCizu,    '\0', 10 * sizeof(JWORD));
	
	nOrgStep   = pSge->nSlctSteps;
	nUnifPos   = 0;
	nUnifStep  = 0;
	
	/* No i++ in this FOR sentence */
	for (i = 0; i < nOrgStep;  )
	{
		memset (wCombCizu,    '\0', 20 * sizeof(JWORD));
		memset (wThisCizu,    '\0', 10 * sizeof(JWORD));

		/* Calculate the end position which make the full length large than 8 */
		nTmpLen  = 0;
		for (j = i; (j < nOrgStep) && (nTmpLen <= 8); j++)
			nTmpLen += GetNSelect(j, nOrgStep, pSge->pwSlctHz, wThisCizu);
		nEndPos = j - 1;
		
		for (k = nEndPos; k >= i; k--)       /* To be BROKEN */
		{
			memset (wCombCizu, '\0', 20 * sizeof(JWORD));
			nTmpLen = 0;
			for(j = i; j <= k; j++)
				nTmpLen += GetNSelect (j, nOrgStep, pSge->pwSlctHz, &(wCombCizu[nTmpLen]));
			
			if ( IsCizuExist(wCombCizu, nTmpLen) != NON_EXIST_CIZU )
			{
				/* 
				**  Adjust Frequence ALSO!! Single Hanzi is already adjusted, 
				**  No more adjustment again.
				*/
				if (nTmpLen > 1)
					AdjustFreq(wCombCizu, nTmpLen);
				
				i = k + 1;
				JwordNCpy( &(wTmpAllSlct[nUnifPos]), wCombCizu, nTmpLen);
#ifdef _DEBUG				
				JwordInfo( &(wTmpAllSlct[nUnifPos]), 40);
#endif
				/*
				**  Append a 0x0009 after Each Uniformed Cizu Also. (Like in pSge->pwSlctHz(). )
				*/
				wTmpAllSlct[nUnifPos + nTmpLen] = 0x0009;
				nUnifPos  += (nTmpLen + 1);
				nUnifStep ++;
				break;                /* break the FOR(k) recycle */
			}
		}
	}
	
	memset(pSge->pwSlctHz, '\0', UTWO * sizeof(JWORD));
	JwordNCpy (pSge->pwSlctHz, wTmpAllSlct, UTWO);
	pSge->nSlctSteps = nUnifStep;
}


/*
**  Get the Specified Selection Hz2244 in pwSlctHz to pwUdcUnit.
**  0x0009 NO LONGER EXISTING!!
*/
JINT GetNSelect(JINT nXrd, JINT nTotalStep, JWORD* pwSlctHz, JWORD* pwUdcUnit)
{
	JINT    i, j, k, nUnitLen;
	
	assert((nXrd >= 0) && (nXrd < nTotalStep));
	
	j = k = nUnitLen = 0;
	for (i = 0; i < nTotalStep; )
	{
		if (i == nXrd)
		{
			while (pwSlctHz[j] != 0x0009)
			{
				pwUdcUnit[k++] = pwSlctHz[j++];
				nUnitLen++;
			}
			i++;
			break;    /* BREAK the FOR sentence */
		}
		else    /* i != nXrd */
		{
			if (pwSlctHz[j] == 0x0009)
				i++;
			j++;
		}
	}
	
	return nUnitLen;
}

/*
**  Determine the type of this selection.
**  One of following defined type.
**  
	#define SLCT_TYPE_INVALID     0
	#define SLCT_TYPE_NONLINK     1
	#define SLCT_TYPE_PRELINK     2
	#define SLCT_TYPE_SUFLINK     3
	#define SLCT_TYPE_NORMHZ      4
	#define SLCT_TYPE_TWOHZ       5
	#define SLCT_TYPE_THREEHZ     6
	#define SLCT_TYPE_MFOURHZ     7
*/
JINT TypeOfNSelect (JINT nXrd, JWORD* pwSlctHz, JINT nTotalSteps)
{
	JWORD    wTmp[10];
	JINT     nLen;
	
	if ((nXrd >= nTotalSteps) || (nXrd < 0))
		return SLCT_TYPE_INVALID;
	
	memset (wTmp, '\0', 10 * sizeof(JWORD));
	nLen  = GetNSelect (nXrd, nTotalSteps, pwSlctHz, wTmp);
	
	if (nLen >= 4)
		return SLCT_TYPE_MFOURHZ;
	if (nLen == 3)
		return SLCT_TYPE_THREEHZ;
	if (nLen == 2)
		return SLCT_TYPE_TWOHZ;
	if (nLen == 1)
	{
		if (IsXrdNonLinkHz(nXrd, pwSlctHz, nTotalSteps) == TRUE)
			return SLCT_TYPE_NONLINK;
		if (IsXrdPreLinkHz(nXrd, pwSlctHz, nTotalSteps) == TRUE)
			return SLCT_TYPE_PRELINK;
		if (IsXrdSufLinkHz(nXrd, pwSlctHz, nTotalSteps) == TRUE)
			return SLCT_TYPE_SUFLINK;
		return SLCT_TYPE_NORMHZ;
	}
	
	return SLCT_TYPE_INVALID;
}


/*
**  Check to see whether there is at least one NONLINKHZ selection among nSteps Selection.
**  If there IS,    return TRUE
**  else (IS NOT),  return FALSE
**  NONLINKHZ was defined in file <PyBasic.h>, 
*/
JINT HasNonLinkHz(JWORD* pwSlctHz, JINT nTotalSteps)
{
	JINT    i;
	JINT    nRet;
	
	nRet = FALSE;
	for (i = 0; i < nTotalSteps; i++)
	{
		nRet = IsXrdNonLinkHz (i, pwSlctHz, nTotalSteps);
		if (nRet == TRUE)
			break;
	}
	
	return nRet;
}


/*
**  Determine if this Seletion is NONLINKHZ.
**  If yes, return TRUE, else, return FALSE.
**  NONLINKHZ was defined in file <PyBasic.h>
*/
JINT IsXrdNonLinkHz(JINT nXrd, JWORD* pwSlctHz, JINT nTotalSteps)
{
	JWORD    wTmp[10], wHz;
	JINT     nLen;
	JINT     nRet;
	JINT     i;
	
	nRet  = FALSE;
	memset (wTmp, '\0', 10 * sizeof(JWORD));
	nLen  = GetNSelect (nXrd, nTotalSteps, pwSlctHz, wTmp);
	if (nLen == 1)
	{
		for (i = 0; i < NUM_NONLINKHZ; i++)
		{
			wHz = (JWORD)((NONLINKHZ[2 * i] << 8) + NONLINKHZ[2 * i + 1]);
			if (wTmp[0] == wHz)
			{
				nRet = TRUE;
				return nRet;
			}
		}
	}
	
	return nRet;
}

/*
**  Is this PRELINKHZ ? Same as IsXrdNonLinkHz
*/
JINT IsXrdPreLinkHz(JINT nXrd, JWORD* pwSlctHz, JINT nTotalSteps)
{
	JWORD    wTmp[10], wHz;
	JINT     nLen;
	JINT     nRet;
	JINT     i;
	
	nRet  = FALSE;
	memset (wTmp, '\0', 10 * sizeof(JWORD));
	nLen  = GetNSelect (nXrd, nTotalSteps, pwSlctHz, wTmp);
	if (nLen == 1)
	{
		for (i = 0; i < NUM_PRELINKHZ; i++)
		{
			wHz = (JWORD)((PRELINKHZ[2 * i] << 8) + PRELINKHZ[2 * i + 1]);
			if (wTmp[0] == wHz)
			{
				nRet = TRUE;
				return nRet;
			}
		}
	}
	
	return nRet;
}


/*
**  Is this SUFLINKHZ ? Same as IsXrdNonLinkHz
*/
JINT IsXrdSufLinkHz(JINT nXrd, JWORD* pwSlctHz, JINT nTotalSteps)
{
	JWORD    wTmp[10], wHz;
	JINT     nLen;
	JINT     nRet;
	JINT     i;
	
	nRet  = FALSE;
	memset (wTmp, '\0', 10 * sizeof(JWORD));
	nLen  = GetNSelect (nXrd, nTotalSteps, pwSlctHz, wTmp);
	if (nLen == 1)
	{
		for (i = 0; i < NUM_SUFLINKHZ; i++)
		{
			wHz = (JWORD)((SUFLINKHZ[2 * i] << 8) + SUFLINKHZ[2 * i + 1]);
			if (wTmp[0] == wHz)
			{
				nRet = TRUE;
				return nRet;
			}
		}
	}
	
	return nRet;
}


/*
**  Read out all those data in System Ciku file to pCkAll.
*/
JINT ReadUdcData(CHAR* szUdcName)
{
	FILE*   pfUdc;
	JINT    i, k, nTmp;
	JINT    nFileSize;
	JINT    nWarpFlag;     /* Flag to indicate whether it is necessary to */
	
	nWarpFlag = FALSE;

	pfUdc = fopen(szUdcName, "rb");
	if (pfUdc == NULL)
	{
		return FALSE;
	}
	
	fseek(pfUdc, 0, SEEK_SET);
	if ((JINT)fread (&(udcAll.udcfh), 1, sizeof(UdCikuHeader), pfUdc) != sizeof(UdCikuHeader) )
	{
		fclose(pfUdc);
		return FALSE;
	}
	
	/* Check Magic Word in Header */
	if ((udcAll.udcfh.nMagicDescHi != 0x35303539) || (udcAll.udcfh.nMagicDescLow != 0x34333442))
	{
		/* Is SPARC or x86 File? */
		if ((udcAll.udcfh.nMagicDescHi == 0x39353035) && (udcAll.udcfh.nMagicDescLow == 0x42343334))
		{
			nWarpFlag = TRUE;
		}
		else
		{
			fclose(pfUdc);
			return FALSE;
		}
	}

	if (nWarpFlag == TRUE)
		WarpCikuHeader((CikuHeader *)&(udcAll.udcfh));

	nFileSize = udcAll.udcfh.nFileSize;
	
	fseek(pfUdc, 0, SEEK_END);
	if (nFileSize != ftell(pfUdc))
	{
		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))
	{
		fclose(pfUdc);
		return FALSE;
	}
	
	if (nWarpFlag == TRUE)
		WarpIndex( (ShIndex *)(&(udcAll.udci)) );

	/* 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)
	{
		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 )
	{
		fclose(pfUdc);
		return FALSE;
	}
	
	/* Warp pwUdcSh if necessary */
	if (nWarpFlag == TRUE)
	{
		for (i = 0; i < nTmp; i++)
			WarpByte ( (VOID*)((JWORD*)(udcAll.pwUdcSh) + i), 2);
	}

	/* 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)
		{
			fclose(pfUdc);
			return FALSE;
		}
		
		if (nWarpFlag == TRUE)
		{
			for (k = 0; k < nTmp; k++)
				WarpByte ( (VOID*)((JWORD*)(udcAll.pwUdc28[i]) + k), 2);
		}
	}
	
	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;
}


/*
**  Free Memory which was allocated for udcAll.pwUdcSh and udcAll.pwUdc28[NUM_YINJIE].
**  This function can only be called After QUIT this Input Method.
*/
VOID FreeUdcData()
{
	JINT    i;

	free (udcAll.pwUdcSh);
	udcAll.pwUdcSh = NULL;

	for (i = 0; i < NUM_YINJIE; i++)
	{
		free (udcAll.pwUdc28[i]);
		udcAll.pwUdc28[i] = NULL;
	}
}


/*
**  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 = GbkHz2244ToYj(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)
	{
#ifdef _DRAW_IM_WIN_H
		XBell (pDspIme, 100);
#endif
		return FALSE;
	}

	nFirstYj = GbkHz2244ToYj(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)
	{
#ifdef _DRAW_IM_WIN_H
		XBell (pDspIme, 100);
#endif
		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;
}

/*
**  Init Structure UdcCandi. UdcCandi is an element of struct SesElement.
**  This function is called in InitSge().
*/
VOID InitStructUc(UdcCandi* puc)
{
	JINT    i;

	puc->nNumSpecCandi   = 0;
	puc->nNumUdc28Candi  = 0;
	puc->nSizUdc28Candi  = 0;

	for (i = 0; i < 6; i++)
		puc->pwSpecCandi[i] = 0x0000;

	free (puc->pwUdc28Candi);
	puc->pwUdc28Candi    = NULL;
}

