]> git.tdb.fi Git - libs/core.git/blob - source/iso2022jp.cpp
More sophisticated error handling
[libs/core.git] / source / 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
10 void Iso2022Jp::Encoder::encode_char(wchar_t c_)
11 {
12         // Win32 has typedef unsigned short wchar_t
13         int c=c_;
14
15         if(c>=0 && c<=0x7F && c!=0x5C && c!=0x7E)
16         {
17                 if(mode!=ASCII && mode!=JISX0201)
18                         switch_mode(ASCII);
19                 append(c);
20         }
21         else if(c==0x5C || c==0x7E)
22         {
23                 if(mode!=ASCII)
24                         switch_mode(ASCII);
25                 append(c);
26         }
27         else if(c==0xA5 || c==0x203E)
28         {
29                 if(mode!=JISX0201)
30                         switch_mode(JISX0201);
31                 if(c==0xA5)
32                         append(0x5C);
33                 else if(c==0x203E)
34                         append(0x7E);
35         }
36         else
37         {
38                 unsigned short jis=ucs_to_jisx0208(c);
39                 if(!jis)
40                         error("Can't express character in ISO-2022-JP");
41                 else
42                 {
43                         if(mode!=JISX0208)
44                                 switch_mode(JISX0208);
45
46                         char buf[2]={jis>>8, jis};
47                         append(buf, 2);
48                 }
49         }
50 }
51
52 void Iso2022Jp::Encoder::sync()
53 {
54         if(mode!=ASCII)
55                 switch_mode(ASCII);
56 }
57
58 void Iso2022Jp::Encoder::switch_mode(Mode m)
59 {
60         mode=m;
61         switch(mode)
62         {
63         case ASCII:    append("\033(B", 3); break;
64         case JISX0201: append("\033(J", 3); break;
65         case JISX0208: append("\033$B", 3); break;
66         }
67 }
68
69 void Iso2022Jp::Encoder::append_replacement()
70 {
71         if(mode!=ASCII)
72                 switch_mode(ASCII);
73         append(032);
74 }
75
76 Iso2022Jp::Decoder::Decoder(ErrorMode em):
77         StringCodec::Decoder(em),
78         mode(ASCII),
79         dec(new Ascii::Decoder),
80         escape(0)
81 { }
82
83 void Iso2022Jp::Decoder::decode_char(const string &str, string::const_iterator &i)
84 {
85         while(i!=str.end())
86         {
87                 if(escape)
88                 {
89                         escape=escape<<8 | static_cast<unsigned char>(*i);
90                         if(*i>='@' && *i<='Z')
91                         {
92                                 switch(escape)
93                                 {
94                                 case 0x1B2842: switch_mode(ASCII); break;    // ESC ( B
95                                 case 0x1B284A: switch_mode(JISX0201); break; // ESC ( J
96                                 case 0x1B2440:                               // ESC $ @
97                                 case 0x1B2442: switch_mode(JISX0208); break; // ESC $ B
98                                 default: error("Invalid ISO-2022-JP escape sequence");
99                                 }
100                                 escape=0;
101                         }
102                         ++i;
103                 }
104                 else if(*i==0x1B)
105                 {
106                         escape=0x1B;
107                         ++i;
108                 }
109                 else
110                 {
111                         dec->decode_char(str, i);
112                         break;
113                 }
114         }
115 }
116
117 void Iso2022Jp::Decoder::sync()
118 {
119         if(escape)
120         {
121                 error("Sync in middle of ISO-2022-JP escape sequence");
122                 escape=0;
123         }
124         
125         if(mode!=ASCII)
126         {
127                 error("Sync while not in ASCII mode");
128                 switch_mode(ASCII);
129         }
130         else
131         {
132                 append(dec->get());
133                 dec->flush();
134         }
135 }
136
137 void Iso2022Jp::Decoder::switch_mode(Mode m)
138 {
139         append(dec->get());
140         delete dec;
141
142         mode=m;
143         switch(mode)
144         {
145         case ASCII: dec=new Ascii::Decoder; break;
146         case JISX0201: dec=new JisX0201::Decoder; break;
147         case JISX0208: dec=new JisX0208::Decoder; break;
148         }
149 }
150
151 } // namespace Msp