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