]> git.tdb.fi Git - libs/core.git/blob - source/stringcodec/iso2022jp.cpp
3332922ccda68e81d354ca5f4e25f35bc96f492c
[libs/core.git] / source / stringcodec / iso2022jp.cpp
1 #include "ascii.h"
2 #include "iso2022jp.h"
3 #include "jisx0201.h"
4 #include "jisx0208.h"
5
6 using namespace std;
7
8 namespace Msp {
9 namespace StringCodec {
10
11 void Iso2022Jp::Encoder::encode_char(unichar ch, string &buf)
12 {
13         if(ch>=0 && ch<=0x7F && ch!=0x5C && ch!=0x7E)
14         {
15                 if(mode!=ASCII && mode!=JISX0201)
16                         switch_mode(ASCII, buf);
17                 buf += ch;
18         }
19         else if(ch==0x5C || ch==0x7E)
20         {
21                 if(mode!=ASCII)
22                         switch_mode(ASCII, buf);
23                 buf += ch;
24         }
25         else if(ch==0xA5 || ch==0x203E)
26         {
27                 if(mode!=JISX0201)
28                         switch_mode(JISX0201, buf);
29                 if(ch==0xA5)
30                         buf += 0x5C;
31                 else if(ch==0x203E)
32                         buf += 0x7E;
33         }
34         else
35         {
36                 Kuten jis = ucs_to_jisx0208(ch);
37                 if(!jis)
38                         return error(ch, buf, invalid_character(ch, "ISO-2022-JP"));
39
40                 if(mode!=JISX0208)
41                         switch_mode(JISX0208, buf);
42
43                 char jbuf[2];
44                 jbuf[0] = jis.ku+0x20;
45                 jbuf[1] = jis.ten+0x20;
46                 buf.append(jbuf, 2);
47         }
48 }
49
50 void Iso2022Jp::Encoder::sync(string &buf)
51 {
52         if(mode!=ASCII)
53                 switch_mode(ASCII, buf);
54 }
55
56 void Iso2022Jp::Encoder::reset()
57 {
58         mode = ASCII;
59 }
60
61 void Iso2022Jp::Encoder::switch_mode(Mode m, string &buf)
62 {
63         mode = m;
64         switch(mode)
65         {
66         case ASCII:    buf.append("\033(B", 3); break;
67         case JISX0201: buf.append("\033(J", 3); break;
68         case JISX0208: buf.append("\033$B", 3); break;
69         default: throw invalid_argument("Iso2022Jp::Encoder::switch_mode");
70         }
71 }
72
73 void Iso2022Jp::Encoder::transliterate(unichar, string &buf)
74 {
75         if(mode!=ASCII)
76                 switch_mode(ASCII, buf);
77         buf += '?';
78 }
79
80
81 Iso2022Jp::Decoder::Decoder(ErrorMode em):
82         Codec::Decoder(em),
83         dec(new Ascii::Decoder)
84 { }
85
86 unichar Iso2022Jp::Decoder::decode_char(const string &str, string::const_iterator &i)
87 {
88         if(i==str.end())
89                 return -1;
90
91         while(i!=str.end())
92         {
93                 auto j = i;
94
95                 unichar result = -1;
96                 if(*j==033)
97                 {
98                         unsigned escape = 0;
99                         for(++j; j!=str.end(); ++j)
100                         {
101                                 escape = escape<<8 | static_cast<unsigned char>(*j);
102                                 if(*j>='@' && *j<='Z')
103                                         break;
104                         }
105
106                         bool ok = true;
107                         switch(escape)
108                         {
109                         case 0x2842: switch_mode(ASCII); break;    // ESC ( B
110                         case 0x284A: switch_mode(JISX0201); break; // ESC ( J
111                         case 0x2440:                               // ESC $ @
112                         case 0x2442: switch_mode(JISX0208); break; // ESC $ B
113                         default: ok = false;
114                         }
115
116                         if(ok)
117                                 i = j;
118                         else
119                                 result = *i;
120                         ++i;
121                 }
122                 else if(dec)
123                         return dec->decode_char(str, i);
124                 else
125                         throw logic_error("no sub-decoder");
126
127                 if(result>=0)
128                         return result;
129         }
130
131         return -1;
132 }
133
134 void Iso2022Jp::Decoder::reset()
135 {
136         delete dec;
137         mode = ASCII;
138         dec = new Ascii::Decoder;
139 }
140
141 void Iso2022Jp::Decoder::switch_mode(Mode m)
142 {
143         delete dec;
144
145         mode = m;
146         switch(mode)
147         {
148         case ASCII: dec = new Ascii::Decoder; break;
149         case JISX0201: dec = new JisX0201::Decoder; break;
150         case JISX0208: dec = new JisX0208::Decoder; break;
151         }
152 }
153
154 } // namespace StringCodec
155 } // namespace Msp