~ubuntu-branches/ubuntu/hardy/kdepim/hardy-proposed

« back to all changes in this revision

Viewing changes to kmail/encodingdetector.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Wenning
  • Date: 2008-11-18 13:39:44 UTC
  • mfrom: (82.1.1 hardy-updates)
  • Revision ID: james.westby@ubuntu.com-20081118133944-py2nova33va86lf9
Tags: 4:3.5.10-0ubuntu1~hardy3
* Add kubuntu_17_upstream_r860376.diff which fixed a pointer problem
  in korganizer leading to objects being lost.
* Add kubuntu_18_upstream_r857911.diff to make sure that the inbox
  folder doesn't stay hidden if content is added.
  - See http://bugs.kde.org/show_bug.cgi?id=168544
* Add kubuntu_19_fix_gcal_crash.diff which fixes problems with remote
  resources crashing kontact, most notably when using GCal. (LP: #286905)
* Add kubuntu_20_upstream_r882942.diff which prevents incidence loss
  under certain conditions as the UID map wasn't being reloaded.
* Add kubuntu_21_upstream_r882976.diff to prevent KMail crashing
  due to certain malicious base64-encoded mail parts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    This file was taken from the KDE 4.x libraries and backported to Qt 3.
 
3
 
 
4
    Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 
5
    Copyright (C) 2003 Dirk Mueller (mueller@kde.org)
 
6
    Copyright (C) 2003 Apple Computer, Inc.
 
7
    Copyright (C) 2007 Nick Shaforostoff (shafff@ukr.net)
 
8
 
 
9
    This library is free software; you can redistribute it and/or
 
10
    modify it under the terms of the GNU Library General Public
 
11
    License as published by the Free Software Foundation; either
 
12
    version 2 of the License, or (at your option) any later version.
 
13
 
 
14
    This library is distributed in the hope that it will be useful,
 
15
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
    Library General Public License for more details.
 
18
 
 
19
    You should have received a copy of the GNU Library General Public License
 
20
    along with this library; see the file COPYING.LIB.  If not, write to
 
21
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
22
    Boston, MA 02110-1301, USA.
 
23
*/
 
24
//----------------------------------------------------------------------------
 
25
//
 
26
// decoder for input stream
 
27
 
 
28
#include "encodingdetector.h"
 
29
 
 
30
#undef DECODE_DEBUG
 
31
//#define DECODE_DEBUG
 
32
 
 
33
#define MAX_BUFFER 16*1024
 
34
 
 
35
#include <assert.h>
 
36
#include <stdlib.h>
 
37
 
 
38
#include "encodingdetector_ja_p.h"
 
39
 
 
40
#include <qregexp.h>
 
41
#include <qtextcodec.h>
 
42
 
 
43
#include <kglobal.h>
 
44
#include <kcharsets.h>
 
45
#include <kdebug.h>
 
46
#include <klocale.h>
 
47
 
 
48
#include <ctype.h>
 
49
 
 
50
// The following table was taken from libpango 1.19.3 and slightly modified.
 
51
// Multiple scripts per language were removed and the entries were reordered so
 
52
// that simple substring matching will work. For example, bam was put before ba
 
53
// so that the first match will be likely the right match. Otherwise "ba" would
 
54
// match "bam" but we would have to search on to find "bam" which is what we want.
 
55
// The original file is called pango-script-lang-table.h
 
56
 
 
57
/* pango-script-lang-table.h:
 
58
 * 
 
59
 * Generated by gen-script-for-lang-new.c
 
60
 * Date: 2007-10-26
 
61
 * Source: fontconfig-2.4.91
 
62
 * 
 
63
 * Do not edit. // I did. Sue me ;)
 
64
 */
 
65
typedef struct _PangoScriptForLang {
 
66
  const char lang[6];
 
67
  EncodingDetector::AutoDetectScript scripts[1];
 
68
} PangoScriptForLang;
 
69
 
 
70
//Unfortunately EncodingDetector does not know all scripts that Pango knows.
 
71
//Also, using EncodingDetector::CentralEuropean for the appropriate countries
 
72
//might give better results in some cases.
 
73
//One especially important (many speakers/literates) omission is the lack of
 
74
//Indian scripts.
 
75
 
 
76
#define PANGO_SCRIPT_ARMENIAN EncodingDetector::None
 
77
#define PANGO_SCRIPT_BENGALI EncodingDetector::None
 
78
#define PANGO_SCRIPT_CANADIAN_ABORIGINAL EncodingDetector::None
 
79
#define PANGO_SCRIPT_CHEROKEE EncodingDetector::None
 
80
#define PANGO_SCRIPT_DEVANAGARI EncodingDetector::None
 
81
#define PANGO_SCRIPT_ETHIOPIC EncodingDetector::None
 
82
#define PANGO_SCRIPT_GUJARATI EncodingDetector::None
 
83
#define PANGO_SCRIPT_GURMUKHI EncodingDetector::None
 
84
#define PANGO_SCRIPT_KANNADA EncodingDetector::None
 
85
#define PANGO_SCRIPT_KHMER EncodingDetector::None
 
86
#define PANGO_SCRIPT_LAO EncodingDetector::None
 
87
#define PANGO_SCRIPT_MALAYALAM EncodingDetector::None
 
88
#define PANGO_SCRIPT_MONGOLIAN EncodingDetector::None
 
89
#define PANGO_SCRIPT_MYANMAR EncodingDetector::None
 
90
#define PANGO_SCRIPT_ORIYA EncodingDetector::None
 
91
#define PANGO_SCRIPT_SINHALA EncodingDetector::None
 
92
#define PANGO_SCRIPT_SYRIAC EncodingDetector::None
 
93
#define PANGO_SCRIPT_TAGALOG EncodingDetector::None
 
94
#define PANGO_SCRIPT_TAMIL EncodingDetector::None
 
95
#define PANGO_SCRIPT_TIBETAN EncodingDetector::None
 
96
#define PANGO_SCRIPT_TELUGU EncodingDetector::None
 
97
 
 
98
//Instead of changing the table even more...
 
99
#define PANGO_SCRIPT_ARABIC EncodingDetector::Arabic
 
100
#define PANGO_SCRIPT_CYRILLIC EncodingDetector::Cyrillic
 
101
#define PANGO_SCRIPT_GEORGIAN EncodingDetector::SouthEasternEurope
 
102
#define PANGO_SCRIPT_GREEK EncodingDetector::Greek
 
103
#define PANGO_SCRIPT_HEBREW EncodingDetector::Hebrew
 
104
#define PANGO_SCRIPT_LATIN EncodingDetector::WesternEuropean
 
105
#define PANGO_SCRIPT_THAI EncodingDetector::Thai
 
106
 
 
107
 
 
108
static const PangoScriptForLang pango_script_for_lang[] = {
 
109
  { "aa",    { PANGO_SCRIPT_LATIN/*62*/ } },
 
110
  { "ab",    { PANGO_SCRIPT_CYRILLIC/*90*/ } },
 
111
  { "af",    { PANGO_SCRIPT_LATIN/*69*/ } },
 
112
  { "am",    { PANGO_SCRIPT_ETHIOPIC/*218*/ } },
 
113
  { "ar",    { PANGO_SCRIPT_ARABIC/*125*/ } },
 
114
  { "as",    { PANGO_SCRIPT_BENGALI/*89*/ } },
 
115
  { "ast",   { PANGO_SCRIPT_LATIN/*66*/ } },
 
116
  { "ava",   { PANGO_SCRIPT_CYRILLIC/*67*/ } },
 
117
  { "ay",    { PANGO_SCRIPT_LATIN/*60*/ } },
 
118
  { "az-ir", { PANGO_SCRIPT_ARABIC/*129*/ } },
 
119
  { "az",    { PANGO_SCRIPT_CYRILLIC/*80*/ } }, //, PANGO_SCRIPT_LATIN/*68*/ } },
 
120
  { "bam",   { PANGO_SCRIPT_LATIN/*60*/ } },
 
121
  { "ba",    { PANGO_SCRIPT_CYRILLIC/*82*/ } },
 
122
  { "be",    { PANGO_SCRIPT_CYRILLIC/*68*/ } },
 
123
  { "bg",    { PANGO_SCRIPT_CYRILLIC/*60*/ } },
 
124
  { "bh",    { PANGO_SCRIPT_DEVANAGARI/*68*/ } },
 
125
  { "bho",   { PANGO_SCRIPT_DEVANAGARI/*68*/ } },
 
126
  { "bi",    { PANGO_SCRIPT_LATIN/*58*/ } },
 
127
  { "bin",   { PANGO_SCRIPT_LATIN/*76*/ } },
 
128
  { "bn",    { PANGO_SCRIPT_BENGALI/*89*/ } },
 
129
  { "bo",    { PANGO_SCRIPT_TIBETAN/*95*/ } },
 
130
  { "br",    { PANGO_SCRIPT_LATIN/*64*/ } },
 
131
  { "bs",    { PANGO_SCRIPT_LATIN/*62*/ } },
 
132
  { "bua",   { PANGO_SCRIPT_CYRILLIC/*70*/ } },
 
133
  { "ca",    { PANGO_SCRIPT_LATIN/*74*/ } },
 
134
  { "ce",    { PANGO_SCRIPT_CYRILLIC/*67*/ } },
 
135
  { "chm",   { PANGO_SCRIPT_CYRILLIC/*76*/ } },
 
136
  { "chr",   { PANGO_SCRIPT_CHEROKEE/*85*/ } },
 
137
  { "ch",    { PANGO_SCRIPT_LATIN/*58*/ } },
 
138
  { "co",    { PANGO_SCRIPT_LATIN/*84*/ } },
 
139
  { "cs",    { PANGO_SCRIPT_LATIN/*82*/ } },
 
140
  { "cu",    { PANGO_SCRIPT_CYRILLIC/*103*/ } },
 
141
  { "cv",    { PANGO_SCRIPT_CYRILLIC/*72*/ } }, //, PANGO_SCRIPT_LATIN/*2*/ } },
 
142
  { "cy",    { PANGO_SCRIPT_LATIN/*78*/ } },
 
143
  { "da",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
144
  { "de",    { PANGO_SCRIPT_LATIN/*59*/ } },
 
145
  { "dz",    { PANGO_SCRIPT_TIBETAN/*95*/ } },
 
146
  { "el",    { PANGO_SCRIPT_GREEK/*69*/ } },
 
147
  { "en",    { PANGO_SCRIPT_LATIN/*72*/ } },
 
148
  { "eo",    { PANGO_SCRIPT_LATIN/*64*/ } },
 
149
  { "es",    { PANGO_SCRIPT_LATIN/*66*/ } },
 
150
//  { "et",    { PANGO_SCRIPT_LATIN/*64*/ } },
 
151
  { "et",    { EncodingDetector::Baltic } },
 
152
  { "eu",    { PANGO_SCRIPT_LATIN/*56*/ } },
 
153
  { "fa",    { PANGO_SCRIPT_ARABIC/*129*/ } },
 
154
  { "fi",    { PANGO_SCRIPT_LATIN/*62*/ } },
 
155
  { "fj",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
156
  { "fo",    { PANGO_SCRIPT_LATIN/*68*/ } },
 
157
  { "fr",    { PANGO_SCRIPT_LATIN/*84*/ } },
 
158
  { "ful",   { PANGO_SCRIPT_LATIN/*62*/ } },
 
159
  { "fur",   { PANGO_SCRIPT_LATIN/*66*/ } },
 
160
  { "fy",    { PANGO_SCRIPT_LATIN/*75*/ } },
 
161
  { "ga",    { PANGO_SCRIPT_LATIN/*80*/ } },
 
162
  { "gd",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
163
  { "gez",   { PANGO_SCRIPT_ETHIOPIC/*218*/ } },
 
164
  { "gl",    { PANGO_SCRIPT_LATIN/*66*/ } },
 
165
  { "gn",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
166
  { "gu",    { PANGO_SCRIPT_GUJARATI/*78*/ } },
 
167
  { "gv",    { PANGO_SCRIPT_LATIN/*54*/ } },
 
168
  { "ha",    { PANGO_SCRIPT_LATIN/*60*/ } },
 
169
  { "haw",   { PANGO_SCRIPT_LATIN/*62*/ } },
 
170
  { "he",    { PANGO_SCRIPT_HEBREW/*27*/ } },
 
171
  { "hi",    { PANGO_SCRIPT_DEVANAGARI/*68*/ } },
 
172
  { "ho",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
173
  { "hr",    { PANGO_SCRIPT_LATIN/*62*/ } },
 
174
  { "hu",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
175
  { "hy",    { PANGO_SCRIPT_ARMENIAN/*77*/ } },
 
176
  { "ia",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
177
  { "ibo",   { PANGO_SCRIPT_LATIN/*58*/ } },
 
178
  { "id",    { PANGO_SCRIPT_LATIN/*54*/ } },
 
179
  { "ie",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
180
  { "ik",    { PANGO_SCRIPT_CYRILLIC/*68*/ } },
 
181
  { "io",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
182
  { "is",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
183
  { "it",    { PANGO_SCRIPT_LATIN/*72*/ } },
 
184
  { "iu",    { PANGO_SCRIPT_CANADIAN_ABORIGINAL/*161*/ } },
 
185
//  { "ja",    { PANGO_SCRIPT_HAN/*6356*/, PANGO_SCRIPT_KATAKANA/*88*/, PANGO_SCRIPT_HIRAGANA/*85*/ } },
 
186
  { "ja",    { EncodingDetector::Japanese } },
 
187
  { "kaa",   { PANGO_SCRIPT_CYRILLIC/*78*/ } },
 
188
  { "ka",    { PANGO_SCRIPT_GEORGIAN/*33*/ } },
 
189
  { "ki",    { PANGO_SCRIPT_LATIN/*56*/ } },
 
190
  { "kk",    { PANGO_SCRIPT_CYRILLIC/*77*/ } },
 
191
  { "kl",    { PANGO_SCRIPT_LATIN/*81*/ } },
 
192
  { "km",    { PANGO_SCRIPT_KHMER/*70*/ } },
 
193
  { "kn",    { PANGO_SCRIPT_KANNADA/*80*/ } },
 
194
//  { "ko",    { PANGO_SCRIPT_HANGUL/*2443*/ } },
 
195
  { "ko",    { EncodingDetector::Korean } },
 
196
  { "kok",   { PANGO_SCRIPT_DEVANAGARI/*68*/ } },
 
197
  { "ks",    { PANGO_SCRIPT_DEVANAGARI/*68*/ } },
 
198
  { "ku-ir", { PANGO_SCRIPT_ARABIC/*32*/ } },
 
199
  { "ku",    { PANGO_SCRIPT_CYRILLIC/*60*/ } }, //, PANGO_SCRIPT_LATIN/*4*/ } },
 
200
  { "kum",   { PANGO_SCRIPT_CYRILLIC/*66*/ } },
 
201
  { "kv",    { PANGO_SCRIPT_CYRILLIC/*70*/ } },
 
202
  { "kw",    { PANGO_SCRIPT_LATIN/*64*/ } },
 
203
  { "ky",    { PANGO_SCRIPT_CYRILLIC/*70*/ } },
 
204
  { "la",    { PANGO_SCRIPT_LATIN/*68*/ } },
 
205
  { "lb",    { PANGO_SCRIPT_LATIN/*75*/ } },
 
206
  { "lez",   { PANGO_SCRIPT_CYRILLIC/*67*/ } },
 
207
  { "ln",    { PANGO_SCRIPT_LATIN/*78*/ } },
 
208
  { "lo",    { PANGO_SCRIPT_LAO/*65*/ } },
 
209
//  { "lt",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
210
  { "lt",    { EncodingDetector::Baltic } },
 
211
//  { "lv",    { PANGO_SCRIPT_LATIN/*78*/ } },
 
212
  { "lv",    { EncodingDetector::Baltic } },
 
213
  { "mg",    { PANGO_SCRIPT_LATIN/*56*/ } },
 
214
  { "mh",    { PANGO_SCRIPT_LATIN/*62*/ } },
 
215
  { "mi",    { PANGO_SCRIPT_LATIN/*64*/ } },
 
216
  { "mk",    { PANGO_SCRIPT_CYRILLIC/*42*/ } },
 
217
  { "ml",    { PANGO_SCRIPT_MALAYALAM/*78*/ } },
 
218
  { "mn",    { PANGO_SCRIPT_MONGOLIAN/*130*/ } },
 
219
  { "mo",    { PANGO_SCRIPT_CYRILLIC/*66*/ } }, //, PANGO_SCRIPT_LATIN/*62*/ } },
 
220
  { "mr",    { PANGO_SCRIPT_DEVANAGARI/*68*/ } },
 
221
  { "mt",    { PANGO_SCRIPT_LATIN/*72*/ } },
 
222
  { "my",    { PANGO_SCRIPT_MYANMAR/*48*/ } },
 
223
  { "nb",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
224
  { "nds",   { PANGO_SCRIPT_LATIN/*59*/ } },
 
225
  { "ne",    { PANGO_SCRIPT_DEVANAGARI/*68*/ } },
 
226
  { "nl",    { PANGO_SCRIPT_LATIN/*82*/ } },
 
227
  { "nn",    { PANGO_SCRIPT_LATIN/*76*/ } },
 
228
  { "no",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
229
  { "nr",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
230
  { "nso",   { PANGO_SCRIPT_LATIN/*58*/ } },
 
231
  { "ny",    { PANGO_SCRIPT_LATIN/*54*/ } },
 
232
  { "oc",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
233
  { "om",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
234
  { "or",    { PANGO_SCRIPT_ORIYA/*79*/ } },
 
235
  { "os",    { PANGO_SCRIPT_CYRILLIC/*66*/ } },
 
236
  { "pa",    { PANGO_SCRIPT_GURMUKHI/*63*/ } },
 
237
  { "pl",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
238
  { "ps-af", { PANGO_SCRIPT_ARABIC/*49*/ } },
 
239
  { "ps-pk", { PANGO_SCRIPT_ARABIC/*49*/ } },
 
240
  { "pt",    { PANGO_SCRIPT_LATIN/*82*/ } },
 
241
  { "rm",    { PANGO_SCRIPT_LATIN/*66*/ } },
 
242
  { "ro",    { PANGO_SCRIPT_LATIN/*62*/ } },
 
243
  { "ru",    { PANGO_SCRIPT_CYRILLIC/*66*/ } },
 
244
  { "sah",   { PANGO_SCRIPT_CYRILLIC/*76*/ } },
 
245
  { "sa",    { PANGO_SCRIPT_DEVANAGARI/*68*/ } },
 
246
  { "sco",   { PANGO_SCRIPT_LATIN/*56*/ } },
 
247
  { "sel",   { PANGO_SCRIPT_CYRILLIC/*66*/ } },
 
248
  { "se",    { PANGO_SCRIPT_LATIN/*66*/ } },
 
249
  { "sh",    { PANGO_SCRIPT_CYRILLIC/*76*/ } },
 
250
  { "si",    { PANGO_SCRIPT_SINHALA/*77*/ } },
 
251
  { "sk",    { PANGO_SCRIPT_LATIN/*86*/ } },
 
252
  { "sl",    { PANGO_SCRIPT_LATIN/*62*/ } },
 
253
  { "sma",   { PANGO_SCRIPT_LATIN/*60*/ } },
 
254
  { "smj",   { PANGO_SCRIPT_LATIN/*60*/ } },
 
255
  { "smn",   { PANGO_SCRIPT_LATIN/*68*/ } },
 
256
  { "sms",   { PANGO_SCRIPT_LATIN/*80*/ } },
 
257
  { "sm",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
258
  { "so",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
259
  { "sq",    { PANGO_SCRIPT_LATIN/*56*/ } },
 
260
  { "sr",    { PANGO_SCRIPT_CYRILLIC/*76*/ } },
 
261
  { "ss",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
262
  { "st",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
263
  { "sv",    { PANGO_SCRIPT_LATIN/*68*/ } },
 
264
  { "sw",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
265
  { "syr",   { PANGO_SCRIPT_SYRIAC/*45*/ } },
 
266
  { "ta",    { PANGO_SCRIPT_TAMIL/*48*/ } },
 
267
  { "te",    { PANGO_SCRIPT_TELUGU/*80*/ } },
 
268
  { "tg",    { PANGO_SCRIPT_CYRILLIC/*78*/ } },
 
269
  { "th",    { PANGO_SCRIPT_THAI/*86*/ } },
 
270
  { "ti-er", { PANGO_SCRIPT_ETHIOPIC/*255*/ } },
 
271
  { "ti-et", { PANGO_SCRIPT_ETHIOPIC/*255*/ } },
 
272
  { "tig",   { PANGO_SCRIPT_ETHIOPIC/*221*/ } },
 
273
  { "tk",    { PANGO_SCRIPT_CYRILLIC/*74*/ } },
 
274
  { "tl",    { PANGO_SCRIPT_TAGALOG/*19*/ } },
 
275
  { "tn",    { PANGO_SCRIPT_LATIN/*58*/ } },
 
276
  { "to",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
277
//  { "tr",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
278
  { "tr",    { EncodingDetector::Turkish } },
 
279
  { "ts",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
280
  { "tt",    { PANGO_SCRIPT_CYRILLIC/*76*/ } },
 
281
  { "tw",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
282
  { "tyv",   { PANGO_SCRIPT_CYRILLIC/*70*/ } },
 
283
  { "ug",    { PANGO_SCRIPT_ARABIC/*125*/ } },
 
284
  { "uk",    { PANGO_SCRIPT_CYRILLIC/*72*/ } },
 
285
  { "ur",    { PANGO_SCRIPT_ARABIC/*145*/ } },
 
286
  { "uz",    { PANGO_SCRIPT_CYRILLIC/*68*/ } },
 
287
  { "ven",   { PANGO_SCRIPT_LATIN/*62*/ } },
 
288
  { "vi",    { PANGO_SCRIPT_LATIN/*186*/ } },
 
289
  { "vot",   { PANGO_SCRIPT_LATIN/*62*/ } },
 
290
  { "vo",    { PANGO_SCRIPT_LATIN/*54*/ } },
 
291
  { "wa",    { PANGO_SCRIPT_LATIN/*70*/ } },
 
292
  { "wen",   { PANGO_SCRIPT_LATIN/*76*/ } },
 
293
  { "wo",    { PANGO_SCRIPT_LATIN/*66*/ } },
 
294
  { "xh",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
295
  { "yap",   { PANGO_SCRIPT_LATIN/*58*/ } },
 
296
  { "yi",    { PANGO_SCRIPT_HEBREW/*27*/ } },
 
297
  { "yo",    { PANGO_SCRIPT_LATIN/*114*/ } },
 
298
//  { "zh-cn", { PANGO_SCRIPT_HAN/*6763*/ } },
 
299
  { "zh-cn", { EncodingDetector::ChineseSimplified } },
 
300
//  { "zh-hk", { PANGO_SCRIPT_HAN/*2213*/ } },
 
301
  { "zh-hk", { EncodingDetector::ChineseTraditional } },
 
302
//  { "zh-mo", { PANGO_SCRIPT_HAN/*2213*/ } },
 
303
  { "zh-mo", { EncodingDetector::ChineseTraditional } },
 
304
//  { "zh-sg", { PANGO_SCRIPT_HAN/*6763*/ } },
 
305
  { "zh-sg", { EncodingDetector::ChineseSimplified } },
 
306
//  { "zh-tw", { PANGO_SCRIPT_HAN/*13063*/ } },
 
307
  { "zh-tw", { EncodingDetector::ChineseTraditional } },
 
308
  { "zu",    { PANGO_SCRIPT_LATIN/*52*/ } },
 
309
  { "\x00",    { EncodingDetector::None } }      //end mark
 
310
};
 
311
 
 
312
enum MIB
 
313
{
 
314
    MibLatin1  = 4,
 
315
    Mib8859_8  = 85,
 
316
    MibUtf8    = 106,
 
317
    MibUcs2    = 1000,
 
318
    MibUtf16   = 1015,
 
319
    MibUtf16BE = 1013,
 
320
    MibUtf16LE = 1014
 
321
};
 
322
 
 
323
static bool is16Bit(QTextCodec* codec)
 
324
{
 
325
    switch (codec->mibEnum())
 
326
    {
 
327
    case MibUtf16:
 
328
    case MibUtf16BE:
 
329
    case MibUtf16LE:
 
330
    case MibUcs2:
 
331
        return true;
 
332
    default:
 
333
        return false;
 
334
    }
 
335
}
 
336
 
 
337
class EncodingDetectorPrivate
 
338
{
 
339
public:
 
340
    QTextCodec *m_codec;
 
341
    QTextDecoder *m_decoder; // utf16
 
342
    QTextCodec *m_defaultCodec;
 
343
    QCString  m_storeDecoderName;
 
344
 
 
345
    EncodingDetector::EncodingChoiceSource m_source;
 
346
    EncodingDetector::AutoDetectScript m_autoDetectLanguage;
 
347
 
 
348
    bool m_visualRTL : 1;
 
349
    bool m_seenBody : 1;
 
350
    bool m_writtingHappened : 1;
 
351
    bool m_analyzeCalled : 1; //for decode()
 
352
    int m_multiByte;
 
353
 
 
354
    QCString m_bufferForDefferedEncDetection;
 
355
 
 
356
    EncodingDetectorPrivate()
 
357
            : m_codec(QTextCodec::codecForMib(MibLatin1))
 
358
            , m_decoder(m_codec->makeDecoder())
 
359
            , m_defaultCodec(m_codec)
 
360
            , m_source(EncodingDetector::DefaultEncoding)
 
361
            , m_autoDetectLanguage(EncodingDetector::SemiautomaticDetection)
 
362
            , m_visualRTL(false)
 
363
            , m_seenBody(false)
 
364
            , m_writtingHappened(false)
 
365
            , m_analyzeCalled(false)
 
366
            , m_multiByte(0)
 
367
    {
 
368
    }
 
369
 
 
370
    EncodingDetectorPrivate(QTextCodec* codec,EncodingDetector::EncodingChoiceSource source, EncodingDetector::AutoDetectScript script)
 
371
            : m_codec(codec)
 
372
            , m_decoder(m_codec->makeDecoder())
 
373
            , m_defaultCodec(m_codec)
 
374
            , m_source(source)
 
375
            , m_autoDetectLanguage(script)
 
376
            , m_visualRTL(false)
 
377
            , m_seenBody(false)
 
378
            , m_writtingHappened(false)
 
379
            , m_analyzeCalled(false)
 
380
            , m_multiByte(0)
 
381
    {
 
382
    }
 
383
 
 
384
    ~EncodingDetectorPrivate()
 
385
    {
 
386
        delete m_decoder;
 
387
    }
 
388
};
 
389
 
 
390
 
 
391
static QCString automaticDetectionForArabic( const unsigned char* ptr, int size )
 
392
{
 
393
    for ( int i = 0; i < size; ++i ) {
 
394
        if ( ( ptr[ i ] >= 0x80 && ptr[ i ] <= 0x9F ) || ptr[ i ] == 0xA1 || ptr[ i ] == 0xA2 || ptr[ i ] == 0xA3
 
395
             || ( ptr[ i ] >= 0xA5 && ptr[ i ] <= 0xAB ) || ( ptr[ i ] >= 0xAE && ptr[ i ] <= 0xBA )
 
396
             || ptr[ i ] == 0xBC || ptr[ i ] == 0xBD || ptr[ i ] == 0xBE || ptr[ i ] == 0xC0
 
397
             || ( ptr[ i ] >= 0xDB && ptr[ i ] <= 0xDF ) || ( ptr[ i ] >= 0xF3 ) ) {
 
398
            return "cp1256";
 
399
        }
 
400
    }
 
401
 
 
402
    return "iso-8859-6";
 
403
}
 
404
 
 
405
static QCString automaticDetectionForBaltic( const unsigned char* ptr, int size )
 
406
{
 
407
    for ( int i = 0; i < size; ++i ) {
 
408
        if ( ( ptr[ i ] >= 0x80 && ptr[ i ] <= 0x9E ) )
 
409
             return "cp1257";
 
410
 
 
411
        if ( ptr[ i ] == 0xA1 || ptr[ i ] == 0xA5 )
 
412
            return "iso-8859-13";
 
413
    }
 
414
 
 
415
    return "iso-8859-13";
 
416
}
 
417
 
 
418
static QCString automaticDetectionForCentralEuropean(const unsigned char* ptr, int size )
 
419
{
 
420
    QCString charset;
 
421
    for ( int i = 0; i < size; ++i ) {
 
422
        if ( ptr[ i ] >= 0x80 && ptr[ i ] <= 0x9F ) {
 
423
            if ( ptr[ i ] == 0x81 || ptr[ i ] == 0x83 || ptr[ i ] == 0x90 || ptr[ i ] == 0x98 )
 
424
                return "ibm852";
 
425
 
 
426
            if ( i + 1 > size )
 
427
                return "cp1250";
 
428
            else { // maybe ibm852 ?
 
429
                charset = "cp1250";
 
430
                continue;
 
431
            }
 
432
        }
 
433
        if ( ptr[ i ] == 0xA5 || ptr[ i ] == 0xAE || ptr[ i ] == 0xBE || ptr[ i ] == 0xC3 || ptr[ i ] == 0xD0 || ptr[ i ] == 0xE3 || ptr[ i ] == 0xF0 ) {
 
434
            if ( i + 1 > size )
 
435
                return "iso-8859-2";
 
436
            else {  // maybe ibm852 ?
 
437
                if ( charset.isNull() )
 
438
                    charset = "iso-8859-2";
 
439
                continue;
 
440
            }
 
441
        }
 
442
    }
 
443
 
 
444
    if ( charset.isNull() )
 
445
        charset = "iso-8859-3";
 
446
 
 
447
    return charset.data();
 
448
}
 
449
 
 
450
static QCString automaticDetectionForCyrillic( const unsigned char* ptr, int size)
 
451
{
 
452
#ifdef DECODE_DEBUG
 
453
        kWarning() << "EncodingDetector: Cyr heuristics";
 
454
#endif
 
455
 
 
456
//     if (ptr[0]==0xef && ptr[1]==0xbb && ptr[2]==0xbf)
 
457
//         return "utf8";
 
458
    int utf8_mark=0;
 
459
    int koi_score=0;
 
460
    int cp1251_score=0;
 
461
 
 
462
    int koi_st=0;
 
463
    int cp1251_st=0;
 
464
 
 
465
//     int koi_na=0;
 
466
//     int cp1251_na=0;
 
467
 
 
468
    int koi_o_capital=0;
 
469
    int koi_o=0;
 
470
    int cp1251_o_capital=0;
 
471
    int cp1251_o=0;
 
472
 
 
473
    int koi_a_capital=0;
 
474
    int koi_a=0;
 
475
    int cp1251_a_capital=0;
 
476
    int cp1251_a=0;
 
477
 
 
478
    int koi_s_capital=0;
 
479
    int koi_s=0;
 
480
    int cp1251_s_capital=0;
 
481
    int cp1251_s=0;
 
482
 
 
483
    int koi_i_capital=0;
 
484
    int koi_i=0;
 
485
    int cp1251_i_capital=0;
 
486
    int cp1251_i=0;
 
487
 
 
488
    int cp1251_small_range=0;
 
489
    int koi_small_range=0;
 
490
    int ibm866_small_range=0;
 
491
 
 
492
    int i;
 
493
    for (i=1; (i<size) && (cp1251_small_range+koi_small_range<1000) ;++i)
 
494
    {
 
495
        if (ptr[i]>0xdf)
 
496
        {
 
497
            ++cp1251_small_range;
 
498
 
 
499
            if (ptr[i]==0xee)//small o
 
500
                ++cp1251_o;
 
501
            else if (ptr[i]==0xe0)//small a
 
502
                ++cp1251_a;
 
503
            else if (ptr[i]==0xe8)//small i
 
504
                ++cp1251_i;
 
505
            else if (ptr[i]==0xf1)//small s
 
506
                ++cp1251_s;
 
507
            else if (ptr[i]==0xf2 && ptr[i-1]==0xf1)//small st
 
508
                ++cp1251_st;
 
509
 
 
510
            else if (ptr[i]==0xef)
 
511
                ++koi_o_capital;
 
512
            else if (ptr[i]==0xe1)
 
513
                ++koi_a_capital;
 
514
            else if (ptr[i]==0xe9)
 
515
                ++koi_i_capital;
 
516
            else if (ptr[i]==0xf3)
 
517
                ++koi_s_capital;
 
518
 
 
519
        }
 
520
        else if (ptr[i]>0xbf)
 
521
        {
 
522
            ++koi_small_range;
 
523
 
 
524
            if (ptr[i]==0xd0||ptr[i]==0xd1)//small o
 
525
                ++utf8_mark;
 
526
            else if (ptr[i]==0xcf)//small o
 
527
                ++koi_o;
 
528
            else if (ptr[i]==0xc1)//small a
 
529
                ++koi_a;
 
530
            else if (ptr[i]==0xc9)//small i
 
531
                ++koi_i;
 
532
            else if (ptr[i]==0xd3)//small s
 
533
                ++koi_s;
 
534
            else if (ptr[i]==0xd4 && ptr[i-1]==0xd3)//small st
 
535
                ++koi_st;
 
536
 
 
537
            else if (ptr[i]==0xce)
 
538
                ++cp1251_o_capital;
 
539
            else if (ptr[i]==0xc0)
 
540
                ++cp1251_a_capital;
 
541
            else if (ptr[i]==0xc8)
 
542
                ++cp1251_i_capital;
 
543
            else if (ptr[i]==0xd1)
 
544
                ++cp1251_s_capital;
 
545
        }
 
546
        else if (ptr[i]>0x9f && ptr[i]<0xb0) //first 16 letterz is 60%
 
547
            ++ibm866_small_range;
 
548
 
 
549
    }
 
550
 
 
551
    //cannot decide?
 
552
    if (cp1251_small_range+koi_small_range+ibm866_small_range<8)
 
553
    {
 
554
        return "";
 
555
    }
 
556
 
 
557
    if (3*utf8_mark>cp1251_small_range+koi_small_range+ibm866_small_range)
 
558
    {
 
559
#ifdef DECODE_DEBUG
 
560
        kWarning() << "Cyr Enc Detection: UTF8";
 
561
#endif
 
562
        return "UTF-8";
 
563
    }
 
564
 
 
565
    if (ibm866_small_range>cp1251_small_range+koi_small_range)
 
566
        return "ibm866";
 
567
 
 
568
//     QCString koi_string = "koi8-u";
 
569
//     QCString cp1251_string = "cp1251";
 
570
 
 
571
    if (cp1251_st==0 && koi_st>1)
 
572
        koi_score+=10;
 
573
    else if (koi_st==0 && cp1251_st>1)
 
574
        cp1251_score+=10;
 
575
 
 
576
    if (cp1251_st && koi_st)
 
577
    {
 
578
        if (cp1251_st/koi_st>2)
 
579
            cp1251_score+=20;
 
580
        else if (koi_st/cp1251_st>2)
 
581
            koi_score+=20;
 
582
    }
 
583
 
 
584
    if (cp1251_a>koi_a)
 
585
        cp1251_score+=10;
 
586
    else if (cp1251_a || koi_a)
 
587
        koi_score+=10;
 
588
 
 
589
    if (cp1251_o>koi_o)
 
590
        cp1251_score+=10;
 
591
    else if (cp1251_o || koi_o)
 
592
        koi_score+=10;
 
593
 
 
594
    if (cp1251_i>koi_i)
 
595
        cp1251_score+=10;
 
596
    else if (cp1251_i || koi_i)
 
597
        koi_score+=10;
 
598
 
 
599
    if (cp1251_s>koi_s)
 
600
        cp1251_score+=10;
 
601
    else if (cp1251_s || koi_s)
 
602
        koi_score+=10;
 
603
 
 
604
    if (cp1251_a_capital>koi_a_capital)
 
605
        cp1251_score+=9;
 
606
    else if (cp1251_a_capital || koi_a_capital)
 
607
        koi_score+=9;
 
608
 
 
609
    if (cp1251_o_capital>koi_o_capital)
 
610
        cp1251_score+=9;
 
611
    else if (cp1251_o_capital || koi_o_capital)
 
612
        koi_score+=9;
 
613
 
 
614
    if (cp1251_i_capital>koi_i_capital)
 
615
        cp1251_score+=9;
 
616
    else if (cp1251_i_capital || koi_i_capital)
 
617
        koi_score+=9;
 
618
 
 
619
    if (cp1251_s_capital>koi_s_capital)
 
620
        cp1251_score+=9;
 
621
    else if (cp1251_s_capital || koi_s_capital)
 
622
        koi_score+=9;
 
623
#ifdef DECODE_DEBUG
 
624
    kWarning()<<"koi_score " << koi_score << " cp1251_score " << cp1251_score;
 
625
#endif
 
626
    if (abs(koi_score-cp1251_score)<10)
 
627
    {
 
628
        //fallback...
 
629
        cp1251_score=cp1251_small_range;
 
630
        koi_score=koi_small_range;
 
631
    }
 
632
    if (cp1251_score>koi_score)
 
633
        return "cp1251";
 
634
    else
 
635
        return "koi8-u";
 
636
 
 
637
 
 
638
//     if (cp1251_score>koi_score)
 
639
//         setEncoding("cp1251",AutoDetectedEncoding);
 
640
//     else
 
641
//         setEncoding("koi8-u",AutoDetectedEncoding);
 
642
//     return true;
 
643
 
 
644
}
 
645
 
 
646
static QCString automaticDetectionForGreek( const unsigned char* ptr, int size )
 
647
{
 
648
    for ( int i = 0; i < size; ++i ) {
 
649
        if ( ptr[ i ] == 0x80 || ( ptr[ i ] >= 0x82 && ptr[ i ] <= 0x87 ) || ptr[ i ] == 0x89 || ptr[ i ] == 0x8B
 
650
             || ( ptr[ i ] >= 0x91 && ptr[ i ] <= 0x97 ) || ptr[ i ] == 0x99 || ptr[ i ] == 0x9B || ptr[ i ] == 0xA4
 
651
             || ptr[ i ] == 0xA5 || ptr[ i ] == 0xAE ) {
 
652
            return "cp1253";
 
653
        }
 
654
    }
 
655
 
 
656
    return "iso-8859-7";
 
657
}
 
658
 
 
659
static QCString automaticDetectionForHebrew( const unsigned char* ptr, int size )
 
660
{
 
661
    for ( int i = 0; i < size; ++i ) {
 
662
        if ( ptr[ i ] == 0x80 || ( ptr[ i ] >= 0x82 && ptr[ i ] <= 0x89 ) || ptr[ i ] == 0x8B
 
663
             || ( ptr[ i ] >= 0x91 && ptr[ i ] <= 0x99 ) || ptr[ i ] == 0x9B || ptr[ i ] == 0xA1 || ( ptr[ i ] >= 0xBF && ptr[ i ] <= 0xC9 )
 
664
             || ( ptr[ i ] >= 0xCB && ptr[ i ] <= 0xD8 ) ) {
 
665
            return "cp1255";
 
666
        }
 
667
 
 
668
        if ( ptr[ i ] == 0xDF )
 
669
            return "iso-8859-8-i";
 
670
    }
 
671
 
 
672
    return "iso-8859-8-i";
 
673
}
 
674
 
 
675
static QCString automaticDetectionForJapanese( const unsigned char* ptr, int size )
 
676
{
 
677
    JapaneseCode kc;
 
678
 
 
679
    switch ( kc.guess_jp( (const char*)ptr, size ) ) {
 
680
    case JapaneseCode::JIS:
 
681
        return "jis7";
 
682
    case JapaneseCode::EUC:
 
683
        return "eucjp";
 
684
    case JapaneseCode::SJIS:
 
685
        return "sjis";
 
686
     case JapaneseCode::UTF8:
 
687
        return "utf8";
 
688
    default:
 
689
        break;
 
690
    }
 
691
 
 
692
    return "";
 
693
}
 
694
 
 
695
static QCString automaticDetectionForTurkish( const unsigned char* ptr, int size )
 
696
{
 
697
    for ( int i = 0; i < size; ++i ) {
 
698
        if ( ptr[ i ] == 0x80 || ( ptr[ i ] >= 0x82 && ptr[ i ] <= 0x8C ) || ( ptr[ i ] >= 0x91 && ptr[ i ] <= 0x9C ) || ptr[ i ] == 0x9F ) {
 
699
            return "cp1254";
 
700
        }
 
701
    }
 
702
 
 
703
    return "iso-8859-9";
 
704
}
 
705
 
 
706
static QCString automaticDetectionForWesternEuropean( const unsigned char* ptr, int size )
 
707
{
 
708
    uint nonansi_count=0;
 
709
    for (int i=0; i<size; ++i)
 
710
    {
 
711
        if (ptr[i]>0x79)
 
712
        {
 
713
             ++nonansi_count;
 
714
            if ( ptr[i]>0xc1 && ptr[i]<0xf0 && i+1<size && ptr[i+1]>0x7f && ptr[i+1]<0xc0)
 
715
            {
 
716
                return "UTF-8";
 
717
            }
 
718
            if (ptr[i] >= 0x78 && ptr[i] <= 0x9 )
 
719
            {
 
720
                return "cp1252";
 
721
            }
 
722
        }
 
723
 
 
724
    }
 
725
 
 
726
    if (nonansi_count>0)
 
727
        return "iso-8859-15";
 
728
 
 
729
    return "";
 
730
}
 
731
 
 
732
// Other browsers allow comments in the head section, so we need to also.
 
733
// It's important not to look for tags inside the comments.
 
734
static void skipComment(const char *&ptr, const char *pEnd)
 
735
{
 
736
    const char *p = ptr;
 
737
    // Allow <!-->; other browsers do.
 
738
    if (*p=='>')
 
739
    {
 
740
        p++;
 
741
    }
 
742
    else
 
743
    {
 
744
        while (p!=pEnd)
 
745
        {
 
746
            if (*p=='-')
 
747
            {
 
748
                // This is the real end of comment, "-->".
 
749
                if (p[1]=='-' && p[2]=='>')
 
750
                {
 
751
                    p += 3;
 
752
                    break;
 
753
                }
 
754
                // This is the incorrect end of comment that other browsers allow, "--!>".
 
755
                if (p[1] == '-' && p[2] == '!' && p[3] == '>')
 
756
                {
 
757
                    p += 4;
 
758
                    break;
 
759
                }
 
760
            }
 
761
            p++;
 
762
        }
 
763
    }
 
764
    ptr=p;
 
765
}
 
766
 
 
767
// Returns the position of the encoding string.
 
768
static int findXMLEncoding(const QCString &str, int &encodingLength)
 
769
{
 
770
    int len = str.length();
 
771
    int pos = str.find("encoding");
 
772
    if (pos == -1)
 
773
        return -1;
 
774
    pos += 8;
 
775
 
 
776
    // Skip spaces and stray control characters.
 
777
    while (pos<len && str[pos]<=' ')
 
778
        ++pos;
 
779
 
 
780
    //Bail out if nothing after
 
781
    // Skip equals sign.
 
782
    if (pos>=len || str[pos] != '=')
 
783
        return -1;
 
784
    ++pos;
 
785
 
 
786
    // Skip spaces and stray control characters.
 
787
    while (pos<len && str[pos]<=' ')
 
788
        ++pos;
 
789
 
 
790
    //Bail out if nothing after
 
791
    if (pos >= len)
 
792
        return -1;
 
793
 
 
794
    // Skip quotation mark.
 
795
    char quoteMark = str[pos];
 
796
    if (quoteMark != '"' && quoteMark != '\'')
 
797
        return -1;
 
798
    ++pos;
 
799
 
 
800
    // Find the trailing quotation mark.
 
801
    int end=pos;
 
802
    while (end<len && str[end]!=quoteMark)
 
803
        ++end;
 
804
 
 
805
    if (end>=len)
 
806
        return -1;
 
807
 
 
808
    encodingLength = end-pos;
 
809
    return pos;
 
810
}
 
811
 
 
812
 
 
813
bool EncodingDetector::errorsIfUtf8 (const char* data, int length)
 
814
{
 
815
    if (d->m_codec->mibEnum()!=MibUtf8)
 
816
        return false; //means no errors
 
817
// #define highest1Bits (unsigned char)0x80
 
818
// #define highest2Bits (unsigned char)0xC0
 
819
// #define highest3Bits (unsigned char)0xE0
 
820
// #define highest4Bits (unsigned char)0xF0
 
821
// #define highest5Bits (unsigned char)0xF8
 
822
static const unsigned char highest1Bits = 0x80;
 
823
static const unsigned char highest2Bits = 0xC0;
 
824
static const unsigned char highest3Bits = 0xE0;
 
825
static const unsigned char highest4Bits = 0xF0;
 
826
static const unsigned char highest5Bits = 0xF8;
 
827
 
 
828
    for (int i=0; i<length; ++i)
 
829
    {
 
830
        unsigned char c = data[i];
 
831
 
 
832
        if (d->m_multiByte>0)
 
833
        {
 
834
            if ((c & highest2Bits) == 0x80)
 
835
            {
 
836
                --(d->m_multiByte);
 
837
                continue;
 
838
            }
 
839
#ifdef DECODE_DEBUG
 
840
            kWarning() << "EncDetector: Broken UTF8";
 
841
#endif
 
842
            return true;
 
843
        }
 
844
 
 
845
        // most significant bit zero, single char
 
846
        if ((c & highest1Bits) == 0x00)
 
847
            continue;
 
848
 
 
849
        // 110xxxxx => init 1 following bytes
 
850
        if ((c & highest3Bits) == 0xC0)
 
851
        {
 
852
            d->m_multiByte = 1;
 
853
            continue;
 
854
        }
 
855
 
 
856
        // 1110xxxx => init 2 following bytes
 
857
        if ((c & highest4Bits) == 0xE0)
 
858
        {
 
859
            d->m_multiByte = 2;
 
860
            continue;
 
861
        }
 
862
 
 
863
        // 11110xxx => init 3 following bytes
 
864
        if ((c & highest5Bits) == 0xF0)
 
865
        {
 
866
            d->m_multiByte = 3;
 
867
            continue;
 
868
        }
 
869
#ifdef DECODE_DEBUG
 
870
        kWarning() << "EncDetector:_Broken UTF8";
 
871
#endif
 
872
        return true;
 
873
    }
 
874
    return false;
 
875
}
 
876
 
 
877
EncodingDetector::EncodingDetector() : d(new EncodingDetectorPrivate)
 
878
{
 
879
}
 
880
 
 
881
EncodingDetector::EncodingDetector(QTextCodec* codec, EncodingChoiceSource source, AutoDetectScript script) :
 
882
    d(new EncodingDetectorPrivate(codec,source,script))
 
883
{
 
884
}
 
885
 
 
886
EncodingDetector::~EncodingDetector()
 
887
{
 
888
    delete d;
 
889
}
 
890
 
 
891
void EncodingDetector::setAutoDetectLanguage( EncodingDetector::AutoDetectScript lang)
 
892
{
 
893
    d->m_autoDetectLanguage=lang;
 
894
}
 
895
EncodingDetector::AutoDetectScript EncodingDetector::autoDetectLanguage() const
 
896
{
 
897
    return d->m_autoDetectLanguage;
 
898
}
 
899
 
 
900
EncodingDetector::EncodingChoiceSource EncodingDetector::encodingChoiceSource() const
 
901
{
 
902
    return d->m_source;
 
903
}
 
904
 
 
905
const char* EncodingDetector::encoding() const
 
906
{
 
907
    d->m_storeDecoderName = d->m_codec->name();
 
908
    return d->m_storeDecoderName.data();
 
909
}
 
910
 
 
911
bool EncodingDetector::visuallyOrdered() const
 
912
{
 
913
    return d->m_visualRTL;
 
914
}
 
915
 
 
916
// const QTextCodec* EncodingDetector::codec() const
 
917
// {
 
918
//     return d->m_codec;
 
919
// }
 
920
 
 
921
QTextDecoder* EncodingDetector::decoder()
 
922
{
 
923
    return d->m_decoder;
 
924
}
 
925
 
 
926
bool EncodingDetector::setEncoding(const char *_encoding, EncodingChoiceSource type)
 
927
{
 
928
    QTextCodec *codec;
 
929
    QCString enc(_encoding);
 
930
    if(/*enc.isNull() || */enc.isEmpty())
 
931
    {
 
932
        if (type==DefaultEncoding)
 
933
            codec=d->m_defaultCodec;
 
934
        else
 
935
            return false;
 
936
    }
 
937
    else
 
938
    {
 
939
        //QString->QTextCodec
 
940
 
 
941
        enc = enc.lower();
 
942
         // hebrew visually ordered
 
943
        if(enc=="visual")
 
944
            enc="iso8859-8";
 
945
        bool b;
 
946
        codec = KGlobal::charsets()->codecForName(enc, b);
 
947
        if (!b)
 
948
        return false;
 
949
    }
 
950
 
 
951
    if (d->m_codec->mibEnum()==codec->mibEnum())
 
952
        return true;
 
953
 
 
954
    if ((type==EncodingFromMetaTag || type==EncodingFromXMLHeader) && is16Bit(codec))
 
955
    {
 
956
        //Sometimes the codec specified is absurd, i.e. UTF-16 despite
 
957
        //us decoding a meta tag as ASCII. In that case, ignore it.
 
958
        return false;
 
959
    }
 
960
 
 
961
    if (codec->mibEnum() == Mib8859_8)
 
962
    {
 
963
        //We do NOT want to use Qt's QHebrewCodec, since it tries to reorder itself.
 
964
        codec = QTextCodec::codecForName("iso8859-8-i");
 
965
 
 
966
        // visually ordered unless one of the following
 
967
        if(!(enc=="iso-8859-8-i"||enc=="iso_8859-8-i"||enc=="csiso88598i"||enc=="logical"))
 
968
            d->m_visualRTL = true;
 
969
    }
 
970
 
 
971
    d->m_codec = codec;
 
972
    d->m_source = type;
 
973
    delete d->m_decoder;
 
974
    d->m_decoder = d->m_codec->makeDecoder();
 
975
#ifdef DECODE_DEBUG
 
976
    kDebug(6005) << "EncodingDetector::encoding used is" << d->m_codec->name();
 
977
#endif
 
978
    return true;
 
979
}
 
980
 
 
981
bool EncodingDetector::analyze(const QByteArray &data)
 
982
{
 
983
    return analyze( data.data(), data.size() );
 
984
}
 
985
 
 
986
bool EncodingDetector::analyze(const char *data, int len)
 
987
{
 
988
    // Check for UTF-16 or UTF-8 BOM mark at the beginning, which is a sure sign of a Unicode encoding.
 
989
    // maximumBOMLength = 10
 
990
    // Even if the user has chosen utf16 we still need to auto-detect the endianness
 
991
    if (len >= 10 && ((d->m_source != UserChosenEncoding) || is16Bit(d->m_codec)))
 
992
    {
 
993
        // Extract the first three bytes.
 
994
        const uchar *udata = (const uchar *)data;
 
995
        uchar c1 = *udata++;
 
996
        uchar c2 = *udata++;
 
997
        uchar c3 = *udata++;
 
998
 
 
999
        // Check for the BOM
 
1000
        const char *autoDetectedEncoding;
 
1001
        if ((c1 == 0xFE && c2 == 0xFF) || (c1 == 0xFF && c2 == 0xFE))
 
1002
        {
 
1003
            autoDetectedEncoding = "ISO-10646-UCS-2";
 
1004
        }
 
1005
        else if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF)
 
1006
        {
 
1007
            autoDetectedEncoding = "UTF-8";
 
1008
        }
 
1009
        else if (c1 == 0x00 || c2 == 0x00)
 
1010
        {
 
1011
            uchar c4 = *udata++;
 
1012
            uchar c5 = *udata++;
 
1013
            uchar c6 = *udata++;
 
1014
            uchar c7 = *udata++;
 
1015
            uchar c8 = *udata++;
 
1016
            uchar c9 = *udata++;
 
1017
            uchar c10 = *udata++;
 
1018
 
 
1019
            int nul_count_even = (c2 != 0) + (c4 != 0) + (c6 != 0) + (c8 != 0) + (c10 != 0);
 
1020
            int nul_count_odd = (c1 != 0) + (c3 != 0) + (c5 != 0) + (c7 != 0) + (c9 != 0);
 
1021
            if ((nul_count_even==0 && nul_count_odd==5) || (nul_count_even==5 && nul_count_odd==0))
 
1022
                autoDetectedEncoding = "ISO-10646-UCS-2";
 
1023
            else
 
1024
                autoDetectedEncoding = 0;
 
1025
        }
 
1026
        else
 
1027
        {
 
1028
            autoDetectedEncoding = 0;
 
1029
        }
 
1030
 
 
1031
        // If we found a BOM, use the encoding it implies.
 
1032
        if (autoDetectedEncoding != 0)
 
1033
        {
 
1034
            d->m_source = BOM;
 
1035
            d->m_codec = QTextCodec::codecForName(autoDetectedEncoding);
 
1036
            assert(d->m_codec);
 
1037
            //enc = d->m_codec->name();
 
1038
            delete d->m_decoder;
 
1039
            d->m_decoder = d->m_codec->makeDecoder();
 
1040
#ifdef DECODE_DEBUG
 
1041
            kWarning() << "Detection by BOM";
 
1042
#endif
 
1043
            if (is16Bit(d->m_codec) && c2==0x00)
 
1044
            {
 
1045
                // utf16LE, we need to put the decoder in LE mode
 
1046
                char reverseUtf16[3] = {(char)0xFF, (char)0xFE, 0x00};
 
1047
                d->m_decoder->toUnicode(reverseUtf16, 2);
 
1048
            }
 
1049
            return true;
 
1050
        }
 
1051
    }
 
1052
 
 
1053
    //exit from routine in case it was called to only detect byte order for utf-16
 
1054
    if (d->m_source==UserChosenEncoding)
 
1055
    {
 
1056
#ifdef DECODE_DEBUG
 
1057
        kWarning() << "EncodingDetector: UserChosenEncoding exit ";
 
1058
#endif
 
1059
 
 
1060
        if (errorsIfUtf8(data, len))
 
1061
            setEncoding("",DefaultEncoding);
 
1062
        return true;
 
1063
    }
 
1064
#if 0  //This is for plaintext, so don't try to parse HTML headers -- ahartmetz
 
1065
    if (!d->m_seenBody)
 
1066
    {
 
1067
        // we still don't have an encoding, and are in the head
 
1068
        // the following tags are allowed in <head>:
 
1069
        // SCRIPT|STYLE|META|LINK|OBJECT|TITLE|BASE
 
1070
        const char *ptr = data;
 
1071
        const char *pEnd = data+len;
 
1072
 
 
1073
        while(ptr != pEnd)
 
1074
        {
 
1075
            if(*ptr!='<')
 
1076
            {
 
1077
                ++ptr;
 
1078
                continue;
 
1079
            }
 
1080
            ++ptr;
 
1081
            // Handle comments.
 
1082
            if (ptr[0] == '!' && ptr[1] == '-' && ptr[2] == '-')
 
1083
            {
 
1084
                ptr += 3;
 
1085
                skipComment(ptr, pEnd);
 
1086
                continue;
 
1087
            }
 
1088
 
 
1089
            // Handle XML header, which can have encoding in it.
 
1090
            if (ptr[0]=='?' && ptr[1]=='x' && ptr[2]=='m' && ptr[3]=='l')
 
1091
            {
 
1092
                const char *end = ptr;
 
1093
                while (*end != '>' && end < pEnd)
 
1094
                    end++;
 
1095
                if (*end == '\0' || end == pEnd)
 
1096
                    break;
 
1097
                QCString str(ptr, end - ptr + 1);
 
1098
                int length;
 
1099
                int pos = findXMLEncoding(str, length);
 
1100
                // also handles the case when specified encoding aint correct
 
1101
                if (pos!=-1 && setEncoding(str.mid(pos, length), EncodingFromXMLHeader))
 
1102
                {
 
1103
                    return true;
 
1104
                }
 
1105
            }
 
1106
 
 
1107
            //look for <meta>, stop if we reach <body>
 
1108
            while (
 
1109
                        !((*ptr >= 'a') && (*ptr <= 'z') ||
 
1110
                        (*ptr >= 'A') && (*ptr <= 'Z'))
 
1111
                        && ptr < pEnd
 
1112
                )
 
1113
                ++ptr;
 
1114
 
 
1115
            char tmp[5];
 
1116
            int length=0;
 
1117
            const char* max=ptr+4;
 
1118
            if (pEnd<max)
 
1119
                max=pEnd;
 
1120
            while (
 
1121
                        ((*ptr >= 'a') && (*ptr <= 'z') ||
 
1122
                        (*ptr >= 'A') && (*ptr <= 'Z') ||
 
1123
                        (*ptr >= '0') && (*ptr <= '9'))
 
1124
                        && ptr < max
 
1125
                )
 
1126
            {
 
1127
                tmp[length] = tolower( *ptr );
 
1128
                ++ptr;
 
1129
                ++length;
 
1130
            }
 
1131
            tmp[length] = 0;
 
1132
            if (tmp[0]=='m'&&tmp[1]=='e'&&tmp[2]=='t'&&tmp[3]=='a')
 
1133
            {
 
1134
                // found a meta tag...
 
1135
                const char* end = ptr;
 
1136
                while(*end != '>' && *end != '\0' && end<pEnd)
 
1137
                    end++;
 
1138
                //if ( *end == '\0' ) break;
 
1139
                QCString str( ptr, (end-ptr)+1);
 
1140
                str = str.lower();
 
1141
                int pos=0;
 
1142
                        //if( (pos = str.find("http-equiv", pos)) == -1) break;
 
1143
                        //if( (pos = str.find("content-type", pos)) == -1) break;
 
1144
                if( (pos = str.find("charset")) == -1)
 
1145
                    continue;
 
1146
                pos+=6;
 
1147
                // skip to '='
 
1148
                if( (pos = str.find('=', pos)) == -1)
 
1149
                    continue;
 
1150
 
 
1151
                // skip whitespace before encoding itself
 
1152
                while (pos < (int)str.length() && str[pos] <= ' ')
 
1153
                    ++pos;
 
1154
                if ( pos == (int)str.length())
 
1155
                    continue;
 
1156
 
 
1157
                int endpos = pos;
 
1158
                while( endpos < str.length() &&
 
1159
                        (str[endpos] != ' ' && str[endpos] != '"' && str[endpos] != '\''
 
1160
                                    && str[endpos] != ';' && str[endpos] != '>') )
 
1161
                    ++endpos;
 
1162
    #ifdef DECODE_DEBUG
 
1163
                kDebug( 6005 ) << "EncodingDetector: found charset in <meta>: " << str.mid(pos,endpos-pos).data();
 
1164
    #endif
 
1165
                if (setEncoding(str.mid(pos,endpos-pos), EncodingFromMetaTag))
 
1166
                    return true;
 
1167
            }
 
1168
            else if (tmp[0]=='b'&&tmp[1]=='o'&&tmp[2]=='d'&&tmp[3]=='y')
 
1169
            {
 
1170
                d->m_seenBody=true;
 
1171
                break;
 
1172
            }
 
1173
        }
 
1174
    }
 
1175
 
 
1176
    if (d->m_source==EncodingFromHTTPHeader)
 
1177
        return true;
 
1178
#endif
 
1179
    //if (len<20)     //make a guess even if the file is short -- ahartmetz
 
1180
    if (len < 1)
 
1181
    {
 
1182
        setEncoding("",DefaultEncoding);
 
1183
        return false;
 
1184
    }
 
1185
#ifdef DECODE_DEBUG
 
1186
    kDebug( 6005 ) << "EncodingDetector: using heuristics (" << strlen(data) << ")";
 
1187
#endif
 
1188
 
 
1189
    switch ( d->m_autoDetectLanguage )
 
1190
    {
 
1191
        case EncodingDetector::Arabic:
 
1192
            return setEncoding(automaticDetectionForArabic( (const unsigned char*) data, len ), AutoDetectedEncoding);
 
1193
//             break;
 
1194
        case EncodingDetector::Baltic:
 
1195
            return setEncoding(automaticDetectionForBaltic( (const unsigned char*) data, len ), AutoDetectedEncoding);
 
1196
//             break;
 
1197
        case EncodingDetector::CentralEuropean:
 
1198
            return setEncoding(automaticDetectionForCentralEuropean( (const unsigned char*) data, len ), AutoDetectedEncoding);
 
1199
            break;
 
1200
        case EncodingDetector::Cyrillic:
 
1201
            return setEncoding(automaticDetectionForCyrillic( (const unsigned char*) data, len), AutoDetectedEncoding);
 
1202
//             break;
 
1203
        case EncodingDetector::Greek:
 
1204
            return setEncoding(automaticDetectionForGreek( (const unsigned char*) data, len ), AutoDetectedEncoding);
 
1205
//             break;
 
1206
        case EncodingDetector::Hebrew:
 
1207
            return setEncoding(automaticDetectionForHebrew( (const unsigned char*) data, len ), AutoDetectedEncoding);
 
1208
//             break;
 
1209
        case EncodingDetector::Japanese:
 
1210
            return setEncoding(automaticDetectionForJapanese( (const unsigned char*) data, len ), AutoDetectedEncoding);
 
1211
//             break;
 
1212
        case EncodingDetector::Turkish:
 
1213
            return setEncoding(automaticDetectionForTurkish( (const unsigned char*) data, len ), AutoDetectedEncoding);
 
1214
//             break;
 
1215
        case EncodingDetector::WesternEuropean:
 
1216
            if (setEncoding(automaticDetectionForWesternEuropean( (const unsigned char*) data, len ), AutoDetectedEncoding))
 
1217
                return true;
 
1218
            else if (d->m_defaultCodec->mibEnum()==MibLatin1) //detection for khtml
 
1219
            {
 
1220
                return setEncoding("iso-8859-15",AutoDetectedEncoding);
 
1221
            }
 
1222
            else //use default provided by eg katepart
 
1223
            {
 
1224
                return setEncoding("",DefaultEncoding);
 
1225
            }
 
1226
//             break;
 
1227
        case EncodingDetector::SemiautomaticDetection:
 
1228
        case EncodingDetector::ChineseSimplified:
 
1229
        case EncodingDetector::ChineseTraditional:
 
1230
        case EncodingDetector::Korean:
 
1231
        case EncodingDetector::Thai:
 
1232
        case EncodingDetector::Unicode:
 
1233
        case EncodingDetector::NorthernSaami:
 
1234
        case EncodingDetector::SouthEasternEurope:
 
1235
        case EncodingDetector::None:
 
1236
            // huh. somethings broken in this code ### FIXME
 
1237
            //enc = 0; //Reset invalid codec we tried, so we get back to latin1 fallback.
 
1238
            break;
 
1239
        }
 
1240
 
 
1241
        setEncoding("",DefaultEncoding);
 
1242
        return true;
 
1243
}
 
1244
 
 
1245
 
 
1246
EncodingDetector::AutoDetectScript EncodingDetector::scriptForName(const QString& lang)
 
1247
{
 
1248
    if (lang.isEmpty())
 
1249
        return EncodingDetector::None;
 
1250
    else if (lang==i18n("@item Text character set", "Unicode"))
 
1251
        return EncodingDetector::Unicode;
 
1252
    else if (lang==i18n("@item Text character set", "Cyrillic"))
 
1253
        return EncodingDetector::Cyrillic;
 
1254
    else if (lang==i18n("@item Text character set", "Western European"))
 
1255
        return EncodingDetector::WesternEuropean;
 
1256
    else if (lang==i18n("@item Text character set", "Central European"))
 
1257
        return EncodingDetector::CentralEuropean;
 
1258
    else if (lang==i18n("@item Text character set", "Greek"))
 
1259
        return EncodingDetector::Greek;
 
1260
    else if (lang==i18n("@item Text character set", "Hebrew"))
 
1261
        return EncodingDetector::Hebrew;
 
1262
    else if (lang==i18n("@item Text character set", "Turkish"))
 
1263
        return EncodingDetector::Turkish;
 
1264
    else if (lang==i18n("@item Text character set", "Japanese"))
 
1265
        return EncodingDetector::Japanese;
 
1266
    else if (lang==i18n("@item Text character set", "Baltic"))
 
1267
        return EncodingDetector::Baltic;
 
1268
    else if (lang==i18n("@item Text character set", "Arabic"))
 
1269
        return EncodingDetector::Arabic;
 
1270
 
 
1271
    return EncodingDetector::None;
 
1272
}
 
1273
 
 
1274
bool EncodingDetector::hasAutoDetectionForScript(EncodingDetector::AutoDetectScript script)
 
1275
{
 
1276
    switch (script)
 
1277
    {
 
1278
        case EncodingDetector::Arabic:
 
1279
            return true;
 
1280
        case EncodingDetector::Baltic:
 
1281
            return true;
 
1282
        case EncodingDetector::CentralEuropean:
 
1283
            return true;
 
1284
        case EncodingDetector::Cyrillic:
 
1285
            return true;
 
1286
        case EncodingDetector::Greek:
 
1287
            return true;
 
1288
        case EncodingDetector::Hebrew:
 
1289
            return true;
 
1290
        case EncodingDetector::Japanese:
 
1291
            return true;
 
1292
        case EncodingDetector::Turkish:
 
1293
            return true;
 
1294
        case EncodingDetector::WesternEuropean:
 
1295
            return true;
 
1296
        case EncodingDetector::ChineseTraditional:
 
1297
            return true;
 
1298
        case EncodingDetector::ChineseSimplified:
 
1299
            return true;
 
1300
        case EncodingDetector::Unicode:
 
1301
            return true;
 
1302
            break;
 
1303
        default:
 
1304
            return false;
 
1305
    }
 
1306
}
 
1307
 
 
1308
QString EncodingDetector::nameForScript(EncodingDetector::AutoDetectScript script)
 
1309
{
 
1310
    switch (script)
 
1311
    {
 
1312
        case EncodingDetector::Arabic:
 
1313
            return i18n("@item Text character set", "Arabic");
 
1314
            break;
 
1315
        case EncodingDetector::Baltic:
 
1316
            return i18n("@item Text character set", "Baltic");
 
1317
            break;
 
1318
        case EncodingDetector::CentralEuropean:
 
1319
            return i18n("@item Text character set", "Central European");
 
1320
            break;
 
1321
        case EncodingDetector::Cyrillic:
 
1322
            return i18n("@item Text character set", "Cyrillic");
 
1323
            break;
 
1324
        case EncodingDetector::Greek:
 
1325
            return i18n("@item Text character set", "Greek");
 
1326
            break;
 
1327
        case EncodingDetector::Hebrew:
 
1328
            return i18n("@item Text character set", "Hebrew");
 
1329
            break;
 
1330
        case EncodingDetector::Japanese:
 
1331
            return i18n("@item Text character set", "Japanese");
 
1332
            break;
 
1333
        case EncodingDetector::Turkish:
 
1334
            return i18n("@item Text character set", "Turkish");
 
1335
            break;
 
1336
        case EncodingDetector::WesternEuropean:
 
1337
            return i18n("@item Text character set", "Western European");
 
1338
            break;
 
1339
        case EncodingDetector::ChineseTraditional:
 
1340
            return i18n("@item Text character set", "Chinese Traditional");
 
1341
            break;
 
1342
        case EncodingDetector::ChineseSimplified:
 
1343
            return i18n("@item Text character set", "Chinese Simplified");
 
1344
            break;
 
1345
        case EncodingDetector::Korean:
 
1346
            return i18n("@item Text character set", "Korean");
 
1347
            break;
 
1348
        case EncodingDetector::Thai:
 
1349
            return i18n("@item Text character set", "Thai");
 
1350
            break;
 
1351
        case EncodingDetector::Unicode:
 
1352
            return i18n("@item Text character set", "Unicode");
 
1353
            break;
 
1354
        //case EncodingDetector::SemiautomaticDetection:
 
1355
        default:
 
1356
            return QString();
 
1357
 
 
1358
        }
 
1359
}
 
1360
 
 
1361
EncodingDetector::AutoDetectScript EncodingDetector::scriptForLanguageCode(const QString &lc)
 
1362
{
 
1363
  // It might make sense to do something special if the locale ends with
 
1364
  // ".UTF-8" or "@utf8"
 
1365
  const char *langStr = pango_script_for_lang[0].lang;
 
1366
  // There is obvious optimization potential...
 
1367
  for ( int i = 0; langStr; i++ ) {
 
1368
     langStr = pango_script_for_lang[i].lang;
 
1369
     // startsWith() works for empty strings: every string "starts with" an empty string.
 
1370
     if ( lc.startsWith( QString::fromAscii( langStr ) ) )
 
1371
       return pango_script_for_lang[i].scripts[0];
 
1372
  }
 
1373
  return None;
 
1374
}
 
1375
 
 
1376
#undef DECODE_DEBUG
 
1377