Milán Major

netscape-revival

1 branch
Code

lib/libi18n/npc.c

#include "unicpriv.h"
#include "intlpriv.h"
#include "npc.h"


extern int MK_OUT_OF_MEMORY;


#ifdef XP_MAC
#define UTF8_1_CSID 	CS_MAC_ROMAN
#else
#define UTF8_1_CSID  	CS_LATIN1
#endif	


/*==========================================================================
		Table to Map NPC First Byte to Char Set ID
==========================================================================*/
int16	npctocsid[MAXCSIDINNPC] =
{
	CS_DEFAULT,	CS_ASCII,	CS_LATIN1,	CS_JIS,	CS_SJIS,	CS_EUCJP,	CS_MAC_ROMAN,	CS_BIG5,	
	CS_GB_8BIT,	CS_CNS_8BIT,	CS_LATIN2,	CS_MAC_CE,	CS_KSC_8BIT,	CS_2022_KR, 	CS_8859_3,	CS_8859_4,	
	CS_8859_5,	CS_8859_6,	CS_8859_7,	CS_8859_8,	CS_8859_9,	CS_SYMBOL,	CS_DINGBATS,	CS_DECTECH,
	CS_CNS11643_1,	CS_CNS11643_2,	CS_JISX0208,	CS_JISX0201,	CS_KSC5601,	CS_TIS620,	CS_JISX0212,	CS_GB2312,
	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_X_BIG5,	CS_UNKNOWN,	CS_KOI8_R,
	CS_MAC_CYRILLIC,	CS_CP_1251,	CS_MAC_GREEK,	CS_CP_1253,	CS_CP_1250,	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,
	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,
	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_UNKNOWN,	CS_USER_DEFINED_ENCODING,	CS_UNKNOWN,
};
/*==========================================================================
		MACRO for npctocsid map
==========================================================================*/
/*==========================================================================
		MACRO for npcmap


	Let's make a 256 array which contain 		
	(1) the index to the npcXXXX function		4 bits	
	(2) npcXXXX function context				4 bits
			npcError -		not used
			npcOneByte - 	not used 
			npcTwoByte - 	not used 
			npcMultiByte - 	csinfo_tbl index
			npcUTF8_1 - 	not used
			npcUTF8_2 - 	not used
			npcUTF8_3 - 	not used
			npcUTF8_4 - 	not used
			npcUTF8_5 - 	not used
			npcUTF8_6 - 	not used			
==========================================================================*/
#define NPCIndex(fb)		((npcmap[fb]) & 0x0F)
#define NPCContext(fb)		((npcmap[fb] >> 4) & 0x0F)
#define NCELL(idx,ctx)		((ctx << 4) | (idx))
/*--------------------------------------------------------------------------
		enum for the method index
--------------------------------------------------------------------------*/
enum {
	npcErrI = 0,
	npcSBI,
	npcTBI,
	npcMBI,
	npcUTF8_1I,
	npcUTF8_2I,
	npcUTF8_3I,
	npcUTF8_4I,
	npcUTF8_5I,
	npcUTF8_6I,
	npcNum
};

/*--------------------------------------------------------------------------
		enum for the multibyte csinfo index
--------------------------------------------------------------------------*/
/*	This have to correspond to the sequence of csinfo_tbl in fe_ccc.c */
enum {
	csinfoSJISIdx = 0,
	/*	csinfoEUCJPIdx = 1,	This should never be used */
	csinfoKSC_8BITIdx = 2,
	csinfoGB_8BITIdx = 3,
	/* csinfoCNS_8BITIdx = 4, This should never be used */
	csinfoBIG5Idx = 5,
	csinfoCNS11643_1Idx = 6,
	csinfoCNS11643_2Idx = 7,
	csinfoJISX0208Idx = 8,
	csinfoKSC5601Idx = 9,
	csinfoJISX0212Idx = 10,
	csinfoGB2312Idx = 11
};

/*--------------------------------------------------------------------------
		enum for the method index and csinfo index
--------------------------------------------------------------------------*/
enum {
	npcSJIS = 		NCELL(npcMBI,csinfoSJISIdx),
	npcKSC_8BIT = 	NCELL(npcMBI,csinfoKSC_8BITIdx),
	npcGB_8BIT = 	NCELL(npcMBI,csinfoGB_8BITIdx),
	npcBIG5 = 		NCELL(npcMBI,csinfoBIG5Idx),
	npcCNS11643_1 = NCELL(npcMBI,csinfoCNS11643_1Idx),
	npcCNS11643_2 = NCELL(npcMBI,csinfoCNS11643_2Idx),
	npcJISX0208 = 	NCELL(npcMBI,csinfoJISX0208Idx),
	npcKSC5601 = 	NCELL(npcMBI,csinfoKSC5601Idx),
	npcJISX0212 = 	NCELL(npcMBI,csinfoJISX0212Idx),
	npcGB2312 = 	NCELL(npcMBI,csinfoGB2312Idx)
};
/*--------------------------------------------------------------------------
		npcmap : Map first byte of npc to [npc method index + method context ]
--------------------------------------------------------------------------*/
unsigned char npcmap[256] = {
/*	-------------------	Range for UTF8 One bytes	------------------------ */						
/* 00-07 */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 08-0F */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 10-17 */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 18-1F */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 20-27 */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 28-2F */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 30-37 */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 38-3F */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 40-47 */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 48-4F */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 50-57 */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 58-5F */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 60-67 */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 68-6F */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 70-77 */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/* 78-7F */	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,	npcUTF8_1I,
/*	-------------------	Range for non-Unicode encoding	-------------------- */						
/* 80-87 */	npcSBI,		npcSBI,		npcSBI,		npcErrI,	npcSJIS,	npcErrI,	npcSBI,		npcBIG5,
/* 88-8F */	npcGB_8BIT,	npcErrI,	npcSBI,		npcSBI,		npcKSC_8BIT,npcErrI,	npcSBI,		npcSBI,
/* 90-97 */	npcSBI,		npcSBI,		npcSBI,		npcSBI,		npcSBI,		npcSBI,		npcSBI,		npcSBI,
/* 98-9F */	npcCNS11643_1,	npcCNS11643_2,	npcJISX0208,	npcSBI,	npcKSC5601,	npcSBI,	npcJISX0212,	npcGB2312,
/* A0-A7 */	npcErrI,	npcErrI,	npcErrI,	npcErrI,	npcErrI,	npcBIG5,	npcErrI,	npcSBI,
/* A8-AF */	npcSBI,		npcSBI,		npcSBI,		npcSBI,	npcErrI,	npcErrI,	npcErrI,	npcErrI,
/* B0-B7 */	npcErrI,	npcErrI,	npcErrI,	npcErrI,	npcErrI,	npcErrI,	npcErrI,	npcErrI,
/* B8-BF */	npcErrI,	npcErrI,	npcErrI,	npcErrI,	npcErrI,	npcErrI,	npcSBI,		npcErrI,
/*	-------------------	Range for UTF8 Two bytes	------------------------ */						
/* C0-C7 */	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,
/* C8-CF */	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,
/* D0-D7 */	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,
/* D8-DF */	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,	npcUTF8_2I,
/*	-------------------	Range for UTF8 Three bytes	------------------------ */						
/* E0-E7 */	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,
/* E8-EF */	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,	npcUTF8_3I,
/*	-------------------	Range for UTF8 Four bytes	------------------------ */						
/* F0-F7 */	npcUTF8_4I,	npcUTF8_4I,	npcUTF8_4I,	npcUTF8_4I,	npcUTF8_4I,	npcUTF8_4I,	npcUTF8_4I,	npcUTF8_4I,
/*	-------------------	Range for UTF8 Five and Six bytes	---------------- */						
/* F8-FF */	npcUTF8_5I,	npcUTF8_5I,	npcUTF8_5I,	npcUTF8_5I,	npcUTF8_6I,	npcUTF8_6I,	npcErrI,	npcErrI
};
/*==========================================================================
		MACRO for Multibyte length
==========================================================================*/
extern csinfo_t csinfo_tbl[];
#define MBCheck(i,j,fb)			( (csinfo_tbl[i].enc[j].range[0] <= (fb) ) && (csinfo_tbl[i].enc[j].range[1] >= (fb) ))
#define MBRange(i,j,fb,e)		( MBCheck(i,j,fb) ? csinfo_tbl[i].enc[j].bytes :(e))
#define MBLen(i,fb)				( MBRange(i,0,fb, MBRange(i,1,fb,MBRange(i,2,fb,1))))
/*int16 MBLen(int16 i, unsigned char fb)
{
	int j;
	for(j=0;j<3;j++)
	{
		XP_Bool cas1,cas2;
		int16 l,h;
		csinfo_t *pt;
		pt = &csinfo_tbl[i];
		l = pt->enc[j].range[0];
		h = pt->enc[j].range[1];
		cas1 =( l <= fb);
		cas2 =( fb <= h);
		if(cas1 && cas2)
			return csinfo_tbl[i].enc[j].bytes;
	}
	return 1;
}
*/
/*==========================================================================
		ToNPC
		This function will only be called when the csid is not UTF8 or UCS2
*/		
/*
	We need special case for EUC
	It have to convert 
		CS_EUC_JP			to CS_JISX0208, CS_JISX0201, CS_JISX0212	if it is XP_UNIX
		CS_CNS_8BIT			to CS_LATIN1, CS_CNS11643_P1, CS_CNS11643_P2
		CS_GB_8BIT			to CS_LATIN1, CS_GB2312
		CS_KSC_8BIT			to CS_LATIN1, CS_KSC5601
		
*/
#define CSIDTONPCFB(csid)		(((csid) & 0x3F) | 0x80)
#define YEN_SIGN 0x5c

XP_Bool ToNPC(unsigned char *in, uint16 inlen, uint16* inread, unsigned char *out, uint16 outbuflen, uint16* outlen, uint16 incsid)
{
	unsigned char npcfb = CSIDTONPCFB(incsid);
	uint16 il,ol;
	il = 0;
	ol = 0;
	switch(incsid)
	{	
		case CS_UCS2:
			{
				/* we may have problem with BYTE ORDER here. Since we cannot store state information for the converter. 
				   We need to change the interface later to make the converter maintain state.	
				   		State = BYTE_ORDER_UNKNOWN
				   				BYTE_ORDER_NO_SWAP
				   				BYTE_ORDER_NEED_SWAP
				   Currently, we assume it is always BYTE_ORDER_NO_SWAP
				*/
				uint16 ucs2; 
				for(;il+1 < inlen; il+=2)
				{
					ucs2 = ( in[il] << 8 ) | in[il+1];
					
					if(ucs2 < 0x80)				/*	case of one byte UTF8 */
					{
						if(ol< outbuflen)
							out[ol++] = ucs2 & 0x7F;
						else
							break;
					}
					else if(ucs2 < 0x800)		/*	case of two byte UTF8 */
					{
						if((ol+1)< outbuflen)
						{
							out[ol++] = 0xC0 | (( ucs2 >> 6 ) & 0x3F);
							out[ol++] = 0x80 | ( ucs2 & 0x3F);
						}
						else
							break;
					} else	if((ucs2 < 0xD800) || (0xE000 < ucs2 ))
					{				/*	case of three byte UTF8 */
						if((ol+2)< outbuflen)
						{
							out[ol++] = 0xE0 | (( ucs2 >> 12 ) & 0x0F);
							out[ol++] = 0x80 | (( ucs2 >> 6 )  & 0x3F);
							out[ol++] = 0x80 | ( ucs2 & 0x3F);
						}
						else
							break;
					}	
					else
					{			/*	If we just got a character of UTF-16 Low Half Zone, ignore it */
						if(ucs2 >= 0xDC00)	
						{
							/*	Error, eat two byte */
							/*	Do NOTHING HERE */
						}
						else 	/*	Handle UTF-16 High Half Zone */
						{	
							uint16 y ;
							if(il+3 < inlen)
							{
								y = ( in[il+2] << 8 ) | in[il+3];
								if(( 0xDC00 <= y) && (y < 0xE000))
								{
									uint32	t;
									t = ( ( ucs2 & 0x3FF ) << 10 ) | (y & 0x3FF ) | 0x10000;
									if((ol+2)< outbuflen)
									{
										out[ol++] = 0xE0 | (( t >> 12 ) & 0x0F);
										out[ol++] = 0x80 | (( t >> 6 )  & 0x3F);
										out[ol++] = 0x80 | ( t & 0x3F);
									}
								} else
								{
									/*	Error, eat two byte */
									/*	Do NOTHING HERE */
								}
								il+=2;
							}
							else
								break;
						}	
					}
				}
			}
			break;
		case CS_UCS4:
			{
				/* we may have problem with BYTE ORDER here. Since we cannot store state information for the converter. 
				   We need to change the interface later to make the converter maintain state.	
				   		State = BYTE_ORDER_UNKNOWN
				   				BYTE_ORDER_NO_SWAP
				   				BYTE_ORDER_NEED_SWAP
				   Currently, we assume it is always BYTE_ORDER_NO_SWAP
				*/
				uint32 ucs4; 
				for(;il+3 < inlen; il+=4)
				{
					ucs4 = ( in[il] << 24 ) | ( in[il+1] << 16 ) | ( in[il+2] << 8 ) | in[il+3];
					if(ucs4 < 0x80)				/*	case of one bytes UTF8 */
					{
						if(ol< outbuflen)
							out[ol++] = ucs4 & 0x7F;
						else
							break;
					}
					else if(ucs4 < 0x800)		/*	case of two bytes UTF8 */
					{
						if((ol+1)< outbuflen)
						{
							out[ol++] = 0xC0 | (( ucs4 >> 6 ) & 0x3F);
							out[ol++] = 0x80 | ( ucs4 & 0x3F);
						}
						else
							break;
					}
					else if(ucs4 < 0x10000)	/*	case of three bytes UTF8 */
					{
						if((ucs4 < 0xD800) || (0xE000 < ucs4 ))
						{
							if((ol+2)< outbuflen)
							{
								out[ol++] = 0xE0 | (( ucs4 >> 12 ) & 0x0F);
								out[ol++] = 0x80 | (( ucs4 >> 6 )  & 0x3F);
								out[ol++] = 0x80 | ( ucs4 & 0x3F);
							}
							else
								break;
						}
						else
						{			/*	If we just got a character of UTF-16 Low Half Zone, ignore it */
							if(ucs4 >= 0xDC00)	
							{
								/*	Error, eat two byte */
								/*	Do NOTHING HERE */
							}
							else 	/*	Handle UTF-16 High Half Zone */
							{	
								uint32 y ;
								if(il+7 < inlen)
								{
									y = ( in[il+4] << 24 ) | ( in[il+5] << 16 ) | ( in[il+6] << 8 ) | in[il+7];
									if(( 0xDC00 <= y) && (y < 0xE000))
									{
										uint32	t;
										t = ( ( ucs4 & 0x3FF ) << 10 ) | (y & 0x3FF ) | 0x10000;
										if((ol+2)< outbuflen)
										{
											out[ol++] = 0xE0 | (( t >> 12 ) & 0x0F);
											out[ol++] = 0x80 | (( t >> 6 )  & 0x3F);
											out[ol++] = 0x80 | ( t & 0x3F);
										}
									} else
									{
										/*	Error, eat two byte */
										/*	Do NOTHING HERE */
									}
									il+=4;
								}
								else
									break;
							}	
						}
					}
					else if(ucs4 < 0x200000)	/*	case of four bytes UTF8 */
					{
						if((ol+3)< outbuflen)
						{
							out[ol++] = 0xF0 | (( ucs4 >> 18 ) & 0x07);
							out[ol++] = 0x80 | (( ucs4 >> 12 ) & 0x3F);
							out[ol++] = 0x80 | (( ucs4 >> 6 )  & 0x3F);
							out[ol++] = 0x80 | ( ucs4 & 0x3F);
						}
						else
							break;
					}
					else if(ucs4 < 0x400000)	/*	case of five bytes UTF8 */
					{
						if((ol+4)< outbuflen)
						{
							out[ol++] = 0xF8 | (( ucs4 >> 24 ) & 0x03);
							out[ol++] = 0x80 | (( ucs4 >> 18 ) & 0x3F);
							out[ol++] = 0x80 | (( ucs4 >> 12 ) & 0x3F);
							out[ol++] = 0x80 | (( ucs4 >> 6 )  & 0x3F);
							out[ol++] = 0x80 | ( ucs4 & 0x3F);
						}
						else
							break;
					}
					else						/*	case of six bytes UTF8 */
					{
						if((ol+4)< outbuflen)
						{
							out[ol++] = 0xFC | (( ucs4 >> 30 ) & 0x01);
							out[ol++] = 0x80 | (( ucs4 >> 24 ) & 0x3F);
							out[ol++] = 0x80 | (( ucs4 >> 18 ) & 0x3F);
							out[ol++] = 0x80 | (( ucs4 >> 12 ) & 0x3F);
							out[ol++] = 0x80 | (( ucs4 >> 6 )  & 0x3F);
							out[ol++] = 0x80 | ( ucs4 & 0x3F);
						}
						else
							break;
					}
				}
			}
			break;
		case CS_UTF7:
				/*	Place holder for UTF7		*/
				/*	We don't support UTF7 yet 	*/
			XP_ASSERT(FALSE);
			break;
		case CS_UTF8:
			{	/* for UTF8, we just copy whatever in the in to out */
				uint len = (inlen > outbuflen) ? outbuflen : inlen;	/* Get the largest one */
				for(;il<len;)
					out[ol++] = in[il++];
			}
			break;
		
		/*	Multibyte */
		case CS_EUCJP:
			{
				unsigned char npcfb0201 = CSIDTONPCFB(CS_JISX0201);
				unsigned char npcfb0208 = CSIDTONPCFB(CS_JISX0208);
				unsigned char npcfb0212 = CSIDTONPCFB(CS_JISX0212);
				for(il=0,ol=0;il<inlen;)
				{
					if((in[il] < 0x80) && (in[il] != YEN_SIGN))	
					{
						if(ol < outbuflen)
							out[ol++] = in[il++];
						else	/*	not enough buffer, let's return */
							break;
					}
					else if (in[il] == YEN_SIGN) {
						if(((ol+1) < outbuflen))
						{
							out[ol++] = npcfb0201;
							out[ol++] = in[il++];
						}
						else {	/* full out buffer, return */
							break;
						}
					}
					else if (in[il] == SS2) {	/* half-width JIS 0201 kana */
						if(((il+1) < inlen) && ((ol+1) < outbuflen))
						{
							out[ol++] = npcfb0201;
							il++;				/* discard SS2 */
							out[ol++] = in[il++];
						}
						else {	/* full outbuf || incomplete inbuf, return */
							break;
						}
					}
					else if (in[il] == SS3) {	/* JIS 0212 */
						if(((il+2) < inlen) &&((ol+2) < outbuflen))
						{
							out[ol++] = npcfb0212;
							il++;				/* discard SS3 */
							out[ol++] = in[il++];
							out[ol++] = in[il++];
						}
						else {	/* full outbuf || incomplete inbuf, return */
							break;
						}
					}
					else {						/* JIS 0208 */
						if(((il+1) < inlen) && ((ol+2) < outbuflen))
						{
							out[ol++] = npcfb0208;
							out[ol++] = in[il++];
							out[ol++] = in[il++];
						}
						else {	/* full outbuf || incomplete inbuf, return */
							break;
						}
					}
				}
			}		
			break;
		
		case CS_CNS_8BIT:
			{
				unsigned char npcfb11643_1 = CSIDTONPCFB(CS_CNS11643_1);
				unsigned char npcfb11643_2 = CSIDTONPCFB(CS_CNS11643_2);
				for(il=0,ol=0;il<inlen;)
				{
					if(in[il] < 0x80)	
					{
						if(ol < outbuflen)
							out[ol++] = in[il++];
						else	/*	not enough buffer, let's return */
							break;
					}
					else if (in[il] == SS2) {	/* CNS11643_2 */
						if(((il+3) < inlen) &&((ol+2) < outbuflen))
						{
							switch(in[il+1])	/* Test Page Indicator */
							{
								case 0xA2:
									out[ol++] = npcfb11643_2;
									break;
								case 0xA1:	/* Handle the special case */
									out[ol++] = npcfb11643_1;
									break;
								/*  what we really should do is add npcfb11643_3 - npcfb11643_14
									here. For now, we simply convert everything in 
									Page 3 to Page 16 to Page 1 
								*/
								default:
									out[ol++] = npcfb11643_1;
									break;
							}
							il++;				/* discard SS3 */
							il++;				/* discard Page Indicator*/
							out[ol++] = in[il++];
							out[ol++] = in[il++];
						}
						else {	/* full outbuf || incomplete inbuf, return */
							break;
						}
					}
					else {						/*  CNS11643_1 */
						if(((il+1) < inlen) && ((ol+2) < outbuflen))
						{
							out[ol++] = npcfb11643_1;
							out[ol++] = in[il++];
							out[ol++] = in[il++];
						}
						else {	/* full outbuf || incomplete inbuf, return */
							break;
						}
					}
				}
			}		
			break;
		
		case CS_BIG5:
		case CS_GB_8BIT:
		case CS_KSC_8BIT:
			{
				uint16 csinfo_index = NPCContext(npcfb);
				for(il=0,ol=0;il<inlen;)
				{
					if(in[il] < 0x80)	
					{
						if(ol < outbuflen)
							out[ol++] = in[il++];
						else	/*	no enough buffer, let's return */
							break;
					}
					else 
					{
						uint16	L = MBLen(csinfo_index,in[il]);
						if(((ol+L) < outbuflen) && (il+L-1 < inlen))
						{
							int j;
							out[ol++] = npcfb;
							for(j=0;j<L;j++)							
								out[ol++] = in[il++];
						}
						else	/*	not enough buffer, let's return */
							break;
					}
				}
			}		
			break;

		case CS_SJIS:	/* Same as CS_BIG5, CS_GB_8BIT, and CS_GB_8BIT case except YEN SIGN handling */
			{
				uint16 csinfo_index = NPCContext(npcfb);
				for(il=0,ol=0;il<inlen;)
				{
					if((in[il] < 0x80) && (in[il] != YEN_SIGN))	
					{
						if(ol < outbuflen)
							out[ol++] = in[il++];
						else	/*	not enough buffer, let's return */
							break;
					}
					else 
					{
						uint16	L = MBLen(csinfo_index,in[il]);
						if(((ol+L) < outbuflen) && (il+L-1 < inlen))
						{
							int j;
							out[ol++] = npcfb;
							for(j=0;j<L;j++)					 		
								out[ol++] = in[il++];
						}
						else	/*	no enough buffer, let's return */
							break;
					}
				}
			}		
			break;
		default:	/*	Default is one byte */
			{
				for(il=0,ol=0; il < inlen ;)
				{
					if(in[il] < 0x80)
					{
						if(ol < outbuflen)
							out[ol++] = in[il++];
						else	/*	no enough buffer, let's return */
							break;
					}
					else
					{
						if(((ol+1) < outbuflen))
						{
							out[ol++] = npcfb;
							out[ol++] = in[il++];
						}
						else	/*	not enough buffer, let's return */
							break;
					}
				}
			}		
			break;
	}
	*inread = il;
	*outlen = ol;	
	return TRUE;
}

/*==========================================================================
		NPC Private function
==========================================================================*/


/*==========================================================================
		MACRO for UTF8 to UCS2 (or UCS4) conversion 

	UTF-8					UCS-4
	z < C0;					z
	z < E0; y				(z-C0) *2^6 + (y-80);
	z < F0; y; x;			(z-E0) *2^12 + (y-80) *2^6  + (x-80);
	
	z < F8; y; x; w;		(z-F0) *2^18 + (y-80) *2^12 + (x-80) *2^6  + (w-80);
	z < FC; y; x; w; v;		(z-F8) *2^24 + (y-80) *2^18 + (x-80) *2^12 + (w-80) *2^6 + (v-80);
	z; y; x; w; v; u;		(z-FC) *2^30 + (y-80) *2^24 + (x-80) *2^18 + (w-80) *2^12+ (v-80) *2^6 + (u-80);
==========================================================================*/
#define MXS(c,x,s)			(((c) - (x)) <<  (s))
#define M80S(c,s)			MXS(c,0x80,s)	
#define UTF8_1_to_UCS2(in)	((uint16) (in)[0])
#define UTF8_2_to_UCS2(in)	((uint16) (MXS((in)[0],0xC0, 6) | M80S((in)[1], 0)))
#define UTF8_3_to_UCS2(in)	((uint16) (MXS((in)[0],0xE0,12) | M80S((in)[1], 6) | M80S((in)[2], 0) ))
/*	
	untested but useful macros. Test them before you unmark them.
#define UTF8_4_to_UCS4(in)	((int32) (MXS((in)[0],0xF0,18) | M80S((in)[1],12) | M80S((in)[2], 6) | M80S((in)[3], 0) ))
#define UTF8_5_to_UCS4(in)	((int32) (MXS((in)[0],0xF8,24) | M80S((in)[1],18) | M80S((in)[2],12) | M80S((in)[3], 6) | M80S((in)[4], 0)  ))
#define UTF8_6_to_UCS4(in)	((int32) (MXS((in)[0],0xFC,30) | M80S((in)[1],24) | M80S((in)[2],18) | M80S((in)[3],12) | M80S((in)[4], 6) | M80S((in)[5],0)  ))
*/

XP_Bool
INTL_ConvertNPC(unsigned char *in, uint16 inlen, uint16 *inread,
	unsigned char *out, uint16 outbuflen, uint16 *outlen, int16 *outcsid)
{
	uint16 cinlen;
	uint16 cinread;
	uint16 coutbuflen;
	uint16 coutlen;
	XP_Bool csid_unknown = TRUE;
	uint16 thisidx;
	int16 thiscsid;
	
	int item;

	for(cinread = 0,coutlen = 0, cinlen = inlen,coutbuflen = outbuflen,item=0; 
			cinread < inlen;
			*outlen = coutlen,*inread = cinread,item++)
	{
		thisidx = NPCIndex(in[cinread]);
		switch(thisidx)
		{
			
			case npcSBI:	/*	In here we processs the non-ASCII portion of single byte character */
				{
					thiscsid =  NPCToCSID(in[cinread++]);	/* get csid from the first byte */
					if(csid_unknown)
					{
						*outcsid = thiscsid;				/* set csid if csid unknown */
						csid_unknown = FALSE;				/* now we know it */
					}
					else 
					{
						if(thiscsid != *outcsid )			/* return if csid is known and is differnt from this one */
							return (item>0);				/* if we already procress something, return true */
					}
			   		if((cinlen < 2) || (coutbuflen < 1))	/* return if boundary error */
			               return (item>0);					/* if we already procress something, return true */
			    	out[coutlen++] = in[cinread++];			/* Copy the second byte */
			    	coutbuflen--;							/* Adjust the coutbuflen and cinlen */
			    	cinlen -= 2;
		    	}
				/*	Continue the loop */
				break;
			case npcTBI:	/*	In here we processs two byte characters 
									(e.g. JIS0208, JIS0212, GB2312, KSC5601, CNS11643_1, CNS11643_2 ) 	*/
				{
					thiscsid =  NPCToCSID(in[cinread++]);	/* get csid from the first byte */
					if(csid_unknown)		
					{
						*outcsid = thiscsid;				/* set csid if csid unknown */
						csid_unknown = FALSE;				/* now we know it */
					}
					else 
					{
						if(thiscsid != *outcsid )			/* return if csid is known and is differnt from this one */
							return (item>0);				/* if we already procress something, return true */
					}
					if((cinlen < 3) || (coutbuflen < 2))	/* return if boundary error */
						return (item>0);					/* if we already procress something, return true */
					out[coutlen++] = in[cinread++];			/* Copy the second byte */
					out[coutlen++] = in[cinread++];			/* Copy the third byte */
					coutbuflen -= 2;						/* Adjust the coutbuflen and cinlen */
					cinlen -= 3;			
				}
				/*	Continue the loop */
				break;
			case npcMBI:	/*	In here we processs multi byte character (e.g. SJIS, BIG5, GB_8BIT, KSC_8BIT ) */
				{
					uint16 L;
					uint16 i;
					uint16 csinfo_index = NPCContext(in[cinread]);	/* get csinfo_index from the first byte */
					thiscsid =  NPCToCSID(in[cinread++]);			/* get csid from the first byte */
					if(csid_unknown)
					{
						*outcsid = thiscsid;						/* set csid if csid unknown */
						csid_unknown = FALSE;						/* now we know it */
					}
					else 
					{
						if(thiscsid != *outcsid )			/* return if csid is known and is differnt from this one */
							return  (item>0);				/* if we already procress something, return true */
					}
					if(cinlen < 2)							/* return if boundary error */
						return (item>0);					/* if we already procress something, return true */
					L = MBLen(csinfo_index,in[cinread]);	/* get length */
					
					/*	check length */
					if( (cinlen < L+1) || (coutbuflen <L))	/* return if boundary error */
						return (item>0);						/* if we already procress something, return true */
					for(i=0;i<L;i++)
						out[cinread++] = in[coutlen++];		/* Copy the rest byte */
					cinlen -= L+1;							/* Adjust the coutbuflen and cinlen */
					coutbuflen -= L;
				}
				/*	Continue the loop */
				break;
			case npcUTF8_1I:
				{
					thiscsid =  UTF8_1_CSID;
					if(csid_unknown)
					{
						*outcsid = thiscsid;				/* set csid if csid unknown */
						/* for ascii portion, although we set the outcsid, we still think
							we unknow csid so, the outcsid could be overwrite */
					}
					if((cinlen < 1) || (coutbuflen < 1))
						return (item>0);
					out[coutlen++] = in[cinread++];
				}
				/*	Continue the loop */
				break;
			case npcUTF8_2I:
				/*	In here, we handle the case for 2 bytes UTF8 */
				/*	It will return only process one NPC for UTF8 2 byte cases */
				/*  Later, we may change it so it can process more than one NPC  */
				{
					uint16 ucs2;
					if(item != 0)
						return TRUE;
					if(inlen < 2)
						return FALSE;
					*inread = 2;
					ucs2 = UTF8_2_to_UCS2(in);
					return UCS2_To_Other(ucs2,out,outbuflen,outlen,outcsid);
				}
				/*	return- don't continue the loop */
				break;
			case npcUTF8_3I:
				/*	In here, we handle the case for 3 bytes UTF8 */
				/*	It will return only process one NPC for UTF8 3 byte cases */
				/*  Later, we may change it so it can process more than one NPC  */
				{
					uint16 ucs2;
					if(item != 0)
						return TRUE;
					if(inlen < 3)
						return FALSE;
					*inread = 3;
					ucs2 = UTF8_3_to_UCS2(in);
					return UCS2_To_Other(ucs2,out,outbuflen,outlen,outcsid);
				}
				/*	return- don't continue the loop */
				break;
			case npcUTF8_4I:
			case npcUTF8_5I:
			case npcUTF8_6I:
				/*	In here, we handle the case for UCS4 */
				/*  Currently , we simply eat all UCS4 and generate a '?'	*/
				/*	Later, we can change it so it will generate something like "[U+XXXXXXXX]" */
				{
					uint16 ucs4inlen;
					thiscsid = UTF8_1_CSID;
					if(csid_unknown)
						*outcsid = thiscsid;
					else 
					{
						if(thiscsid != *outcsid )
							return (item>0);
					}
					switch(thisidx)
					{	
						case npcUTF8_4I:	ucs4inlen = 4; break;
						case npcUTF8_5I:	ucs4inlen = 5; break;
						case npcUTF8_6I:	ucs4inlen = 6; break;
					}
					if((cinlen < ucs4inlen) || (coutbuflen < 1))
						return (item>0);
					out[coutlen++] = '?';
					cinread += ucs4inlen;
				}
				/*	Continue the loop */
				break;
			case npcErrI:
			default:
				/*	In here, we handle Error cases */
				/*	We should never hit here unless something very wrong. */
				XP_ASSERT(FALSE);
				return FALSE;
				/*	return- don't continue the loop */
		}
	}	

	return TRUE;
}


unsigned char *
intl_ISO88591ToNPC(CCCDataObject *obj, const unsigned char *buf, int32 len)
{
	uint16		inread;
	uint16		outbuflen;
	int16		outcsid;
	uint16		outlen;
	unsigned char	*ret;

	if ((!obj) || (!buf) || (len < 0))
	{
		return NULL;
	}

	outbuflen = ((len * 2) + 1);
	ret = XP_ALLOC(outbuflen);
	if (!ret)
	{
		obj->retval = MK_OUT_OF_MEMORY;
		return NULL;
	}

	INTL_ConvertNPC((unsigned char *) buf, (uint16) len, &inread, ret,
		outbuflen - 1, &outlen, &outcsid);

	ret[outlen] = 0;
	obj->len = outlen;

	return ret;
}


#ifdef NOT_YET

unsigned char *
intl_2022KRToNPC(CCCDataObject *obj, const unsigned char *buf, int32 len)
{
}


unsigned char *
intl_ASCIIToNPC(CCCDataObject *obj, const unsigned char *buf, int32 len)
{
}


unsigned char *
intl_BIG5ToNPC(CCCDataObject *obj, const unsigned char *buf, int32 len)
{
}


unsigned char *
intl_EUCCNToNPC(CCCDataObject *obj, const unsigned char *buf, int32 len)
{
}


unsigned char *
intl_EUCJPToNPC(CCCDataObject *obj, const unsigned char *buf, int32 len)
{
}


unsigned char *
intl_EUCKRToNPC(CCCDataObject *obj, const unsigned char *buf, int32 len)
{
}


unsigned char *
intl_EUCTWToNPC(CCCDataObject *obj, const unsigned char *buf, int32 len)
{
}


unsigned char *
intl_ISO88592ToNPC(CCCDataObject *obj, const unsigned char *buf, int32 len)
{
}


unsigned char *
intl_JISToNPC(CCCDataObject *obj, const unsigned char *buf, int32 len)
{
}


unsigned char *
intl_SJISToNPC(CCCDataObject *obj, const unsigned char *buf, int32 len)
{
}

#endif /* NOT_YET */