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