1use crate::{
2 DecodeError, Decoder, EncodeError, Encoder,
3 jisx::{JIS_X_0201_LATIN_DECODE_TABLE, JIS_X_0208_DECODE_TABLE, JIS_X_0208_ENCODE_TABLE},
4};
5
6pub const ISO_2022_JP_NAME: &str = "ISO-2022-JP";
8
9#[derive(Clone, Copy, Default)]
10enum State {
11 #[default]
13 ISO646,
14 JISX0201Latin,
16 JISX0208,
18 JISX0208Old,
20}
21
22const ESCSEQ_ISO646: &[u8] = b"\x1B\x28\x42";
23const ESCSEQ_JISX0201_LATIN: &[u8] = b"\x1B\x28\x4A";
24const ESCSEQ_JISX0208: &[u8] = b"\x1B\x24\x42";
25const ESCSEQ_JISX0208_OLD: &[u8] = b"\x1B\x24\x40";
26
27#[derive(Default)]
29pub struct ISO2022JPEncoder {
30 state: State,
31}
32
33impl Encoder for ISO2022JPEncoder {
34 fn name(&self) -> &'static str {
35 ISO_2022_JP_NAME
36 }
37
38 fn encode(
39 &mut self,
40 src: &str,
41 dst: &mut [u8],
42 finish: bool,
43 ) -> Result<(usize, usize), crate::EncodeError> {
44 if src.is_empty() {
45 return if finish {
46 Ok((0, 0))
47 } else {
48 Err(EncodeError::InputIsEmpty)
49 };
50 }
51
52 let (mut read, mut write) = (0, 0);
53 for c in src.chars() {
54 if c.is_ascii() {
55 if !matches!(self.state, State::ISO646) {
56 if dst.len() < write + 4 {
57 break;
58 }
59 dst[write..write + 3].copy_from_slice(ESCSEQ_ISO646);
60 write += 3;
61 self.state = State::ISO646;
62 }
63
64 if dst.len() < write + 1 {
65 break;
66 }
67 dst[write] = c as u8;
68 write += 1;
69 read += 1;
70 } else {
71 let Ok(pos) =
72 JIS_X_0208_ENCODE_TABLE.binary_search_by_key(&(c as u32), |v| v.0 as u32)
73 else {
74 return Err(EncodeError::Unmappable {
75 read: read + c.len_utf8(),
76 write,
77 c,
78 });
79 };
80
81 let close = (read + c.len_utf8() == src.len() && finish) as usize * 3;
88
89 if !matches!(self.state, State::JISX0208) {
90 if dst.len() < write + 5 + close {
91 break;
92 }
93 dst[write..write + 3].copy_from_slice(ESCSEQ_JISX0208);
94 write += 3;
95 self.state = State::JISX0208;
96 }
97 if dst.len() < write + 2 + close {
98 break;
99 }
100 let d = JIS_X_0208_ENCODE_TABLE[pos].1;
101 dst[write] = (d >> 8) as u8;
102 dst[write + 1] = (d & 0xFF) as u8;
103 write += 2;
104 read += c.len_utf8();
105 }
106 }
107
108 if finish
109 && read == src.len()
110 && !matches!(self.state, State::ISO646)
111 && write + 3 <= dst.len()
112 {
113 dst[write..write + 3].copy_from_slice(ESCSEQ_ISO646);
114 self.state = State::ISO646;
115 write += 3;
116 }
117
118 Ok((read, write))
119 }
120}
121
122#[derive(Default)]
124pub struct ISO2022JPDecoder {
125 state: State,
126}
127
128impl Decoder for ISO2022JPDecoder {
129 fn name(&self) -> &'static str {
130 ISO_2022_JP_NAME
131 }
132
133 fn decode(
134 &mut self,
135 src: &[u8],
136 dst: &mut String,
137 finish: bool,
138 ) -> Result<(usize, usize), crate::DecodeError> {
139 if src.is_empty() {
140 return if finish {
141 Ok((0, 0))
142 } else {
143 Err(DecodeError::InputIsEmpty)
144 };
145 }
146 let len = dst.capacity() - dst.len();
147 if len < 4 {
148 return Err(DecodeError::OutputTooShort);
149 }
150
151 macro_rules! check_capacity {
152 ($len:expr) => {
153 if dst.capacity() - dst.len() < $len {
154 break;
155 }
156 };
157 }
158
159 let (mut read, mut write) = (0, 0);
160 while read < src.len() {
161 if src[read] >= 0x80 {
162 return Err(DecodeError::Malformed {
163 read: read + 1,
164 write,
165 length: 1,
166 offset: 0,
167 });
168 }
169
170 if src[read] == b'\x1B' {
171 if read + 3 > src.len() {
172 break;
173 }
174
175 match &src[read..read + 3] {
176 ESCSEQ_ISO646 => self.state = State::ISO646,
177 ESCSEQ_JISX0201_LATIN => self.state = State::JISX0201Latin,
178 ESCSEQ_JISX0208 => self.state = State::JISX0208,
179 ESCSEQ_JISX0208_OLD => self.state = State::JISX0208Old,
180 _ => {
181 return Err(DecodeError::Malformed {
183 read: read + 3,
184 write,
185 length: 3,
186 offset: 0,
187 });
188 }
189 }
190 read += 3;
191 } else {
192 match self.state {
193 State::ISO646 => {
194 check_capacity!(1);
195 dst.push(src[read] as char);
196 read += 1;
197 write += 1;
198 }
199 State::JISX0201Latin => {
200 check_capacity!(1);
201 if src[read].is_ascii_control() {
202 dst.push(src[read] as char);
203 } else {
204 dst.push(JIS_X_0201_LATIN_DECODE_TABLE[src[read] as usize - 0x20]);
205 }
206 read += 1;
207 write += 1;
208 }
209 State::JISX0208 | State::JISX0208Old => {
210 if read + 1 >= src.len() {
211 break;
212 }
213 let mut ku = src[read] as usize - 0x20;
214 let mut ten = src[read + 1] as usize - 0x20;
215 if matches!(self.state, State::JISX0208Old) {
216 (ku, ten) = match (ku, ten) {
219 (15, 18) => (81, 44),
220 (17, 8) => (81, 83),
221 (18, 33) => (72, 57),
222 (18, 40) => (56, 87),
223 (18, 85) => (66, 61),
224 (19, 34) => (61, 84),
225 (19, 49) => (74, 60),
226 (22, 58) => (79, 83),
227 (24, 59) => (65, 71),
228 (27, 40) => (72, 1),
229 (30, 56) => (79, 54),
230 (32, 7) => (75, 44),
231 (35, 58) => (51, 67),
232 (36, 54) => (65, 73),
233 (36, 77) => (58, 76),
234 (36, 82) => (61, 24),
235 (37, 85) => (76, 77),
236 (38, 71) => (73, 3),
237 (40, 15) => (58, 55),
238 (42, 88) => (47, 53),
239 (43, 88) => (72, 13),
240 (46, 21) => (67, 37),
241 (21, 37) => (83, 0),
242 (42, 73) => (83, 1),
243 (44, 57) => (83, 2),
244 (63, 85) => (83, 3),
245 (81, 44) => (15, 18),
247 (81, 83) => (17, 8),
248 (72, 57) => (18, 33),
249 (56, 87) => (18, 40),
250 (66, 61) => (18, 85),
251 (61, 84) => (19, 34),
252 (74, 60) => (19, 49),
253 (79, 83) => (22, 58),
254 (65, 71) => (24, 59),
255 (72, 1) => (27, 40),
256 (79, 54) => (30, 56),
257 (75, 44) => (32, 7),
258 (51, 67) => (35, 58),
259 (65, 73) => (36, 54),
260 (58, 76) => (36, 77),
261 (61, 24) => (36, 82),
262 (76, 77) => (37, 85),
263 (73, 3) => (38, 71),
264 (58, 55) => (40, 15),
265 (47, 53) => (42, 88),
266 (72, 13) => (43, 88),
267 (67, 37) => (46, 21),
268 (83, 0) => (21, 37),
269 (83, 1) => (42, 73),
270 (83, 2) => (44, 57),
271 (83, 3) => (63, 85),
272 _ => (ku, ten),
273 };
274 }
275 if JIS_X_0208_DECODE_TABLE[ku].len() <= ten
276 || JIS_X_0208_DECODE_TABLE[ku][ten] == char::REPLACEMENT_CHARACTER
277 {
278 return Err(DecodeError::Malformed {
279 read: read + 2,
280 write,
281 length: 2,
282 offset: 0,
283 });
284 }
285
286 let c = JIS_X_0208_DECODE_TABLE[ku][ten];
287 check_capacity!(c.len_utf8());
288 dst.push(c);
289 read += 2;
290 write += c.len_utf8();
291 }
292 }
293 }
294 }
295 Ok((read, write))
296 }
297}
298
299#[cfg(test)]
300mod tests {
301 use super::*;
302
303 #[test]
304 fn iso2022jp_tests() {
305 let src = include_bytes!("../resources/jistests/日本国憲法前文_iso2022jp.txt").as_slice();
306 let mut buf = String::with_capacity(1 << 15);
307 ISO2022JPDecoder::default()
308 .decode(src, &mut buf, true)
309 .unwrap();
310 let ucs = include_str!("../resources/jistests/日本国憲法前文_unicode.txt");
311 assert_eq!(buf, ucs);
312
313 let mut dst = vec![0; 1 << 15];
314 let (_, write) = ISO2022JPEncoder::default()
315 .encode(&buf, &mut dst, true)
316 .unwrap();
317 dst.truncate(write);
318 assert_eq!(src, dst);
319 }
320}