~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/plugins/codecs/jp/qjiscodec.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the internationalization module of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
// Most of the code here was originally written by Serika Kurusugawa,
 
30
// a.k.a. Junji Takagi, and is included in Qt with the author's permission
 
31
// and the grateful thanks of the Trolltech team.
 
32
 
 
33
/*! \class QJisCodec
 
34
    \reentrant
 
35
    \internal
 
36
 
 
37
  \brief The QJisCodec class provides conversion to and from JIS character sets.
 
38
 
 
39
  More precisely, the QJisCodec class subclasses QTextCodec to
 
40
  provide support for JIS X 0201 Latin, JIS X 0201 Kana, JIS X 0208
 
41
  and JIS X 0212.
 
42
 
 
43
  The environment variable UNICODEMAP_JP can be used to fine-tune
 
44
  QJisCodec, QSjisCodec and QEucJpCodec. The mapping names are as for
 
45
  the Japanese XML working group's \link
 
46
  http://www.y-adagio.com/public/standards/tr_xml_jpf/toc.htm XML
 
47
  Japanese Profile\endlink, because it names and explains all the
 
48
  widely used mappings. Here are brief descriptions, written by
 
49
  Serika Kurusugawa:
 
50
 
 
51
  \list
 
52
 
 
53
  \i "unicode-0.9" or "unicode-0201" for Unicode style. This assumes
 
54
  JISX0201 for 0x00-0x7f. (0.9 is a table version of jisx02xx mapping
 
55
  used for Uniocde spec version 1.1.)
 
56
 
 
57
  \i "unicode-ascii" This assumes US-ASCII for 0x00-0x7f; some
 
58
  chars (JISX0208 0x2140 and JISX0212 0x2237) are different from
 
59
  Unicode 1.1 to avoid conflict.
 
60
 
 
61
  \i "open-19970715-0201" ("open-0201" for convenience) or
 
62
  "jisx0221-1995" for JISX0221-JISX0201 style. JIS X 0221 is JIS
 
63
  version of Unicode, but a few chars (0x5c, 0x7e, 0x2140, 0x216f,
 
64
  0x2131) are different from Unicode 1.1. This is used when 0x5c is
 
65
  treated as YEN SIGN.
 
66
 
 
67
  \i "open-19970715-ascii" ("open-ascii" for convenience) for
 
68
  JISX0221-ASCII style. This is used when 0x5c is treated as REVERSE
 
69
  SOLIDUS.
 
70
 
 
71
  \i "open-19970715-ms" ("open-ms" for convenience) or "cp932" for
 
72
  Microsoft Windows style. Windows Code Page 932. Some chars (0x2140,
 
73
  0x2141, 0x2142, 0x215d, 0x2171, 0x2172) are different from Unicode
 
74
  1.1.
 
75
 
 
76
  \i "jdk1.1.7" for Sun's JDK style. Same as Unicode 1.1, except that
 
77
  JIS 0x2140 is mapped to UFF3C. Either ASCII or JISX0201 can be used
 
78
  for 0x00-0x7f.
 
79
 
 
80
  \endlist
 
81
 
 
82
  In addition, the extensions "nec-vdc", "ibm-vdc" and "udc" are
 
83
  supported.
 
84
 
 
85
  For example, if you want to use Unicode style conversion but with
 
86
  NEC's extension, set \c UNICODEMAP_JP to
 
87
  <nobr>\c {unicode-0.9, nec-vdc}.</nobr> (You will probably
 
88
  need to quote that in a shell command.)
 
89
 
 
90
  Most of the code here was written by Serika Kurusugawa,
 
91
  a.k.a. Junji Takagi, and is included in Qt with the author's
 
92
  permission and the grateful thanks of the Trolltech team. Here is
 
93
  the copyright statement for that code:
 
94
 
 
95
  \legalese
 
96
 
 
97
  Copyright (C) 1999 Serika Kurusugawa. All rights reserved.
 
98
 
 
99
  Redistribution and use in source and binary forms, with or without
 
100
  modification, are permitted provided that the following conditions
 
101
  are met:
 
102
  \list 1
 
103
  \i Redistributions of source code must retain the above copyright
 
104
     notice, this list of conditions and the following disclaimer.
 
105
  \i Redistributions in binary form must reproduce the above copyright
 
106
     notice, this list of conditions and the following disclaimer in the
 
107
     documentation and/or other materials provided with the distribution.
 
108
  \endlist
 
109
 
 
110
  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS".
 
111
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
112
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
113
  ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
114
  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
115
  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
116
  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
117
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
118
  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
119
  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
120
  SUCH DAMAGE.
 
121
*/
 
122
 
 
123
#include "qjiscodec.h"
 
124
#include "qlist.h"
 
125
 
 
126
enum {
 
127
    Esc = 0x1b,
 
128
    So = 0x0e,         // Shift Out
 
129
    Si = 0x0f,         // Shift In
 
130
 
 
131
    ReverseSolidus = 0x5c,
 
132
    YenSign = 0x5c,
 
133
    Tilde = 0x7e,
 
134
    Overline = 0x7e
 
135
};
 
136
 
 
137
#define        IsKana(c)        (((c) >= 0xa1) && ((c) <= 0xdf))
 
138
#define        IsJisChar(c)        (((c) >= 0x21) && ((c) <= 0x7e))
 
139
 
 
140
#define        QValidChar(u)        ((u) ? QChar((ushort)(u)) : QChar(QChar::ReplacementCharacter))
 
141
 
 
142
enum Iso2022State{ Ascii, MinState = Ascii,
 
143
                   JISX0201_Latin, JISX0201_Kana,
 
144
                   JISX0208_1978, JISX0208_1983,
 
145
                   JISX0212, MaxState = JISX0212,
 
146
                   UnknownState };
 
147
 
 
148
static const char Esc_CHARS[] = "()*+-./";
 
149
 
 
150
static const char Esc_Ascii[]                 = {Esc, '(', 'B', 0 };
 
151
static const char Esc_JISX0201_Latin[]        = {Esc, '(', 'J', 0 };
 
152
static const char Esc_JISX0201_Kana[]        = {Esc, '(', 'I', 0 };
 
153
static const char Esc_JISX0208_1978[]        = {Esc, '$', '@', 0 };
 
154
static const char Esc_JISX0208_1983[]        = {Esc, '$', 'B', 0 };
 
155
static const char Esc_JISX0212[]        = {Esc, '$', '(', 'D', 0 };
 
156
static const char * const Esc_SEQ[] = { Esc_Ascii,
 
157
                                        Esc_JISX0201_Latin,
 
158
                                        Esc_JISX0201_Kana,
 
159
                                        Esc_JISX0208_1978,
 
160
                                        Esc_JISX0208_1983,
 
161
                                        Esc_JISX0212 };
 
162
 
 
163
/*! \internal */
 
164
QJisCodec::QJisCodec() : conv(QJpUnicodeConv::newConverter(QJpUnicodeConv::Default))
 
165
{
 
166
}
 
167
 
 
168
 
 
169
/*! \internal */
 
170
QJisCodec::~QJisCodec()
 
171
{
 
172
    delete (QJpUnicodeConv*)conv;
 
173
    conv = 0;
 
174
}
 
175
 
 
176
QByteArray QJisCodec::convertFromUnicode(const QChar *uc, int len, ConverterState *cs) const
 
177
{
 
178
    char replacement = '?';
 
179
    if (cs) {
 
180
        if (cs->flags & ConvertInvalidToNull)
 
181
            replacement = 0;
 
182
    }
 
183
    int invalid = 0;
 
184
 
 
185
    QByteArray result;
 
186
    Iso2022State state = Ascii;
 
187
    Iso2022State prev = Ascii;
 
188
    for (int i = 0; i < len; i++) {
 
189
        QChar ch = uc[i];
 
190
        uint j;
 
191
        if (ch.row() == 0x00 && ch.cell() < 0x80) {
 
192
            // Ascii
 
193
            if (state != JISX0201_Latin ||
 
194
                ch.cell() == ReverseSolidus || ch.cell() == Tilde) {
 
195
                state = Ascii;
 
196
            }
 
197
            j = ch.cell();
 
198
        } else if ((j = conv->unicodeToJisx0201(ch.row(), ch.cell())) != 0) {
 
199
            if (j < 0x80) {
 
200
                // JIS X 0201 Latin
 
201
                if (state != Ascii ||
 
202
                    ch.cell() == YenSign || ch.cell() == Overline) {
 
203
                    state = JISX0201_Latin;
 
204
                }
 
205
            } else {
 
206
                // JIS X 0201 Kana
 
207
                state = JISX0201_Kana;
 
208
                j &= 0x7f;
 
209
            }
 
210
        } else if ((j = conv->unicodeToJisx0208(ch.row(), ch.cell())) != 0) {
 
211
            // JIS X 0208
 
212
            state = JISX0208_1983;
 
213
        } else if ((j = conv->unicodeToJisx0212(ch.row(), ch.cell())) != 0) {
 
214
            // JIS X 0212
 
215
            state = JISX0212;
 
216
        } else {
 
217
            // Invalid
 
218
            state = UnknownState;
 
219
            j = replacement;
 
220
            ++invalid;
 
221
        }
 
222
        if (state != prev) {
 
223
            if (state == UnknownState) {
 
224
                result += Esc_Ascii;
 
225
            } else {
 
226
                result += Esc_SEQ[state - MinState];
 
227
            }
 
228
            prev = state;
 
229
        }
 
230
        if (j < 0x0100) {
 
231
            result += j & 0xff;
 
232
        } else {
 
233
            result += (j >> 8) & 0xff;
 
234
            result += j & 0xff;
 
235
        }
 
236
    }
 
237
    if (prev != Ascii) {
 
238
        result += Esc_Ascii;
 
239
    }
 
240
 
 
241
    if (cs) {
 
242
        cs->invalidChars += invalid;
 
243
    }
 
244
    return result;
 
245
}
 
246
 
 
247
QString QJisCodec::convertToUnicode(const char* chars, int len, ConverterState *cs) const
 
248
{
 
249
    uchar buf[4];
 
250
    int nbuf = 0;
 
251
    Iso2022State state = Ascii, prev = Ascii;
 
252
    bool esc = false;
 
253
    QChar replacement = QChar::ReplacementCharacter;
 
254
    if (cs) {
 
255
        if (cs->flags & ConvertInvalidToNull)
 
256
            replacement = QChar::Null;
 
257
        nbuf = cs->remainingChars;
 
258
        buf[0] = (cs->state_data[0] >> 24) & 0xff;
 
259
        buf[1] = (cs->state_data[0] >> 16) & 0xff;
 
260
        buf[2] = (cs->state_data[0] >>  8) & 0xff;
 
261
        buf[3] = (cs->state_data[0] >>  0) & 0xff;
 
262
        state = (Iso2022State)((cs->state_data[1] >>  0) & 0xff);
 
263
        prev = (Iso2022State)((cs->state_data[1] >>  8) & 0xff);
 
264
        esc = cs->state_data[2];
 
265
    }
 
266
    int invalid = 0;
 
267
 
 
268
    QString result;
 
269
    for (int i=0; i<len; i++) {
 
270
        uchar ch = chars[i];
 
271
        if (esc) {
 
272
            // Escape sequence
 
273
            state = UnknownState;
 
274
            switch (nbuf) {
 
275
            case 0:
 
276
                if (ch == '$' || strchr(Esc_CHARS, ch)) {
 
277
                    buf[nbuf++] = ch;
 
278
                } else {
 
279
                    nbuf = 0;
 
280
                    esc = false;
 
281
                }
 
282
                break;
 
283
            case 1:
 
284
                if (buf[0] == '$') {
 
285
                    if (strchr(Esc_CHARS, ch)) {
 
286
                        buf[nbuf++] = ch;
 
287
                    } else {
 
288
                        switch (ch) {
 
289
                        case '@':
 
290
                            state = JISX0208_1978;        // Esc $ @
 
291
                            break;
 
292
                        case 'B':
 
293
                            state = JISX0208_1983;        // Esc $ B
 
294
                            break;
 
295
                        }
 
296
                        nbuf = 0;
 
297
                        esc = false;
 
298
                    }
 
299
                } else {
 
300
                    if (buf[0] == '(') {
 
301
                        switch (ch) {
 
302
                        case 'B':
 
303
                            state = Ascii;        // Esc (B
 
304
                            break;
 
305
                        case 'I':
 
306
                            state = JISX0201_Kana;        // Esc (I
 
307
                            break;
 
308
                        case 'J':
 
309
                            state = JISX0201_Latin;        // Esc (J
 
310
                            break;
 
311
                        }
 
312
                    }
 
313
                    nbuf = 0;
 
314
                    esc = false;
 
315
                }
 
316
                break;
 
317
            case 2:
 
318
                if (buf[1] == '(') {
 
319
                    switch (ch) {
 
320
                    case 'D':
 
321
                        state = JISX0212;        // Esc $ (D
 
322
                        break;
 
323
                    }
 
324
                }
 
325
                nbuf = 0;
 
326
                esc = false;
 
327
                break;
 
328
            }
 
329
        } else {
 
330
            if (ch == Esc) {
 
331
                // Escape sequence
 
332
                nbuf = 0;
 
333
                esc = true;
 
334
            } else if (ch == So) {
 
335
                // Shift out
 
336
                prev = state;
 
337
                state = JISX0201_Kana;
 
338
                nbuf = 0;
 
339
            } else if (ch == Si) {
 
340
                // Shift in
 
341
                if (prev == Ascii || prev == JISX0201_Latin) {
 
342
                    state = prev;
 
343
                } else {
 
344
                    state = Ascii;
 
345
                }
 
346
                nbuf = 0;
 
347
            } else {
 
348
                uint u;
 
349
                switch (nbuf) {
 
350
                case 0:
 
351
                    switch (state) {
 
352
                    case Ascii:
 
353
                        if (ch < 0x80) {
 
354
                            result += QLatin1Char(ch);
 
355
                            break;
 
356
                        }
 
357
                        /* fall through */
 
358
                    case JISX0201_Latin:
 
359
                        u = conv->jisx0201ToUnicode(ch);
 
360
                        result += QValidChar(u);
 
361
                        break;
 
362
                    case JISX0201_Kana:
 
363
                        u = conv->jisx0201ToUnicode(ch | 0x80);
 
364
                        result += QValidChar(u);
 
365
                        break;
 
366
                    case JISX0208_1978:
 
367
                    case JISX0208_1983:
 
368
                    case JISX0212:
 
369
                        buf[nbuf++] = ch;
 
370
                        break;
 
371
                    default:
 
372
                        result += QChar::ReplacementCharacter;
 
373
                        break;
 
374
                    }
 
375
                    break;
 
376
                case 1:
 
377
                    switch (state) {
 
378
                    case JISX0208_1978:
 
379
                    case JISX0208_1983:
 
380
                        u = conv->jisx0208ToUnicode(buf[0] & 0x7f, ch & 0x7f);
 
381
                        result += QValidChar(u);
 
382
                        break;
 
383
                    case JISX0212:
 
384
                        u = conv->jisx0212ToUnicode(buf[0] & 0x7f, ch & 0x7f);
 
385
                        result += QValidChar(u);
 
386
                        break;
 
387
                    default:
 
388
                        result += replacement;
 
389
                        ++invalid;
 
390
                        break;
 
391
                    }
 
392
                    nbuf = 0;
 
393
                    break;
 
394
                }
 
395
            }
 
396
        }
 
397
    }
 
398
 
 
399
    if (cs) {
 
400
        cs->remainingChars = nbuf;
 
401
        cs->invalidChars += invalid;
 
402
        cs->state_data[0] = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
 
403
        cs->state_data[1] = (prev << 8) + state;
 
404
        cs->state_data[2] = esc;
 
405
    }
 
406
 
 
407
    return result;
 
408
}
 
409
 
 
410
 
 
411
 
 
412
/*! \internal */
 
413
int QJisCodec::_mibEnum()
 
414
{
 
415
    return 39;
 
416
}
 
417
 
 
418
/*! \internal */
 
419
QByteArray QJisCodec::_name()
 
420
{
 
421
    return "ISO-2022-JP";
 
422
}
 
423
 
 
424
/*!
 
425
    Returns the codec's mime name.
 
426
*/
 
427
QList<QByteArray> QJisCodec::_aliases()
 
428
{
 
429
    QList<QByteArray> list;
 
430
    list << "JIS7"; // Qt 3 compat
 
431
    return list;
 
432
}
 
433