rtoss - Blame information for rev 146

Subversion Repositories:
Rev:
Rev Author Line No. Line
89 roytam 1 #include "stdafx.h"
2 #include "app.h"
3 #include "textfile.h"
4 #include "ktlarray.h"
5 using namespace ki;
6  
129 roytam 7 #ifndef NO_CHARDET
89 roytam 8  
129 roytam 9 #define CHARDET_RESULT_OK                   0
10 #define CHARDET_RESULT_NOMEMORY             (-1)
11 #define CHARDET_RESULT_INVALID_DETECTOR     (-2)
89 roytam 12  
129 roytam 13 typedef void* chardet_t;
14  
15 #endif //NO_CHARDET
16  
89 roytam 17 //=========================================================================
18 // テキストファイル読み出し共通インタ[フェイス
19 //=========================================================================
20  
21 struct ki::TextFileRPimpl : public Object
22 {
23         inline TextFileRPimpl()
24                 : state(EOL) {}
25  
26         virtual size_t ReadLine( unicode* buf, ulong siz )
27                 = 0;
28  
29         enum { EOF=0, EOL=1, EOB=2 } state;
30 };
31  
32  
33  
34 //-------------------------------------------------------------------------
35 // Unicode系用のベ[スクラス
36 //      UTF-8以外はそんなに出会わないだろうから遅くてもよしとする。
37 //-------------------------------------------------------------------------
38  
39 struct rBasicUTF : public ki::TextFileRPimpl
40 {
134 roytam 41         inline rBasicUTF() : BOF(true) {}
89 roytam 42         virtual unicode PeekC() = 0;
43         virtual unicode GetC() {unicode ch=PeekC(); Skip(); return ch;}
44         virtual void Skip() = 0;
45         virtual bool Eof() = 0;
46  
134 roytam 47         bool BOF;
131 roytam 48  
89 roytam 49         size_t ReadLine( unicode* buf, ulong siz )
50         {
51                 state = EOF;
52  
53                 // 改行が出るまで読む
54                 unicode *w=buf, *e=buf+siz;
55                 while( !Eof() )
56                 {
57                         *w = GetC();
134 roytam 58                         if(BOF && *w!=0xfeff) BOF = false;
89 roytam 59                         if( *w==L'\r' || *w==L'\n' )
60                         {
61                                 state = EOL;
62                                 break;
63                         }
134 roytam 64                         else if( !BOF && ++w==e )
89 roytam 65                         {
66                                 state = EOB;
67                                 break;
68                         }
134 roytam 69                         if(BOF) BOF = false;
89 roytam 70                 }
71  
72                 // 改行コ[ドスキップ処理
73                 if( state == EOL )
74                         if( *w==L'\r' && !Eof() && PeekC()==L'\n' )
75                                 Skip();
76  
134 roytam 77                 if(BOF) BOF = false;
89 roytam 78                 // 読んだ文字数
79                 return w-buf;
80         }
81 };
82  
83  
84  
85 //-------------------------------------------------------------------------
86 // UCS2ベタ/UCS4ベタ。それぞれUTF16, UTF32の代わりとして使う。
87 // ついでに同じtemplateで、ISO-8859-1も処理してしまう。^^;
88 //-------------------------------------------------------------------------
89  
90 template<typename T>
91 struct rUCS : public rBasicUTF
92 {
93         rUCS( const uchar* b, ulong s, bool bigendian )
94                 : fb( reinterpret_cast<const T*>(b) )
95                 , fe( reinterpret_cast<const T*>(b+(s/sizeof(T))*sizeof(T)) )
96                 , be( bigendian ) {}
97  
98         const T *fb, *fe;
99         const bool be;
100  
101         // エンディアン変換
102         inline  byte swap(  byte val ) { return val; }
103         inline dbyte swap( dbyte val ) { return (val<<8) |(val>>8); }
104         inline qbyte swap( qbyte val ) { return ((val>>24)&0xff |
105                                                  (val>>8)&0xff00 |
106                                                                                          (val<<8)&0xff0000|
107                                                                                          (val<<24)); }
108  
109         virtual void Skip() { ++fb; }
110         virtual bool Eof() { return fb==fe; }
111         virtual unicode PeekC() { return (unicode)(be ? swap(*fb) : *fb); }
112 };
113  
114 typedef rUCS< byte> rWest;
115 typedef rUCS<dbyte> rUtf16;
116  
117 // UTF-32読み込み
118 struct rUtf32 : public rUCS<qbyte>
119 {
120         rUtf32( const uchar* b, ulong s, bool bigendian )
121                 : rUCS<qbyte>(b,s,bigendian)
122                 , state(0) {}
123  
124         int state;
125         qbyte curChar() { return be ? swap(*fb) : *fb; }
126         bool inBMP(qbyte c) { return c<0x10000; }
127  
128         virtual unicode PeekC()
129         {
130                 qbyte c = curChar();
131                 if( inBMP(c) )
132                         return (unicode)c;
133                 return (unicode)(state==0 ? 0xD800 + (((c-0x10000) >> 10)&0x3ff)
134                                               : 0xDC00 + ( (c-0x10000)       &0x3ff));
135         }
136  
137         virtual void Skip()
138         {
139                 if( inBMP(curChar()) )
140                         ++fb;
141                 else if( state==0 )
142                         state=1;
143                 else
144                         ++fb, state=0;
145         }
146 };
147  
148  
90 roytam 149 //-------------------------------------------------------------------------
150 // UTF-1
151 //-------------------------------------------------------------------------
152 struct rUtf1 : public rBasicUTF
153 {
154         rUtf1( const uchar* b, ulong s )
155                 : fb( b )
135 roytam 156                 , fe( b+s )
157                 , SurrogateLow( 0 ) {}
89 roytam 158  
90 roytam 159         const uchar *fb, *fe;
135 roytam 160         qbyte SurrogateLow;
90 roytam 161  
162         inline byte conv( uchar x )
163         {
164                 if( x<=0x20 )      return x + 0xBE;
165                 else if( x<=0x7E ) return x - 0x21;
166                 else if( x<=0x9F ) return x + 0x60;
167                 else               return x - 0x42;
168         }
169  
140 roytam 170         bool Eof() { return SurrogateLow ? false : fb==fe; }
90 roytam 171         void Skip()
172         {
135 roytam 173                 if( SurrogateLow ) return; // don't go further if leftover exists
174  
90 roytam 175                 if( *fb >= 0xFC && *fb <= 0xFF )      { fb+=5; }
176                 else if( *fb >= 0xF6 && *fb <= 0xFB ) { fb+=3; }
177                 else if( *fb >= 0xA0 && *fb <= 0xF5 ) { fb+=2; }
178                 else /*if( *fb <= 0x9F )*/            {  ++fb; }
179         }
180         unicode PeekC()
181         {
135 roytam 182                 qbyte ch;
183  
184                 if( SurrogateLow )
185                 {
186                         ch = SurrogateLow;
187                         SurrogateLow = 0;
188                         return (unicode)ch;
189                 }
190  
191                 if( *fb <= 0x9F )                         { ch = (*fb); }
192                 else if( *fb == 0xA0 )                    { ch = (*(fb+1)); }
193                 else if( *fb >= 0xA1 && *fb <= 0xF5 )     { ch = ((*fb-0xA1) * 0xBE + conv(*(fb+1)) + 0x100); }
194                 else if( *fb >= 0xF6 && *fb <= 0xFB )     { ch = ((*fb-0xF6) * 0x8D04 + conv(*(fb+1)) * 0xBE + conv(*(fb+2)) + 0x4016); }
195                 else /*if( *fb >= 0xFC && *fb <= 0xFF )*/ { ch = ((*fb-0xFC) * 0x4DAD6810 + conv(*(fb+1)) * 0x68A8F8 + conv(*(fb+2)) * 0x8D04 + conv(*(fb+3)) * 0xBE + conv(*(fb+4)) + 0x38E2E); }
196  
197                 if( ch > 0x10000 )
198                 {
199                         SurrogateLow = (0xDC00 + (((ch-0x10000)    )&0x3ff));
200                         ch = (0xD800 + (((ch-0x10000)>>10)&0x3ff));
201                 }
202                 return (unicode)ch;
90 roytam 203         }
204 };
205  
89 roytam 206 //-------------------------------------------------------------------------
92 roytam 207 // UTF-9 (draft-abela-utf9-00)
208 //-------------------------------------------------------------------------
209 struct rUtf9 : public rBasicUTF
210 {
211         rUtf9( const uchar* b, ulong s )
212                 : fb( b )
135 roytam 213                 , fe( b+s )
214                 , SurrogateLow( 0 ) {}
92 roytam 215  
216         const uchar *fb, *fe;
135 roytam 217         qbyte SurrogateLow;
92 roytam 218  
140 roytam 219         bool Eof() { return SurrogateLow ? false : fb==fe; }
92 roytam 220         void Skip()
221         {
135 roytam 222                 if( SurrogateLow ) return; // don't go further if leftover exists
223  
92 roytam 224                 if( *fb >= 0x98 && *fb <= 0x9F )      { fb+=5; }
225                 else if( *fb >= 0x94 && *fb <= 0x97 ) { fb+=4; }
226                 else if( *fb >= 0x90 && *fb <= 0x93 ) { fb+=3; }
227                 else if( *fb >= 0x80 && *fb <= 0x8F ) { fb+=2; }
228                 else /* 0~0x7F,0xA0~0xFF */           {  ++fb; }
229         }
230         unicode PeekC()
231         {
135 roytam 232                 qbyte ch;
233  
234                 if( SurrogateLow )
235                 {
236                         ch = SurrogateLow;
237                         SurrogateLow = 0;
238                         return (unicode)ch;
239                 }
240  
140 roytam 241                 if( *fb >= 0x98 && *fb <= 0x9F )      { ch = (((*fb & 0x07) << 28) + ((*(fb+1) & 0x7F) << 21) + ((*(fb+2) & 0x7F) << 14) + ((*(fb+3) & 0x7F) << 7) + (*(fb+4) & 0x7F)); }
242                 else if( *fb >= 0x94 && *fb <= 0x97 ) { ch = (((*fb & 0x03) << 21) + ((*(fb+1) & 0x7F) << 14) + ((*(fb+2) & 0x7F) << 7) + (*(fb+3) & 0x7F)); }
243                 else if( *fb >= 0x90 && *fb <= 0x93 ) { ch = (((*fb & 0x03) << 14) + ((*(fb+1) & 0x7F) << 7) + (*(fb+2) & 0x7F)); }
244                 else if( *fb >= 0x80 && *fb <= 0x8F ) { ch = (((*fb & 0x7F) << 7) + (*(fb+1) & 0x7F)); }
245                 else /* 0~0x7F,0xA0~0xFF */           { ch = (*fb); }
135 roytam 246  
247                 if( ch > 0x10000 )
248                 {
249                         SurrogateLow = (0xDC00 + (((ch-0x10000)    )&0x3ff));
250                         ch = (0xD800 + (((ch-0x10000)>>10)&0x3ff));
251                 }
252                 return (unicode)ch;
92 roytam 253         }
254 };
255  
256 //-------------------------------------------------------------------------
89 roytam 257 // UTF-5
258 //     0-  F : 1bbbb
259 //    10- FF : 1bbbb 0bbbb
260 //   100-FFF : 1bbbb 0bbbb 0bbbb
261 // というように、16進での一桁を一文字で表していくフォ[マット。
262 // 各 0bbbb は '0', '1', ... '9', 'A', ... 'F'
263 // 各 1bbbb は 'G', 'H', ... 'P', 'Q', ... 'V' の字で表現。
264 //-------------------------------------------------------------------------
265  
266 struct rUtf5 : public rBasicUTF
267 {
268         rUtf5( const uchar* b, ulong s )
269                 : fb( b )
270                 , fe( b+s ) {}
271  
272         const uchar *fb, *fe;
273  
274         // 16進文字から整数値へ変換
275         inline byte conv( uchar x )
276         {
277                 if( '0'<=x && x<='9' ) return x-'0';
278                 else                   return x-'A'+0x0A;
279         }
280  
281         void Skip() { do ++fb; while( fb<fe && *fb<'G' ); }
282         bool Eof() { return fb==fe; }
283         unicode PeekC()
284         {
285                 unicode ch = (*fb-'G');
286                 for( const uchar* p=fb+1; p<fe && *p<'G'; ++p )
287                         ch = (ch<<4)|conv(*p);
288                 return ch;
289         }
290 };
291  
292  
293  
294 //-------------------------------------------------------------------------
295 // UTF-7
296 //   ASCII範囲の字はそのまま。それ以外はUTF-16の値をbase64エンコ[ド
297 //   して出力。エンコ[ドされた部分は + と - で挟まれる。また '+' と
298 //   いう字自体を表現するために "+-" という形式を用いる。
299 //-------------------------------------------------------------------------
300  
301 namespace
302 {
303         static const uchar u7c[128]={
304         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
305         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
306         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3e,0xff,0xff,0xff,0x3f,
307         0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0xff,0xff,0xff,0xff,0xff,0xff,
308         0xff,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
309         0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xff,0xff,0xff,0xff,0xff,
310         0xff,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
311         0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0xff,0xff,0xff,0xff };
312 }
313  
314 struct rUtf7 : public rBasicUTF
315 {
316         rUtf7( const uchar* b, ulong s )
317                 : fb( b )
318                 , fe( b+s )
319                 , rest( -1 ) { fillbuf(); }
320  
321         const uchar *fb, *fe;
322         unicode buf[3]; // b64を8文字毎に読んでバッファに溜めておく
323         int rest;       // バッファの空き
324         bool inB64;     // base64エリア内ならtrue
325  
326         void Skip() { if(--rest==0) fillbuf(); }
327         bool Eof() { return fb==fe && rest==0; }
328         unicode PeekC() { return buf[rest-1]; }
329  
330         void fillbuf()
331         {
332                 if( fb<fe )
333                         if( !inB64 )
334                                 if( *fb=='+' )
335                                         if( fb+1<fe && fb[1]=='-' )
336                                                 rest=1, buf[0]=L'+', fb+=2;  // +-
337                                         else
338                                                 ++fb, inB64=true, fillbuf(); // 単独 +
339                                 else
340                                         rest=1, buf[0]=*fb++;            // 普通の字
341                         else
342                         {
343                                 // 何文字デコ[ドできるか数える
344                                 int N=0, E=Max(int(fb-fe),8);
345                                 while( N<E && fb[N]<0x80 && u7c[fb[N]]!=0xff )
346                                         ++N;
347  
348                                 // デコ[ド
349                                 buf[0]=buf[1]=buf[2]=0;
350                                 switch( N )
351                                 {
352                                 case 8: buf[2]|= u7c[fb[7]];
353                                 case 7: buf[2]|=(u7c[fb[6]]<< 6);
354                                 case 6: buf[2]|=(u7c[fb[5]]<<12), buf[1]|=(u7c[fb[5]]>>4);
355                                 case 5: buf[1]|=(u7c[fb[4]]<< 2);
356                                 case 4: buf[1]|=(u7c[fb[3]]<< 8);
357                                 case 3: buf[1]|=(u7c[fb[2]]<<14), buf[0]|=(u7c[fb[2]]>>2);
358                                 case 2: buf[0]|=(u7c[fb[1]]<< 4);
359                                 case 1: buf[0]|=(u7c[fb[0]]<<10);
360                                         unicode t;
361                                         rest = 1;
362                                         if( N==8 )
363                                                 rest=3, t=buf[0], buf[0]=buf[2], buf[2]=t;
364                                         else if( N>=6 )
365                                                 rest=2, t=buf[0], buf[0]=buf[1], buf[1]=t;
366                                 }
367  
368                                 // 使った分進む
369                                 if( N<E )
370                                 {
371                                         inB64=false;
372                                         if( fb[N]=='-' )
373                                                 ++fb;
374                                 }
375                                 fb += N;
376                                 if( N==0 )
377                                         fillbuf();
378                         }
379         }
380 };
381  
135 roytam 382 //-------------------------------------------------------------------------
383 // SCSU (UTR #6)
384 // Code portion is taken from:
385 // http://czyborra.com/scsu/scsu.c written by Roman Czyborra@dds.nl
386 //-------------------------------------------------------------------------
387 namespace
388 {
136 roytam 389         static const int SCSU_win[256]={
135 roytam 390         0x0000, 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380,
391         0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x0700, 0x0780,
392         0x0800, 0x0880, 0x0900, 0x0980, 0x0A00, 0x0A80, 0x0B00, 0x0B80,
393         0x0C00, 0x0C80, 0x0D00, 0x0D80, 0x0E00, 0x0E80, 0x0F00, 0x0F80,
394         0x1000, 0x1080, 0x1100, 0x1180, 0x1200, 0x1280, 0x1300, 0x1380,
395         0x1400, 0x1480, 0x1500, 0x1580, 0x1600, 0x1680, 0x1700, 0x1780,
396         0x1800, 0x1880, 0x1900, 0x1980, 0x1A00, 0x1A80, 0x1B00, 0x1B80,
397         0x1C00, 0x1C80, 0x1D00, 0x1D80, 0x1E00, 0x1E80, 0x1F00, 0x1F80,
398         0x2000, 0x2080, 0x2100, 0x2180, 0x2200, 0x2280, 0x2300, 0x2380,
399         0x2400, 0x2480, 0x2500, 0x2580, 0x2600, 0x2680, 0x2700, 0x2780,
400         0x2800, 0x2880, 0x2900, 0x2980, 0x2A00, 0x2A80, 0x2B00, 0x2B80,
401         0x2C00, 0x2C80, 0x2D00, 0x2D80, 0x2E00, 0x2E80, 0x2F00, 0x2F80,
402         0x3000, 0x3080, 0x3100, 0x3180, 0x3200, 0x3280, 0x3300, 0x3800,
403         0xE000, 0xE080, 0xE100, 0xE180, 0xE200, 0xE280, 0xE300, 0xE380,
404         0xE400, 0xE480, 0xE500, 0xE580, 0xE600, 0xE680, 0xE700, 0xE780,
405         0xE800, 0xE880, 0xE900, 0xE980, 0xEA00, 0xEA80, 0xEB00, 0xEB80,
406         0xEC00, 0xEC80, 0xED00, 0xED80, 0xEE00, 0xEE80, 0xEF00, 0xEF80,
407         0xF000, 0xF080, 0xF100, 0xF180, 0xF200, 0xF280, 0xF300, 0xF380,
408         0xF400, 0xF480, 0xF500, 0xF580, 0xF600, 0xF680, 0xF700, 0xF780,
409         0xF800, 0xF880, 0xF900, 0xF980, 0xFA00, 0xFA80, 0xFB00, 0xFB80,
410         0xFC00, 0xFC80, 0xFD00, 0xFD80, 0xFE00, 0xFE80, 0xFF00, 0xFF80,
411         0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
412         0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
413         0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
414         0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
415         0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
416         0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
417         0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
418         0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
419         0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
420         0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
421         0x0000, 0x00C0, 0x0250, 0x0370, 0x0530, 0x3040, 0x30A0, 0xFF60};
89 roytam 422  
136 roytam 423         static int SCSU_start[8]={0x0000,0x0080,0x0100,0x0300,0x2000,0x2080,0x2100,0x3000},
424         SCSU_slide[8]={0x0080,0x00C0,0x0400,0x0600,0x0900,0x3040,0x30A0,0xFF00};
135 roytam 425 }
426 struct rSCSU : public rBasicUTF
427 {
428         rSCSU( const uchar* b, ulong s )
429                 : fb( b )
430                 , fe( b+s )
431                 , active( 0 )
432                 , mode( 0 )
137 roytam 433                 , skip( 0 )
434                 , c( 0 )
435                 , d( 0 ) {}
89 roytam 436  
135 roytam 437         const uchar *fb, *fe;
138 roytam 438         char active, mode;
439         ulong skip;
135 roytam 440         uchar c, d;
441  
442         void Skip() { fb+=skip; skip=0; }
443         bool Eof() { return fb==fe; }
141 roytam 444         uchar GetChar() { return fb+skip>fe ? 0 : *(fb+(skip++)); }
135 roytam 445         unicode PeekC()
446         {
447                 c = GetChar();
137 roytam 448                 if (!mode && c >= 0x80)
135 roytam 449                 {
136 roytam 450                         return (c - 0x80 + SCSU_slide[active]);
135 roytam 451                 }
137 roytam 452                 else if (!mode && c >= 0x20 && c <= 0x7F)
135 roytam 453                 {
454                         return c;
455                 }
137 roytam 456                 else if (!mode && c == 0x0 || c == 0x9 || c == 0xA || c == 0xC || c == 0xD)
135 roytam 457                 {
458                         return c;
459                 }
137 roytam 460                 else if (!mode && c >= 0x1 && c <= 0x8) /* SQn */
135 roytam 461                 { // single quote
462                         d = GetChar();
136 roytam 463                         return (d < 0x80 ? d + SCSU_start[c - 0x1] : d - 0x80 + SCSU_slide[c - 0x1]);
135 roytam 464                 }
137 roytam 465                 else if (!mode && c >= 0x10 && c <= 0x17) /* SCn */
135 roytam 466                 { // change window
467                         active = c - 0x10;
468  
469                         Skip();
470                         return PeekC();
471                 }
137 roytam 472                 else if (!mode && c >= 0x18 && c <= 0x1F) /* SDn */
135 roytam 473                 { // define window
474                         active = c - 0x18;
136 roytam 475                         SCSU_slide[active] = SCSU_win[GetChar()];
135 roytam 476  
477                         Skip();
478                         return PeekC();
479                 }
137 roytam 480                 else if (!mode && c == 0xB) /* SDX */
135 roytam 481                 {
482                         c = GetChar(); d = GetChar();
136 roytam 483                         SCSU_slide[active = c>>5] = 0x10000 + (((c & 0x1F) << 8 | d) << 7);
135 roytam 484  
485                         Skip();
486                         return PeekC();
487                 }
137 roytam 488                 else if (!mode && c == 0xE) /* SQU */
135 roytam 489                 {
490                         c = GetChar();
491                         return (c << 8 | GetChar());
492                 }
137 roytam 493                 else if (mode || c == 0xF) /* SCU */
135 roytam 494                 { // change to Unicode mode
137 roytam 495  
496                         if(!mode) c = GetChar();
135 roytam 497                         mode = 1;
498  
137 roytam 499                         if (c <= 0xDF || c >= 0xF3)
135 roytam 500                         {
137 roytam 501                                 return (c << 8 | GetChar());
502                         }
503                         else if (c == 0xF0) /* UQU */
504                         {
135 roytam 505                                 c = GetChar();
137 roytam 506                                 return (c << 8 | GetChar());
507                         }
508                         else if (c >= 0xE0 && c <= 0xE7) /* UCn */
509                         {
510                                 active = c - 0xE0; mode = 0;
135 roytam 511  
137 roytam 512                                 Skip();
513                                 return PeekC();
514                         }
515                         else if (c >= 0xE8 && c <= 0xEF) /* UDn */
516                         {
517                                 SCSU_slide[active=c-0xE8] = SCSU_win[GetChar()]; mode = 0;
135 roytam 518  
137 roytam 519                                 Skip();
520                                 return PeekC();
521                         }
522                         else if (c == 0xF1) /* UDX */
523                         {
524                                 c = GetChar(); d = GetChar();
525                                 SCSU_slide[active = c>>5] = 0x10000 + (((c & 0x1F) << 8 | d) << 7); mode = 0;
135 roytam 526  
137 roytam 527                                 Skip();
528                                 return PeekC();
135 roytam 529                         }
141 roytam 530                         else
531                         {
532                                 Skip();
533                                 return PeekC();
534                         }
135 roytam 535                 }
141 roytam 536                 else
537                 {
538                         Skip();
539                         return PeekC();
540                 }
135 roytam 541         }
542 };
543  
89 roytam 544 //-------------------------------------------------------------------------
138 roytam 545 // BOCU-1
546 // code portion from BOCU1.pm by Naoya Tozuka
547 //-------------------------------------------------------------------------
548 namespace {
549         static const uchar bocu1_byte_to_trail[256] = {
550 //   0x00 - 0x20
551     -1,   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
552     0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -1,   -1,   0x10, 0x11, 0x12, 0x13,
553     -1,
554 //   0x21 - 0xff
555           0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
556     0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32,
557     0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42,
558     0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52,
559     0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
560     0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
561     0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82,
562     0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
563     0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2,
564     0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2,
565     0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2,
566     0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2,
567     0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2,
568         0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2 };
569 }
570 struct rBOCU1 : public rBasicUTF
571 {
572         rBOCU1( const uchar* b, ulong s )
573                 : fb( b )
574                 , fe( b+s )
575                 , skip( 0 )
576                 , pc( 0x40 )
577                 , cp( 0 ) {}
578  
579         const uchar *fb, *fe;
580         ulong skip;
581         unicode cp, pc;
582  
583         void Skip() { fb+=skip; skip=0; }
584         bool Eof() { return fb==fe; }
585         uchar GetChar() { return *(fb+(skip++)); }
586         unicode PeekC()
587         {
588                 uchar c = GetChar();
589                 long diff = 0;
590                 uchar t1,t2,t3;
591  
592         if (c <= 0x20) {
593             cp = c;
594         } else if (c == 0x21) { // 21 t1 t2 t3
595             t1 = bocu1_byte_to_trail[ GetChar() ];
596             t2 = bocu1_byte_to_trail[ GetChar() ];
597             t3 = bocu1_byte_to_trail[ GetChar() ];
598             //croak "illegal trail char" if t1 < 0 || t2 < 0 || t3 < 0;
599             diff = 14161247 + t1 * 59049 + t2 * 243 + t3;
600         } else if (c < 0x25) { // [22-24] t1 t2
601             t1 = bocu1_byte_to_trail[ GetChar() ];
602             t2 = bocu1_byte_to_trail[ GetChar() ];
603             //croak "illegal trail char" if t1 < 0 || t2 < 0;
604             diff = -2195326 + c * 59049 + t1 * 243 + t2;
605         } else if (c < 0x50) { // [25-4F] t1
606             t1 = bocu1_byte_to_trail[ GetChar() ];
607             //croak "illegal trail char" if t1 < 0;
608             diff = -19504 + c * 243 + t1;
609         } else if (c < 0xd0) { // [50-CF]
610             diff = c - 0x90;
611         } else if (c < 0xfb) { // [D0-FA] t1
612             t1 = bocu1_byte_to_trail[ GetChar() ];
613             //croak "illegal trail char" if t1 < 0;
614             diff = -50480 + c * 243 + t1;
615         } else if (c < 0xfe) { // [FB-FD] t1 t2
616             t1 = bocu1_byte_to_trail[ GetChar() ];
617             t2 = bocu1_byte_to_trail[ GetChar() ];
618             //croak "illegal trail char" if t1 < 0 || t2 < 0;
619             diff = -14810786 + c * 59049 + t1 * 243 + t2;
620         } else if (c == 0xfe) { // FE t1 t2 t3
621             t1 = bocu1_byte_to_trail[ GetChar() ];
622             t2 = bocu1_byte_to_trail[ GetChar() ];
623             t3 = bocu1_byte_to_trail[ GetChar() ];
624             //croak "illegal trail char" if t1 < 0 || t2 < 0 || t3 < 0;
625             diff = 187660 + t1 * 59049 + t2 * 243 + t3;
626         } else if (c == 0xff) {
627             // reset
628             cp = 0;
629             diff = 0;
630         }
631  
632         // codepoint, next pc
633         if (c <= 0x20) {
634             if (c < 0x20) pc = 0x40;
635             //push(@codepoints,c);
636                         return c;
637         } else if (c < 0xff) {
638             cp = (unicode)(pc + diff);
639             if (pc + diff < 0) cp = 0;
640             //push(@codepoints,cp);
641             if (cp < 0x20) {
642                 pc = 0x40;
643             } else if (cp == 0x20) {
644                 // keep pc
645             } else if (0x3040 <= cp && cp <= 0x309f) {
646                 pc = 0x3070;
647             } else if (0x4e00 <= cp && cp <= 0x9fa5) {
648                 pc = 0x7711;
649             } else if (0xac00 <= cp && cp <= 0xd7a3) {
650                 pc = 0xc1d1;
651             } else {
652                 pc = (cp & ~0x7f) + 0x40;
653             }
654                         return cp;
655         } else { // 0xff : reset
656             pc = 0x40;
657  
658                         Skip();
659                         return PeekC();
660         }
661         }
662 };
663  
664  
665 //-------------------------------------------------------------------------
89 roytam 666 // UTF8/MBCS
667 //  CR,LFが1バイト文字としてきちんと出てくるので、
668 //  切り分けが簡単な形式をここでまとめて扱う。UTF8以外の変換は
669 //  Windowsに全て任せている。
670 //-------------------------------------------------------------------------
671  
672 namespace
673 {
674         typedef char* (WINAPI * uNextFunc)(WORD,const char*,DWORD);
675  
676         static const byte mask[] = { 0, 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
677         static inline int GetMaskIndex(uchar n)
678         {
679                 if( uchar(n+2) < 0xc2 ) return 1; // 00〜10111111, fe, ff
680                 if( n          < 0xe0 ) return 2; // 110xxxxx
681                 if( n          < 0xf0 ) return 3; // 1110xxxx
682                 if( n          < 0xf8 ) return 4; // 11110xxx
683                 if( n          < 0xfc ) return 5; // 111110xx
684                                         return 6; // 1111110x
685         }
686  
687         static char* WINAPI CharNextUtf8( WORD, const char* p, DWORD )
688         {
689                 return const_cast<char*>( p+GetMaskIndex(uchar(*p)) );
690         }
691  
692         // Win95対策。
693         //   http://support.microsoft.com/default.aspx?scid=%2Fisapi%2Fgomscom%2Easp%3Ftarget%3D%2Fjapan%2Fsupport%2Fkb%2Farticles%2Fjp175%2F3%2F92%2Easp&LN=JA
694         // MSDNにはWin95以降でサポ[トと書いてあるのにCP_UTF8は
695         // 使えないらしいので、自前の変換関数で。
696         typedef int (WINAPI * uConvFunc)(UINT,DWORD,const char*,int,wchar_t*,int);
697         static int WINAPI Utf8ToWideChar( UINT, DWORD, const char* sb, int ss, wchar_t* wb, int ws )
698         {
699                 const uchar *p = reinterpret_cast<const uchar*>(sb);
700                 const uchar *e = reinterpret_cast<const uchar*>(sb+ss);
701                 wchar_t     *w = wb; // バッファサイズチェック無し(仕様)
702  
703                 for( int t; p<e; ++w )
704                 {
705                         t  = GetMaskIndex(*p);
706                         qbyte qch = (*p++ & mask[t]);
707                         while( p<e && --t )
708                                 qch<<=6, qch|=(*p++)&0x3f;
709                         if(qch<0x10000)
710                                 *w = (wchar_t)qch;
711                         else
712                                 *w++ = (wchar_t)(0xD800 + (((qch-0x10000)>>10)&0x3ff)),
713                                 *w   = (wchar_t)(0xDC00 + (((qch-0x10000)    )&0x3ff));
714                 }
715                 return int(w-wb);
716         }
717 }
718  
719 struct rMBCS : public TextFileRPimpl
720 {
721         // ファイルポインタ&コ[ドペ[ジ
722         const char* fb;
723         const char* fe;
724         const int   cp;
725         uNextFunc next;
726         uConvFunc conv;
727  
728         // 初期設定
729         rMBCS( const uchar* b, ulong s, int c )
730                 : fb( reinterpret_cast<const char*>(b) )
731                 , fe( reinterpret_cast<const char*>(b+s) )
732                 , cp( c==UTF8 ? UTF8N : c )
124 roytam 733 #if !defined(TARGET_VER) || (defined(TARGET_VER) && TARGET_VER>310)
89 roytam 734                 , next( cp==UTF8N ?   CharNextUtf8 : CharNextExA )
124 roytam 735 #endif
145 roytam 736                 , conv( cp==UTF8N && (app().isWin95()||!::IsValidCodePage(65001))
89 roytam 737                                   ? Utf8ToWideChar : MultiByteToWideChar )
738         {
739                 if( cp==UTF8N && fe-fb>=3
740                  && b[0]==0xef && b[1]==0xbb && b[2]==0xbf )
741                         fb += 3; // BOMスキップ
742         }
743  
744         size_t ReadLine( unicode* buf, ulong siz )
745         {
746                 // バッファの終[か、ファイルの終[の近い方まで読み込む
747                 const char *p, *end = Min( fb+siz/2, fe );
748                 state = (end==fe ? EOF : EOB);
749  
750                 // 改行が出るまで進む
751                 for( p=fb; p<end; )
752                         if( *p=='\r' || *p=='\n' )
753                         {
754                                 state = EOL;
755                                 break;
756                         }
124 roytam 757 #if !defined(TARGET_VER) || (defined(TARGET_VER) && TARGET_VER>350)
96 roytam 758                         else if( (*p) & 0x80 && p+1<end )
89 roytam 759                         {
760                                 p = next(cp,p,0);
761                         }
123 roytam 762 #endif
89 roytam 763                         else
764                         {
765                                 ++p;
766                         }
767  
768                 // Unicodeへ変換
121 roytam 769                 ulong len;
89 roytam 770 #ifndef _UNICODE
121 roytam 771                 len = conv( cp, 0, fb, p-fb, buf, siz );
89 roytam 772 #else
121 roytam 773                 if(!app().isNewShell())
774                 {
775                         len = conv( cp, 0, fb, p-fb, buf, siz );
776                 }
777                 else
778                 {
779                         len = ::MultiByteToWideChar( cp, 0, fb, int(p-fb), buf, siz );
780                 }
89 roytam 781 #endif
782                 // 改行コ[ドスキップ処理
783                 if( state == EOL )
784                         if( *(p++)=='\r' && p<fe && *p=='\n' )
785                                 ++p;
786                 fb = p;
787  
788                 // 終了
789                 return len;
790         }
791 };
792  
793  
794  
795 //-------------------------------------------------------------------------
796 // ISO-2022 の適当な実装
797 //
798 //      コ[ドペ[ジとして、G0, G1, G2, G3 の四面を持つ。
799 //      それぞれ決まったエスケ[プシ[ケンスによって、
800 //      さまざまな文字集合を各面に呼び出すことが出来る。
801 //      とりあえず現在のバ[ジョンで対応しているふりなのは
802 //      次の通り。()内に、そのいい加減っぷりを示す。
803 //
804 //              <<いつでも>>
805 //              1B 28 42    : G0へ ASCII
806 //              1B 28 4A    : G0へ JIS X 0201 ロ[マ字 (のかわりにASCII)
807 //              1B 29 4A    : G1へ JIS X 0201 ロ[マ字 (のかわりにASCII)
808 //              1B 2A 4A    : G2へ JIS X 0201 ロ[マ字 (のかわりにASCII)
809 //              1B 3B 4A    : G3へ JIS X 0201 ロ[マ字 (のかわりにASCII)
810 //              1B 2E 41    : G2へ ISO-8859-1
811 //              <<CP932が有効な場合>>
812 //              1B 28 49    : G0へ JIS X 0201 カナ
813 //              1B 29 49    : G1へ JIS X 0201 カナ
814 //              1B 2A 49    : G2へ JIS X 0201 カナ
815 //              1B 2B 49    : G3へ JIS X 0201 カナ
816 //              1B 24 40    : G0へ JIS X 0208(1978)
817 //              1B 24 42    : G0へ JIS X 0208(1983)    (年度は区別しない)
818 //              <<CP936が有効な場合>>
819 //              1B 24 41    : G0へ GB 2312
820 //              1B 24 29 41 : G1へ GB 2312
821 //              1B 24 2A 41 : G2へ GB 2312
822 //              1B 24 2B 41 : G3へ GB 2312
823 //              <<CP949が有効な場合>>
824 //              1B 24 28 43 : G0へ KS X 1001
825 //              1B 24 29 43 : G1へ KS X 1001
826 //              1B 24 2A 43 : G2へ KS X 1001
827 //              1B 24 2B 43 : G3へ KS X 1001
828 //
829 //      各面に呼び出した文字集合は、
830 //              GL (0x21〜0xfe) GR (0xa0〜0xff)
831 //      のどちらかへマップすることで、実際のバイト値となる。
832 //      マップ命令となるバイト列は、次の通り
833 //
834 //              0F    : GL        へG0を呼び出し
835 //              0E    : GL        へG1を呼び出し
836 //              1B 7E : GR        へG1を呼び出し
837 //              8E    : GL/GR両方 へG2を一瞬だけ呼び出し。1B 4E も同義
838 //              8F    : GL/GR両方 へG3を一瞬だけ呼び出し。1B 4F も同義
839 //
840 //-------------------------------------------------------------------------
841  
842 enum CodeSet { ASCII, LATIN, KANA, JIS, KSX, GB };
843  
844 struct rIso2022 : public TextFileRPimpl
845 {
846         // Helper: JIS X 0208 => SJIS
847         void jis2sjis( uchar k, uchar t, char* s )
848         {
849                 if(k>=0x3f)     s[0] = (char)(((k+1)>>1)+0xc0);
850                 else            s[0] = (char)(((k+1)>>1)+0x80);
851                 if( k&1 )       s[1] = (char)((t>>6) ? t+0x40 : t+0x3f);
852                 else            s[1] = (char)(t+0x9e);
853         }
854  
855         // ファイルポインタ
856         const uchar* fb;
857         const uchar* fe;
858         bool      fixed; // ESCによる切り替えを行わないならtrue
859         bool    mode_hz; // HZの場合。
860  
861         // 作業変数
862         CodeSet *GL, *GR, G[4];
863         int gWhat; // 次の字は 1:GL/GR 2:G2 3:G3 で出力
864         ulong len;
865  
866         // 初期化
867         rIso2022( const uchar* b, ulong s, bool f, bool hz,
868                 CodeSet g0, CodeSet g1, CodeSet g2=ASCII, CodeSet g3=ASCII )
869                 : fb( b )
870                 , fe( b+s )
871                 , fixed( f )
872                 , mode_hz( hz )
873                 , GL( &G[0] )
874                 , GR( &G[1] )
875                 , gWhat( 1 )
876         {
877                 G[0]=g0, G[1]=g1, G[2]=g2, G[3]=g3;
878         }
879  
880         void DoSwitching( const uchar*& p )
881         {
882                 if( fixed )
883                 {
884                         if( p[0]==0x24 && p[1]!=0x40 && p[1]!=0x41 && p[1]!=0x42
885                          && p+2 < fe && (p[2]==0x41 || p[2]==0x43) )
886                                 ++p;
887                 }
888                 else
889                 {
890                         if( p[1]==0x4A )
891                                 G[ (p[0]-0x28)%4 ] = ASCII;         // 1B [28-2B] 4A
892                         else if( p[1]==0x49 )
893                                 G[ (p[0]-0x28)%4 ] = KANA;          // 1B [28-2B] 49
894                         else if( *reinterpret_cast<const dbyte*>(p)==0x4228 )
895                                 G[ 0 ] = ASCII;                     // 1B 28 42
896                         else if( *reinterpret_cast<const dbyte*>(p)==0x412E )
897                                 G[ 2 ] = LATIN;                     // 1B 2E 41
898                         else if( p[0]==0x24 )
899                                 if( p[1]==0x40 || p[1]==0x42 )
900                                         G[ 0 ] = JIS;                   // 1B 24 [40|42]
901                                 else if( p[1]==0x41 )
902                                         G[ 0 ] = GB;                    // 1B 24 41
903                                 else if( p+2 < fe )
904                                         if( p[2]==0x41 )
905                                                 G[ ((*++p)-0x28)%4 ] = GB;  // 1B 24 [28-2B] 41
906                                         else if( p[2]==0x43 )
907                                                 G[ ((*++p)-0x28)%4 ] = KSX; // 1B 24 [28-2B] 43
908                 }
909                 ++p;
910         }
911  
912         void DoOutput( unicode*& buf, const uchar*& p )
913         {
914                 // 文字集合取り出し
915                 CodeSet cs =
916                         (gWhat==2 ? G[2] :
917                         (gWhat==3 ? G[3] :
918                         (*p&0x80  ? *GR  : *GL)));
919  
920                 char c[2];
921                 ulong wt=1;
922                 switch( cs )
923                 {
924                 case ASCII:
925                         *buf = (*p)&0x7f;
926                         break;
927                 case LATIN:
928                         *buf = (*p)|0x80;
929                         break;
930                 case KANA:
931                         c[0] = (*p)|0x80;
932                         wt = ::MultiByteToWideChar(
933                                 932, MB_PRECOMPOSED, c, 1, buf, 2 );
934                         break;
935                 case GB:
936                 case KSX:
937                         c[0] = (*  p)|0x80;
938                         c[1] = (*++p)|0x80;
939                         wt = ::MultiByteToWideChar(
940                                 (cs==GB?936:949), MB_PRECOMPOSED, c, 2, buf, 2 );
941                         break;
942                 case JIS:
943                         jis2sjis( (p[0]&0x7f)-0x20, (p[1]&0x7f)-0x20, c );
944                         ++p;
945                         wt = ::MultiByteToWideChar(
946                                 932, MB_PRECOMPOSED, c, 2, buf, 2 );
947                         break;
948                 }
949                 buf+=wt;
950                 len+=wt;
951         }
952  
953         size_t ReadLine( unicode* buf, ulong siz )
954         {
955                 len=0;
956  
957                 // バッファの終[か、ファイルの終[の近い方まで読み込む
958                 const uchar *p, *end = Min( fb+siz/2, fe );
959                 state = (end==fe ? EOF : EOB);
960  
961                 // 改行が出るまで進む
962                 for( p=fb; p<end; ++p )
963                         switch( *p )
964                         {
965                         case '\r':
966                         case '\n': state =   EOL; goto outofloop;
967                         case 0x0F:    GL = &G[0]; break;
968                         case 0x0E:    GL = &G[1]; break;
969                         case 0x8E: gWhat =     2; break;
970                         case 0x8F: gWhat =     3; break;
971                         case 0x1B:
972                                 if( p+1<fe ) {
973                                         ++p; if( *p==0x7E )    GR = &G[1];
974                                         else if( *p==0x4E ) gWhat =  2;
975                                         else if( *p==0x4F ) gWhat =  3;
976                                         else if( p+1<fe )   DoSwitching(p);
977                                 }break;
978                         case 0x7E: if( mode_hz && p+1<fe ) {
979                                         ++p; if( *p==0x7D ){ GL = &G[0]; break; }
980                                         else if( *p==0x7B ){ GL = &G[1]; break; }
981                                 } // fall through...
96 roytam 982                         default:
983                                 if( p+1>=end ) goto outofloop;
984                                 DoOutput( buf, p ); gWhat=1; break;
89 roytam 985                         }
986                 outofloop:
987  
988                 // 改行コ[ドスキップ処理
989                 if( state == EOL )
990                         if( *(p++)=='\r' && p<fe && *p=='\n' )
991                                 ++p;
992                 fb = p;
993  
994                 // 終了
995                 return len;
996         }
997 };
998  
999  
1000  
1001 //-------------------------------------------------------------------------
1002 // 自動判定などなど
1003 //-------------------------------------------------------------------------
1004  
1005 TextFileR::TextFileR( int charset )
1006         : cs_( charset )
1007         , nolbFound_(true)
1008 {
1009 }
1010  
1011 TextFileR::~TextFileR()
1012 {
1013         Close();
1014 }
1015  
1016 size_t TextFileR::ReadLine( unicode* buf, ulong siz )
1017 {
1018         return impl_->ReadLine( buf, siz );
1019 }
1020  
1021 int TextFileR::state() const
1022 {
1023         return impl_->state;
1024 }
1025  
1026 void TextFileR::Close()
1027 {
1028         fp_.Close();
1029 }
1030  
1031 bool TextFileR::Open( const TCHAR* fname )
1032 {
1033         // ファイルを開く
1034         if( !fp_.Open(fname) )
1035                 return false;
1036         const uchar* buf = fp_.base();
1037         const ulong  siz = fp_.size();
1038  
1039         // 必要なら自動判定
1040         cs_ = AutoDetection( cs_, buf, Min<ulong>(siz,16<<10) ); // 先頭16KB
1041  
1042         // 対応するデコ[ダを作成
1043         switch( cs_ )
1044         {
1045         case Western: impl_ = new rWest(buf,siz,true); break;
1046         case UTF16b:
1047         case UTF16BE: impl_ = new rUtf16(buf,siz,true); break;
1048         case UTF16l:
1049         case UTF16LE: impl_ = new rUtf16(buf,siz,false); break;
1050         case UTF32b:
1051         case UTF32BE: impl_ = new rUtf32(buf,siz,true); break;
1052         case UTF32l:
1053         case UTF32LE: impl_ = new rUtf32(buf,siz,false); break;
131 roytam 1054         case UTF1Y:
90 roytam 1055         case UTF1:    impl_ = new rUtf1(buf,siz); break;
89 roytam 1056         case UTF5:    impl_ = new rUtf5(buf,siz); break;
1057         case UTF7:    impl_ = new rUtf7(buf,siz); break;
131 roytam 1058         case UTF9Y:
92 roytam 1059         case UTF9:    impl_ = new rUtf9(buf,siz); break;
135 roytam 1060         case SCSU:    impl_ = new rSCSU(buf,siz); break;
138 roytam 1061         case BOCU1:   impl_ = new rBOCU1(buf,siz); break;
89 roytam 1062         case EucJP:   impl_ = new rIso2022(buf,siz,true,false,ASCII,JIS,KANA); break;
1063         case IsoJP:   impl_ = new rIso2022(buf,siz,false,false,ASCII,KANA); break;
1064         case IsoKR:   impl_ = new rIso2022(buf,siz,true,false,ASCII,KSX); break;
1065         case IsoCN:   impl_ = new rIso2022(buf,siz,true,false,ASCII,GB); break;
1066         case HZ:      impl_ = new rIso2022(buf,siz,true,true, ASCII,GB); break;
1067         default:      impl_ = new rMBCS(buf,siz,cs_); break;
1068         }
1069  
1070         return true;
1071 }
1072  
1073 int TextFileR::AutoDetection( int cs, const uchar* ptr, ulong siz )
1074 {
1075 //-- まず、文字の出現回数の統計を取る
1076  
1077         int  freq[256];
1078         bool bit8 = false;
1079         mem00( freq, sizeof(freq) );
1080         for( ulong i=0; i<siz; ++i )
1081         {
1082                 if( ptr[i] >= 0x80 )
1083                         bit8 = true;
1084                 ++freq[ ptr[i] ];
1085         }
1086  
1087 //-- 改行コ[ド決定 (UTF16/32/7のとき問題あり。UTF5に至っては判定不可…)
1088  
1089              if( freq['\r'] > freq['\n']*2 ) lb_ = CR;
1090         else if( freq['\n'] > freq['\r']*2 ) lb_ = LF;
1091         else                                 lb_ = CRLF;
1092         nolbFound_ = freq['\r']==0 && freq['\n']==0;
1093  
1094 //-- デフォルトコ[ド
1095  
1096         int defCs = ::GetACP();
1097  
1098 //-- 小さすぎる場合はここで終了
1099  
1100         if( siz <= 4 )
1101                 return cs==AutoDetect ? defCs : cs;
1102  
1103 //-- 明示指定がある場合はここで終了
1104  
134 roytam 1105         ulong bom4 = (ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | (ptr[3]);
1106         ulong bom2 = (ptr[0]<<8)  | (ptr[1]);
89 roytam 1107  
1108         if( cs==UTF8 || cs==UTF8N )
1109                 cs = (bom4>>8==0xefbbbf ? UTF8 : UTF8N);
1110         else if( cs==UTF32b || cs==UTF32BE )
1111                 cs = (bom4==0x0000feff ? UTF32b : UTF32BE);
1112         else if( cs==UTF32l || cs==UTF32LE )
1113                 cs = (bom4==0xfffe0000 ? UTF32l : UTF32LE);
1114         else if( cs==UTF16b || cs==UTF16BE )
1115                 cs = (bom2==0xfeff ? UTF16b : UTF16BE);
1116         else if( cs==UTF16l || cs==UTF16LE )
1117                 cs = (bom2==0xfffe ? UTF16l : UTF16LE);
1118  
1119         if( cs != AutoDetect )
1120                 return cs;
1121  
1122 //-- BOMチェック・7bitチェック
1123  
1124         bool Jp = ::IsValidCodePage(932)!=FALSE;
1125  
131 roytam 1126         if( (bom4>>8) == 0xefbbbf )      cs = UTF8;
1127         else if( (bom4>>8) == 0xf7644c ) cs = UTF1Y;
1128         else if( (bom4>>8) == 0x93fdff ) cs = UTF9Y;
136 roytam 1129         else if( (bom4>>8) == 0x0efeff ) cs = SCSU;
138 roytam 1130         else if( (bom4>>8) == 0xfbee28 ) cs = BOCU1;
89 roytam 1131         else if( bom4 == 0x0000feff ) cs = UTF32b;
1132         else if( bom4 == 0xfffe0000 ) cs = UTF32l;
1133         else if( bom2 == 0xfeff )     cs = UTF16b;
1134         else if( bom2 == 0xfffe )     cs = UTF16l;
1135         else if( bom4 == 0x1b242943 && ::IsValidCodePage(949) ) cs = IsoKR;
1136         else if( bom4 == 0x1b242941 && ::IsValidCodePage(936) ) cs = IsoCN;
1137         else if( Jp && !bit8 && freq[0x1b]>0 )                  cs = IsoJP;
1138  
1139         if( cs != AutoDetect )
1140                 return cs;
1141  
1142 //-- UTF-5 チェック
1143  
1144         ulong u5sum = 0;
1145         for( uchar c='0'; c<='9'; ++c ) u5sum += freq[c];
1146         for( uchar c='A'; c<='V'; ++c ) u5sum += freq[c];
1147         if( siz == u5sum )
1148                 return UTF5;
1149  
133 roytam 1150 //-- UTF-16/32 detection
1151         if( freq[ 0 ] ) // nulls in content?
1152         { // then it may be UTF-16/32 without BOM
134 roytam 1153                 if(CheckUTFConfidence(ptr,siz,sizeof(dbyte),true)) return UTF16LE;
1154                 if(CheckUTFConfidence(ptr,siz,sizeof(dbyte),false)) return UTF16BE;
1155                 if(CheckUTFConfidence(ptr,siz,sizeof(qbyte),true)) return UTF32LE;
1156                 if(CheckUTFConfidence(ptr,siz,sizeof(qbyte),false)) return UTF32BE;
133 roytam 1157         }
1158  
130 roytam 1159 //-- chardet and MLang detection
1160         if( app().isNewShell() )
1161         { // chardet works better when size > 64
1162                 if( siz > 80 )
1163                 {
1164                         cs = chardetAutoDetection( ptr, siz );
1165                         if( cs ) return cs;
1166                 }
1167                 cs = MLangAutoDetection( ptr, siz );
1168                 if( cs ) return cs;
1169         }
1170         else
1171         { // chardet is the only auto detection method
1172                 cs = chardetAutoDetection( ptr, siz );
1173                 if( cs ) return cs;
1174         }
1175  
1176 // last resort
89 roytam 1177 //-- 暫定版 UTF-8 / 日本語EUC チェック
1178  
1179         // 改行コ[ドがLFか、ある程度の大きさか、でないと
1180         // 無条件で ANSI-CP と見なしてしまう。
1181         if( bit8 && (siz>4096 || lb_==1
1182          || freq[0xfd]>0 || freq[0xfe]>0 || freq[0xff]>0 || freq[0x80]>0) )
1183         {
1184                 // UHCやGBKはEUC-JPと非常に混同しやすいので、そっちがデフォルトの場合は
1185                 // EUC-JP自動判定を切る
130 roytam 1186                 if( Jp && defCs==SJIS )
89 roytam 1187                 {
1188                         // EUCとしておかしい値が無いかチェック
1189                         bool be=true;
1190                         for( int k=0x90; k<=0xa0; ++k )if( freq[k]>0 ){be=false;break;}
1191                         for( int k=0x7f; k<=0x8d; ++k )if( freq[k]>0 ){be=false;break;}
1192                         if( be )
1193                                 return EucJP;
1194                 }
1195                 {
1196                         // UTF8として読めるかどうかチェック
1197                         bool b8=true;
1198                         int mi=1;
1199                         for( ulong i=0; i<siz && b8; ++i )
1200                                 if( --mi )
1201                                 {
1202                                         if( ptr[i]<0x80 || ptr[i]>=0xc0 )
1203                                                 b8 = false;
1204                                 }
1205                                 else
1206                                 {
1207                                         mi = 1;
1208                                         if( ptr[i] > 0x7f )
1209                                         {
1210                                                 mi = GetMaskIndex( ptr[i] );
1211                                                 if( mi == 1 )//ptr[i] >= 0xfe )
1212                                                         b8 = false;
1213                                         }
1214                                 }
1215                         if( b8 )
1216                                 return UTF8N;
1217                 }
1218         }
1219  
130 roytam 1220  
1221 //-- 判定結果
1222  
1223         return cs ? cs : defCs;
1224 }
1225  
1226 int TextFileR::MLangAutoDetection( const uchar* ptr, ulong siz )
1227 {
1228         int cs = 0;
1229 #if !defined(TARGET_VER) || (defined(TARGET_VER) && TARGET_VER>310)
1230 #ifndef NO_MLANG
1231         app().InitModule( App::OLE );
1232         IMultiLanguage2 *lang = NULL;
1233         if( S_OK == ::CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_ALL, IID_IMultiLanguage2, (LPVOID*)&lang ) )
1234         {
1235                 int detectEncCount = 5;
1236                 DetectEncodingInfo detectEnc[5];
1237                 lang->DetectInputCodepage(MLDETECTCP_DBCS, 0, (char *)(ptr), (INT *)(&siz), detectEnc, &detectEncCount); // 2 ugly C-cast here
1238  
1239                 // MLang fine tunes
1240                 if ( detectEncCount > 1 && detectEnc[0].nCodePage == 1252 ) // sometimes it gives multiple results with 1252 in the first
1241                 {
1242                         if ( detectEncCount == 2 && detectEnc[1].nCodePage == 850 ) // seems to be wrongly detected
1243                         {
1244                                 cs = 0;
1245                         }
1246                         else
1247                         {
1248                                 cs =  detectEnc[detectEncCount-1].nCodePage; // always use last one
1249                         }
1250                 }
1251                 else if ( detectEncCount > 1 && detectEnc[0].nCodePage > 950 ) // non asian codepage in first
1252                 {
1253                         int highestConfidence = 0;
1254                         for(int x=0;x<detectEncCount;x++)
1255                         {
1256                                 if(highestConfidence < detectEnc[x].nConfidence)
1257                                 {
1258                                         highestConfidence = detectEnc[x].nConfidence; // use codepage with highest Confidence
1259                                         cs = detectEnc[x].nCodePage;
1260                                 }
1261                         }
1262                 }
1263                 else
1264                 {
1265                         cs =  detectEnc[0].nCodePage;
1266                 }
1267  
1268 # ifdef MLANG_DEBUG
1269                 TCHAR tmp[10];
1270                 ::wsprintf(tmp,TEXT("%d"),cs);
1271                 ::MessageBox(NULL,tmp,TEXT("MLangDetect"),0);
1272 # endif
1273  
1274                 if (cs == 20127) cs = 0; // 20127 == ASCII, 0 = unknown
1275  
1276                 if (lang)
1277                         lang->Release();
1278         }
1279 #endif //NO_MLANG
1280 #endif //TARGET_VER
1281         return cs;
1282 }
1283  
1284 int TextFileR::chardetAutoDetection( const uchar* ptr, ulong siz )
1285 {
1286         int cs = 0;
129 roytam 1287 #ifndef NO_CHARDET
1288         // function calls
1289         int (__cdecl*chardet_create)(chardet_t*) = 0;
1290         void (__cdecl*chardet_destroy)(chardet_t) = 0;
1291         int (__cdecl*chardet_handle_data)(chardet_t, const char*, unsigned int) = 0;
1292         int (__cdecl*chardet_data_end)(chardet_t) = 0;
1293         int (__cdecl*chardet_get_charset)(chardet_t, char*, unsigned int) = 0;
1294         //int (__cdecl*chardet_reset)(chardet_t) = 0;
1295         HINSTANCE hIL;
99 roytam 1296  
129 roytam 1297         chardet_t pdet = NULL;
1298         char charset[128];
1299  
1300 # define STR2CP(a,b) if(0 == ::lstrcmpA(charset,a)) { \
1301                                         chardet_destroy(pdet); \
1302                                         ::FreeLibrary(hIL); \
1303                                         return b; \
1304                                 }
1305  
1306  
1307         if(hIL = ::LoadLibrary(TEXT("chardet.dll")))
1308         {
1309                 chardet_create = (int(__cdecl*)(chardet_t*))::GetProcAddress(hIL, "chardet_create");
1310                 chardet_destroy = (void(__cdecl*)(chardet_t))::GetProcAddress(hIL, "chardet_destroy");
1311                 chardet_handle_data = (int(__cdecl*)(chardet_t, const char*, unsigned int))::GetProcAddress(hIL, "chardet_handle_data");
1312                 chardet_data_end = (int(__cdecl*)(chardet_t))::GetProcAddress(hIL, "chardet_data_end");
1313                 chardet_get_charset = (int(__cdecl*)(chardet_t, char*, unsigned int))::GetProcAddress(hIL, "chardet_get_charset");
1314                 //chardet_reset = (int(__cdecl*)(chardet_t))::GetProcAddress(hIL, "chardet_reset");
1315  
1316             if( (chardet_create && chardet_destroy && chardet_handle_data && chardet_data_end && chardet_get_charset) && 0 == chardet_create(&pdet) )
1317             {
1318                         if(siz == 16384) siz-=1; // prevert off-by-one error
1319                         if(0 == chardet_handle_data(pdet, (const char *)ptr, siz))
1320                         {
1321                                 chardet_data_end(pdet);
1322                                 chardet_get_charset(pdet, charset, 128);
1323  
1324                                 STR2CP("Shift_JIS",SJIS)
1325                                 STR2CP("EUC-JP",EucJP)
1326                                 STR2CP("EUC-KR",UHC)
133 roytam 1327                                 STR2CP("x-euc-tw",CNS)
129 roytam 1328                                 STR2CP("Big5",Big5)
1329                                 STR2CP("gb18030",GBK)
1330                                 STR2CP("UTF-8",UTF8)
1331                                 STR2CP("windows-1253",Greek)
1332                                 STR2CP("KOI8-R",Koi8R)
1333                                 STR2CP("windows-1251",Cyrillic)
1334                                 STR2CP("IBM866",CyrillicDOS)
1335                                 STR2CP("IBM855",CyrillicIBM)
1336                                 STR2CP("windows-1255",Hebrew)
1337                                 STR2CP("windows-1250",Central)
1338                                 STR2CP("TIS-620",Thai)
1339  
1340                         }
1341                 }
1342  
1343         }
1344 # undef STR2CP
1345 #endif //NO_CHARDET
89 roytam 1346         return cs;
1347 }
1348  
133 roytam 1349 // functions for detecting BOM-less UTF-16/32
1350 bool TextFileR::IsNonUnicodeRange(qbyte u)
1351 { // Unicode 5.2 based
1352                         return  (0x000840 <= u && u < 0x000900) ||
1353                                         //(0x0018B0 <= u && u < 0x001900) ||    // U+18B0-18FF : Unified        Canadian Aboriginal Syllabics Extended
1354                                         (0x001AB0 <= u && u < 0x001B00) ||
1355                                         (0x001BC0 <= u && u < 0x001C00) ||
1356                                         (0x001C80 <= u && u < 0x001CD0) ||
1357                                         //(0x002C60 <= u && u < 0x002C80) ||    // U+2C60-2C7F : Latin Extended-C
1358                                         //(0x002DE0 <= u && u < 0x002E00) ||    // U+2DE0-2DFF : Cyrillic Extended-A
1359                                         (0x002FE0 <= u && u < 0x002FF0) ||
1360                                         //(0x00A4D0 <= u && u < 0x00A700) ||    // U+A4D0-A4FF,A500-A63F,A640-A69F,A6A0-A6FF : Lisu, Vai, Cyrillic Extended-B, Bamum
1361                                         //(0x00A720 <= u && u < 0x00A800) ||    // U+A720-A7FF : Latin Extended-D
1362                                         (0x00A9E0 <= u && u < 0x00AA00) ||      //
1363                                         (0x00AAE0 <= u && u < 0x00ABC0) ||
1364                                         //(0x00D7B0 <= u && u < 0x00D800) ||    // U+D7B0-D7FF : Hangul Jamo Extended-B
1365                                         (0x010200 <= u && u < 0x01027F) ||      // U+10280-1029F,102A0-102DF : Lycian, Carian
1366                                         (0x0102E0 <= u && u < 0x010300) ||      // U+10300-1032F,10330-1034F : Old Italic, Gothic
1367                                         (0x010350 <= u && u < 0x010380) ||      // U+10380-1039F,103A0-103DF : Ugaritic, Old Persian
1368                                         (0x0103E0 <= u && u < 0x010400) ||      // U+10400-1044F,10450-1047F,10480-104AF : Deseret, Shavian, Osmanya
1369                                         (0x0104B0 <= u && u < 0x010800) ||      // U+10800-1083F,10840-1085F : Cypriot Syllabary, Imperial Aramaic
1370                                         (0x010860 <= u && u < 0x0108FF) ||      // U+10900-1091F,10920-1093F : Phoenician, Lydian
1371                                         (0x010940 <= u && u < 0x010A00) ||      // U+10A00-10A5F,10A60-10A7F : Kharoshthi, Old South Arabian
1372                                         (0x010A80 <= u && u < 0x010AFF) ||      // U+10B00-10B3F,10B40-10B5F,10B60-10B7F : Avestan, Inscriptional Parthian, Inscriptional Pahlavi
1373                                         (0x010B80 <= u && u < 0x010BFF) ||      // U+10C00-10C4F : Old Turkic
1374                                         (0x010C50 <= u && u < 0x010E5F) ||      // U+10E60-10E7F : Rumi Numeral Symbols
1375                                         (0x010E80 <= u && u < 0x01107F) ||      // U+11080-110CF : Kaithi
1376                                         (0x0110D0 <= u && u < 0x011FFF) ||      // U+12000-123FF,12400-1247F : Cuneiform, Cuneiform Numbers and Punctuation
1377                                         (0x012480 <= u && u < 0x012FFF) ||      // U+13000-1342F : Egyption Ideographs
1378                                         (0x013430 <= u && u < 0x01D000) ||      // U+1D000-1D0FF,1D100-1D1FF,1D200-1D24F : Byzantine Musical Symbols, Musical Symbols, Ancient Greek Musical Notation
1379                                         (0x01D250 <= u && u < 0x01D300) ||      // U+1D300-1D35F,1D360-1D37F : Tai Xuan Jing Symbols, Counting Rod Numerals
1380                                         (0x01D380 <= u && u < 0x01D400) ||      // U+1D400-1D7FF : Mathematical Alphanumeric Symbols
1381                                         (0x01D800 <= u && u < 0x01F000) ||      // U+1F000-1F02F,1F030-1F09F : Mahjong Tiles, Domino Tiles
1382                                         (0x01F0A0 <= u && u < 0x01F0FF) ||      // U+1F100-1F1FF,1F200-1F2FF : Enclosed Alphanumeric Supplement, Enclosed Ideographic Supplement
1383                                         (0x01F300 <= u && u < 0x020000) ||      // U+20000-2A6DF : CJK Unified Ideographs Extension B
1384                                         (0x02A6E0 <= u && u < 0x02A700) ||      // U+2A700-2B73F : CJK Unified Ideographs Extension C
1385                                         (0x02B740 <= u && u < 0x02F800) ||      // U+2F800-2FA1F : CJK Compatibility Ideographs Supplement
1386                                         (0x02FA20 <= u && u < 0x0E0000) ||      // U+E0000-E007F : Tags
1387                                         (0x0E0080 <= u && u < 0x0E0100) ||      // U+E0100-E01EF : Variation Selectors Supplement
1388                                         (0x0E01F0 <= u && u < 0x0F0000) ||      // U+F0000-FFFFD : Supplementary Private Use Area A
1389                                         (0x110000 <= u); // U+100000-10FFFD : Supplementary Private Use Area B , U+110000-FFFFFFFF non-used
1390 }
1391 bool TextFileR::IsAscii(uchar c) { return 0x20 <= c && c < 0x80; }
1392 bool TextFileR::IsSurrogateLead(qbyte w) { return 0xD800 <= w && w <= 0xDBFF; }
1393  
134 roytam 1394 bool TextFileR::CheckUTFConfidence(const uchar* ptr, ulong siz, unsigned int uChrSize, bool LE)
1395 {
1396         qbyte uchr;
1397         ulong usize = siz / uChrSize, x = 0;
1398         ulong unconfidence = 0, confidence = 0;
1399         bool impossible = false, prevIsNull = false;
1400         for( x=0; x < usize; x++ )
1401         {
1402                 if(uChrSize == 2 && LE == true)
1403                         uchr = ptr[x*2] | ptr[x*2+1]<<8;
1404                 else if(uChrSize == 2 && LE == false)
1405                         uchr = ptr[x*2+1] | ptr[x*2]<<8;
1406                 else if(uChrSize == 4 && LE == true)
1407                         uchr = ptr[x*4] | ptr[x*4+1]<<8 | ptr[x*4+2]<<16 | ptr[x*4+3]<<24;
1408                 else if(uChrSize == 4 && LE == false)
1409                         uchr = ptr[x*4+3] | ptr[x*4+2]<<8 | ptr[x*4+1]<<16 | ptr[x*4]<<24;
133 roytam 1410  
134 roytam 1411                 if( IsNonUnicodeRange(uchr) || (uChrSize==2 && uchr==0) ) // \0\0 maybe a part of UTF-32
1412                 {
1413                         impossible = true;
1414                         break;
1415                 }
1416                 if((0x00 <= uchr && uchr < 0x80)) confidence+=4; // unicode ASCII
1417                 else if(uChrSize==2 && IsAscii(ptr[x*2]) && IsAscii(ptr[x*2+1])) // both char are ASCII
1418                 {
1419                         confidence+=2;
1420                         ++unconfidence;
1421                 }
1422                 else if(uChrSize==2 && IsSurrogateLead(uchr)) ++unconfidence; // Surrogate pairs are less-used
1423                 else ++confidence; // other Unicode chars
1424                 if(uChrSize == 2 && prevIsNull && (LE ? !ptr[x*2] : !ptr[x*2+1])) ++unconfidence; // assume successive U+xx00 is less chance appeared
1425  
1426                 if(uChrSize == 2)
1427                         prevIsNull = LE ? !ptr[x*2] : !ptr[x*2+1];
1428         }
1429 # ifdef UTF_DEBUG
1430         TCHAR utfTmp[80];
1431         ::wsprintf(utfTmp,TEXT("uChrSize=%d,LE=%d,usize=%d, confidence=%d, unconfidence=%d, result=%d"),uChrSize,LE,usize,confidence,unconfidence,(impossible?0:(confidence-unconfidence > usize)));
1432         ::MessageBox(NULL,utfTmp,TEXT("UTFDetect"),0);
1433 # endif
1434  
1435         if( impossible ) return false;
1436         else return (confidence-unconfidence > usize);
1437 }
1438  
89 roytam 1439 //=========================================================================
1440 // テキストファイル出力共通インタ[フェイス
1441 //=========================================================================
1442  
1443 struct ki::TextFileWPimpl : public Object
1444 {
1445         virtual void WriteLine( const unicode* buf, ulong siz )
1446                 { while( siz-- ) WriteChar( *buf++ ); }
1447  
1448         virtual void WriteLB( const unicode* buf, ulong siz )
1449                 { WriteLine( buf, siz ); }
1450  
1451         virtual void WriteChar( unicode ch )
1452                 {}
1453  
1454         ~TextFileWPimpl()
1455                 { delete [] buf_; }
1456  
1457 protected:
1458  
1459         TextFileWPimpl( FileW& w )
1460                 : fp_   (w)
1461                 , bsiz_ (65536)
1462                 , buf_  (new char[bsiz_]) {}
1463  
1464         void ReserveMoreBuffer()
1465                 {
1466                         char* nBuf = new char[bsiz_<<=1];
1467                         delete [] buf_;
1468                         buf_ = nBuf;
1469                 }
1470  
1471         FileW& fp_;
1472         ulong  bsiz_;
1473         char*  buf_;
1474 };
1475  
1476  
1477  
1478 //-------------------------------------------------------------------------
1479 // Unicodeテキスト
1480 //-------------------------------------------------------------------------
1481  
1482 struct wUtf16LE : public TextFileWPimpl
1483 {
1484         wUtf16LE( FileW& w, bool bom ) : TextFileWPimpl(w)
1485                 { if(bom){ unicode ch=0xfeff; fp_.Write(&ch,2); } }
1486         void WriteLine( const unicode* buf, ulong siz ) {fp_.Write(buf,siz*2);}
1487 };
1488  
1489 struct wUtf16BE : public TextFileWPimpl
1490 {
1491         wUtf16BE( FileW& w, bool bom ) : TextFileWPimpl(w)
1492                 { if(bom) WriteChar(0xfeff); }
1493         void WriteChar( unicode ch ) { fp_.WriteC(ch>>8), fp_.WriteC(ch&0xff); }
1494 };
1495  
1496 struct wUtf32LE : public TextFileWPimpl
1497 {
1498         wUtf32LE( FileW& w, bool bom ) : TextFileWPimpl(w)
1499                 { if(bom) {unicode c=0xfeff; WriteLine(&c,1);} }
1500 //      void WriteChar( unicode ch )
1501 //              { fp_.WriteC(ch&0xff), fp_.WriteC(ch>>8), fp_.WriteC(0), fp_.WriteC(0); }
1502         virtual void WriteLine( const unicode* buf, ulong siz )
1503         {
1504                 while( siz-- )
1505                 {
1506                         unicode c = *buf++;
1507                         qbyte  cc = c;
1508                         if( (0xD800<=c && c<=0xDBFF) && siz>0 ) // trail char が正しいかどうかはチェックする気がない
1509                         {
1510                                 unicode c2 = *buf++; siz--;
1511                                 cc = 0x10000 + (((c-0xD800)&0x3ff)<<10) + ((c2-0xDC00)&0x3ff);
1512                         }
1513                         for(int i=0; i<=3; ++i)
1514                                 fp_.WriteC( (uchar)(cc>>(8*i)) );
1515                 }
1516         }
1517 };
1518  
1519 struct wUtf32BE : public TextFileWPimpl
1520 {
1521         wUtf32BE( FileW& w, bool bom ) : TextFileWPimpl(w)
1522                 { if(bom) {unicode c=0xfeff; WriteLine(&c,1);} }
1523 //      void WriteChar( unicode ch )
1524 //              { fp_.WriteC(0), fp_.WriteC(0), fp_.WriteC(ch>>8), fp_.WriteC(ch&0xff); }
1525         virtual void WriteLine( const unicode* buf, ulong siz )
1526         {
1527                 while( siz-- )
1528                 {
1529                         unicode c = *buf++;
1530                         qbyte  cc = c;
1531                         if( (0xD800<=c && c<=0xDBFF) && siz>0 ) // trail char が正しいかどうかはチェックする気がない
1532                         {
1533                                 unicode c2 = *buf++; siz--;
1534                                 cc = 0x10000 + (((c-0xD800)&0x3ff)<<10) + ((c2-0xDC00)&0x3ff);
1535                         }
1536                         for(int i=3; i>=0; --i)
1537                                 fp_.WriteC( (uchar)(cc>>(8*i)) );
1538                 }
1539         }
1540 };
1541  
1542 struct wWest : public TextFileWPimpl
1543 {
1544         wWest( FileW& w ) : TextFileWPimpl(w) {}
1545         void WriteChar( unicode ch ) { fp_.WriteC(ch>0xff ? '?' : (uchar)ch); }
1546 };
1547  
90 roytam 1548 struct wUtf1 : public TextFileWPimpl
1549 {
135 roytam 1550         wUtf1( FileW& w, bool bom ) : TextFileWPimpl(w), SurrogateHi(0)
131 roytam 1551         {
1552                 if( bom ) // BOM書き込み
1553                         fp_.Write( "\xF7\x64\x4C", 3 );
1554         }
135 roytam 1555  
1556         qbyte SurrogateHi;
1557  
90 roytam 1558         inline qbyte conv ( qbyte x )
1559         {
1560                 if( x<=0x5D )      return x + 0x21;
1561                 else if( x<=0xBD ) return x + 0x42;
1562                 else if( x<=0xDE ) return x - 0xBE;
1563                 else               return x - 0x60;
1564         }
1565         void WriteChar( unicode ch )
1566         {
135 roytam 1567                 qbyte c = ch;
1568                 if( 0xD800<=ch&&ch<=0xDBFF )
1569                 {
1570                         SurrogateHi = c; return;
1571                 }
1572                 else if( 0xDC00<=ch&&ch<=0xDFFF )
1573                         if( SurrogateHi )
1574                                 c = 0x10000 + (((SurrogateHi-0xD800)&0x3ff)<<10) + ((c-0xDC00)&0x3ff), SurrogateHi = 0;
1575                         else return; // find Surrogate Low part only, discard it
1576                 else // find Surrogate Hi part only, discard it
1577                         SurrogateHi = 0;
1578  
1579                 if( c <= 0x9f )
1580                         fp_.WriteC( static_cast<uchar>(c) );
1581                 else if( c <= 0xff )
90 roytam 1582                         fp_.WriteC( 0xA0 ),
135 roytam 1583                         fp_.WriteC( static_cast<uchar>(c) );
1584                 else if( c <= 0x4015 )
1585                         fp_.WriteC( static_cast<uchar>(0xA1 + (c - 0x100) / 0xBE) ),
1586                         fp_.WriteC( static_cast<uchar>(conv((c - 0x100) % 0xBE)) );
1587                 else if( c <= 0x38E2D )
1588                         fp_.WriteC( static_cast<uchar>(0xF6 + (c - 0x4016) / (0xBE*0xBE))  ),
1589                         fp_.WriteC( static_cast<uchar>(conv((c - 0x4016) / 0xBE % 0xBE)) ),
1590                         fp_.WriteC( static_cast<uchar>(conv((c - 0x4016) % 0xBE)) );
90 roytam 1591                 else
135 roytam 1592                         fp_.WriteC( static_cast<uchar>(0xFC + (c - 0x38E2E) / (0xBE*0xBE*0xBE*0xBE))  ),
1593                         fp_.WriteC( static_cast<uchar>(conv((c - 0x38E2E) / (0xBE*0xBE*0xBE) % 0xBE)) ),
1594                         fp_.WriteC( static_cast<uchar>(conv((c - 0x38E2E) / (0xBE*0xBE) % 0xBE)) ),
1595                         fp_.WriteC( static_cast<uchar>(conv((c - 0x38E2E) / 0xBE % 0xBE)) ),
1596                         fp_.WriteC( static_cast<uchar>(conv((c - 0x38E2E) % 0xBE)) );
90 roytam 1597         }
1598 };
1599  
92 roytam 1600 struct wUtf9 : public TextFileWPimpl
1601 {
135 roytam 1602         wUtf9( FileW& w, bool bom ) : TextFileWPimpl(w), SurrogateHi(0)
131 roytam 1603         {
1604                 if( bom ) // BOM書き込み
1605                         fp_.Write( "\x93\xFD\xFF", 3 );
1606         }
135 roytam 1607  
1608         qbyte SurrogateHi;
1609  
92 roytam 1610         void WriteChar( unicode ch )
1611         {
135 roytam 1612                 qbyte c = ch;
1613                 if( 0xD800<=ch&&ch<=0xDBFF )
1614                 {
1615                         SurrogateHi = c; return;
1616                 }
1617                 else if( 0xDC00<=ch&&ch<=0xDFFF )
1618                         if( SurrogateHi )
1619                                 c = 0x10000 + (((SurrogateHi-0xD800)&0x3ff)<<10) + ((c-0xDC00)&0x3ff), SurrogateHi = 0;
1620                         else return; // find Surrogate Low part only, discard it
1621                 else // find Surrogate Hi part only, discard it
1622                         SurrogateHi = 0;
1623  
1624                 if( c <= 0x7F || (c >= 0xA0 && c <= 0xFF ))
1625                         fp_.WriteC( static_cast<uchar>(c) );
1626                 else if( c <= 0x07FF )
1627                         fp_.WriteC( static_cast<uchar>(0x80 | (c >> 7)) ),
1628                         fp_.WriteC( static_cast<uchar>(0x80 | (c & 0x7F)) );
1629                 else if( c <= 0xFFFF )
1630                         fp_.WriteC( static_cast<uchar>(0x90 | (c >> 14)) ),
1631                         fp_.WriteC( static_cast<uchar>(0x80 | (c >> 7) & 0x7F) ),
1632                         fp_.WriteC( static_cast<uchar>(0x80 | (c & 0x7F)) );
1633                 else if( c <= 0x7FFFFF )
1634                         fp_.WriteC( static_cast<uchar>(0x94 | (c >> 21)) ),
1635                         fp_.WriteC( static_cast<uchar>(0x80 | (c >> 14) & 0x7F) ),
1636                         fp_.WriteC( static_cast<uchar>(0x80 | (c >> 7) & 0x7F) ),
1637                         fp_.WriteC( static_cast<uchar>(0x80 | (c & 0x7F)) );
92 roytam 1638                 else
135 roytam 1639                         fp_.WriteC( static_cast<uchar>(0x98 | (c >> 28) & 0x07) ),
1640                         fp_.WriteC( static_cast<uchar>(0x80 | (c >> 21) & 0x7F) ),
1641                         fp_.WriteC( static_cast<uchar>(0x80 | (c >> 14) & 0x7F) ),
1642                         fp_.WriteC( static_cast<uchar>(0x80 | (c >> 7) & 0x7F) ),
1643                         fp_.WriteC( static_cast<uchar>(0x80 | (c & 0x7F)) );
92 roytam 1644         }
1645 };
1646  
89 roytam 1647 struct wUtf5 : public TextFileWPimpl
1648 {
1649         wUtf5( FileW& w ) : TextFileWPimpl(w) {}
1650         void WriteChar( unicode ch )
1651         {
1652                 static const char conv[] = {
1653                         '0','1','2','3','4','5','6','7',
1654                                 '8','9','A','B','C','D','E','F' };
1655                 if(ch<0x10)
1656                 {
1657                         fp_.WriteC(ch+'G');
1658                 }
1659                 else if(ch<0x100)
1660                 {
1661                         fp_.WriteC((ch>>4)+'G');
1662                         fp_.WriteC(conv[ch&0xf]);
1663                 }
1664                 else if(ch<0x1000)
1665                 {
1666                         fp_.WriteC((ch>>8)+'G');
1667                         fp_.WriteC(conv[(ch>>4)&0xf]);
1668                         fp_.WriteC(conv[ch&0xf]);
1669                 }
1670                 else
1671                 {
1672                         fp_.WriteC((ch>>12)+'G');
1673                         fp_.WriteC(conv[(ch>>8)&0xf]);
1674                         fp_.WriteC(conv[(ch>>4)&0xf]);
1675                         fp_.WriteC(conv[ch&0xf]);
1676                 }
1677         }
1678 };
1679  
136 roytam 1680 //-------------------------------------------------------------------------
1681 // SCSU Encoder
1682 // Code portion from http://unicode.org/Public/PROGRAMS/SCSUMini/scsumini.c
1683 // created by: Markus W. Scherer
1684 //-------------------------------------------------------------------------
89 roytam 1685  
136 roytam 1686 namespace {
1687         static const ulong SCSU_offsets[16]={
1688                 /* initial offsets for the 8 dynamic (sliding) windows */
1689                 0x0080, /* Latin-1 */
1690                 0x00C0, /* Latin Extended A */
1691                 0x0400, /* Cyrillic */
1692                 0x0600, /* Arabic */
1693                 0x0900, /* Devanagari */
1694                 0x3040, /* Hiragana */
1695                 0x30A0, /* Katakana */
1696                 0xFF00, /* Fullwidth ASCII */
89 roytam 1697  
136 roytam 1698                 /* offsets for the 8 static windows */
1699                 0x0000, /* ASCII for quoted tags */
1700                 0x0080, /* Latin - 1 Supplement (for access to punctuation) */
1701                 0x0100, /* Latin Extended-A */
1702                 0x0300, /* Combining Diacritical Marks */
1703                 0x2000, /* General Punctuation */
1704                 0x2080, /* Currency Symbols */
1705                 0x2100, /* Letterlike Symbols and Number Forms */
1706                 0x3000  /* CJK Symbols and punctuation */
1707         };
1708 }
1709 struct wSCSU : public TextFileWPimpl
1710 {
1711         /* SCSU command byte values */
1712         enum {
1713                 SQ0=0x01, /* Quote from window pair 0 */
1714                 SQU=0x0E, /* Quote a single Unicode character */
1715                 SCU=0x0F, /* Change to Unicode mode */
1716                 SC0=0x10, /* Select window 0 */
1717  
1718                 UC0=0xE0, /* Select window 0 */
1719                 UQU=0xF0  /* Quote a single Unicode character */
1720         };
1721  
1722         wSCSU( FileW& w ) : TextFileWPimpl(w), isUnicodeMode(0), win(0)
1723         {
1724                 WriteChar( 0xfeff ); // Write BOM
1725         }
1726  
1727     char isUnicodeMode, win;
1728  
1729         char isInWindow(ulong offset, ulong c)
1730         {
1731                 return (char)(offset<=c && c<=(offset+0x7f));
1732         }
1733  
1734         // get the index of the static/dynamic window that contains c; -1 if none
1735         int getWindow(ulong c)
1736         {
1737                 int i;
1738  
1739                 for(i=0; i<16; ++i) {
1740                         if(isInWindow(SCSU_offsets[i], c)) {
1741                                 return i;
1742                         }
1743                 }
1744                 return -1;
1745         }
1746  
1747         void WriteChar( unicode c )
1748         {
1749                 char window; // dynamic window 0..7
1750                 int w;       // result of getWindow(), -1..7
1751  
1752                 if( c<0 || c>0x10ffff || (isUnicodeMode&~1)!=0 || (win&~7)!=0 )
1753                 {
1754                         return;
1755                 }
1756  
1757                 window=win;
1758                 if( !isUnicodeMode )
1759                 {
1760                         // single-byte mode
1761                         if(c<0x20)
1762                         {
1763                                 /*
1764                                 * Encode C0 control code:
1765                                 * Check the code point against the bit mask 0010 0110 0000 0001
1766                                 * which contains 1-bits at the bit positions corresponding to
1767                                 * code points 0D 0A 09 00 (CR LF TAB NUL)
1768                                 * which are encoded directly.
1769                                 * All other C0 control codes are quoted with SQ0.
1770                                 */
1771                                 if( c<=0xf && ((1<<c)&0x2601)==0 ) {
1772                                         fp_.WriteC( static_cast<uchar>(SQ0) );
1773                                 }
1774                                 fp_.WriteC( static_cast<uchar>(c) );
1775                         }
1776                         else if( c<=0x7f )
1777                         {
1778                                 // encode US-ASCII directly
1779                                 fp_.WriteC( static_cast<uchar>(c) );
1780                         }
1781                         else if( isInWindow(SCSU_offsets[window], c) )
1782                         {
1783                                 // use the current dynamic window
1784                                 fp_.WriteC( static_cast<uchar>(0x80+(c-SCSU_offsets[window])) );
1785                         }
1786                         else if( (w=getWindow(c))>=0 )
1787                         {
1788                                 if( w<=7 )
1789                                 {
1790                                         // switch to a dynamic window
1791                                         fp_.WriteC( static_cast<uchar>(SC0+w) );
1792                                         fp_.WriteC( static_cast<uchar>(0x80+(c-SCSU_offsets[w])) );
1793                                         win=window=(char)w;
1794                                 }
1795                                 else
1796                                 {
1797                                         // quote from a static window
1798                                         fp_.WriteC( static_cast<uchar>(SQ0+(w-8)) );
1799                                         fp_.WriteC( static_cast<uchar>(c-SCSU_offsets[w]) );
1800                                 }
1801                         }
1802                         else if( c==0xfeff )
1803                         {
1804                                 // encode the signature character U+FEFF with SQU
1805                                 fp_.WriteC( static_cast<uchar>(SQU) );
1806                                 fp_.WriteC( static_cast<uchar>(0xfe) );
1807                                 fp_.WriteC( static_cast<uchar>(0xff) );
1808                         }
1809                         else
1810                         {
1811                                 // switch to Unicode mode
1812                                 fp_.WriteC( static_cast<uchar>(SCU) );
1813                                 isUnicodeMode=1;
1814                                 WriteChar( c );
1815                         }
1816                 }
1817                 else
1818                 {
1819                         /* Unicode mode */
1820                         if( c<=0x7f )
1821                         {
1822                                 // US-ASCII: switch to single-byte mode with the previous dynamic window
1823                                 isUnicodeMode=0;
1824                                 fp_.WriteC( static_cast<uchar>(UC0+window) );
1825                                 WriteChar( c );
1826                         }
1827                         else if( (w=getWindow(c))>=0 && w<=7 )
1828                         {
1829                                 // switch to single-byte mode with a matching dynamic window
1830                                 fp_.WriteC( static_cast<uchar>(UC0+w) );
1831                                 win=window=(char)w;
1832                                 isUnicodeMode=0;
1833                                 WriteChar( c );
1834                         }
1835                         else
1836                         {
1837                                 if( 0xe000<=c && c<=0xf2ff )
1838                                 {
1839                                         fp_.WriteC( static_cast<uchar>(UQU) );
1840                                 }
1841                                 fp_.WriteC( static_cast<uchar>(c>>8) );
1842                                 fp_.WriteC( static_cast<uchar>(c) );
1843                         }
1844                 }
1845         }
1846 };
138 roytam 1847 //-------------------------------------------------------------------------
1848 // BOCU-1
1849 // code portion from BOCU1.pm by Naoya Tozuka
1850 //-------------------------------------------------------------------------
139 roytam 1851 namespace {
1852         static const uchar bocu1_trail_to_byte[243] = {
1853 //   0 - 19 (0x0 - 0x13)
1854           0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
1855     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,             0x1c, 0x1d, 0x1e, 0x1f,
1856 //   20 - 242 (0x14 - 0xf2)
1857           0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1858     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
1859     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1860     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
1861     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
1862     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
1863     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1864     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1865     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
1866     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1867     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1868     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1869     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
1870         0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
1871 }
138 roytam 1872 struct wBOCU1 : public TextFileWPimpl
1873 {
1874         wBOCU1( FileW& w ) : TextFileWPimpl(w), pc ( 0x40 ), cp ( 0 ), diff( 0 )
1875         { // write BOM
1876                 fp_.WriteC( static_cast<uchar>(0xfb) );
1877                 fp_.WriteC( static_cast<uchar>(0xee) );
1878                 fp_.WriteC( static_cast<uchar>(0x28) );
1879         }
136 roytam 1880  
138 roytam 1881         unicode cp, pc;
1882         long diff;
136 roytam 1883  
138 roytam 1884         void WriteChar( unicode ch )
1885         {
1886                 uchar t1,t2,t3;
1887  
1888                 if (ch <= 0x20) {
1889             if(ch != 0x20) pc = 0x40;
1890                         fp_.WriteC( static_cast<uchar>(ch) );
1891         } else {
1892             diff = ch - pc;
1893             if (diff < -187660) { // [...,-187660) : 21
1894                 diff -= -14536567;
1895                 t3 = (uchar)(diff % 243); diff/=243;
1896                 t2 = (uchar)(diff % 243); diff/=243;
1897                 t1 = (uchar)(diff % 243); diff/=243;
1898                                 fp_.WriteC( static_cast<uchar>(0x21) );
1899                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t1 ]) );
1900                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t2 ]) );
1901                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t3 ]) );
1902             } else if (diff < -10513) { // [-187660,-10513) : 22-24
1903                 diff -= -187660;
1904                 t2 = (uchar)(diff % 243); diff/=243;
1905                 t1 = (uchar)(diff % 243); diff/=243;
1906                                 fp_.WriteC( static_cast<uchar>(0x22 + diff) );
1907                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t1 ]) );
1908                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t2 ]) );
1909             } else if (diff < -64) { // [-10513,-64) : 25-4F
1910                 diff -= -10513;
1911                 t1 = (uchar)(diff % 243); diff/=243;
1912                                 fp_.WriteC( static_cast<uchar>(0x25 + diff) );
1913                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t1 ]) );
1914             } else if (diff < 64) { // [-64,63) : 50-CF
1915                 diff -= -64;
1916                                 fp_.WriteC( static_cast<uchar>(0x50 + diff) );
1917             } else if (diff < 10513) { // [64,10513) : D0-FA
1918                 diff -= 64;
1919                 t1 = (uchar)(diff % 243); diff/=243;
1920                                 fp_.WriteC( static_cast<uchar>(0xd0 + diff) );
1921                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t1 ]) );
1922             } else if (diff < 187660) { // [10513,187660) : FB-FD
1923                 diff -= 10513;
1924                 t2 = (uchar)(diff % 243); diff/=243;
1925                 t1 = (uchar)(diff % 243); diff/=243;
1926                                 fp_.WriteC( static_cast<uchar>(0xfb + diff) );
1927                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t1 ]) );
1928                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t2 ]) );
1929             } else { // [187660,...) : FE
1930                 diff -= 187660;
1931                 t3 = (uchar)(diff % 243); diff/=243;
1932                 t2 = (uchar)(diff % 243); diff/=243;
1933                 t1 = (uchar)(diff % 243); diff/=243;
1934                                 fp_.WriteC( static_cast<uchar>(0xfe) );
1935                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t1 ]) );
1936                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t2 ]) );
1937                                 fp_.WriteC( static_cast<uchar>(bocu1_trail_to_byte[ t3 ]) );
1938             }
1939  
1940             // next pc
1941             if (0x3040 <= ch && ch <= 0x309f) {
1942                 pc = 0x3070;
1943             } else if (0x4e00 <= ch && ch <= 0x9fa5) {
1944                 pc = 0x7711;
1945             } else if (0xac00 <= ch && ch <= 0xd7a3) {
1946                 pc = 0xc1d1;
1947             } else {
1948                 pc = ch & ~0x7f | 0x40;
1949             }
1950                 }
1951  
1952         }
1953 };
1954  
1955  
89 roytam 1956 //-------------------------------------------------------------------------
1957 // Win95対策の自前UTF8/UTF7処理
1958 //-------------------------------------------------------------------------
121 roytam 1959 //#ifndef _UNICODE
89 roytam 1960  
1961 struct wUTF8 : public TextFileWPimpl
1962 {
1963         wUTF8( FileW& w, int cp )
1964                 : TextFileWPimpl(w)
1965         {
1966                 if( cp == UTF8 ) // BOM書き込み
1967                         fp_.Write( "\xEF\xBB\xBF", 3 );
1968         }
1969  
1970         void WriteLine( const unicode* str, ulong len )
1971         {
1972                 //        0000-0000-0xxx-xxxx | 0xxxxxxx
1973                 //        0000-0xxx-xxyy-yyyy | 110xxxxx 10yyyyyy
1974                 //        xxxx-yyyy-yyzz-zzzz | 1110xxxx 10yyyyyy 10zzzzzz
1975                 // x-xxyy-yyyy-zzzz-zzww-wwww | 11110xxx 10yyyyyy 10zzzzzz 10wwwwww
1976                 // ...
1977                 while( len-- )
1978                 {
1979                         qbyte ch = *str;
1980                         if( (0xD800<=ch&&ch<=0xDBFF) && len )
1981                                 ch = 0x10000 + (((ch-0xD800)&0x3ff)<<10) + ((*++str-0xDC00)&0x3ff), len--;
1982  
1983                         if( ch <= 0x7f )
1984                                 fp_.WriteC( static_cast<uchar>(ch) );
1985                         else if( ch <= 0x7ff )
1986                                 fp_.WriteC( 0xc0 | static_cast<uchar>(ch>>6) ),
1987                                 fp_.WriteC( 0x80 | static_cast<uchar>(ch&0x3f) );
1988                         else if( ch<= 0xffff )
1989                                 fp_.WriteC( 0xe0 | static_cast<uchar>(ch>>12) ),
1990                                 fp_.WriteC( 0x80 | static_cast<uchar>((ch>>6)&0x3f) ),
1991                                 fp_.WriteC( 0x80 | static_cast<uchar>(ch&0x3f) );
1992                         else if( ch<= 0x1fffff )
1993                                 fp_.WriteC( 0xf0 | static_cast<uchar>(ch>>18) ),
1994                                 fp_.WriteC( 0x80 | static_cast<uchar>((ch>>12)&0x3f) ),
1995                                 fp_.WriteC( 0x80 | static_cast<uchar>((ch>>6)&0x3f) ),
1996                                 fp_.WriteC( 0x80 | static_cast<uchar>(ch&0x3f) );
1997                         else if( ch<= 0x3ffffff )
1998                                 fp_.WriteC( 0xf8 | static_cast<uchar>(ch>>24) ),
1999                                 fp_.WriteC( 0x80 | static_cast<uchar>((ch>>18)&0x3f) ),
2000                                 fp_.WriteC( 0x80 | static_cast<uchar>((ch>>12)&0x3f) ),
2001                                 fp_.WriteC( 0x80 | static_cast<uchar>((ch>>6)&0x3f) ),
2002                                 fp_.WriteC( 0x80 | static_cast<uchar>(ch&0x3f) );
2003                         else
2004                                 fp_.WriteC( 0xfc | static_cast<uchar>(ch>>30) ),
2005                                 fp_.WriteC( 0x80 | static_cast<uchar>((ch>>24)&0x3f) ),
2006                                 fp_.WriteC( 0x80 | static_cast<uchar>((ch>>18)&0x3f) ),
2007                                 fp_.WriteC( 0x80 | static_cast<uchar>((ch>>12)&0x3f) ),
2008                                 fp_.WriteC( 0x80 | static_cast<uchar>((ch>>6)&0x3f) ),
2009                                 fp_.WriteC( 0x80 | static_cast<uchar>(ch&0x3f) );
2010                         ++str;
2011                 }
2012         }
2013 };
2014  
2015  
2016  
2017 struct wUTF7 : public TextFileWPimpl
2018 {
2019         wUTF7( FileW& w ) : TextFileWPimpl(w) {}
2020  
2021         void WriteLine( const unicode* str, ulong len )
2022         {
2023                 static const uchar mime[64] = {
2024                 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
2025                 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
2026                 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
2027                 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'};
2028  
2029                 // XxxxxxYyyyyyZzzz | zzWwwwwwUuuuuuVv | vvvvTtttttSsssss
2030                 bool mode_m = false;
2031                 while( len )
2032                 {
2033                         if( *str <= 0x7f )
2034                         {
2035                                 fp_.WriteC( static_cast<uchar>(*str) );
2036                                 if( *str == L'+' )
2037                                         fp_.WriteC( '-' );
2038                                 ++str, --len;
2039                         }
2040                         else
2041                         {
2042                                 if(!mode_m) fp_.WriteC( '+' ), mode_m=true;
2043                                 unicode tx[3] = {0,0,0};
2044                                 int n=0;
2045                                 tx[0] = *str, ++str, --len, ++n;
2046                                 if( len && *str>0x7f )
2047                                 {
2048                                         tx[1] = *str, ++str, --len, ++n;
2049                                         if( len && *str>0x7f )
2050                                                 tx[2] = *str, ++str, --len, ++n;
2051                                 }
2052                                 {
2053                                         fp_.WriteC( mime[ tx[0]>>10 ] );
2054                                         fp_.WriteC( mime[ (tx[0]>>4)&0x3f ] );
2055                                         fp_.WriteC( mime[ (tx[0]<<2|tx[1]>>14)&0x3f ] );
2056                                         if( n>=2 )
2057                                         {
2058                                                 fp_.WriteC( mime[ (tx[1]>>8)&0x3f ] );
2059                                                 fp_.WriteC( mime[ (tx[1]>>2)&0x3f ] );
2060                                                 fp_.WriteC( mime[ (tx[1]<<4|tx[2]>>12)&0x3f ] );
2061                                                 if( n>=3 )
2062                                                 {
2063                                                         fp_.WriteC( mime[ (tx[2]>>6)&0x3f ] );
2064                                                         fp_.WriteC( mime[ tx[2]&0x3f ] );
2065                                                 }
2066                                         }
2067                                 }
2068                                 if( len && *str<=0x7f )
2069                                         fp_.WriteC( '-' ), mode_m = false;
2070                         }
2071                 }
2072         }
2073 };
2074  
2075  
2076  
121 roytam 2077 //#endif
89 roytam 2078 //-------------------------------------------------------------------------
2079 // Windows頼りの変換
2080 //-------------------------------------------------------------------------
2081  
2082 struct wMBCS : public TextFileWPimpl
2083 {
2084         wMBCS( FileW& w, int cp )
2085                 : TextFileWPimpl(w), cp_(cp)
2086         {
2087                 if( cp == UTF8 )
2088                 {
2089                         // BOM書き込み
2090                         cp_ = UTF8N;
2091                         fp_.Write( "\xEF\xBB\xBF", 3 );
2092                 }
2093         }
2094  
2095         void WriteLine( const unicode* str, ulong len )
2096         {
2097                 // WideCharToMultiByte API を利用した変換
2098                 int r;
2099                 while(
2100                         0==(r=::WideCharToMultiByte(cp_,0,str,len,buf_,bsiz_,NULL,NULL))
2101                  && ::GetLastError()==ERROR_INSUFFICIENT_BUFFER )
2102                         ReserveMoreBuffer();
2103  
2104                 // ファイルへ書き込み
2105                 fp_.Write( buf_, r );
2106         }
2107  
2108         int cp_;
2109 };
2110  
2111  
2112  
2113 //-------------------------------------------------------------------------
2114 // ISO-2022 サブセットその1。
2115 // ASCIIともう一つしか文字集合を使わないもの
2116 //-------------------------------------------------------------------------
2117  
2118 struct wIso2022 : public TextFileWPimpl
2119 {
2120         wIso2022( FileW& w, int cp )
2121                 : TextFileWPimpl(w), hz_(cp==HZ)
2122         {
2123                 switch( cp )
2124                 {
2125                 case IsoKR:
2126                         fp_.Write( "\x1B\x24\x29\x43", 4 );
2127                         cp_ = UHC;
2128                         break;
2129  
2130                 case IsoCN:
2131                         fp_.Write( "\x1B\x24\x29\x41", 4 );
2132                         // fall through...
2133                 default:
2134                         cp_ = GBK;
2135                         break;
2136                 }
2137         }
2138  
2139         void WriteLine( const unicode* str, ulong len )
2140         {
2141                 // まず WideCharToMultiByte API を利用して変換
2142                 int r;
2143                 while(
2144                         0==(r=::WideCharToMultiByte(cp_,0,str,len,buf_,bsiz_,NULL,NULL))
2145                  && ::GetLastError()==ERROR_INSUFFICIENT_BUFFER )
2146                         ReserveMoreBuffer();
2147  
2148                 bool ascii = true;
2149                 for( int i=0; i<r; ++i )
2150                         if( buf_[i] & 0x80 )
2151                         {
2152                                 // 非ASCII部分は最上位ビットを落としてから出力
2153                                 if( ascii )
2154                                 {
2155                                         if( hz_ )
2156                                                 fp_.WriteC( 0x7E ), fp_.WriteC( 0x7B );
2157                                         else
2158                                                 fp_.WriteC( 0x0E );
2159                                         ascii = false;
2160                                 }
2161                                 fp_.WriteC( buf_[i++] & 0x7F );
2162                                 fp_.WriteC( buf_[i]   & 0x7F );
2163                         }
2164                         else
2165                         {
2166                                 // ASCII部分はそのまま出力
2167                                 if( !ascii )
2168                                 {
2169                                         if( hz_ )
2170                                                 fp_.WriteC( 0x7E ), fp_.WriteC( 0x7D );
2171                                         else
2172                                                 fp_.WriteC( 0x0F );
2173                                         ascii = true;
2174                                 }
2175                                 fp_.WriteC( buf_[i] );
2176  
2177                                 // ただしHZの場合、0x7E は 0x7E 0x7E と表す
2178                                 if( hz_ && buf_[i]==0x7E )
2179                                         fp_.WriteC( 0x7E );
2180                         }
2181  
2182                 // 最後は確実にASCIIに戻す
2183                 if( !ascii )
2184                         if( hz_ )
2185                                 fp_.WriteC( 0x7E ), fp_.WriteC( 0x7D );
2186                         else
2187                                 fp_.WriteC( 0x0F );
2188         }
2189  
2190         int  cp_;
2191         bool hz_;
2192 };
2193  
2194  
2195  
2196  
2197 //-------------------------------------------------------------------------
2198 // ISO-2022 サブセットその2。日本語EUC
2199 //-------------------------------------------------------------------------
2200  
2201 // Helper: SJIS ==> JIS X 0208
2202 static void sjis2jis( uchar s1, uchar s2, char* k )
2203 {
2204         if( ((s1==0xfa || s1==0xfb) && s2>=0x40) || (s1==0xfc && (s2&0xf0)==0x40) )
2205         {
2206                 // IBM外字のマッピング
2207 static const WORD IBM_sjis2kuten[] = {
2208 /*fa40*/0x5c51,0x5c52,0x5c53,0x5c54,0x5c55,0x5c56,0x5c57,0x5c58,0x5c59,0x5c5a,0x0d15,0x0d16,0x0d17,0x0d18,0x0d19,0x0d1a,
2209 /*fa50*/0x0d1b,0x0d1c,0x0d1d,0x0d1e,0x022c,0x5c5c,0x5c5d,0x5c5e,0x0d4a,0x0d42,0x0d44,0x0248,0x5901,0x5902,0x5903,0x5904,
2210 /*fa60*/0x5905,0x5906,0x5907,0x5908,0x5909,0x590a,0x590b,0x590c,0x590d,0x590e,0x590f,0x5910,0x5911,0x5912,0x5913,0x5914,
2211 /*fa70*/0x5915,0x5916,0x5917,0x5918,0x5919,0x591a,0x591b,0x591c,0x591d,0x591e,0x591f,0x5920,0x5921,0x5922,0x5923,/**/0x0109,
2212 /*fa80*/0x5924,0x5925,0x5926,0x5927,0x5928,0x5929,0x592a,0x592b,0x592c,0x592d,0x592e,0x592f,0x5930,0x5931,0x5932,0x5933,
2213 /*fa90*/0x5934,0x5935,0x5936,0x5937,0x5938,0x5939,0x593a,0x593b,0x593c,0x593d,0x593e,0x593f,0x5940,0x5941,0x5942,0x5943,
2214 /*faa0*/0x5944,0x5945,0x5946,0x5947,0x5948,0x5949,0x594a,0x594b,0x594c,0x594d,0x594e,0x594f,0x5950,0x5951,0x5952,0x5953,
2215 /*fab0*/0x5954,0x5955,0x5956,0x5957,0x5958,0x5959,0x595a,0x595b,0x595c,0x595d,0x595e,0x5a01,0x5a02,0x5a03,0x5a04,0x5a05,
2216 /*fac0*/0x5a06,0x5a07,0x5a08,0x5a09,0x5a0a,0x5a0b,0x5a0c,0x5a0d,0x5a0e,0x5a0f,0x5a10,0x5a11,0x5a12,0x5a13,0x5a14,0x5a15,
2217 /*fad0*/0x5a16,0x5a17,0x5a18,0x5a19,0x5a1a,0x5a1b,0x5a1c,0x5a1d,0x5a1e,0x5a1f,0x5a20,0x5a21,0x5a22,0x5a23,0x5a24,0x5a25,
2218 /*fae0*/0x5a26,0x5a27,0x5a28,0x5a29,0x5a2a,0x5a2b,0x5a2c,0x5a2d,0x5a2e,0x5a2f,0x5a30,0x5a31,0x5a32,0x5a33,0x5a34,0x5a35,
2219 /*faf0*/0x5a36,0x5a37,0x5a38,0x5a39,0x5a3a,0x5a3b,0x5a3c,0x5a3d,0x5a3e,0x5a3f,0x5a40,0x5a41,0x5a42,/**/0x0109,0x0109,0x0109,
2220 /*fb40*/0x5a43,0x5a44,0x5a45,0x5a46,0x5a47,0x5a48,0x5a49,0x5a4a,0x5a4b,0x5a4c,0x5a4d,0x5a4e,0x5a4f,0x5a50,0x5a51,0x5a52,
2221 /*fb50*/0x5a53,0x5a54,0x5a55,0x5a56,0x5a57,0x5a58,0x5a59,0x5a5a,0x5a5b,0x5a5c,0x5a5d,0x5a5e,0x5b01,0x5b02,0x5b03,0x5b04,
2222 /*fb60*/0x5b05,0x5b06,0x5b07,0x5b08,0x5b09,0x5b0a,0x5b0b,0x5b0c,0x5b0d,0x5b0e,0x5b0f,0x5b10,0x5b11,0x5b12,0x5b13,0x5b14,
2223 /*fb70*/0x5b15,0x5b16,0x5b17,0x5b18,0x5b19,0x5b1a,0x5b1b,0x5b1c,0x5b1d,0x5b1e,0x5b1f,0x5b20,0x5b21,0x5b22,0x5b23,/**/0x0109,
2224 /*fb80*/0x5b24,0x5b25,0x5b26,0x5b27,0x5b28,0x5b29,0x5b2a,0x5b2b,0x5b2c,0x5b2d,0x5b2e,0x5b2f,0x5b30,0x5b31,0x5b32,0x5b33,
2225 /*fb90*/0x5b34,0x5b35,0x5b36,0x5b37,0x5b38,0x5b39,0x5b3a,0x5b3b,0x5b3c,0x5b3d,0x5b3e,0x5b3f,0x5b40,0x5b41,0x5b42,0x5b43,
2226 /*fba0*/0x5b44,0x5b45,0x5b46,0x5b47,0x5b48,0x5b49,0x5b4a,0x5b4b,0x5b4c,0x5b4d,0x5b4e,0x5b4f,0x5b50,0x5b51,0x5b52,0x5b53,
2227 /*fbb0*/0x5b54,0x5b55,0x5b56,0x5b57,0x5b58,0x5b59,0x5b5a,0x5b5b,0x5b5c,0x5b5d,0x5b5e,0x5c01,0x5c02,0x5c03,0x5c04,0x5c05,
2228 /*fbc0*/0x5c06,0x5c07,0x5c08,0x5c09,0x5c0a,0x5c0b,0x5c0c,0x5c0d,0x5c0e,0x5c0f,0x5c10,0x5c11,0x5c12,0x5c13,0x5c14,0x5c15,
2229 /*fbd0*/0x5c16,0x5c17,0x5c18,0x5c19,0x5c1a,0x5c1b,0x5c1c,0x5c1d,0x5c1e,0x5c1f,0x5c20,0x5c21,0x5c22,0x5c23,0x5c24,0x5c25,
2230 /*fbe0*/0x5c26,0x5c27,0x5c28,0x5c29,0x5c2a,0x5c2b,0x5c2c,0x5c2d,0x5c2e,0x5c2f,0x5c30,0x5c31,0x5c32,0x5c33,0x5c34,0x5c35,
2231 /*fbf0*/0x5c36,0x5c37,0x5c38,0x5c39,0x5c3a,0x5c3b,0x5c3c,0x5c3d,0x5c3e,0x5c3f,0x5c40,0x5c41,0x5c42,/**/0x0109,0x0109,0x0109,
2232 /*fc40*/0x5c43,0x5c44,0x5c45,0x5c46,0x5c47,0x5c48,0x5c49,0x5c4a,0x5c4b,0x5c4c,0x5c4d,0x5c4e,/**/0x0109,0x0109,0x0109,0x0109,
2233 };
2234                 k[0] = IBM_sjis2kuten[ (s1-0xfa)*12*16 + (s2-0x40) ]>>8;
2235                 k[1] = IBM_sjis2kuten[ (s1-0xfa)*12*16 + (s2-0x40) ]&0xff;
2236         }
2237         else
2238         {
2239                 // その他
2240                 if( s2>=0x9f )
2241                 {
2242                         if( s1>=0xe0 ) k[0] = ((s1-0xc0)<<1);
2243                         else           k[0] = ((s1-0x80)<<1);
2244                         k[1] = s2-0x9e;
2245                 }
2246                 else
2247                 {
2248                         if( s1>=0xe0 ) k[0] = ((s1-0xc0)<<1)-1;
2249                         else           k[0] = ((s1-0x80)<<1)-1;
2250  
2251                         if( s2 & 0x80 ) k[1] = s2-0x40;
2252                         else                    k[1] = s2-0x3f;
2253                 }
2254         }
2255  
2256         k[0] += 0x20;
2257         k[1] += 0x20;
2258 }
2259  
2260 struct wEucJp : public TextFileWPimpl
2261 {
2262         wEucJp( FileW& w )
2263                 : TextFileWPimpl(w) {}
2264  
2265         void WriteLine( const unicode* str, ulong len )
2266         {
2267                 // まず WideCharToMultiByte API を利用して変換
2268                 int r;
2269                 while(
2270                         0==(r=::WideCharToMultiByte(932,0,str,len,buf_,bsiz_,NULL,NULL))
2271                  && ::GetLastError()==ERROR_INSUFFICIENT_BUFFER )
2272                         ReserveMoreBuffer();
2273  
2274                 for( int i=0; i<r; ++i )
2275                         if( buf_[i] & 0x80 )
2276                         {
2277                                 if( 0xA1<=(uchar)buf_[i] && (uchar)buf_[i]<=0xDF )
2278                                 {
2279                                         // カナ
2280                                         fp_.WriteC( 0x8E );
2281                                         fp_.WriteC( buf_[i] );
2282                                 }
2283                                 else
2284                                 {
2285                                         // JIS X 0208
2286                                         sjis2jis( buf_[i], buf_[i+1], buf_+i );
2287                                         fp_.WriteC( buf_[i++] | 0x80 );
2288                                         fp_.WriteC( buf_[i]   | 0x80 );
2289                                 }
2290                         }
2291                         else
2292                         {
2293                                 // ASCII部分はそのまま出力
2294                                 fp_.WriteC( buf_[i] );
2295                         }
2296         }
2297 };
2298  
2299  
2300  
2301 //-------------------------------------------------------------------------
2302 // ISO-2022 サブセットその3。ISO-2022-JP
2303 //-------------------------------------------------------------------------
2304  
2305 struct wIsoJp : public TextFileWPimpl
2306 {
2307         wIsoJp( FileW& w )
2308                 : TextFileWPimpl(w)
2309         {
2310                 fp_.Write( "\x1b\x28\x42", 3 );
2311         }
2312  
2313         void WriteLine( const unicode* str, ulong len )
2314         {
2315                 // まず WideCharToMultiByte API を利用して変換
2316                 int r;
2317                 while(
2318                         0==(r=::WideCharToMultiByte(932,0,str,len,buf_,bsiz_,NULL,NULL))
2319                  && ::GetLastError()==ERROR_INSUFFICIENT_BUFFER )
2320                         ReserveMoreBuffer();
2321  
2322                 enum { ROMA, KANJI, KANA } state = ROMA;
2323                 for( int i=0; i<r; ++i )
2324                         if( buf_[i] & 0x80 )
2325                         {
2326                                 if( 0xA1<=(uchar)buf_[i] && (uchar)buf_[i]<=0xDF )
2327                                 {
2328                                         // カナ
2329                                         if( state != KANA )
2330                                                 fp_.Write( "\x1b\x28\x49", 3 ), state = KANA;
2331                                         fp_.WriteC( buf_[i] & 0x7f );
2332                                 }
2333                                 else
2334                                 {
2335                                         // JIS X 0208
2336                                         if( state != KANJI )
2337                                                 fp_.Write( "\x1b\x24\x42", 3 ), state = KANJI;
2338                                         sjis2jis( buf_[i], buf_[i+1], buf_+i );
2339                                         fp_.WriteC( buf_[i++] );
2340                                         fp_.WriteC( buf_[i]   );
2341                                 }
2342                         }
2343                         else
2344                         {
2345                                 // ASCII部分はそのまま出力
2346                                 if( state != ROMA )
2347                                         fp_.Write( "\x1b\x28\x42", 3 ), state = ROMA;
2348                                 fp_.WriteC( buf_[i] );
2349                         }
2350  
2351                 if( state != ROMA )
2352                         fp_.Write( "\x1b\x28\x42", 3 ), state = ROMA;
2353         }
2354 };
2355  
2356  
2357  
2358  
2359 //-------------------------------------------------------------------------
2360 // 書き込みル[チンの準備等々
2361 //-------------------------------------------------------------------------
2362  
2363 TextFileW::TextFileW( int charset, int linebreak )
2364         : cs_( charset ), lb_(linebreak)
2365 {
2366 }
2367  
2368 TextFileW::~TextFileW()
2369 {
2370         Close();
2371 }
2372  
2373 void TextFileW::Close()
2374 {
2375         impl_ = NULL;
2376         fp_.Close();
2377 }
2378  
2379 void TextFileW::WriteLine( const unicode* buf, ulong siz, bool lastline )
2380 {
2381         impl_->WriteLine( buf, siz );
2382         if( !lastline )
2383         {
2384                 static const ulong lbLst[] = {0x0D, 0x0A, 0x000A000D};
2385                 static const ulong lbLen[] = {   1,    1,          2};
2386                 impl_->WriteLB(
2387                         reinterpret_cast<const unicode*>(&lbLst[lb_]), lbLen[lb_] );
2388         }
2389 }
2390  
2391 bool TextFileW::Open( const TCHAR* fname )
2392 {
2393         if( !fp_.Open( fname, true ) )
2394                 return false;
2395  
2396         switch( cs_ )
2397         {
2398         case Western: impl_ = new wWest( fp_ ); break;
131 roytam 2399         case UTF1Y:
2400         case UTF1:    impl_ = new wUtf1( fp_, cs_==UTF1Y ); break;
89 roytam 2401         case UTF5:    impl_ = new wUtf5( fp_ ); break;
131 roytam 2402         case UTF9:
2403         case UTF9Y:    impl_ = new wUtf9( fp_, cs_==UTF9Y ); break;
89 roytam 2404         case UTF16l:
2405         case UTF16LE: impl_ = new wUtf16LE( fp_, cs_==UTF16l ); break;
2406         case UTF16b:
2407         case UTF16BE: impl_ = new wUtf16BE( fp_, cs_==UTF16b ); break;
2408         case UTF32l:
2409         case UTF32LE: impl_ = new wUtf32LE( fp_, cs_==UTF32l ); break;
2410         case UTF32b:
2411         case UTF32BE: impl_ = new wUtf32BE( fp_, cs_==UTF32b ); break;
136 roytam 2412         case SCSU:    impl_ = new wSCSU( fp_ ); break;
138 roytam 2413         case BOCU1:   impl_ = new wBOCU1( fp_ ); break;
89 roytam 2414         case EucJP:   impl_ = new wEucJp( fp_ ); break;
2415         case IsoJP:   impl_ = new wIsoJp( fp_ ); break;
2416         case IsoKR:   impl_ = new wIso2022( fp_, cs_ ); break;
2417         case IsoCN:   impl_ = new wIso2022( fp_, cs_ ); break;
2418         case HZ:      impl_ = new wIso2022( fp_, cs_ ); break;
2419         case UTF8:
2420         case UTF8N:
2421         default:
2422 #ifndef _UNICODE
124 roytam 2423                 if( /*app().isWin95() &&*/ (cs_==UTF8 || cs_==UTF8N) )
89 roytam 2424                         impl_ = new wUTF8( fp_, cs_ );
124 roytam 2425                 else if( /*app().isWin95() &&*/ cs_==UTF7 )
89 roytam 2426                         impl_ = new wUTF7( fp_ );
2427                 else
121 roytam 2428 #else
146 roytam 2429                 if( (cs_==UTF8 || cs_==UTF8N) && !::IsValidCodePage(65001) )
121 roytam 2430                         impl_ = new wUTF8( fp_, cs_ );
146 roytam 2431                 else