1 /* 2 * Copyright (C) 1999-2001 Free Software Foundation, Inc. 3 * This file is part of the GNU LIBICONV Library. 4 * 5 * The GNU LIBICONV Library is free software; you can redistribute it 6 * and/or modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either version 2 8 * of the License, or (at your option) any later version. 9 * 10 * The GNU LIBICONV Library is distributed in the hope that it will be 11 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public 16 * License along with the GNU LIBICONV Library; see the file COPYING.LIB. 17 * If not, write to the Free Software Foundation, Inc., 51 Franklin Street, 18 * Fifth Floor, Boston, MA 02110-1301, USA. 19 */ 20 21 /* 22 * ISO-2022-JP 23 */ 24 25 /* Specification: RFC 1468 */ 26 27 #define ESC 0x1b 28 29 /* 30 * The state can be one of the following values. 31 */ 32 #define STATE_ASCII 0 33 #define STATE_JISX0201ROMAN 1 34 #define STATE_JISX0208 2 35 36 static int 37 iso2022_jp_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, int n) 38 { 39 state_t state = conv->istate; 40 int count = 0; 41 unsigned char c; 42 for (;;) { 43 c = *s; 44 if (c == ESC) { 45 if (n < count+3) 46 goto none; 47 if (s[1] == '(') { 48 if (s[2] == 'B') { 49 state = STATE_ASCII; 50 s += 3; count += 3; 51 if (n < count+1) 52 goto none; 53 continue; 54 } 55 if (s[2] == 'J') { 56 state = STATE_JISX0201ROMAN; 57 s += 3; count += 3; 58 if (n < count+1) 59 goto none; 60 continue; 61 } 62 return RET_ILSEQ; 63 } 64 if (s[1] == '$') { 65 if (s[2] == '@' || s[2] == 'B') { 66 /* We don't distinguish JIS X 0208-1978 and JIS X 0208-1983. */ 67 state = STATE_JISX0208; 68 s += 3; count += 3; 69 if (n < count+1) 70 goto none; 71 continue; 72 } 73 return RET_ILSEQ; 74 } 75 return RET_ILSEQ; 76 } 77 break; 78 } 79 switch (state) { 80 case STATE_ASCII: 81 if (c < 0x80) { 82 int ret = ascii_mbtowc(conv,pwc,s,1); 83 if (ret == RET_ILSEQ) 84 return RET_ILSEQ; 85 if (ret != 1) abort(); 86 conv->istate = state; 87 return count+1; 88 } else 89 return RET_ILSEQ; 90 case STATE_JISX0201ROMAN: 91 if (c < 0x80) { 92 int ret = jisx0201_mbtowc(conv,pwc,s,1); 93 if (ret == RET_ILSEQ) 94 return RET_ILSEQ; 95 if (ret != 1) abort(); 96 conv->istate = state; 97 return count+1; 98 } else 99 return RET_ILSEQ; 100 case STATE_JISX0208: 101 if (n < count+2) 102 goto none; 103 if (s[0] < 0x80 && s[1] < 0x80) { 104 int ret = jisx0208_mbtowc(conv,pwc,s,2); 105 if (ret == RET_ILSEQ) 106 return RET_ILSEQ; 107 if (ret != 2) abort(); 108 conv->istate = state; 109 return count+2; 110 } else 111 return RET_ILSEQ; 112 default: abort(); 113 } 114 115 none: 116 conv->istate = state; 117 return RET_TOOFEW(count); 118 } 119 120 static int 121 iso2022_jp_wctomb (conv_t conv, unsigned char *r, ucs4_t wc, int n) 122 { 123 state_t state = conv->ostate; 124 unsigned char buf[2]; 125 int ret; 126 127 /* Try ASCII. */ 128 ret = ascii_wctomb(conv,buf,wc,1); 129 if (ret != RET_ILUNI) { 130 if (ret != 1) abort(); 131 if (buf[0] < 0x80) { 132 int count = (state == STATE_ASCII ? 1 : 4); 133 if (n < count) 134 return RET_TOOSMALL; 135 if (state != STATE_ASCII) { 136 r[0] = ESC; 137 r[1] = '('; 138 r[2] = 'B'; 139 r += 3; 140 state = STATE_ASCII; 141 } 142 r[0] = buf[0]; 143 conv->ostate = state; 144 return count; 145 } 146 } 147 148 /* Try JIS X 0201-1976 Roman. */ 149 ret = jisx0201_wctomb(conv,buf,wc,1); 150 if (ret != RET_ILUNI) { 151 if (ret != 1) abort(); 152 if (buf[0] < 0x80) { 153 int count = (state == STATE_JISX0201ROMAN ? 1 : 4); 154 if (n < count) 155 return RET_TOOSMALL; 156 if (state != STATE_JISX0201ROMAN) { 157 r[0] = ESC; 158 r[1] = '('; 159 r[2] = 'J'; 160 r += 3; 161 state = STATE_JISX0201ROMAN; 162 } 163 r[0] = buf[0]; 164 conv->ostate = state; 165 return count; 166 } 167 } 168 169 /* Try JIS X 0208-1990 in place of JIS X 0208-1978 and JIS X 0208-1983. */ 170 ret = jisx0208_wctomb(conv,buf,wc,2); 171 if (ret != RET_ILUNI) { 172 if (ret != 2) abort(); 173 if (buf[0] < 0x80 && buf[1] < 0x80) { 174 int count = (state == STATE_JISX0208 ? 2 : 5); 175 if (n < count) 176 return RET_TOOSMALL; 177 if (state != STATE_JISX0208) { 178 r[0] = ESC; 179 r[1] = '$'; 180 r[2] = 'B'; 181 r += 3; 182 state = STATE_JISX0208; 183 } 184 r[0] = buf[0]; 185 r[1] = buf[1]; 186 conv->ostate = state; 187 return count; 188 } 189 } 190 191 return RET_ILUNI; 192 } 193 194 static int 195 iso2022_jp_reset (conv_t conv, unsigned char *r, int n) 196 { 197 state_t state = conv->ostate; 198 if (state != STATE_ASCII) { 199 if (n < 3) 200 return RET_TOOSMALL; 201 r[0] = ESC; 202 r[1] = '('; 203 r[2] = 'B'; 204 /* conv->ostate = 0; will be done by the caller */ 205 return 3; 206 } else 207 return 0; 208 } 209 210 #undef STATE_JISX0208 211 #undef STATE_JISX0201ROMAN 212 #undef STATE_ASCII 213