blob: d1c3ef815d50a17b81ce0d1aae79c985559841c8 [file] [log] [blame]
/***************************************************************************
*
* rw_iso2022.cpp
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 1994-2006 Rogue Wave Software.
*
**************************************************************************/
#define _RWSTD_LIB_SRC
#include <rw/_defs.h>
#ifndef _RWSTD_NO_V3_LOCALE
#include <string.h> // for strxxx()
#include <iosfwd> // for mbstate_t
#include <loc/_codecvt.h>
#include <loc/_localedef.h>
#include "iso2022.h"
#include "locale_body.h"
#define CHSET_ANSI_X_3_4_1968 6
#define CHSET_JIS_X_0201_KANA 13
#define CHSET_JIS_X_0201_ROMAN 14
#define CHSET_JIS_X_0208_1978 42
#define CHSET_JIS_X_0208_1983 87
#define CHSET_JIS_X_0212_1990 159
#define CHSET_GB2312_1980 58
#define CHSET_KSC_5601_1987 149
#define CHSET_ISO_8859_1 100
#define CHSET_ISO_8859_7 126
#define DBIDX_ANSI_X_3_4_1968 1
#define DBIDX_ISO_8859_1 2
#define DBIDX_ISO_8859_2 3
#define DBIDX_ISO_8859_3 4
#define DBIDX_ISO_8859_4 5
#define DBIDX_ISO_8859_5 6
#define DBIDX_ISO_8859_6 7
#define DBIDX_ISO_8859_7 8
#define DBIDX_ISO_8859_8 9
#define DBIDX_EUC_JP 10
#define DBIDX_EUC_KR 11
#define DBIDX_GB2312 12
#define ISO_2022_JP_SET_ASCII "\x1B(B"
#define ISO_2022_JP_SET_JIS201_ROMAN "\x1B(J"
#define ISO_2022_JP_SET_JIS201_KANA "\x1B(I"
#define ISO_2022_JP_SET_JIS208_78 "\x1B$@"
#define ISO_2022_JP_SET_JIS208_83 "\x1B$B"
#define ISO_2022_JP_SET_GB2312_80 "\x1B$A"
#define ISO_2022_JP_SET_KSC5601_87 "\x1B$(C"
#define ISO_2022_JP_SET_JIS212_90 "\x1B$(D"
#define ISO_2022_JP_SET_ISO_8859_1 "\x1B.A"
#define ISO_2022_JP_SET_ISO_8859_7 "\x1B.F"
#define ISO_2022_JP_SET_SS2 "\x1BN"
#define ASCII_CHAR_LEN 1
#define EUCJP_ASCII_CHAR_LEN 1
#define EUCJP_JISX0201_ROMAN_CHAR_LEN 1
#define EUCJP_JISX0201_KANA_CHAR_LEN 2
#define EUCJP_JISX0208_CHAR_LEN 2
#define EUCJP_JISX0212_CHAR_LEN 3
#define GB2312_CHAR_LEN 2
#define KSC5601_CHAR_LEN 2
#define ISO_8859_1_CHAR_LEN 1
#define ISO_8859_7_CHAR_LEN 1
#define ISO_2022_SET_SB94_G0 0x28
#define ISO_2022_SET_SB94_G1 0x29
#define ISO_2022_SET_SB94_G2 0x2A
#define ISO_2022_SET_SB94_G3 0x2B
#define ISO_2022_SET_SB96_G1 0x2D
#define ISO_2022_SET_SB96_G2 0x2E
#define ISO_2022_SET_SB96_G3 0x2F
#define ISO_2022_SET_MB 0x24
#define ISO_2022_SET_MB94_G0 0x28
#define ISO_2022_SET_MB94_G1 0x29
#define ISO_2022_SET_MB94_G2 0x2A
#define ISO_2022_SET_MB94_G3 0x2B
#define ISO_2022_SET_MB96_G1 0x2D
#define ISO_2022_SET_MB96_G2 0x2E
#define ISO_2022_SET_MB96_G3 0x2F
#define ISO_2022_SET_SS2 0x4E
#define ESCAPE_CHAR 0x1B
#if !defined (_UTF8_MB_CUR_MAX)
# define _UTF8_MB_CUR_MAX 6
#endif
#define CODECVT_ERROR _V3_LOCALE::codecvt_base::error
#define CODECVT_OK _V3_LOCALE::codecvt_base::ok
#define CODECVT_PARTIAL _V3_LOCALE::codecvt_base::partial
_RWSTD_NAMESPACE (__rw) {
enum __rw_codeset_type_t {
sb94 = 0, sb96, mb94, mb96
};
// State of the ISO-2022 conversions
struct __rw_iso2022_state_t {
// 0 - unused, 1 - used, default 0
unsigned used:1;
// invoked code elements: valid values 1-4, invalid 0, default 0
unsigned gl_map:3;
unsigned gr_map:3;
// shift state: 0 - one character, 1 - two characters, default 0
unsigned shift_state:1;
// single-shift 2 and 3 functions
unsigned sshift2:1;
unsigned sshift3:1;
// equivalent of G0-G3 code elements
unsigned char g_map [4]; // default 0
};
// Mapping between the code of the character set and the name
struct __rw_chset_map_t
{
const char* name; // codeset canonical name
unsigned char index; // database index
unsigned char width; // encoding width
const char* seq; // designating sequence
unsigned int seqlen; // designating sequence length
};
// Database file mappings
struct __rw_db_map_t
{
const void* pv; // pointer to mapping
_RWSTD_SIZE_T size; // size of mapping
const char* name; // canonical name
};
// make sure there is just one copy of the empty string used
// in the table below (space optimization in case the compiler
// doesn't collapse them automatically
static const char __rw_empty[] = "";
// Array of mappings: code registration number to name
static const __rw_chset_map_t __rw_chset_map [256] = {
#define EMPTY __rw_empty, 0, 0, 0, 0
{/* 0x00 */ EMPTY }, {/* 0x01 */ EMPTY }, {/* 0x02 */ EMPTY },
{/* 0x03 */ EMPTY }, {/* 0x04 */ EMPTY }, {/* 0x05 */ EMPTY },
{
/* 0x06 */ "ANSI_X3.4-1968", DBIDX_ANSI_X_3_4_1968, 0,
ISO_2022_JP_SET_ASCII,
sizeof (ISO_2022_JP_SET_ASCII) - 1U
},
{/* 0x07 */ EMPTY }, {/* 0x08 */ EMPTY }, {/* 0x09 */ EMPTY },
{/* 0x0a */ EMPTY }, {/* 0x0b */ EMPTY }, {/* 0x0c */ EMPTY },
{
/* 0x0d */ "EUC-JP", DBIDX_EUC_JP, 0,
ISO_2022_JP_SET_JIS201_KANA,
sizeof (ISO_2022_JP_SET_JIS201_KANA) - 1U
},
{
/* 0x0e */ "EUC-JP", DBIDX_EUC_JP, 0,
ISO_2022_JP_SET_JIS201_ROMAN,
sizeof (ISO_2022_JP_SET_JIS201_ROMAN) - 1U
},
{/* 0x0f */ EMPTY }, {/* 0x10 */ EMPTY }, {/* 0x11 */ EMPTY },
{/* 0x12 */ EMPTY }, {/* 0x13 */ EMPTY }, {/* 0x14 */ EMPTY },
{/* 0x15 */ EMPTY }, {/* 0x16 */ EMPTY }, {/* 0x17 */ EMPTY },
{/* 0x18 */ EMPTY }, {/* 0x19 */ EMPTY }, {/* 0x1a */ EMPTY },
{/* 0x1b */ EMPTY }, {/* 0x1c */ EMPTY }, {/* 0x1d */ EMPTY },
{/* 0x1e */ EMPTY }, {/* 0x1f */ EMPTY }, {/* 0x20 */ EMPTY },
{/* 0x21 */ EMPTY }, {/* 0x22 */ EMPTY }, {/* 0x23 */ EMPTY },
{/* 0x24 */ EMPTY }, {/* 0x25 */ EMPTY }, {/* 0x26 */ EMPTY },
{/* 0x27 */ EMPTY }, {/* 0x28 */ EMPTY }, {/* 0x29 */ EMPTY },
{
/* 0x2a */ "EUC-JP", DBIDX_EUC_JP, 1,
ISO_2022_JP_SET_JIS208_78,
sizeof (ISO_2022_JP_SET_JIS208_78) - 1U
},
{/* 0x2b */ EMPTY }, {/* 0x2c */ EMPTY }, {/* 0x2d */ EMPTY },
{/* 0x2e */ EMPTY }, {/* 0x2f */ EMPTY }, {/* 0x30 */ EMPTY },
{/* 0x31 */ EMPTY }, {/* 0x32 */ EMPTY }, {/* 0x33 */ EMPTY },
{/* 0x34 */ EMPTY }, {/* 0x35 */ EMPTY }, {/* 0x36 */ EMPTY },
{/* 0x37 */ EMPTY }, {/* 0x38 */ EMPTY }, {/* 0x39 */ EMPTY },
{
/* 0x3a */ "GB2312", DBIDX_GB2312, 1,
ISO_2022_JP_SET_GB2312_80,
sizeof (ISO_2022_JP_SET_GB2312_80) - 1U
},
{/* 0x3b */ EMPTY },
{/* 0x3c */ EMPTY }, {/* 0x3d */ EMPTY }, {/* 0x3e */ EMPTY },
{/* 0x3f */ EMPTY }, {/* 0x40 */ EMPTY }, {/* 0x41 */ EMPTY },
{/* 0x42 */ EMPTY }, {/* 0x43 */ EMPTY }, {/* 0x44 */ EMPTY },
{/* 0x45 */ EMPTY }, {/* 0x46 */ EMPTY }, {/* 0x47 */ EMPTY },
{/* 0x48 */ EMPTY }, {/* 0x49 */ EMPTY }, {/* 0x4a */ EMPTY },
{/* 0x4b */ EMPTY }, {/* 0x4c */ EMPTY }, {/* 0x4d */ EMPTY },
{/* 0x4e */ EMPTY }, {/* 0x4f */ EMPTY }, {/* 0x50 */ EMPTY },
{/* 0x51 */ EMPTY }, {/* 0x52 */ EMPTY }, {/* 0x53 */ EMPTY },
{/* 0x54 */ EMPTY }, {/* 0x55 */ EMPTY }, {/* 0x56 */ EMPTY },
{
/* 0x57 */ "EUC-JP", DBIDX_EUC_JP, 1,
ISO_2022_JP_SET_JIS208_83,
sizeof (ISO_2022_JP_SET_JIS208_83) - 1U
},
{/* 0x58 */ EMPTY }, {/* 0x59 */ EMPTY }, {/* 0x5a */ EMPTY },
{/* 0x5b */ EMPTY }, {/* 0x5c */ EMPTY }, {/* 0x5d */ EMPTY },
{/* 0x5e */ EMPTY }, {/* 0x5f */ EMPTY }, {/* 0x60 */ EMPTY },
{/* 0x61 */ EMPTY }, {/* 0x62 */ EMPTY }, {/* 0x63 */ EMPTY },
{
/* 0x64 */ "ISO-8859-1", DBIDX_ISO_8859_1, 0,
ISO_2022_JP_SET_ISO_8859_1,
sizeof (ISO_2022_JP_SET_ISO_8859_1) - 1U
},
{/* 0x65 */ EMPTY }, {/* 0x66 */ EMPTY }, {/* 0x67 */ EMPTY },
{/* 0x68 */ EMPTY }, {/* 0x69 */ EMPTY }, {/* 0x6a */ EMPTY },
{/* 0x6b */ EMPTY }, {/* 0x6c */ EMPTY }, {/* 0x6d */ EMPTY },
{/* 0x6e */ EMPTY }, {/* 0x6f */ EMPTY }, {/* 0x70 */ EMPTY },
{/* 0x71 */ EMPTY }, {/* 0x72 */ EMPTY }, {/* 0x73 */ EMPTY },
{/* 0x74 */ EMPTY }, {/* 0x75 */ EMPTY }, {/* 0x76 */ EMPTY },
{/* 0x77 */ EMPTY }, {/* 0x78 */ EMPTY }, {/* 0x79 */ EMPTY },
{/* 0x7a */ EMPTY }, {/* 0x7b */ EMPTY }, {/* 0x7c */ EMPTY },
{/* 0x7d */ EMPTY },
{
/* 0x7e */ "ISO-8859-7", DBIDX_ISO_8859_7, 0,
ISO_2022_JP_SET_ISO_8859_7,
sizeof (ISO_2022_JP_SET_ISO_8859_7) - 1U
},
{/* 0x7f */ EMPTY }, {/* 0x80 */ EMPTY }, {/* 0x81 */ EMPTY },
{/* 0x82 */ EMPTY }, {/* 0x83 */ EMPTY }, {/* 0x84 */ EMPTY },
{/* 0x85 */ EMPTY }, {/* 0x86 */ EMPTY }, {/* 0x87 */ EMPTY },
{/* 0x88 */ EMPTY }, {/* 0x89 */ EMPTY }, {/* 0x8a */ EMPTY },
{/* 0x8b */ EMPTY }, {/* 0x8c */ EMPTY }, {/* 0x8d */ EMPTY },
{/* 0x8e */ EMPTY }, {/* 0x8f */ EMPTY }, {/* 0x90 */ EMPTY },
{/* 0x91 */ EMPTY }, {/* 0x92 */ EMPTY }, {/* 0x93 */ EMPTY },
{/* 0x94 */ EMPTY },
{
/* 0x95 */ "EUC-KR", DBIDX_EUC_KR, 1,
ISO_2022_JP_SET_KSC5601_87,
sizeof (ISO_2022_JP_SET_KSC5601_87) - 1U
},
{/* 0x96 */ EMPTY }, {/* 0x97 */ EMPTY }, {/* 0x98 */ EMPTY },
{/* 0x99 */ EMPTY }, {/* 0x9a */ EMPTY }, {/* 0x9b */ EMPTY },
{/* 0x9c */ EMPTY }, {/* 0x9d */ EMPTY }, {/* 0x9e */ EMPTY },
{
/* 0x9f */ "EUC-JP", DBIDX_EUC_JP, 1,
ISO_2022_JP_SET_JIS212_90,
sizeof (ISO_2022_JP_SET_JIS212_90) - 1U
},
{/* 0xa0 */ EMPTY }, {/* 0xa1 */ EMPTY }, {/* 0xa2 */ EMPTY },
{/* 0xa3 */ EMPTY }, {/* 0xa4 */ EMPTY }, {/* 0xa5 */ EMPTY },
{/* 0xa6 */ EMPTY }, {/* 0xa7 */ EMPTY }, {/* 0xa8 */ EMPTY },
{/* 0xa9 */ EMPTY }, {/* 0xaa */ EMPTY }, {/* 0xab */ EMPTY },
{/* 0xac */ EMPTY }, {/* 0xad */ EMPTY }, {/* 0xae */ EMPTY },
{/* 0xaf */ EMPTY }, {/* 0xb0 */ EMPTY }, {/* 0xb1 */ EMPTY },
{/* 0xb2 */ EMPTY }, {/* 0xb3 */ EMPTY }, {/* 0xb4 */ EMPTY },
{/* 0xb5 */ EMPTY }, {/* 0xb6 */ EMPTY }, {/* 0xb7 */ EMPTY },
{/* 0xb8 */ EMPTY }, {/* 0xb9 */ EMPTY }, {/* 0xba */ EMPTY },
{/* 0xbb */ EMPTY }, {/* 0xbc */ EMPTY }, {/* 0xbd */ EMPTY },
{/* 0xbe */ EMPTY }, {/* 0xbf */ EMPTY }, {/* 0xc0 */ EMPTY },
{/* 0xc1 */ EMPTY }, {/* 0xc2 */ EMPTY }, {/* 0xc3 */ EMPTY },
{/* 0xc4 */ EMPTY }, {/* 0xc5 */ EMPTY }, {/* 0xc6 */ EMPTY },
{/* 0xc7 */ EMPTY }, {/* 0xc8 */ EMPTY }, {/* 0xc9 */ EMPTY },
{/* 0xca */ EMPTY }, {/* 0xcb */ EMPTY }, {/* 0xcc */ EMPTY },
{/* 0xcd */ EMPTY }, {/* 0xce */ EMPTY }, {/* 0xcf */ EMPTY },
{/* 0xd0 */ EMPTY }, {/* 0xd1 */ EMPTY }, {/* 0xd2 */ EMPTY },
{/* 0xd3 */ EMPTY }, {/* 0xd4 */ EMPTY }, {/* 0xd5 */ EMPTY },
{/* 0xd6 */ EMPTY }, {/* 0xd7 */ EMPTY }, {/* 0xd8 */ EMPTY },
{/* 0xd9 */ EMPTY }, {/* 0xda */ EMPTY }, {/* 0xdb */ EMPTY },
{/* 0xdc */ EMPTY }, {/* 0xdd */ EMPTY }, {/* 0xde */ EMPTY },
{/* 0xdf */ EMPTY }, {/* 0xe0 */ EMPTY }, {/* 0xe1 */ EMPTY },
{/* 0xe2 */ EMPTY }, {/* 0xe3 */ EMPTY }, {/* 0xe4 */ EMPTY },
{/* 0xe5 */ EMPTY }, {/* 0xe6 */ EMPTY }, {/* 0xe7 */ EMPTY },
{/* 0xe8 */ EMPTY }, {/* 0xe9 */ EMPTY }, {/* 0xea */ EMPTY },
{/* 0xeb */ EMPTY }, {/* 0xec */ EMPTY }, {/* 0xed */ EMPTY },
{/* 0xee */ EMPTY }, {/* 0xef */ EMPTY }, {/* 0xf0 */ EMPTY },
{/* 0xf1 */ EMPTY }, {/* 0xf2 */ EMPTY }, {/* 0xf3 */ EMPTY },
{/* 0xf4 */ EMPTY }, {/* 0xf5 */ EMPTY }, {/* 0xf6 */ EMPTY },
{/* 0xf7 */ EMPTY }, {/* 0xf8 */ EMPTY }, {/* 0xf9 */ EMPTY },
{/* 0xfa */ EMPTY }, {/* 0xfb */ EMPTY }, {/* 0xfc */ EMPTY },
{/* 0xfd */ EMPTY }, {/* 0xfe */ EMPTY }, {/* 0xff */ EMPTY }
};
// Mapping pointer - size of mapping - canonical name
static __rw_db_map_t __rw_db_map [32] = {
{ 0, 0, __rw_empty }, { 0, 0, "ANSI_X3.4-1968" },
{ 0, 0, "ISO-8859-1" }, { 0, 0, "ISO-8859-2" },
{ 0, 0, "ISO-8859-3" }, { 0, 0, "ISO-8859-4" },
{ 0, 0, "ISO-8859-5" }, { 0, 0, "ISO-8859-6" },
{ 0, 0, "ISO-8859-7" }, { 0, 0, "ISO-8859-8" },
{ 0, 0, "EUC-JP" }, { 0, 0, "EUC-KR" },
{ 0, 0, "GB2312" }, { 0, 0, __rw_empty },
{ 0, 0, __rw_empty }, { 0, 0, __rw_empty },
{ 0, 0, __rw_empty }, { 0, 0, __rw_empty },
{ 0, 0, __rw_empty }, { 0, 0, __rw_empty },
{ 0, 0, __rw_empty }, { 0, 0, __rw_empty },
{ 0, 0, __rw_empty }, { 0, 0, __rw_empty },
{ 0, 0, __rw_empty }, { 0, 0, __rw_empty },
{ 0, 0, __rw_empty }, { 0, 0, __rw_empty },
{ 0, 0, __rw_empty }, { 0, 0, __rw_empty },
{ 0, 0, __rw_empty }, { 0, 0, __rw_empty }
};
// Retrieves the type of the encoding as indicated by the name
int __rw_encoding_from_name (const char* name)
{
_RWSTD_ASSERT (0 != name);
static const char pfx [] = "ISO-2022-";
if (0 != strncmp (pfx, name, sizeof pfx - 1U))
return stateless;
name += sizeof pfx - 1U;
if (0 == strcmp (name, "JP-2")) {
return iso2022_jp2;
}
if (0 == strcmp (name, "JP")) {
return iso2022_jp;
}
if (0 == strcmp (name, "KR")) {
return iso2022_kr;
}
if (0 == strcmp (name, "CN")) {
return iso2022_cn;
}
return stateless;
}
// Array of ISO-2022 encoding states; the array has a default size of 256
// entries; the declaration of the array is guarded for size
//
// The usage of the structs in the array:
// - the struct "allocated" are marked as used;
// - the index of the struct in the array is stored in the std::mbstate_t
// struct used in codecvt facet;
// - the std::mbstate_t values are shifted from the real iso2022_state
// struct index by one so that a value of zero in an std::mbstate_t
// variable indicates a new conversion for which a state has to be
// allocated
#if _RWSTD_MBSTATE_T_SIZE == 1
# define ISO_2022_ARRAY_SIZE 255
# define ISO_2022_STATE_INDEX_T unsigned char
#else
# define ISO_2022_ARRAY_SIZE 511
# define ISO_2022_STATE_INDEX_T unsigned short
#endif
// array of available states (limits the number of distinct mbstate_t
// objects with unique value that may be simultaneously valid)
static __rw_iso2022_state_t __rw_iso2022_states [ISO_2022_ARRAY_SIZE];
// returns an index in the array of state structures or -1 if none
// is available; ISO-2022-JP and ISO-2022-JP-2 assume different
// initializations
static inline
int __rw_allocate_state ()
{
_RWSTD_MT_CLASS_GUARD (__rw_iso2022_state_t);
for (int i = 0; i < ISO_2022_ARRAY_SIZE; i++)
if (__rw_iso2022_states [i].used == 0) {
__rw_iso2022_states [i].used = 1;
return i;
}
return -1;
}
// deallocates state and makes it available for future conversions
// if `initial_only' is non-zero suceeds only if the `iso_state'
// argument represents an initial shift state
static inline
void __rw_deallocate_state (__rw_iso2022_state_t &iso_state,
_RWSTD_MBSTATE_T &state,
bool initial_only)
{
_RWSTD_MT_CLASS_GUARD (__rw_iso2022_state_t);
if (initial_only) {
// test the state object for return to initial shift state
const int i = iso_state.gl_map - 1;
_RWSTD_ASSERT (i >= 0 && i < 4);
if ( iso_state.g_map [i] != CHSET_ANSI_X_3_4_1968
|| iso_state.sshift2
|| iso_state.sshift3)
return;
// proceed only if `iostate' is in an initial shift state
}
// zero out both structures
memset (&state, 0, sizeof state);
memset (&iso_state, 0, sizeof iso_state);
}
static __rw_iso2022_state_t*
__rw_get_iso2022_state (_RWSTD_MBSTATE_T& state, int enc)
{
__rw_iso2022_state_t* pstate = 0;
// retrieve the array index
ISO_2022_STATE_INDEX_T* pc =
_RWSTD_REINTERPRET_CAST (ISO_2022_STATE_INDEX_T*, &state);
int n = *pc;
_RWSTD_ASSERT(n >= 0 && n <= ISO_2022_ARRAY_SIZE);
// a value of zero in std::mbstate_t indicates conversion anew,
// calling for a state allocation
if (n == 0) {
n = __rw_allocate_state ();
// the case when the allocation was not possible
if (n == -1)
return pstate;
// store the state index
*pc = _RWSTD_STATIC_CAST (ISO_2022_STATE_INDEX_T, n + 1);
}
else
n--;
// store the pointer to the state object
pstate = &__rw_iso2022_states [n];
// initialize the state according to the encoding type
switch (enc) {
case iso2022_jp:
case iso2022_jp2:
pstate->g_map [0] = CHSET_ANSI_X_3_4_1968;
pstate->gl_map = 1;
break;
default:
break;
}
return pstate;
}
// Retrieval of the character set's registration number; the code
// designator values overlap (they are, however, distinct in each category)
static inline
unsigned char __rw_sb94_encoding_reg (unsigned char c)
{
unsigned char reg = 0;
switch (c) {
case 0x42:
reg = CHSET_ANSI_X_3_4_1968; /* ANSI X-3.4/1968 */
break;
case 0x49:
reg = CHSET_JIS_X_0201_KANA; /* JIS X 0201 Katakana */
break;
case 0x4a:
reg = CHSET_JIS_X_0201_ROMAN; /* JIS X 0201 Roman */
break;
}
return reg;
}
static inline
unsigned char __rw_sb96_encoding_reg (unsigned char c)
{
unsigned char reg = 0;
switch (c) {
case 0x41:
reg = CHSET_ISO_8859_1; /* ISO-8859-1 */
break;
case 0x46:
reg = CHSET_ISO_8859_7; /* ISO-8859-7 */
break;
}
return reg;
}
static inline
unsigned char __rw_mb94_encoding_reg (unsigned char c)
{
unsigned char reg = 0;
switch (c) {
case 0x40:
reg = CHSET_JIS_X_0208_1978; /* JIS X 0208-1978 */
break;
case 0x41:
reg = CHSET_GB2312_1980; /* GB 2312-80 */
break;
case 0x42:
reg = CHSET_JIS_X_0208_1983; /* JIS X 0208-1983 */
break;
case 0x43:
reg = CHSET_KSC_5601_1987; /* KSC 5601 Korean */
break;
case 0x44:
reg = CHSET_JIS_X_0212_1990; /* JIS X 0212-1990 */
break;
}
return reg;
}
static inline
unsigned char __rw_mb96_encoding_reg (unsigned char)
{
return 0;
}
// Retrieves the code registration associated with a particular encoding class
// and a particular character set designator in that class
static inline
unsigned char __rw_get_encoding_reg (__rw_codeset_type_t type,
unsigned char code)
{
switch (type) {
case sb94:
return __rw_sb94_encoding_reg (code);
case sb96:
return __rw_sb96_encoding_reg (code);
case mb94:
return __rw_mb94_encoding_reg (code);
case mb96:
return __rw_mb96_encoding_reg (code);
}
return 0;
}
#if 0 // unused
// Retrieval of the character set's registration name
static inline
const char* __rw_get_encoding_name (unsigned char n)
{
return (__rw_chset_map [n].name [0] == 0)?0:__rw_chset_map [n].name;
}
// A way of mapping a combination type-code to an index in the array of
// codecvt databases mappings. The databases mappings are installed in
// the array of mappings like this:
// 1 - ANSI.X-3.4-1968
// 2-9 - ISO-8859-1, 2, 3, 4, 5, 6, 7, 8
// 10 - EUC-JP
// 11 - EUC-KR
// 12 - GB2312-1980
static inline
unsigned char __rw_get_encoding_dbindex (__rw_codeset_type_t t,
unsigned char code)
{
unsigned char reg = __rw_get_encoding_reg (t, code);
if (reg == 0)
return 0;
return __rw_chset_map [reg].index;
}
#endif // 0/1
static inline
const void* __rw_get_encoding_database (unsigned char n)
{
// if already mapped return it
if (__rw_db_map [n].pv)
return __rw_db_map [n].pv;
// a wrong index would point to a struct bearing no name
if (__rw_db_map [n].name [0] == 0)
return 0;
// if not, obtain it from __rw_get_facet_data
int cat = __rw_get_cat ((__rw_facet::_C_wcodecvt_byname + 1) / 2);
__rw_db_map [n].pv =
__rw_get_facet_data (cat, __rw_db_map[n].size, 0,
__rw_db_map [n].name);
return __rw_db_map [n].pv;
}
// Insert designating sequence in the destination buffer; the encoding is
// given by the last parameter and is currently one of the following:
// - ISO_2022-JP
// - ISO_2022-JP2
static _V3_LOCALE::codecvt_base::result
__rw_iso2022jp_designate (__rw_iso2022_state_t& state,
char*& to,
char* to_end,
unsigned char reg,
int enc)
{
// length of a designating sequence in ISO-2022-JP and
// ISO-2022-JP-2 is 3 or 4 elements
_RWSTD_SIZE_T len = sizeof (ISO_2022_JP_SET_ASCII) - 1U;
_RWSTD_SIZE_T sslen = 0;
// register designation
bool g2 = false;
const char* esc = 0;
const char* ss = 0;
switch (reg) {
case CHSET_ANSI_X_3_4_1968:
esc = ISO_2022_JP_SET_ASCII;
break;
case CHSET_JIS_X_0201_ROMAN:
esc = ISO_2022_JP_SET_JIS201_ROMAN;
break;
case CHSET_JIS_X_0208_1978:
esc = ISO_2022_JP_SET_JIS208_78;
break;
case CHSET_JIS_X_0208_1983:
esc = ISO_2022_JP_SET_JIS208_83;
break;
case CHSET_GB2312_1980:
esc = (enc == iso2022_jp)?0:ISO_2022_JP_SET_GB2312_80;
break;
case CHSET_ISO_8859_1:
esc = (enc == iso2022_jp)?0:ISO_2022_JP_SET_ISO_8859_1;
ss = ISO_2022_JP_SET_SS2;
sslen = sizeof (ISO_2022_JP_SET_SS2) - 1U;
g2 = true;
break;
case CHSET_ISO_8859_7:
esc = (enc == iso2022_jp)?0:ISO_2022_JP_SET_ISO_8859_7;
ss = ISO_2022_JP_SET_SS2;
sslen = sizeof (ISO_2022_JP_SET_SS2) - 1U;
g2 = true;
break;
// only JIS X 0212-1990 and KSC5601-1987 are 4 elements long
case CHSET_JIS_X_0212_1990:
if (enc != iso2022_jp) {
esc = ISO_2022_JP_SET_JIS212_90;
len = sizeof (ISO_2022_JP_SET_JIS212_90) - 1U;
}
break;
case CHSET_KSC_5601_1987:
if (enc != iso2022_jp) {
esc = ISO_2022_JP_SET_KSC5601_87;
len = sizeof (ISO_2022_JP_SET_KSC5601_87) - 1U;
}
break;
default:
return CODECVT_ERROR;
}
if (g2) {
if (state.sshift2 == 1) {
// there is already a correct designation and a single
// shift function inserted in the destination buffer
return CODECVT_OK;
}
// insert the designation
if (reg != state.g_map [2]) {
// FIXME - check correctness
if (_RWSTD_STATIC_CAST (_RWSTD_SIZE_T, to_end - to) < len)
return CODECVT_PARTIAL;
memcpy (to, esc, len);
to += len;
// adjust the state
state.g_map [2] = reg;
}
// insert the single shift function
// FIXME - check correctness
if (_RWSTD_STATIC_CAST (_RWSTD_SIZE_T, to_end - to) < len)
return CODECVT_PARTIAL;
memcpy (to, ss, sslen);
to += sslen;
// adjust the single shift indicator
state.sshift2 = 1;
} else {
// FIXME - check correctness
if (_RWSTD_STATIC_CAST (_RWSTD_SIZE_T, to_end - to) < len)
return CODECVT_PARTIAL;
memcpy (to, esc, len);
to += len;
// adjust the state
state.g_map [0] = reg;
state.gl_map = 1;
state.shift_state = __rw_chset_map [reg].width;
}
return CODECVT_OK;
}
// Process one escape sequence in an ISO-2022 stream;
//
// Upon entry:
// - from - points to the first byte after the ESCAPE_CHAR indicator;
// - enc - encoding type.
static _V3_LOCALE::codecvt_base::result
__rw_iso2022_escape (__rw_iso2022_state_t& state,
const char*& from,
const char* from_end,
int enc)
{
// copy of source pointer
const char* ps = from + 1;
// test for end of sequence
if (from_end == ps)
return CODECVT_OK;
__rw_codeset_type_t type = sb94;
switch (*ps) {
case ISO_2022_SET_SS2:
// Single-Shift 2 invokes G2 in GL for one character;
// adjust the source pointer...
from = ++ps;
// ...and set the single-shift 2 flag in the state structure
state.sshift2 = 1;
return CODECVT_OK;
case ISO_2022_SET_SB94_G0:
type = sb94;
break;
case ISO_2022_SET_SB96_G2:
type = sb96;
break;
case ISO_2022_SET_MB:
type = mb94;
// test for end of sequence
if (from_end == ps + 1)
return CODECVT_OK;
// advance one more; this designation is 4 bytes long
if (*(ps + 1) == ISO_2022_SET_MB94_G0)
ps++;
break;
default:
return CODECVT_ERROR;
}
if (from_end == ++ps)
return CODECVT_OK;
// retrieve the registration code and store the state
const unsigned char reg = __rw_get_encoding_reg (type, *ps++);
if (!reg)
return CODECVT_ERROR;
// check the registration code returned by the function above
if (enc == iso2022_jp &&
(reg == CHSET_JIS_X_0212_1990 || reg == CHSET_GB2312_1980 ||
reg == CHSET_KSC_5601_1987 || reg == CHSET_ISO_8859_1 ||
reg == CHSET_ISO_8859_7)) {
return CODECVT_ERROR;
}
// designation is always in G0 unless the type is sb96
state.g_map [type == sb96 ? 2 : 0] = reg;
// however, the invocation is always in GL for ISO-2022-xxx!!
state.gl_map = 1;
state.shift_state = __rw_chset_map [reg].width;
// adjust the source pointer
from = ps;
return CODECVT_OK;
}
/****************************************************************************/
// ISO-2022-JP conversion from ANSI_X3.4-1968
// Convert one character.
// Returns:
// _V3_LOCALE::codecvt_base::ok in case the conversion succeeded
// _V3_LOCALE::codecvt_base::partial for partial conversions
// _V3_LOCALE::codecvt_base::error erroneous sequence
static _V3_LOCALE::codecvt_base::result
__rw_ascii_to_iso2022 (__rw_iso2022_state_t& state,
const char*& from,
const char* from_end,
char*& to,
char* to_end,
int enc)
{
// the registration
unsigned char reg = CHSET_ANSI_X_3_4_1968;
unsigned int width = __rw_chset_map [reg].width + 1;
_RWSTD_ASSERT (from_end-from >= int(width));
_RWSTD_UNUSED (from_end);
_V3_LOCALE::codecvt_base::result ret;
// check the designation sequence
if (state.g_map [0] != reg) {
char* pd = to;
// insert a designation sequence in this place
ret = __rw_iso2022jp_designate (state, pd, to_end, reg, enc);
if (ret != CODECVT_OK)
return ret;
state.gl_map = 1;
state.g_map [0] = reg;
state.shift_state = __rw_chset_map [reg].width;
// adjust destination pointer
to = pd;
if (to == to_end)
return ret;
}
// FIXME - check the validity of this test
if (to_end - to < int (width))
return CODECVT_PARTIAL;
*to++ = char (*from++ & 0x7f);
if (width > 1)
*to++ = char (*from++ & 0x7f);
return CODECVT_OK;
}
// ISO-2022-JP conversion from KSC5601-1987
// Convert one character.
// Returns:
// _V3_LOCALE::codecvt_base::ok in case the conversion succeeded
// _V3_LOCALE::codecvt_base::partial for partial conversions
// _V3_LOCALE::codecvt_base::error erroneous sequence
static _V3_LOCALE::codecvt_base::result
__rw_ksc5601_to_iso2022 (__rw_iso2022_state_t& state,
const char*& from,
const char* from_end,
char*& to,
char* to_end,
int enc)
{
// the registration
unsigned char reg = CHSET_KSC_5601_1987;
unsigned int width = __rw_chset_map [reg].width + 1;
_RWSTD_ASSERT(from_end-from >= int(width));
_RWSTD_UNUSED(from_end);
_V3_LOCALE::codecvt_base::result ret;
// check the designation sequence
if (state.g_map [0] != reg) {
char* pd = to;
// insert a designation sequence in this place
ret = __rw_iso2022jp_designate (state, pd, to_end, reg, enc);
if (ret != CODECVT_OK)
return ret;
state.gl_map = 1;
state.g_map [0] = reg;
state.shift_state = __rw_chset_map [reg].width;
// adjust destination pointer
to = pd;
if (to == to_end)
return ret;
}
// FIXME - check the validity of this test
if (to_end - to < int (width))
return CODECVT_PARTIAL;
*to++ = char (*from++ & 0x7f);
if (width > 1)
*to++ = char (*from++ & 0x7f);
return CODECVT_OK;
}
// ISO-2022-JP conversion from GB2312-1980
// Convert one character.
// Returns:
// _V3_LOCALE::codecvt_base::ok in case the conversion succeeded
// _V3_LOCALE::codecvt_base::partial for partial conversions
// _V3_LOCALE::codecvt_base::error erroneous sequence
static _V3_LOCALE::codecvt_base::result
__rw_gb2312_to_iso2022 (__rw_iso2022_state_t& state,
const char*& from,
const char* from_end,
char*& to,
char* to_end,
int enc)
{
// the registration
unsigned char reg = CHSET_GB2312_1980;
unsigned int width = __rw_chset_map [reg].width + 1;
_RWSTD_ASSERT(from_end-from >= int(width));
_RWSTD_UNUSED(from_end);
_V3_LOCALE::codecvt_base::result ret;
// check the designation sequence
if (state.g_map [0] != reg) {
char* pd = to;
// insert a designation sequence in this place
ret = __rw_iso2022jp_designate (state, pd, to_end, reg, enc);
if (ret != CODECVT_OK)
return ret;
state.gl_map = 1;
state.g_map [0] = reg;
state.shift_state = __rw_chset_map [reg].width;
// adjust destination pointer
to = pd;
if (to == to_end)
return ret;
}
// FIXME - check the validity of this test
if (to_end - to < int(width))
return CODECVT_PARTIAL;
*to++ = char (*from++ & 0x7f);
if (width > 1)
*to++ = char (*from++ & 0x7f);
return CODECVT_OK;
}
// ISO-2022-JP conversion from ISO-8859-7
// Convert one character.
// Returns:
// _V3_LOCALE::codecvt_base::ok in case the conversion succeeded
// _V3_LOCALE::codecvt_base::partial for partial conversions
// _V3_LOCALE::codecvt_base::error erroneous sequence
static _V3_LOCALE::codecvt_base::result
__rw_iso88597_to_iso2022 (__rw_iso2022_state_t& state,
const char*& from,
const char* from_end,
char*& to,
char* to_end,
int enc)
{
// the registration
unsigned char reg2 = CHSET_ISO_8859_7;
unsigned int width2 = __rw_chset_map [reg2].width + 1;
_RWSTD_ASSERT(from_end-from >= int(width2));
_RWSTD_UNUSED(from_end);
_V3_LOCALE::codecvt_base::result ret;
// always call designate for this one; designation will at least insert a
// single shift function in the destination buffer
ret = __rw_iso2022jp_designate (state, to, to_end, reg2, enc);
if (ret != CODECVT_OK)
return ret;
// adjust the G2 designation
state.g_map [2] = reg2;
// FIXME - check the validity of this test
if (to_end - to < int (width2))
return CODECVT_PARTIAL;
*to++ = char (*from++ & 0x7f);
if (width2 > 1)
*to++ = char (*from++ & 0x7f);
// clear the single shift functions
state.sshift2 = state.sshift3 = 0;
return CODECVT_OK;
}
// ISO-2022-JP conversion from ISO-8859-1
// Convert one character.
// Returns:
// _V3_LOCALE::codecvt_base::ok in case the conversion succeeded
// _V3_LOCALE::codecvt_base::partial for partial conversions
// _V3_LOCALE::codecvt_base::error erroneous sequence
static _V3_LOCALE::codecvt_base::result
__rw_iso88591_to_iso2022 (__rw_iso2022_state_t& state,
const char*& from,
const char* from_end,
char*& to,
char* to_end,
int enc)
{
// the registration
unsigned char reg2 = CHSET_ISO_8859_1;
unsigned int width2 = __rw_chset_map [reg2].width + 1;
_RWSTD_ASSERT(from_end-from >= int(width2));
_RWSTD_UNUSED(from_end);
_V3_LOCALE::codecvt_base::result ret;
// always call designate for this one; designation will at least insert a
// single shift function in the destination buffer
ret = __rw_iso2022jp_designate (state, to, to_end, reg2, enc);
if (ret != CODECVT_OK)
return ret;
// adjust the G2 designation
state.g_map [2] = reg2;
// FIXME - check the validity of this test
if (to_end - to < int (width2))
return CODECVT_PARTIAL;
*to++ = char (*from++ & 0x7f);
if (width2 > 1)
*to++ = char (*from++ & 0x7f);
// clear the single shift functions
state.sshift2 = state.sshift3 = 0;
return CODECVT_OK;
}
// ISO-2022-JP conversion from packed EUC-JP
// Convert one character.
// Returns:
// _V3_LOCALE::codecvt_base::ok in case the conversion succeeded
// _V3_LOCALE::codecvt_base::partial for partial conversions
// _V3_LOCALE::codecvt_base::error erroneous sequence
static _V3_LOCALE::codecvt_base::result
__rw_eucjp_to_iso2022 (__rw_iso2022_state_t& state,
const char*& from,
const char* from_end,
char*& to,
char* to_end,
int enc)
{
int width = 0;
unsigned char reg = 0;
_V3_LOCALE::codecvt_base::result ret;
// convert and store the encoding
unsigned char c = *_RWSTD_REINTERPRET_CAST(const unsigned char*, from);
switch (c) {
case 0x8e:
// JIS X 0201 Katakana
reg = CHSET_JIS_X_0201_KANA;
from++;
break;
case 0x8f:
// JIS X 0212 1990
reg = CHSET_JIS_X_0212_1990;
from++;
break;
default:
if (c > 0x80) {
// JIS X 0208-1978
reg = CHSET_JIS_X_0208_1978;
} else {
// JIS X 0201 Roman/ANSI_X3.4-1968
reg = CHSET_ANSI_X_3_4_1968;
}
break;
}
// width in elements of the ISO-2022 output
width = __rw_chset_map [reg].width + 1;
// check the designation sequence
if (state.g_map [0] != reg) {
char* pd = to;
// insert a designation sequence in this place
ret = __rw_iso2022jp_designate (state, pd, to_end, reg, enc);
if (ret != CODECVT_OK)
return ret;
// adjust destination pointer
to = pd;
state.gl_map = 1;
state.g_map [0] = reg;
state.shift_state = __rw_chset_map [reg].width;
if (to == to_end)
return ret;
}
// insert the character in the destination buffer
if (width > from_end - from)
return CODECVT_OK;
// FIXME - check the validity of this test
if (to_end - to < __rw_chset_map[reg].width)
return CODECVT_PARTIAL;
*to++ = char (*from++ & 0x7f);
if (width > 1)
*to++ = char (*from++ & 0x7f);
return CODECVT_OK;
}
// ISO-2022-JP conversion to GB2312-1980
// Converts one character.
// Returns:
// _V3_LOCALE::codecvt_base::ok in case the conversion succeeded
// _V3_LOCALE::codecvt_base::partial for partial conversions
// _V3_LOCALE::codecvt_base::error erroneous sequence
static inline
_V3_LOCALE::codecvt_base::result
__rw_iso2022_to_gb2312 (const char*& from,
const char* from_end,
char*& to,
int /* reg */,
int /* enc */)
{
_V3_LOCALE::codecvt_base::result res = CODECVT_OK;
if (from_end - from < GB2312_CHAR_LEN)
return res;
// store the destination bytes after setting the highest bit
*to++ = char (*from++ | 0x80);
*to++ = char (*from++ | 0x80);
return res;
}
// ISO-2022-JP conversion to KSC2312
// Converts one character.
// Returns:
// _V3_LOCALE::codecvt_base::ok in case the conversion succeeded
// _V3_LOCALE::codecvt_base::partial for partial conversions
// _V3_LOCALE::codecvt_base::error erroneous sequence
static inline
_V3_LOCALE::codecvt_base::result
__rw_iso2022_to_ksc5601 (const char*& from,
const char* from_end,
char*& to,
int /* reg */,
int /* enc */)
{
_V3_LOCALE::codecvt_base::result res = CODECVT_OK;
if (from_end - from < KSC5601_CHAR_LEN)
return res;
// store the destination bytes after setting the highest bit
*to++ = char (*from++ | 0x80);
*to++ = char (*from++ | 0x80);
return res;
}
// ISO-2022-JP conversion to ISO-8859-1
// Converts one character.
// Returns:
// _V3_LOCALE::codecvt_base::ok in case the conversion succeeded
// _V3_LOCALE::codecvt_base::partial for partial conversions
// _V3_LOCALE::codecvt_base::error erroneous sequence
static inline
_V3_LOCALE::codecvt_base::result
__rw_iso2022_to_iso88591 (const char*& from,
const char* from_end,
char*& to,
int /* reg */,
int /* enc */)
{
_V3_LOCALE::codecvt_base::result res = CODECVT_OK;
if (from_end - from < ISO_8859_1_CHAR_LEN)
return res;
// store the destination bytes after setting the highest bit
*to++ = char (*from++ | 0x80);
return res;
}
// ISO-2022-JP conversion to ISO-8859-7
// Converts one character.
// Returns:
// _V3_LOCALE::codecvt_base::ok in case the conversion succeeded
// _V3_LOCALE::codecvt_base::partial for partial conversions
// _V3_LOCALE::codecvt_base::error erroneous sequence
static inline
_V3_LOCALE::codecvt_base::result
__rw_iso2022_to_iso88597 (const char*& from,
const char* from_end,
char*& to,
int /* reg */,
int /* enc */)
{
_V3_LOCALE::codecvt_base::result res = CODECVT_OK;
if (from_end - from < ISO_8859_7_CHAR_LEN)
return res;
// store the destination bytes after setting the highest bit
*to++ = char (*from++ | 0x80);
return res;
}
// ISO-2022-JP conversion to packed EUC-JP
// Converts one character.
// Returns:
// _V3_LOCALE::codecvt_base::ok in case the conversion succeeded
// _V3_LOCALE::codecvt_base::partial for partial conversions
// _V3_LOCALE::codecvt_base::error erroneous sequence
static _V3_LOCALE::codecvt_base::result
__rw_iso2022_to_eucjp (const char*& from,
const char* from_end,
char*& to,
int reg,
int enc)
{
// encoding registration number
int width = __rw_chset_map [reg].width + 1;
// test the length of the input
if (from_end - from < width)
return CODECVT_OK;
_V3_LOCALE::codecvt_base::result res = CODECVT_OK;
// from either the ANSI_X3.4-1968 or JIS X 0201 Roman or JIS X 0201 Kana
switch (reg) {
case CHSET_ANSI_X_3_4_1968:
case CHSET_JIS_X_0201_ROMAN:
// these character sets encode on one byte in EUC-JP
*to++ = *from++;
break;
case CHSET_JIS_X_0208_1978:
case CHSET_JIS_X_0208_1983:
*to++ = char (*from++ | 0x80);
*to++ = char (*from++ | 0x80);
break;
// The following belong to ISO-2022-JP-2
case CHSET_JIS_X_0201_KANA:
if (enc == iso2022_jp) {
res = CODECVT_ERROR;
break;
}
// this character set encode on two bytes in EUC-JP
*to++ = '\x8e';
*to++ = char (*from++ | 0x80);
break;
case CHSET_JIS_X_0212_1990:
if (enc == iso2022_jp) {
res = CODECVT_ERROR;
break;
}
*to++ = '\x8f';
*to++ = char (*from++ | 0x80);
*to++ = char (*from++ | 0x80);
break;
default:
res = CODECVT_ERROR;
break;
}
return res;
}
// Converts one character from the external representation to the
// intermediary encoding that is later used in retrieving the internal
// representation of that character
static _V3_LOCALE::codecvt_base::result
__rw_iso2022_to_interm (__rw_iso2022_state_t& state,
const char*& from,
const char* from_end,
char*& to,
unsigned char& reg,
int enc)
{
_V3_LOCALE::codecvt_base::result res = CODECVT_OK;
bool first = true;
for (; *from == ESCAPE_CHAR; first = false) {
// clear up the single shift functions set before
if (first == false)
state.sshift2 = state.sshift3 = 0;
const char* tmp = from;
res = __rw_iso2022_escape (state, from, from_end, enc);
// the detected escape sequence has not been consumed because it
// was incomplete or an error has been returned
if (res != CODECVT_OK || tmp == from)
return res;
}
if (*from <= 0x20) {
;// FIXME - process control characters
}
// if any single shift sequence has been selected, then clear up the
// flag and adjust the registration code accordingly
if (state.sshift2 == 1) {
state.sshift2 = 0;
// registration code switches to whatever code has been selected
// in G2 (one of ISO-8859-1 and ISO-8859-7)
reg = state.g_map [2];
} else {
// refresh the reg value
reg = state.g_map [0];
}
// ISO-2022-JP and ISO-2022-JP-2 use G0 exclusively
switch (reg) {
case CHSET_ANSI_X_3_4_1968:
case CHSET_JIS_X_0201_KANA:
case CHSET_JIS_X_0201_ROMAN:
case CHSET_JIS_X_0208_1978:
case CHSET_JIS_X_0208_1983:
case CHSET_JIS_X_0212_1990:
res = __rw_iso2022_to_eucjp (from, from_end, to, reg, enc);
break;
case CHSET_GB2312_1980:
res = __rw_iso2022_to_gb2312 (from, from_end, to, reg, enc);
break;
case CHSET_KSC_5601_1987:
res = __rw_iso2022_to_ksc5601 (from, from_end, to, reg, enc);
break;
case CHSET_ISO_8859_1:
res = __rw_iso2022_to_iso88591 (from, from_end, to, reg, enc);
break;
case CHSET_ISO_8859_7:
res = __rw_iso2022_to_iso88597 (from, from_end, to, reg, enc);
break;
}
// clear any single shift functions, if any
state.sshift2 = state.sshift3 = 0;
return CODECVT_OK;
}
static _V3_LOCALE::codecvt_base::result
__rw_ucs4_to_eucjp (const wchar_t*& from,
const wchar_t* from_end,
char*& to,
char* to_end,
const _RW::__rw_codecvt_t* impl)
{
typedef unsigned char UChar;
// "impl" as raw pointer to unsigned ints
const char* impl_raw =
_RWSTD_REINTERPRET_CAST(const char*,impl);
// utf8 temporary buffer
char tmp [_UTF8_MB_CUR_MAX];
char* ptmp = tmp;
// tbls will point to the first lookup table
const unsigned int* tbls = impl->utf8_to_ext_tab ();;
const unsigned int* tbl = tbls;
_RWSTD_ASSERT(tbls);
if (from == from_end || to == to_end)
return CODECVT_OK;
_RWSTD_SIZE_T ret = __rw_itoutf8 (*from, ptmp);
unsigned int wc = tbl [UChar (*ptmp)];
while (wc & 0x80000000) {
if (wc == _RWSTD_UINT_MAX)
// FIXME - this is an error condition
return CODECVT_ERROR;
if (ret-- == 0)
// FIXME - this is an error condition
return CODECVT_ERROR;
// get next table
wc &= 0x7fffffff;
tbl = tbls + 256 * wc;
wc = tbl [UChar (*++ptmp)];
}
// store the encoding sequence at destination
_RWSTD_SIZE_T offset = wc + sizeof (_RW::__rw_codecvt_t);
while (impl_raw [offset]) {
if (to == to_end)
return CODECVT_PARTIAL;
else
*to++ = impl_raw [offset++];
}
from++;
return CODECVT_OK;
}
static unsigned char /* registration code */
__rw_ucs4_to_interm ( const wchar_t*& from,
char*& to)
{
typedef unsigned char UChar;
static const struct {
UChar db;
UChar reg;
} db_array [] = {
{ DBIDX_ANSI_X_3_4_1968, CHSET_ANSI_X_3_4_1968 },
{ DBIDX_EUC_JP , CHSET_JIS_X_0212_1990 },
{ DBIDX_EUC_KR , CHSET_KSC_5601_1987 },
{ DBIDX_GB2312 , CHSET_GB2312_1980 },
{ DBIDX_ISO_8859_7 , CHSET_ISO_8859_7 },
{ DBIDX_ISO_8859_1 , CHSET_ISO_8859_1 }
};
// utf8 temporary buffer
char tmp [_UTF8_MB_CUR_MAX];
for (int i = 0; i < int(sizeof (db_array)/sizeof (unsigned char)); i++) {
char* ptmp = tmp;
// obtain the database mapping
const void* pdb = __rw_get_encoding_database (db_array [i].db);
if (pdb == 0)
continue;
// cast the database map pointer to the correct type
const _RW::__rw_codecvt_t* impl =
_RWSTD_STATIC_CAST(const _RW::__rw_codecvt_t*, pdb);
// the "raw access" pointer used in finding the external repr.
const char* impl_raw = _RWSTD_REINTERPRET_CAST(const char*,impl);
// tbls will point to the first lookup table
const unsigned int* tbls = impl->utf8_to_ext_tab ();
const unsigned int* tbl = tbls;
_RWSTD_ASSERT(tbls);
_RWSTD_SIZE_T ret = __rw_itoutf8 (*from, ptmp);
bool success = true;
unsigned int wc = tbl [UChar (*ptmp)];
while (wc & 0x80000000) {
if (wc == _RWSTD_UINT_MAX || ret-- == 0) {
success = false;
break;
}
// get next table
wc &= 0x7fffffff;
tbl = tbls + 256 * wc;
wc = tbl [UChar (*++ptmp)];
}
// continue on the next lookup
if (!success)
continue;
// store the encoding sequence at destination
_RWSTD_SIZE_T offset = wc + sizeof (_RW::__rw_codecvt_t);
while (impl_raw [offset])
*to++ = impl_raw [offset++];
// advance source pointer to next position
from++;
// Find the registration code of the encoding and return it
return db_array [i].reg;
}
// invalid registration code
return 0;
}
// does the conversion of one character to internal representation
static _V3_LOCALE::codecvt_base::result
__rw_iso2022_to_ucs4 (_RWSTD_MBSTATE_T& state,
__rw_iso2022_state_t* iso_state,
const char*& from,
const char* from_end,
wchar_t*& to,
wchar_t* /* to_end */,
int enc)
{
_V3_LOCALE::codecvt_base::result res;
// the registration code of the character set
unsigned char reg = iso_state->g_map [0];
int width = iso_state->shift_state + 1;
// test input width
if (from_end - from < width) {
// test and deallocate state
if (iso_state->g_map [0] == CHSET_ANSI_X_3_4_1968)
__rw_deallocate_state (*iso_state, state, false);
return CODECVT_OK;
}
// temporary buffer to accomodate the intermediary encoding
char tmp_buffer [8];
char* tmp_to = tmp_buffer;
char* tmp_to_end;
const char* from_next = from;
// convert one character at a time and note that the registration
// code is actually modified by the following call in the case
// of single shift functions
res = __rw_iso2022_to_interm (*iso_state, from_next, from_end,
tmp_to, reg, enc);
if (res != CODECVT_OK ||
(from_next == from && tmp_to == tmp_buffer)) {
__rw_deallocate_state (*iso_state, state, CODECVT_ERROR != res);
return res;
}
// the input sequence started with an escape sequence
if (tmp_to == tmp_buffer) {
from = from_next;
return res;
}
tmp_to_end = tmp_to;
tmp_to = tmp_buffer;
// get the proper database for decoding input
const void* pdb = __rw_get_encoding_database (__rw_chset_map [reg].index);
if (pdb == 0) {
__rw_deallocate_state (*iso_state, state, false);
return CODECVT_ERROR;
}
const _RW::__rw_codecvt_t* pimpl =
_RWSTD_STATIC_CAST(const _RW::__rw_codecvt_t*, pdb);
// retrieve the lookup table start
const unsigned int* tbls = pimpl->n_to_w_tab ();
const unsigned int* tbl = tbls;
_RWSTD_ASSERT(tbls);
// wider character representations will be looked upon in the
// database tables
unsigned int wc = tbl [*(unsigned char*)tmp_to];
while (wc & 0x80000000) {
if (wc == _RWSTD_UINT_MAX) {
__rw_deallocate_state (*iso_state, state, false);
return CODECVT_ERROR;
}
// wc is table index
tbl = tbls + 256*(wc & 0x7fffffff);
tmp_to++;
// we have reached end of EUC-JP temporary buffer and we found
// here an incomplete sequence; the incomplete sequence here
// is an error
if (tmp_to == tmp_to_end) {
__rw_deallocate_state (*iso_state, state, false);
return CODECVT_ERROR;
}
wc = tbl [*(unsigned char*)tmp_to];
}
// update source pointer and store the value at destination
from = from_next;
*to++ = pimpl->get_ucs4_at_offset(wc);
return CODECVT_OK;
}
/****************************************************************************/
// Conversion from ISO-2022-JP to UCS-4
_V3_LOCALE::codecvt_base::result
__rw_iso2022jp_do_in (_RWSTD_MBSTATE_T& state,
const char*& from,
const char* from_end,
wchar_t*& to,
wchar_t* to_end)
{
// the iso2022 state
__rw_iso2022_state_t* iso_state =
__rw_get_iso2022_state (state, iso2022_jp);
if (iso_state == 0)
return CODECVT_ERROR;
// Loop until the source buffer is consumed, an error occurs, or
// the destination buffer reaches capacity
const char* from_next = from;
wchar_t* to_next = to;
while (from_end - from && to_end - to) {
// operation result
_V3_LOCALE::codecvt_base::result res;
res = __rw_iso2022_to_ucs4 (state, iso_state, from_next,
from_end, to_next, to_end, iso2022_jp);
if (res != CODECVT_OK)
return res;
// an ok result with no conversion
if (res == CODECVT_OK &&
from_next == from && to_next == to)
return res;
from = from_next;
to = to_next;
}
// deallocate state if the conversion has gone back to initial state
__rw_deallocate_state (*iso_state, state, true);
return CODECVT_OK;
}
// Conversion from UCS-4 to ISO-2022-JP
_V3_LOCALE::codecvt_base::result
__rw_iso2022jp_do_out (_RWSTD_MBSTATE_T& state,
const wchar_t*& from,
const wchar_t* from_end,
char*& to,
char* to_end)
{
// the iso2022 state
__rw_iso2022_state_t* iso_state =
__rw_get_iso2022_state (state, iso2022_jp);
if (iso_state == 0)
return CODECVT_ERROR;
// destination buffer to accomodate the EUC-JP encoding
char euc_buffer [8];
// use the EUC-JP database for a full lookup
const void* pdb = __rw_get_encoding_database (DBIDX_EUC_JP);
if (pdb == 0){
__rw_deallocate_state (*iso_state, state, false);
return CODECVT_ERROR;
}
const _RW::__rw_codecvt_t* pimpl =
_RWSTD_STATIC_CAST(const _RW::__rw_codecvt_t*, pdb);
_RWSTD_ASSERT(pimpl);
// Loop until the source buffer is consumed, an error occurs, or
// the destination buffer reaches capacity
while (from_end - from && to_end - to) {
_V3_LOCALE::codecvt_base::result res;
// convert the UCS-4 value to EUC-JP
const wchar_t* ps = from;
const wchar_t* pse = from_end;
char* euc = euc_buffer;
char* euce = euc_buffer + 8;
res = __rw_ucs4_to_eucjp (ps, pse, euc, euce, pimpl);
if (res != CODECVT_OK ||
(ps == from && euc == euc_buffer)) {
__rw_deallocate_state (*iso_state, state, CODECVT_ERROR != res);
return res;
}
char* pd = to;
// convert the EUC-JP value to ISO-2022
euce = euc;
const char* ceuc = euc_buffer;
res = __rw_eucjp_to_iso2022 (*iso_state, ceuc,
euce, pd, to_end, iso2022_jp);
if (res != CODECVT_OK ||
(ceuc == euc_buffer && pd == to)) {
__rw_deallocate_state (*iso_state, state, CODECVT_ERROR != res);
return res;
}
//adjust source pointer
from = ps;
to = pd;
}
// deallocate state if the conversion has gone back to
// initial state
__rw_deallocate_state (*iso_state, state, true);
return CODECVT_OK;
}
_V3_LOCALE::codecvt_base::result
__rw_iso2022jp_do_unshift (_RWSTD_MBSTATE_T& state,
char*& to, char* to_end)
{
_V3_LOCALE::codecvt_base::result res =
CODECVT_ERROR;
// the iso2022 state
__rw_iso2022_state_t* iso_state =
__rw_get_iso2022_state (state, iso2022_jp);
if (iso_state == 0)
return res;
if (iso_state->g_map [iso_state->gl_map - 1] != CHSET_ANSI_X_3_4_1968)
res = __rw_iso2022jp_designate (*iso_state, to, to_end,
CHSET_ANSI_X_3_4_1968, iso2022_jp);
else
res = CODECVT_OK;
// deallocate a state if the conversion has gone back to
// initial shift state and operation succeeded, OR, if
// the result is error
__rw_deallocate_state (*iso_state, state, CODECVT_ERROR != res);
return res;
}
_RWSTD_SIZE_T
__rw_iso2022jp_do_length (_RWSTD_MBSTATE_T& state,
const char* from, const char* from_end,
_RWSTD_SIZE_T max)
{
_RWSTD_ASSERT(from <= from_end);
// the iso2022 state
__rw_iso2022_state_t* iso_state =
__rw_get_iso2022_state (state, iso2022_jp);
if (iso_state == 0)
return CODECVT_ERROR;
int ret = 0;
_V3_LOCALE::codecvt_base::result res = CODECVT_OK;
while (max && from_end - from) {
while (*from == ESCAPE_CHAR)
if (*from == ESCAPE_CHAR) {
const char* tmp = from;
res = __rw_iso2022_escape (*iso_state, from, from_end, iso2022_jp);
if (res != CODECVT_OK || from == tmp)
break;
continue;
}
if (from_end - from < int(iso_state->shift_state) + 1)
break;
ret++, max--;
from += iso_state->shift_state + 1;
}
// deallocate a state if the conversion has gone back to initial shift
// state
__rw_deallocate_state (*iso_state, state, CODECVT_ERROR != res);
return ret;
}
_RWSTD_SIZE_T
__rw_iso2022jp_do_max_length ()
{
return 2;
}
int __rw_iso2022jp_do_encoding ()
{
return -1;
}
bool __rw_iso2022jp_do_always_noconv ()
{
return false;
}
/****************************************************************************/
// Conversion from ISO-2022-JP to UCS-4
_V3_LOCALE::codecvt_base::result
__rw_iso2022jp2_do_in (_RWSTD_MBSTATE_T& state,
const char*& from,
const char* from_end,
wchar_t*& to,
wchar_t* to_end)
{
// the iso2022 state
__rw_iso2022_state_t* iso_state =
__rw_get_iso2022_state (state, iso2022_jp);
if (iso_state == 0)
return CODECVT_ERROR;
// Loop until the source buffer is consumed, an error occurs, or
// the destination buffer reaches capacity
while (from_end - from && to_end - to) {
const char* from_next = from;
wchar_t* to_next = to;
// operation result
_V3_LOCALE::codecvt_base::result res;
res = __rw_iso2022_to_ucs4 (state, iso_state, from_next,
from_end, to_next, to_end, iso2022_jp2);
if (res != CODECVT_OK)
return res;
// an ok result with no conversion
if (res == CODECVT_OK &&
from_next == from && to_next == to)
return res;
from = from_next;
to = to_next;
}
// deallocate state if the conversion has gone back to initial state
__rw_deallocate_state (*iso_state, state, true);
return CODECVT_OK;
}
// Conversion from UCS-4 to ISO-2022-JP-2
_V3_LOCALE::codecvt_base::result
__rw_iso2022jp2_do_out (_RWSTD_MBSTATE_T& state,
const wchar_t*& from,
const wchar_t* from_end,
char*& to,
char* to_end)
{
// the iso2022 state
__rw_iso2022_state_t* iso_state =
__rw_get_iso2022_state (state, iso2022_jp);
if (iso_state == 0)
return CODECVT_ERROR;
// destination buffer to accomodate the intermediate encoding
char tmp [8];
// Loop until the source buffer is consumed, an error occurs, or
// the destination buffer reaches capacity
while (from_end - from && to_end - to) {
_V3_LOCALE::codecvt_base::result res;
// convert the UCS-4 value to intermediary encoding
const wchar_t* ps = from;
char* tmps = tmp;
char* tmpe = tmp + 8;
unsigned char reg =
__rw_ucs4_to_interm (ps, tmps);
if (reg == 0) {
// deallocate state
__rw_deallocate_state (*iso_state, state, false);
// error condition - none of the databases contained a mapping
// of the character
return CODECVT_ERROR;
}
char* pd = to;
// convert the intermediary value to ISO-2022
tmpe = tmps;
const char* ctmps = tmp;
// the registration of the encoding dictates how the conversion is
// to be performed further
switch (reg) {
case CHSET_ANSI_X_3_4_1968:
res = __rw_ascii_to_iso2022 (*iso_state, ctmps, tmpe,
pd, to_end, iso2022_jp2);
break;
case CHSET_JIS_X_0212_1990:
res = __rw_eucjp_to_iso2022 (*iso_state, ctmps, tmpe,
pd, to_end, iso2022_jp2);
break;
case CHSET_KSC_5601_1987:
res = __rw_ksc5601_to_iso2022 (*iso_state, ctmps, tmpe,
pd, to_end, iso2022_jp2);
break;
case CHSET_GB2312_1980:
res = __rw_gb2312_to_iso2022 (*iso_state, ctmps, tmpe,
pd, to_end, iso2022_jp2);
break;
case CHSET_ISO_8859_7:
res = __rw_iso88597_to_iso2022 (*iso_state, ctmps, tmpe,
pd, to_end, iso2022_jp2);
break;
case CHSET_ISO_8859_1:
res = __rw_iso88591_to_iso2022 (*iso_state, ctmps, tmpe,
pd, to_end, iso2022_jp2);
break;
default:
return CODECVT_ERROR;
}
if (res != CODECVT_OK || (ctmps==tmp && pd==to)) {
__rw_deallocate_state (*iso_state, state, CODECVT_ERROR != res);
return res;
}
//adjust source pointer
from = ps;
to = pd;
// after a successful insertion the single shift functions
// must be cleared
iso_state->sshift2 = iso_state->sshift3 = 0;
}
// deallocate state if the conversion has gone back to
// initial state
__rw_deallocate_state (*iso_state, state, true);
return CODECVT_OK;
}
_V3_LOCALE::codecvt_base::result
__rw_iso2022jp2_do_unshift (_RWSTD_MBSTATE_T& state,
char*& to, char* to_end)
{
return __rw_iso2022jp_do_unshift (state, to, to_end);
}
_RWSTD_SIZE_T
__rw_iso2022jp2_do_length (_RWSTD_MBSTATE_T& state,
const char* from, const char* from_end,
_RWSTD_SIZE_T max)
{
_RWSTD_ASSERT(from <= from_end);
// the iso2022 state
__rw_iso2022_state_t* iso_state =
__rw_get_iso2022_state (state, iso2022_jp);
if (iso_state == 0)
return CODECVT_ERROR;
int ret = 0;
_V3_LOCALE::codecvt_base::result res = CODECVT_OK;
while (max && from_end - from) {
bool first = true;
for (; *from == ESCAPE_CHAR; first = false) {
// clear up the single shift functions set before
if (first == false)
iso_state->sshift2 = iso_state->sshift3 = 0;
const char* tmp = from;
res = __rw_iso2022_escape (*iso_state, from, from_end,
iso2022_jp2);
// the detected escape sequence has not been consumed because it
// was incomplete
if (res != CODECVT_OK || tmp == from)
return ret;
}
if (*from <= 0x20) {
;// FIXME - process control characters
}
// the registration for all character sets other than the ISO's
// is stored in the first register, G0.
unsigned char reg = iso_state->g_map [0];
unsigned int width;
if (iso_state->sshift2 == 1) {
width = 1;
} else {
width = __rw_chset_map [reg].width + 1;
}
if (from_end - from < int (width))
break;
ret++, max--;
from += width;
// clean up the single shift function
iso_state->sshift2 = iso_state->sshift3 = 0;
}
// deallocate a state if the conversion has gone back to initial shift
// state
__rw_deallocate_state (*iso_state, state, CODECVT_ERROR != res);
return ret;
}
_RWSTD_SIZE_T
__rw_iso2022jp2_do_max_length ()
{
return 2;
}
int __rw_iso2022jp2_do_encoding ()
{
return -1;
}
bool __rw_iso2022jp2_do_always_noconv ()
{
return false;
}
} // namespace __rw
#endif // _RWSTD_NO_V3_LOCALE