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., 59 Temple Place - 18 * Suite 330, Boston, MA 02111-1307, 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 36static int 37iso2022_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 115none: 116 conv->istate = state; 117 return RET_TOOFEW(count); 118} 119 120static int 121iso2022_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 /* Extra compatibility with cp932. */ 192 { 193 int count = (state == STATE_JISX0208 ? 2 : 5); 194 if (n < count) 195 return RET_TOOSMALL; 196 switch (wc) { 197 case 0x2225: buf[0] = 0x21; buf[1] = 0x42; break; 198 case 0xff0d: buf[0] = 0x21; buf[1] = 0x5d; break; 199 case 0xff5e: buf[0] = 0x21; buf[1] = 0x41; break; 200 case 0xffe0: buf[0] = 0x21; buf[1] = 0x71; break; 201 case 0xffe1: buf[0] = 0x21; buf[1] = 0x72; break; 202 case 0xffe2: buf[0] = 0x22; buf[1] = 0x4c; break; 203 default: buf[0] = 0; 204 } 205 if (buf[0] != 0) { 206 if (state != STATE_JISX0208) { 207 r[0] = ESC; 208 r[1] = '$'; 209 r[2] = 'B'; 210 r += 3; 211 state = STATE_JISX0208; 212 } 213 r[0] = buf[0]; 214 r[1] = buf[1]; 215 conv->ostate = state; 216 return count; 217 } 218 } 219 220 return RET_ILUNI; 221} 222 223static int 224iso2022_jp_reset (conv_t conv, unsigned char *r, int n) 225{ 226 state_t state = conv->ostate; 227 if (state != STATE_ASCII) { 228 if (n < 3) 229 return RET_TOOSMALL; 230 r[0] = ESC; 231 r[1] = '('; 232 r[2] = 'B'; 233 /* conv->ostate = 0; will be done by the caller */ 234 return 3; 235 } else 236 return 0; 237} 238 239#undef STATE_JISX0208 240#undef STATE_JISX0201ROMAN 241#undef STATE_ASCII 242