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