2006-05-17 06:37:31 +04:00
|
|
|
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
2006-05-17 06:39:15 +04:00
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
2006-05-17 06:37:31 +04:00
|
|
|
*
|
2006-05-17 06:39:15 +04:00
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
2006-05-17 06:37:31 +04:00
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
2006-05-17 06:39:15 +04:00
|
|
|
* The Initial Developer of the Original Code is
|
2006-05-17 06:37:31 +04:00
|
|
|
* Netscape.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
2006-05-17 06:37:32 +04:00
|
|
|
* jeroen.dobbelaere@acunia.com
|
2006-05-17 06:37:31 +04:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
2006-05-17 06:39:15 +04:00
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
2006-05-17 06:37:31 +04:00
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
2006-05-17 06:39:15 +04:00
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
2006-05-17 06:37:31 +04:00
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
2006-05-17 06:39:15 +04:00
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
2006-05-17 06:37:31 +04:00
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
1999-01-12 11:34:29 +03:00
|
|
|
#include "unicpriv.h"
|
2006-05-17 06:33:22 +04:00
|
|
|
#define CHK_GR94(b) ( (PRUint8) 0xa0 < (PRUint8) (b) && (PRUint8) (b) < (PRUint8) 0xff )
|
|
|
|
#define CHK_GR94_2Byte(b1,b2) (CHK_GR94(b1) && CHK_GR94(b2))
|
1999-01-12 11:34:29 +03:00
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
typedef PRBool (*uSubScannerFunc) (unsigned char* in, PRUint16* out);
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
|
|
|
|
typedef PRBool (*uScannerFunc) (
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
|
|
|
|
|
|
|
MODULE_PRIVATE PRBool uScan(
|
2006-08-07 11:57:31 +04:00
|
|
|
uScanClassID scanClass,
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
|
|
|
|
|
|
|
#define uSubScanner(sub,in,out) (* m_subscanner[sub])((in),(out))
|
1999-01-12 11:34:29 +03:00
|
|
|
|
|
|
|
PRIVATE PRBool uCheckAndScanAlways1Byte(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
1999-01-12 11:34:29 +03:00
|
|
|
PRIVATE PRBool uCheckAndScanAlways2Byte(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
1999-01-12 11:34:29 +03:00
|
|
|
PRIVATE PRBool uCheckAndScanAlways2ByteShiftGR(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
2006-05-17 06:33:30 +04:00
|
|
|
PRIVATE PRBool uCheckAndScanAlways2ByteGR128(
|
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
2006-08-07 11:57:31 +04:00
|
|
|
MODULE_PRIVATE PRBool uScanShift(
|
|
|
|
uShiftInTable *shift,
|
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
|
|
|
|
1999-01-12 11:34:29 +03:00
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8F(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
1999-01-12 11:34:29 +03:00
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA2(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
1999-06-10 16:56:33 +04:00
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA3(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
1999-06-10 16:56:33 +04:00
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA4(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
1999-06-10 16:56:33 +04:00
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA5(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
1999-06-10 16:56:33 +04:00
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA6(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
1999-06-10 16:56:33 +04:00
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA7(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
2006-05-17 06:33:30 +04:00
|
|
|
PRIVATE PRBool uCnSAlways8BytesDecomposedHangul(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
2006-05-17 06:33:24 +04:00
|
|
|
PRIVATE PRBool uCheckAndScanJohabHangul(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
2006-05-17 06:33:24 +04:00
|
|
|
PRIVATE PRBool uCheckAndScanJohabSymbol(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
1999-07-16 22:20:45 +04:00
|
|
|
|
2006-05-17 06:33:25 +04:00
|
|
|
PRIVATE PRBool uCheckAndScan4BytesGB18030(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
);
|
2006-05-17 06:33:25 +04:00
|
|
|
|
1999-01-12 11:34:29 +03:00
|
|
|
PRIVATE PRBool uScanAlways2Byte(
|
2006-05-17 06:33:29 +04:00
|
|
|
unsigned char* in,
|
|
|
|
PRUint16* out
|
|
|
|
);
|
1999-01-12 11:34:29 +03:00
|
|
|
PRIVATE PRBool uScanAlways2ByteShiftGR(
|
2006-05-17 06:33:29 +04:00
|
|
|
unsigned char* in,
|
|
|
|
PRUint16* out
|
|
|
|
);
|
1999-01-12 11:34:29 +03:00
|
|
|
PRIVATE PRBool uScanAlways1Byte(
|
2006-05-17 06:33:29 +04:00
|
|
|
unsigned char* in,
|
|
|
|
PRUint16* out
|
|
|
|
);
|
1999-01-12 11:34:29 +03:00
|
|
|
PRIVATE PRBool uScanAlways1BytePrefix8E(
|
2006-05-17 06:33:29 +04:00
|
|
|
unsigned char* in,
|
|
|
|
PRUint16* out
|
|
|
|
);
|
|
|
|
/*=================================================================================
|
|
|
|
|
1999-01-12 11:34:29 +03:00
|
|
|
=================================================================================*/
|
2006-05-17 06:39:13 +04:00
|
|
|
PRIVATE const uScannerFunc m_scanner[uNumOfCharsetType] =
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
uCheckAndScanAlways1Byte,
|
|
|
|
uCheckAndScanAlways2Byte,
|
|
|
|
uCheckAndScanAlways2ByteShiftGR,
|
|
|
|
uCheckAndScan2ByteGRPrefix8F,
|
|
|
|
uCheckAndScan2ByteGRPrefix8EA2,
|
|
|
|
uCheckAndScan2ByteGRPrefix8EA3,
|
|
|
|
uCheckAndScan2ByteGRPrefix8EA4,
|
|
|
|
uCheckAndScan2ByteGRPrefix8EA5,
|
|
|
|
uCheckAndScan2ByteGRPrefix8EA6,
|
|
|
|
uCheckAndScan2ByteGRPrefix8EA7,
|
2006-05-17 06:33:30 +04:00
|
|
|
uCnSAlways8BytesDecomposedHangul,
|
2006-05-17 06:33:29 +04:00
|
|
|
uCheckAndScanJohabHangul,
|
|
|
|
uCheckAndScanJohabSymbol,
|
2006-05-17 06:33:30 +04:00
|
|
|
uCheckAndScan4BytesGB18030,
|
|
|
|
uCheckAndScanAlways2ByteGR128
|
1999-01-12 11:34:29 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
|
2006-05-17 06:39:13 +04:00
|
|
|
PRIVATE const uSubScannerFunc m_subscanner[uNumOfCharType] =
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
uScanAlways1Byte,
|
|
|
|
uScanAlways2Byte,
|
|
|
|
uScanAlways2ByteShiftGR,
|
2006-08-07 11:57:31 +04:00
|
|
|
uScanAlways1BytePrefix8E
|
1999-01-12 11:34:29 +03:00
|
|
|
};
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
2006-05-17 06:33:29 +04:00
|
|
|
MODULE_PRIVATE PRBool uScan(
|
2006-08-07 11:57:31 +04:00
|
|
|
uScanClassID scanClass,
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-08-07 11:57:31 +04:00
|
|
|
return (* m_scanner[scanClass]) (state,in,out,inbuflen,inscanlen);
|
1999-01-12 11:34:29 +03:00
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uScanAlways1Byte(
|
2006-05-17 06:33:29 +04:00
|
|
|
unsigned char* in,
|
|
|
|
PRUint16* out
|
|
|
|
)
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
*out = (PRUint16) in[0];
|
|
|
|
return PR_TRUE;
|
1999-01-12 11:34:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uScanAlways2Byte(
|
2006-05-17 06:33:29 +04:00
|
|
|
unsigned char* in,
|
|
|
|
PRUint16* out
|
|
|
|
)
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
*out = (PRUint16) (( in[0] << 8) | (in[1]));
|
|
|
|
return PR_TRUE;
|
1999-01-12 11:34:29 +03:00
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uScanAlways2ByteShiftGR(
|
2006-05-17 06:33:29 +04:00
|
|
|
unsigned char* in,
|
|
|
|
PRUint16* out
|
|
|
|
)
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
*out = (PRUint16) ((( in[0] << 8) | (in[1])) & 0x7F7F);
|
|
|
|
return PR_TRUE;
|
1999-01-12 11:34:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uScanAlways1BytePrefix8E(
|
2006-05-17 06:33:29 +04:00
|
|
|
unsigned char* in,
|
|
|
|
PRUint16* out
|
|
|
|
)
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
*out = (PRUint16) in[1];
|
|
|
|
return PR_TRUE;
|
1999-01-12 11:34:29 +03:00
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uCheckAndScanAlways1Byte(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
/* Don't check inlen. The caller should ensure it is larger than 0 */
|
|
|
|
*inscanlen = 1;
|
|
|
|
*out = (PRUint16) in[0];
|
|
|
|
|
|
|
|
return PR_TRUE;
|
1999-01-12 11:34:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uCheckAndScanAlways2Byte(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
if(inbuflen < 2)
|
|
|
|
return PR_FALSE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*inscanlen = 2;
|
|
|
|
*out = ((in[0] << 8) | ( in[1])) ;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-01-12 11:34:29 +03:00
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uCheckAndScanAlways2ByteShiftGR(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:37:34 +04:00
|
|
|
/*
|
|
|
|
* Both bytes should be in the range of [0xa1,0xfe] for 94x94 character sets
|
|
|
|
* invoked on GR. No encoding implemented in Mozilla uses 96x96 char. sets.
|
|
|
|
* Only 2nd byte range needs to be checked because
|
|
|
|
* 1st byte is checked before calling this in nsUnicodeDecoerHelper.cpp
|
|
|
|
*/
|
|
|
|
if(inbuflen < 2) /* will lead to NS_OK_UDEC_MOREINPUT */
|
2006-05-17 06:33:29 +04:00
|
|
|
return PR_FALSE;
|
2006-05-17 06:37:34 +04:00
|
|
|
else if (! CHK_GR94(in[1]))
|
|
|
|
{
|
|
|
|
*inscanlen = 2;
|
|
|
|
*out = 0xFF; /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2006-05-17 06:33:29 +04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
*inscanlen = 2;
|
|
|
|
*out = (((in[0] << 8) | ( in[1])) & 0x7F7F);
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-01-12 11:34:29 +03:00
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
2006-05-17 06:33:30 +04:00
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uCheckAndScanAlways2ByteGR128(
|
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* The first byte should be in [0xa1,0xfe]
|
|
|
|
* and the second byte can take any value with MSB = 1.
|
|
|
|
* Used by CP949 -> Unicode converter.
|
2006-05-17 06:37:34 +04:00
|
|
|
* Only 2nd byte range needs to be checked because
|
|
|
|
* 1st byte is checked before calling this in nsUnicodeDecoerHelper.cpp
|
2006-05-17 06:33:30 +04:00
|
|
|
*/
|
2006-05-17 06:37:34 +04:00
|
|
|
if(inbuflen < 2) /* will lead to NS_OK_UDEC_MOREINPUT */
|
2006-05-17 06:33:30 +04:00
|
|
|
return PR_FALSE;
|
2006-05-17 06:37:34 +04:00
|
|
|
else if (! in[1] & 0x80) /* 2nd byte range check */
|
|
|
|
{
|
|
|
|
*inscanlen = 2;
|
|
|
|
*out = 0xFF; /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2006-05-17 06:33:30 +04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
*inscanlen = 2;
|
|
|
|
*out = (in[0] << 8) | in[1];
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
1999-01-12 11:34:29 +03:00
|
|
|
=================================================================================*/
|
2006-08-07 11:57:31 +04:00
|
|
|
PRIVATE PRBool uScanShift(
|
|
|
|
uShiftInTable *shift,
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt16 i;
|
2006-08-07 11:57:31 +04:00
|
|
|
const uShiftInCell* cell = &(shift->shiftcell[0]);
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt16 itemnum = shift->numOfItem;
|
|
|
|
for(i=0;i<itemnum;i++)
|
|
|
|
{
|
2006-05-17 06:37:32 +04:00
|
|
|
if( ( in[0] >= cell[i].shiftin_Min) &&
|
|
|
|
( in[0] <= cell[i].shiftin_Max))
|
2006-05-17 06:33:29 +04:00
|
|
|
{
|
|
|
|
if(inbuflen < cell[i].reserveLen)
|
|
|
|
return PR_FALSE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*inscanlen = cell[i].reserveLen;
|
|
|
|
return (uSubScanner(cell[i].classID,in,out));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
1999-01-12 11:34:29 +03:00
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8F(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:37:34 +04:00
|
|
|
if((inbuflen < 3) ||(in[0] != 0x8F))
|
2006-05-17 06:33:29 +04:00
|
|
|
return PR_FALSE;
|
2006-05-17 06:37:34 +04:00
|
|
|
else if (! CHK_GR94(in[1])) /* 2nd byte range check */
|
|
|
|
{
|
|
|
|
*inscanlen = 2;
|
|
|
|
*out = 0xFF; /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
else if (! CHK_GR94(in[2])) /* 3rd byte range check */
|
|
|
|
{
|
|
|
|
*inscanlen = 3;
|
|
|
|
*out = 0xFF; /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2006-05-17 06:33:29 +04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
*inscanlen = 3;
|
|
|
|
*out = (((in[1] << 8) | ( in[2])) & 0x7F7F);
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
1999-01-12 11:34:29 +03:00
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
2006-05-17 06:37:34 +04:00
|
|
|
|
|
|
|
/* Macro definition to use for uCheckAndScan2ByteGRPrefix8EAX()
|
|
|
|
* where X is 2,3,4,5,6,7
|
|
|
|
*/
|
|
|
|
#define CNS_8EAX_4BYTE(PREFIX) \
|
|
|
|
if((inbuflen < 4) || (in[0] != 0x8E)) \
|
|
|
|
return PR_FALSE; \
|
|
|
|
else if((in[1] != (PREFIX))) \
|
|
|
|
{ \
|
|
|
|
*inscanlen = 2; \
|
|
|
|
*out = 0xFF; \
|
|
|
|
return PR_TRUE; \
|
|
|
|
} \
|
|
|
|
else if(! CHK_GR94(in[2])) \
|
|
|
|
{ \
|
|
|
|
*inscanlen = 3; \
|
|
|
|
*out = 0xFF; \
|
|
|
|
return PR_TRUE; \
|
|
|
|
} \
|
|
|
|
else if(! CHK_GR94(in[3])) \
|
|
|
|
{ \
|
|
|
|
*inscanlen = 4; \
|
|
|
|
*out = 0xFF; \
|
|
|
|
return PR_TRUE; \
|
|
|
|
} \
|
|
|
|
else \
|
|
|
|
{ \
|
|
|
|
*inscanlen = 4; \
|
|
|
|
*out = (((in[2] << 8) | ( in[3])) & 0x7F7F); \
|
|
|
|
return PR_TRUE; \
|
|
|
|
}
|
|
|
|
|
1999-01-12 11:34:29 +03:00
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA2(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-01-12 11:34:29 +03:00
|
|
|
{
|
2006-05-17 06:37:34 +04:00
|
|
|
CNS_8EAX_4BYTE(0xA2)
|
1999-01-12 11:34:29 +03:00
|
|
|
}
|
|
|
|
|
1999-06-10 00:22:26 +04:00
|
|
|
/*=================================================================================
|
|
|
|
|
1999-06-10 16:56:33 +04:00
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA3(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-06-10 16:56:33 +04:00
|
|
|
{
|
2006-05-17 06:37:34 +04:00
|
|
|
CNS_8EAX_4BYTE(0xA3)
|
1999-06-10 16:56:33 +04:00
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA4(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-06-10 16:56:33 +04:00
|
|
|
{
|
2006-05-17 06:37:34 +04:00
|
|
|
CNS_8EAX_4BYTE(0xA4)
|
1999-06-10 16:56:33 +04:00
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA5(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-06-10 16:56:33 +04:00
|
|
|
{
|
2006-05-17 06:37:34 +04:00
|
|
|
CNS_8EAX_4BYTE(0xA5)
|
1999-06-10 16:56:33 +04:00
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA6(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-06-10 16:56:33 +04:00
|
|
|
{
|
2006-05-17 06:37:34 +04:00
|
|
|
CNS_8EAX_4BYTE(0xA6)
|
1999-06-10 16:56:33 +04:00
|
|
|
}
|
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA7(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-06-10 16:56:33 +04:00
|
|
|
{
|
2006-05-17 06:37:34 +04:00
|
|
|
CNS_8EAX_4BYTE(0xA7)
|
1999-06-10 16:56:33 +04:00
|
|
|
}
|
1999-06-12 05:38:30 +04:00
|
|
|
/*=================================================================================
|
|
|
|
|
1999-07-16 17:03:32 +04:00
|
|
|
=================================================================================*/
|
|
|
|
#define SBase 0xAC00
|
|
|
|
#define SCount 11172
|
|
|
|
#define LCount 19
|
|
|
|
#define VCount 21
|
|
|
|
#define TCount 28
|
|
|
|
#define NCount (VCount * TCount)
|
2006-05-17 06:39:14 +04:00
|
|
|
|
|
|
|
PRIVATE PRBool uCnSAlways8BytesDecomposedHangul(
|
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
1999-07-16 17:03:32 +04:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
|
|
|
|
PRUint16 LIndex, VIndex, TIndex;
|
|
|
|
/* no 8 bytes, not in a4 range, or the first 2 byte are not a4d4 */
|
2006-05-17 06:39:14 +04:00
|
|
|
if((inbuflen < 8) || (0xa4 != in[0]) || (0xd4 != in[1]) ||
|
|
|
|
(0xa4 != in[2] ) || (0xa4 != in[4]) || (0xa4 != in[6]))
|
2006-05-17 06:33:29 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
|
|
|
|
/* Compute LIndex */
|
2006-05-17 06:39:14 +04:00
|
|
|
if((in[3] < 0xa1) && (in[3] > 0xbe)) { /* illegal leading consonant */
|
2006-05-17 06:33:29 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
else {
|
2006-05-17 06:39:13 +04:00
|
|
|
static const PRUint8 lMap[] = {
|
2006-05-17 06:33:29 +04:00
|
|
|
/* A1 A2 A3 A4 A5 A6 A7 */
|
|
|
|
0, 1,0xff, 2,0xff,0xff, 3,
|
|
|
|
/* A8 A9 AA AB AC AD AE AF */
|
|
|
|
4, 5,0xff,0xff,0xff,0xff,0xff,0xff,
|
|
|
|
/* B0 B1 B2 B3 B4 B5 B6 B7 */
|
|
|
|
0xff, 6, 7, 8,0xff, 9, 10, 11,
|
|
|
|
/* B8 B9 BA BB BC BD BE */
|
|
|
|
12, 13, 14, 15, 16, 17, 18
|
|
|
|
};
|
|
|
|
|
2006-05-17 06:39:14 +04:00
|
|
|
LIndex = lMap[in[3] - 0xa1];
|
2006-05-17 06:33:29 +04:00
|
|
|
if(0xff == (0xff & LIndex))
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Compute VIndex */
|
2006-05-17 06:39:14 +04:00
|
|
|
if((in[5] < 0xbf) && (in[5] > 0xd3)) { /* illegal medial vowel */
|
2006-05-17 06:33:29 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
else {
|
2006-05-17 06:39:14 +04:00
|
|
|
VIndex = in[5] - 0xbf;
|
2006-05-17 06:33:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Compute TIndex */
|
2006-05-17 06:39:14 +04:00
|
|
|
if(0xd4 == in[7])
|
2006-05-17 06:33:29 +04:00
|
|
|
{
|
|
|
|
TIndex = 0;
|
|
|
|
}
|
2006-05-17 06:39:14 +04:00
|
|
|
else if((in[7] < 0xa1) && (in[7] > 0xbe)) {/* illegal trailling consonant */
|
2006-05-17 06:33:29 +04:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
else {
|
2006-05-17 06:39:13 +04:00
|
|
|
static const PRUint8 tMap[] = {
|
2006-05-17 06:33:29 +04:00
|
|
|
/* A1 A2 A3 A4 A5 A6 A7 */
|
|
|
|
1, 2, 3, 4, 5, 6, 7,
|
|
|
|
/* A8 A9 AA AB AC AD AE AF */
|
|
|
|
0xff, 8, 9, 10, 11, 12, 13, 14,
|
|
|
|
/* B0 B1 B2 B3 B4 B5 B6 B7 */
|
|
|
|
15, 16, 17,0xff, 18, 19, 20, 21,
|
|
|
|
/* B8 B9 BA BB BC BD BE */
|
|
|
|
22,0xff, 23, 24, 25, 26, 27
|
|
|
|
};
|
2006-05-17 06:39:14 +04:00
|
|
|
TIndex = tMap[in[7] - 0xa1];
|
2006-05-17 06:33:29 +04:00
|
|
|
if(0xff == (0xff & TIndex))
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*inscanlen = 8;
|
|
|
|
/* the following line is from Unicode 2.0 page 3-13 item 5 */
|
|
|
|
*out = ( LIndex * VCount + VIndex) * TCount + TIndex + SBase;
|
|
|
|
|
|
|
|
return PR_TRUE;
|
1999-07-16 17:03:32 +04:00
|
|
|
}
|
1999-07-16 22:20:45 +04:00
|
|
|
/*=================================================================================
|
|
|
|
|
|
|
|
=================================================================================*/
|
|
|
|
|
2006-05-17 06:33:24 +04:00
|
|
|
PRIVATE PRBool uCheckAndScanJohabHangul(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
2006-05-17 06:33:24 +04:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
/* since we don't have code to convert Johab to Unicode right now *
|
|
|
|
* make this part of code #if 0 to save space untill we fully test it */
|
|
|
|
if(inbuflen < 2)
|
2006-05-17 06:33:24 +04:00
|
|
|
return PR_FALSE;
|
2006-05-17 06:33:29 +04:00
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* See Table 4-45 Johab Encoding's Five-Bit Binary Patterns in page 183
|
|
|
|
* of "CJKV Information Processing" for details
|
|
|
|
*/
|
2006-05-17 06:39:13 +04:00
|
|
|
static const PRUint8 lMap[32]={ /* totaly 19 */
|
2006-05-17 06:33:29 +04:00
|
|
|
0xff,0xff,0, 1, 2, 3, 4, 5, /* 0-7 */
|
|
|
|
6, 7, 8, 9, 10, 11, 12, 13, /* 8-15 */
|
|
|
|
14, 15, 16, 17, 18, 0xff,0xff,0xff, /* 16-23 */
|
|
|
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff /* 24-31 */
|
|
|
|
};
|
2006-05-17 06:39:13 +04:00
|
|
|
static const PRUint8 vMap[32]={ /* totaly 21 */
|
2006-05-17 06:33:29 +04:00
|
|
|
0xff,0xff,0xff,0, 1, 2, 3, 4, /* 0-7 */
|
|
|
|
0xff,0xff,5, 6, 7, 8, 9, 10, /* 8-15 */
|
|
|
|
0xff,0xff,11, 12, 13, 14, 15, 16, /* 16-23 */
|
|
|
|
0xff,0xff,17, 18, 19, 20, 0xff,0xff /* 24-31 */
|
|
|
|
};
|
2006-05-17 06:39:13 +04:00
|
|
|
static const PRUint8 tMap[32]={ /* totaly 29 */
|
2006-05-17 06:33:29 +04:00
|
|
|
0xff,0, 1, 2, 3, 4, 5, 6, /* 0-7 */
|
|
|
|
7, 8, 9, 10, 11, 12, 13, 14, /* 8-15 */
|
|
|
|
15, 16, 0xff,17, 18, 19, 20, 21, /* 16-23 */
|
|
|
|
22, 23, 24, 25, 26, 27, 0xff,0xff /* 24-31 */
|
|
|
|
};
|
|
|
|
PRUint16 ch = (in[0] << 8) | in[1];
|
|
|
|
PRUint16 LIndex, VIndex, TIndex;
|
|
|
|
if(0 == (0x8000 & ch))
|
|
|
|
return PR_FALSE;
|
|
|
|
LIndex=lMap[(ch>>10)& 0x1F];
|
|
|
|
VIndex=vMap[(ch>>5) & 0x1F];
|
|
|
|
TIndex=tMap[(ch>>0) & 0x1F];
|
|
|
|
if((0xff==(LIndex)) ||
|
|
|
|
(0xff==(VIndex)) ||
|
|
|
|
(0xff==(TIndex)))
|
|
|
|
return PR_FALSE;
|
|
|
|
/* the following line is from Unicode 2.0 page 3-13 item 5 */
|
|
|
|
*out = ( LIndex * VCount + VIndex) * TCount + TIndex + SBase;
|
2006-05-17 06:33:30 +04:00
|
|
|
*inscanlen = 2;
|
2006-05-17 06:33:29 +04:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2006-05-17 06:33:24 +04:00
|
|
|
}
|
|
|
|
PRIVATE PRBool uCheckAndScanJohabSymbol(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
2006-05-17 06:33:24 +04:00
|
|
|
{
|
2006-05-17 06:33:29 +04:00
|
|
|
if(inbuflen < 2)
|
|
|
|
return PR_FALSE;
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* The following code are based on the Perl code lised under
|
|
|
|
* "Johab to ISO-2022-KR or EUC-KR Conversion" in page 1014 of
|
|
|
|
* "CJKV Information Processing" by Ken Lunde <lunde@adobe.com>
|
|
|
|
*
|
|
|
|
* sub johab2ks ($) { # Convert Johab to ISO-2022-KR
|
|
|
|
* my @johab = unpack("C*", $_[0]);
|
|
|
|
* my ($offset, $d8_off) = (0,0);
|
|
|
|
* my @out = ();
|
|
|
|
* while(($hi, $lo) = splice($johab, 0, 2)) {
|
|
|
|
* $offset = 1 if ($hi > 223 and $hi < 250);
|
|
|
|
* $d8_off = ($hi == 216 and ($lo > 160 ? 94 : 42));
|
|
|
|
* push (@out, (((($hi - ($hi < 223 ? 200 : 187)) << 1) -
|
|
|
|
* ($lo < 161 ? 1 : 0) + $offset) + $d8_off),
|
|
|
|
* $lo - ($lo < 161 ? ($lo > 126 ? 34 : 16) : 128 ));
|
|
|
|
* }
|
|
|
|
* return pack ("C*", @out);
|
|
|
|
* }
|
|
|
|
* additional comments from Ken Lunde
|
|
|
|
* $d8_off = ($hi == 216 and ($lo > 160 ? 94 : 42));
|
|
|
|
* has three possible return values:
|
|
|
|
* 0 if $hi is not equal to 216
|
|
|
|
* 94 if $hi is euqal to 216 and if $lo is greater than 160
|
|
|
|
* 42 if $hi is euqal to 216 and if $lo is not greater than 160
|
|
|
|
*/
|
|
|
|
unsigned char hi = in[0];
|
|
|
|
unsigned char lo = in[1];
|
|
|
|
PRUint16 offset = (( hi > 223 ) && ( hi < 250)) ? 1 : 0;
|
|
|
|
PRUint16 d8_off = 0;
|
|
|
|
if(216 == hi) {
|
|
|
|
if( lo > 160)
|
|
|
|
d8_off = 94;
|
|
|
|
else
|
|
|
|
d8_off = 42;
|
2006-05-17 06:33:24 +04:00
|
|
|
}
|
2006-05-17 06:33:29 +04:00
|
|
|
|
|
|
|
*out = (((((hi - ((hi < 223) ? 200 : 187)) << 1) -
|
|
|
|
(lo < 161 ? 1 : 0) + offset) + d8_off) << 8 ) |
|
|
|
|
(lo - ((lo < 161) ? ((lo > 126) ? 34 : 16) :
|
|
|
|
128));
|
2006-05-17 06:33:30 +04:00
|
|
|
*inscanlen = 2;
|
2006-05-17 06:33:29 +04:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
2006-05-17 06:33:24 +04:00
|
|
|
}
|
2006-05-17 06:33:25 +04:00
|
|
|
PRIVATE PRBool uCheckAndScan4BytesGB18030(
|
2006-05-17 06:33:29 +04:00
|
|
|
PRInt32* state,
|
|
|
|
unsigned char *in,
|
|
|
|
PRUint16 *out,
|
|
|
|
PRUint32 inbuflen,
|
|
|
|
PRUint32* inscanlen
|
|
|
|
)
|
2006-05-17 06:33:25 +04:00
|
|
|
{
|
|
|
|
PRUint32 data;
|
|
|
|
if(inbuflen < 4)
|
|
|
|
return PR_FALSE;
|
2006-05-17 06:33:29 +04:00
|
|
|
|
2006-05-17 06:33:25 +04:00
|
|
|
if((in[0] < 0x81 ) || (0xfe < in[0]))
|
|
|
|
return PR_FALSE;
|
|
|
|
if((in[1] < 0x30 ) || (0x39 < in[1]))
|
|
|
|
return PR_FALSE;
|
|
|
|
if((in[2] < 0x81 ) || (0xfe < in[2]))
|
|
|
|
return PR_FALSE;
|
|
|
|
if((in[3] < 0x30 ) || (0x39 < in[3]))
|
|
|
|
return PR_FALSE;
|
2006-05-17 06:33:29 +04:00
|
|
|
|
2006-05-17 06:33:25 +04:00
|
|
|
data = (((((in[0] - 0x81) * 10 + (in[1] - 0x30)) * 126) +
|
2006-05-17 06:33:29 +04:00
|
|
|
(in[2] - 0x81)) * 10 ) + (in[3] - 0x30);
|
|
|
|
|
2006-05-17 06:33:25 +04:00
|
|
|
*inscanlen = 4;
|
2007-09-06 09:02:18 +04:00
|
|
|
*out = (data < 0x00010000) ? data : 0xFFFD;
|
2006-05-17 06:33:29 +04:00
|
|
|
return PR_TRUE;
|
2006-05-17 06:33:25 +04:00
|
|
|
}
|