00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "kencodingdetector.h"
00029
00030 #undef DECODE_DEBUG
00031
00032
00033 #define MAX_BUFFER 16*1024
00034
00035 #include <assert.h>
00036
00037 #include "guess_ja_p.h"
00038
00039 #include <QRegExp>
00040 #include <QTextCodec>
00041
00042 #include <kglobal.h>
00043 #include <kcharsets.h>
00044 #include <kdebug.h>
00045 #include <klocale.h>
00046
00047 #include <ctype.h>
00048
00049 enum MIB
00050 {
00051 MibLatin1 = 4,
00052 Mib8859_8 = 85,
00053 MibUtf8 = 106,
00054 MibUcs2 = 1000,
00055 MibUtf16 = 1015,
00056 MibUtf16BE = 1013,
00057 MibUtf16LE = 1014
00058 };
00059
00060 static bool is16Bit(QTextCodec* codec)
00061 {
00062 switch (codec->mibEnum())
00063 {
00064 case MibUtf16:
00065 case MibUtf16BE:
00066 case MibUtf16LE:
00067 case MibUcs2:
00068 return true;
00069 default:
00070 return false;
00071 }
00072 }
00073
00074 class KEncodingDetectorPrivate
00075 {
00076 public:
00077 QTextCodec *m_codec;
00078 QTextDecoder *m_decoder;
00079 QTextCodec *m_defaultCodec;
00080 QByteArray m_storeDecoderName;
00081
00082 KEncodingDetector::EncodingChoiceSource m_source;
00083 KEncodingDetector::AutoDetectScript m_autoDetectLanguage;
00084
00085 bool m_visualRTL : 1;
00086 bool m_seenBody : 1;
00087 bool m_writtingHappened : 1;
00088 bool m_analyzeCalled : 1;
00089 int m_multiByte;
00090
00091 QByteArray m_bufferForDefferedEncDetection;
00092
00093 KEncodingDetectorPrivate()
00094 : m_codec(QTextCodec::codecForMib(MibLatin1))
00095 , m_decoder(m_codec->makeDecoder())
00096 , m_defaultCodec(m_codec)
00097 , m_source(KEncodingDetector::DefaultEncoding)
00098 , m_autoDetectLanguage(KEncodingDetector::SemiautomaticDetection)
00099 , m_visualRTL(false)
00100 , m_seenBody(false)
00101 , m_writtingHappened(false)
00102 , m_analyzeCalled(false)
00103 , m_multiByte(0)
00104 {
00105 }
00106
00107 KEncodingDetectorPrivate(QTextCodec* codec,KEncodingDetector::EncodingChoiceSource source, KEncodingDetector::AutoDetectScript script)
00108 : m_codec(codec)
00109 , m_decoder(m_codec->makeDecoder())
00110 , m_defaultCodec(m_codec)
00111 , m_source(source)
00112 , m_autoDetectLanguage(script)
00113 , m_visualRTL(false)
00114 , m_seenBody(false)
00115 , m_writtingHappened(false)
00116 , m_analyzeCalled(false)
00117 , m_multiByte(0)
00118 {
00119 }
00120
00121 ~KEncodingDetectorPrivate()
00122 {
00123 delete m_decoder;
00124 }
00125 };
00126
00127
00128 static QByteArray automaticDetectionForArabic( const unsigned char* ptr, int size )
00129 {
00130 for ( int i = 0; i < size; ++i ) {
00131 if ( ( ptr[ i ] >= 0x80 && ptr[ i ] <= 0x9F ) || ptr[ i ] == 0xA1 || ptr[ i ] == 0xA2 || ptr[ i ] == 0xA3
00132 || ( ptr[ i ] >= 0xA5 && ptr[ i ] <= 0xAB ) || ( ptr[ i ] >= 0xAE && ptr[ i ] <= 0xBA )
00133 || ptr[ i ] == 0xBC || ptr[ i ] == 0xBD || ptr[ i ] == 0xBE || ptr[ i ] == 0xC0
00134 || ( ptr[ i ] >= 0xDB && ptr[ i ] <= 0xDF ) || ( ptr[ i ] >= 0xF3 ) ) {
00135 return "cp1256";
00136 }
00137 }
00138
00139 return "iso-8859-6";
00140 }
00141
00142 static QByteArray automaticDetectionForBaltic( const unsigned char* ptr, int size )
00143 {
00144 for ( int i = 0; i < size; ++i ) {
00145 if ( ( ptr[ i ] >= 0x80 && ptr[ i ] <= 0x9E ) )
00146 return "cp1257";
00147
00148 if ( ptr[ i ] == 0xA1 || ptr[ i ] == 0xA5 )
00149 return "iso-8859-13";
00150 }
00151
00152 return "iso-8859-13";
00153 }
00154
00155 static QByteArray automaticDetectionForCentralEuropean(const unsigned char* ptr, int size )
00156 {
00157 QByteArray charset = QByteArray();
00158 for ( int i = 0; i < size; ++i ) {
00159 if ( ptr[ i ] >= 0x80 && ptr[ i ] <= 0x9F ) {
00160 if ( ptr[ i ] == 0x81 || ptr[ i ] == 0x83 || ptr[ i ] == 0x90 || ptr[ i ] == 0x98 )
00161 return "ibm852";
00162
00163 if ( i + 1 > size )
00164 return "cp1250";
00165 else {
00166 charset = "cp1250";
00167 continue;
00168 }
00169 }
00170 if ( ptr[ i ] == 0xA5 || ptr[ i ] == 0xAE || ptr[ i ] == 0xBE || ptr[ i ] == 0xC3 || ptr[ i ] == 0xD0 || ptr[ i ] == 0xE3 || ptr[ i ] == 0xF0 ) {
00171 if ( i + 1 > size )
00172 return "iso-8859-2";
00173 else {
00174 if ( charset.isNull() )
00175 charset = "iso-8859-2";
00176 continue;
00177 }
00178 }
00179 }
00180
00181 if ( charset.isNull() )
00182 charset = "iso-8859-3";
00183
00184 return charset.data();
00185 }
00186
00187 static QByteArray automaticDetectionForCyrillic( const unsigned char* ptr, int size)
00188 {
00189 #ifdef DECODE_DEBUG
00190 kWarning() << "KEncodingDetector: Cyr heuristics";
00191 #endif
00192
00193
00194
00195 int utf8_mark=0;
00196 int koi_score=0;
00197 int cp1251_score=0;
00198
00199 int koi_st=0;
00200 int cp1251_st=0;
00201
00202
00203
00204
00205 int koi_o_capital=0;
00206 int koi_o=0;
00207 int cp1251_o_capital=0;
00208 int cp1251_o=0;
00209
00210 int koi_a_capital=0;
00211 int koi_a=0;
00212 int cp1251_a_capital=0;
00213 int cp1251_a=0;
00214
00215 int koi_s_capital=0;
00216 int koi_s=0;
00217 int cp1251_s_capital=0;
00218 int cp1251_s=0;
00219
00220 int koi_i_capital=0;
00221 int koi_i=0;
00222 int cp1251_i_capital=0;
00223 int cp1251_i=0;
00224
00225 int cp1251_small_range=0;
00226 int koi_small_range=0;
00227 int ibm866_small_range=0;
00228
00229 int i;
00230 for (i=1; (i<size) && (cp1251_small_range+koi_small_range<1000) ;++i)
00231 {
00232 if (ptr[i]>0xdf)
00233 {
00234 ++cp1251_small_range;
00235
00236 if (ptr[i]==0xee)
00237 ++cp1251_o;
00238 else if (ptr[i]==0xe0)
00239 ++cp1251_a;
00240 else if (ptr[i]==0xe8)
00241 ++cp1251_i;
00242 else if (ptr[i]==0xf1)
00243 ++cp1251_s;
00244 else if (ptr[i]==0xf2 && ptr[i-1]==0xf1)
00245 ++cp1251_st;
00246
00247 else if (ptr[i]==0xef)
00248 ++koi_o_capital;
00249 else if (ptr[i]==0xe1)
00250 ++koi_a_capital;
00251 else if (ptr[i]==0xe9)
00252 ++koi_i_capital;
00253 else if (ptr[i]==0xf3)
00254 ++koi_s_capital;
00255
00256 }
00257 else if (ptr[i]>0xbf)
00258 {
00259 ++koi_small_range;
00260
00261 if (ptr[i]==0xd0||ptr[i]==0xd1)
00262 ++utf8_mark;
00263 else if (ptr[i]==0xcf)
00264 ++koi_o;
00265 else if (ptr[i]==0xc1)
00266 ++koi_a;
00267 else if (ptr[i]==0xc9)
00268 ++koi_i;
00269 else if (ptr[i]==0xd3)
00270 ++koi_s;
00271 else if (ptr[i]==0xd4 && ptr[i-1]==0xd3)
00272 ++koi_st;
00273
00274 else if (ptr[i]==0xce)
00275 ++cp1251_o_capital;
00276 else if (ptr[i]==0xc0)
00277 ++cp1251_a_capital;
00278 else if (ptr[i]==0xc8)
00279 ++cp1251_i_capital;
00280 else if (ptr[i]==0xd1)
00281 ++cp1251_s_capital;
00282 }
00283 else if (ptr[i]>0x9f && ptr[i]<0xb0)
00284 ++ibm866_small_range;
00285
00286 }
00287
00288
00289 if (cp1251_small_range+koi_small_range+ibm866_small_range<8)
00290 {
00291 return "";
00292 }
00293
00294 if (3*utf8_mark>cp1251_small_range+koi_small_range+ibm866_small_range)
00295 {
00296 #ifdef DECODE_DEBUG
00297 kWarning() << "Cyr Enc Detection: UTF8";
00298 #endif
00299 return "UTF-8";
00300 }
00301
00302 if (ibm866_small_range>cp1251_small_range+koi_small_range)
00303 return "ibm866";
00304
00305
00306
00307
00308 if (cp1251_st==0 && koi_st>1)
00309 koi_score+=10;
00310 else if (koi_st==0 && cp1251_st>1)
00311 cp1251_score+=10;
00312
00313 if (cp1251_st && koi_st)
00314 {
00315 if (cp1251_st/koi_st>2)
00316 cp1251_score+=20;
00317 else if (koi_st/cp1251_st>2)
00318 koi_score+=20;
00319 }
00320
00321 if (cp1251_a>koi_a)
00322 cp1251_score+=10;
00323 else if (cp1251_a || koi_a)
00324 koi_score+=10;
00325
00326 if (cp1251_o>koi_o)
00327 cp1251_score+=10;
00328 else if (cp1251_o || koi_o)
00329 koi_score+=10;
00330
00331 if (cp1251_i>koi_i)
00332 cp1251_score+=10;
00333 else if (cp1251_i || koi_i)
00334 koi_score+=10;
00335
00336 if (cp1251_s>koi_s)
00337 cp1251_score+=10;
00338 else if (cp1251_s || koi_s)
00339 koi_score+=10;
00340
00341 if (cp1251_a_capital>koi_a_capital)
00342 cp1251_score+=9;
00343 else if (cp1251_a_capital || koi_a_capital)
00344 koi_score+=9;
00345
00346 if (cp1251_o_capital>koi_o_capital)
00347 cp1251_score+=9;
00348 else if (cp1251_o_capital || koi_o_capital)
00349 koi_score+=9;
00350
00351 if (cp1251_i_capital>koi_i_capital)
00352 cp1251_score+=9;
00353 else if (cp1251_i_capital || koi_i_capital)
00354 koi_score+=9;
00355
00356 if (cp1251_s_capital>koi_s_capital)
00357 cp1251_score+=9;
00358 else if (cp1251_s_capital || koi_s_capital)
00359 koi_score+=9;
00360 #ifdef DECODE_DEBUG
00361 kWarning()<<"koi_score " << koi_score << " cp1251_score " << cp1251_score;
00362 #endif
00363 if (abs(koi_score-cp1251_score)<10)
00364 {
00365
00366 cp1251_score=cp1251_small_range;
00367 koi_score=koi_small_range;
00368 }
00369 if (cp1251_score>koi_score)
00370 return "cp1251";
00371 else
00372 return "koi8-u";
00373
00374
00375
00376
00377
00378
00379
00380
00381 }
00382
00383 static QByteArray automaticDetectionForGreek( const unsigned char* ptr, int size )
00384 {
00385 for ( int i = 0; i < size; ++i ) {
00386 if ( ptr[ i ] == 0x80 || ( ptr[ i ] >= 0x82 && ptr[ i ] <= 0x87 ) || ptr[ i ] == 0x89 || ptr[ i ] == 0x8B
00387 || ( ptr[ i ] >= 0x91 && ptr[ i ] <= 0x97 ) || ptr[ i ] == 0x99 || ptr[ i ] == 0x9B || ptr[ i ] == 0xA4
00388 || ptr[ i ] == 0xA5 || ptr[ i ] == 0xAE ) {
00389 return "cp1253";
00390 }
00391 }
00392
00393 return "iso-8859-7";
00394 }
00395
00396 static QByteArray automaticDetectionForHebrew( const unsigned char* ptr, int size )
00397 {
00398 for ( int i = 0; i < size; ++i ) {
00399 if ( ptr[ i ] == 0x80 || ( ptr[ i ] >= 0x82 && ptr[ i ] <= 0x89 ) || ptr[ i ] == 0x8B
00400 || ( ptr[ i ] >= 0x91 && ptr[ i ] <= 0x99 ) || ptr[ i ] == 0x9B || ptr[ i ] == 0xA1 || ( ptr[ i ] >= 0xBF && ptr[ i ] <= 0xC9 )
00401 || ( ptr[ i ] >= 0xCB && ptr[ i ] <= 0xD8 ) ) {
00402 return "cp1255";
00403 }
00404
00405 if ( ptr[ i ] == 0xDF )
00406 return "iso-8859-8-i";
00407 }
00408
00409 return "iso-8859-8-i";
00410 }
00411
00412 static QByteArray automaticDetectionForJapanese( const unsigned char* ptr, int size )
00413 {
00414 JapaneseCode kc;
00415
00416 switch ( kc.guess_jp( (const char*)ptr, size ) ) {
00417 case JapaneseCode::JIS:
00418 return "jis7";
00419 case JapaneseCode::EUC:
00420 return "eucjp";
00421 case JapaneseCode::SJIS:
00422 return "sjis";
00423 case JapaneseCode::UTF8:
00424 return "utf8";
00425 default:
00426 break;
00427 }
00428
00429 return "";
00430 }
00431
00432 static QByteArray automaticDetectionForTurkish( const unsigned char* ptr, int size )
00433 {
00434 for ( int i = 0; i < size; ++i ) {
00435 if ( ptr[ i ] == 0x80 || ( ptr[ i ] >= 0x82 && ptr[ i ] <= 0x8C ) || ( ptr[ i ] >= 0x91 && ptr[ i ] <= 0x9C ) || ptr[ i ] == 0x9F ) {
00436 return "cp1254";
00437 }
00438 }
00439
00440 return "iso-8859-9";
00441 }
00442
00443 static QByteArray automaticDetectionForWesternEuropean( const unsigned char* ptr, int size )
00444 {
00445 --size;
00446 uint nonansi_count=0;
00447 for (int i=0; i<size; ++i)
00448 {
00449 if (ptr[i]>0x79)
00450 {
00451 ++nonansi_count;
00452 if ( ptr[i]>0xc1 && ptr[i]<0xf0 && ptr[i+1]>0x7f && ptr[i+1]<0xc0)
00453 {
00454 return "UTF-8";
00455 }
00456 if (ptr[i] >= 0x78 && ptr[i]<=0x9F )
00457 {
00458 return "cp1252";
00459 }
00460 }
00461
00462 }
00463
00464 if (nonansi_count>0)
00465 return "iso-8859-15";
00466
00467 return "";
00468 }
00469
00470
00471
00472 static void skipComment(const char *&ptr, const char *pEnd)
00473 {
00474 const char *p = ptr;
00475
00476 if (*p=='>')
00477 {
00478 p++;
00479 }
00480 else
00481 {
00482 while (p!=pEnd)
00483 {
00484 if (*p=='-')
00485 {
00486
00487 if (p[1]=='-' && p[2]=='>')
00488 {
00489 p += 3;
00490 break;
00491 }
00492
00493 if (p[1] == '-' && p[2] == '!' && p[3] == '>')
00494 {
00495 p += 4;
00496 break;
00497 }
00498 }
00499 p++;
00500 }
00501 }
00502 ptr=p;
00503 }
00504
00505
00506 static int findXMLEncoding(const QByteArray &str, int &encodingLength)
00507 {
00508 int len = str.length();
00509 int pos = str.indexOf("encoding");
00510 if (pos == -1)
00511 return -1;
00512 pos += 8;
00513
00514
00515 while (pos<len && str[pos]<=' ')
00516 ++pos;
00517
00518
00519
00520 if (pos>=len || str[pos] != '=')
00521 return -1;
00522 ++pos;
00523
00524
00525 while (pos<len && str[pos]<=' ')
00526 ++pos;
00527
00528
00529 if (pos >= len)
00530 return -1;
00531
00532
00533 char quoteMark = str[pos];
00534 if (quoteMark != '"' && quoteMark != '\'')
00535 return -1;
00536 ++pos;
00537
00538
00539 int end=pos;
00540 while (end<len && str[end]!=quoteMark)
00541 ++end;
00542
00543 if (end>=len)
00544 return -1;
00545
00546 encodingLength = end-pos;
00547 return pos;
00548 }
00549
00550 bool KEncodingDetector::processNull(char *data, int len)
00551 {
00552 bool bin=false;
00553 if(is16Bit(d->m_codec))
00554 {
00555 for (int i=1; i < len; i+=2)
00556 {
00557 if ((data[i]=='\0') && (data[i-1]=='\0'))
00558 {
00559 bin=true;
00560 data[i]=' ';
00561 }
00562 }
00563 return bin;
00564 }
00565
00566 int i = len-1;
00567 while(--i>=0)
00568 {
00569 if(data[i]==0)
00570 {
00571 bin=true;
00572 data[i]=' ';
00573 }
00574 }
00575 return bin;
00576 }
00577
00578
00579 bool KEncodingDetector::errorsIfUtf8 (const char* data, int length)
00580 {
00581 if (d->m_codec->mibEnum()!=MibUtf8)
00582 return false;
00583
00584
00585
00586
00587
00588 static const unsigned char highest1Bits = 0x80;
00589 static const unsigned char highest2Bits = 0xC0;
00590 static const unsigned char highest3Bits = 0xE0;
00591 static const unsigned char highest4Bits = 0xF0;
00592 static const unsigned char highest5Bits = 0xF8;
00593
00594 for (int i=0; i<length; ++i)
00595 {
00596 unsigned char c = data[i];
00597
00598 if (d->m_multiByte>0)
00599 {
00600 if ((c & highest2Bits) == 0x80)
00601 {
00602 --(d->m_multiByte);
00603 continue;
00604 }
00605 #ifdef DECODE_DEBUG
00606 kWarning() << "EncDetector: Broken UTF8";
00607 #endif
00608 return true;
00609 }
00610
00611
00612 if ((c & highest1Bits) == 0x00)
00613 continue;
00614
00615
00616 if ((c & highest3Bits) == 0xC0)
00617 {
00618 d->m_multiByte = 1;
00619 continue;
00620 }
00621
00622
00623 if ((c & highest4Bits) == 0xE0)
00624 {
00625 d->m_multiByte = 2;
00626 continue;
00627 }
00628
00629
00630 if ((c & highest5Bits) == 0xF0)
00631 {
00632 d->m_multiByte = 3;
00633 continue;
00634 }
00635 #ifdef DECODE_DEBUG
00636 kWarning() << "EncDetector:_Broken UTF8";
00637 #endif
00638 return true;
00639 }
00640 return false;
00641 }
00642
00643
00644 KEncodingDetector::KEncodingDetector() : d(new KEncodingDetectorPrivate)
00645 {
00646 }
00647
00648 KEncodingDetector::KEncodingDetector(QTextCodec* codec, EncodingChoiceSource source, AutoDetectScript script) :
00649 d(new KEncodingDetectorPrivate(codec,source,script))
00650 {
00651 }
00652
00653 KEncodingDetector::~KEncodingDetector()
00654 {
00655 delete d;
00656 }
00657
00658 void KEncodingDetector::setAutoDetectLanguage( KEncodingDetector::AutoDetectScript lang)
00659 {
00660 d->m_autoDetectLanguage=lang;
00661 }
00662 KEncodingDetector::AutoDetectScript KEncodingDetector::autoDetectLanguage() const
00663 {
00664 return d->m_autoDetectLanguage;
00665 }
00666
00667 KEncodingDetector::EncodingChoiceSource KEncodingDetector::encodingChoiceSource() const
00668 {
00669 return d->m_source;
00670 }
00671
00672 const char* KEncodingDetector::encoding() const
00673 {
00674 d->m_storeDecoderName = d->m_codec->name();
00675 return d->m_storeDecoderName.constData();
00676 }
00677
00678 bool KEncodingDetector::visuallyOrdered() const
00679 {
00680 return d->m_visualRTL;
00681 }
00682
00683
00684
00685
00686
00687
00688 QTextDecoder* KEncodingDetector::decoder()
00689 {
00690 return d->m_decoder;
00691 }
00692
00693 bool KEncodingDetector::setEncoding(const char *_encoding, EncodingChoiceSource type)
00694 {
00695 QTextCodec *codec;
00696 QByteArray enc(_encoding);
00697 if(enc.isEmpty())
00698 {
00699 if (type==DefaultEncoding)
00700 codec=d->m_defaultCodec;
00701 else
00702 return false;
00703 }
00704 else
00705 {
00706
00707
00708 enc = enc.toLower();
00709
00710 if(enc=="visual")
00711 enc="iso8859-8";
00712 bool b;
00713 codec = KGlobal::charsets()->codecForName(enc, b);
00714 if (!b)
00715 return false;
00716 }
00717
00718 if (d->m_codec->mibEnum()==codec->mibEnum())
00719 return true;
00720
00721 if ((type==EncodingFromMetaTag || type==EncodingFromXMLHeader) && is16Bit(codec))
00722 {
00723
00724
00725 return false;
00726 }
00727
00728 if (codec->mibEnum() == Mib8859_8)
00729 {
00730
00731 codec = QTextCodec::codecForName("iso8859-8-i");
00732
00733
00734 if(!(enc=="iso-8859-8-i"||enc=="iso_8859-8-i"||enc=="csiso88598i"||enc=="logical"))
00735 d->m_visualRTL = true;
00736 }
00737
00738 d->m_codec = codec;
00739 d->m_source = type;
00740 delete d->m_decoder;
00741 d->m_decoder = d->m_codec->makeDecoder();
00742 #ifdef DECODE_DEBUG
00743 kDebug(6005) << "KEncodingDetector::encoding used is" << d->m_codec->name();
00744 #endif
00745 return true;
00746 }
00747
00748 QString KEncodingDetector::decode(const char *data, int len)
00749 {
00750 processNull(const_cast<char *>(data),len);
00751 if (!d->m_analyzeCalled)
00752 {
00753 analyze(data,len);
00754 d->m_analyzeCalled=true;
00755 }
00756
00757 return d->m_decoder->toUnicode(data,len);
00758 }
00759
00760 QString KEncodingDetector::decode(const QByteArray &data)
00761 {
00762 processNull(const_cast<char *>(data.data()),data.size());
00763 if (!d->m_analyzeCalled)
00764 {
00765 analyze(data.data(),data.size());
00766 d->m_analyzeCalled=true;
00767 }
00768
00769 return d->m_decoder->toUnicode(data);
00770 }
00771
00772 QString KEncodingDetector::decodeWithBuffering(const char *data, int len)
00773 {
00774 #ifdef DECODE_DEBUG
00775 kWarning() << "KEncodingDetector: decoding "<<len<<" bytes";
00776 #endif
00777 if (d->m_writtingHappened)
00778 {
00779 #ifdef DECODE_DEBUG
00780 kWarning() << "KEncodingDetector: d->m_writtingHappened "<< d->m_codec->name();
00781 #endif
00782 processNull(const_cast<char *>(data),len);
00783 return d->m_decoder->toUnicode(data, len);
00784 }
00785 else
00786 {
00787 if (d->m_bufferForDefferedEncDetection.isEmpty())
00788 {
00789 if (analyze(data,len)
00790 && (d->m_seenBody
00791 || !(d->m_source==AutoDetectedEncoding
00792 ||d->m_source==DefaultEncoding
00793 )
00794 )
00795 )
00796 {
00797 #ifdef DECODE_DEBUG
00798 kWarning() << "KEncodingDetector: m_writtingHappened first time "<< d->m_codec->name();
00799 #endif
00800 processNull(const_cast<char *>(data),len);
00801 d->m_writtingHappened=true;
00802 return d->m_decoder->toUnicode(data, len);
00803 }
00804 else
00805 {
00806 #ifdef DECODE_DEBUG
00807 kWarning() << "KEncodingDetector: begin deffer";
00808 #endif
00809 d->m_bufferForDefferedEncDetection=data;
00810 }
00811 }
00812 else
00813 {
00814 d->m_bufferForDefferedEncDetection+=data;
00815 if ( (analyze(data,len)
00816 && (d->m_seenBody
00817 || !(d->m_source==AutoDetectedEncoding
00818 ||d->m_source==DefaultEncoding
00819 )
00820 )
00821 ) || d->m_bufferForDefferedEncDetection.length()>MAX_BUFFER
00822 )
00823 {
00824 d->m_writtingHappened=true;
00825 d->m_bufferForDefferedEncDetection.replace('\0',' ');
00826 QString result(d->m_decoder->toUnicode(d->m_bufferForDefferedEncDetection));
00827 d->m_bufferForDefferedEncDetection.clear();
00828 #ifdef DECODE_DEBUG
00829 kWarning() << "KEncodingDetector: m_writtingHappened in the middle " << d->m_codec->name();
00830 #endif
00831 return result;
00832 }
00833 }
00834 }
00835
00836 return QString();
00837 }
00838
00839 QString KEncodingDetector::flush()
00840 {
00841 if (d->m_bufferForDefferedEncDetection.isEmpty())
00842 return QString();
00843
00844 d->m_bufferForDefferedEncDetection.replace('\0',' ');
00845 QString result(d->m_decoder->toUnicode(d->m_bufferForDefferedEncDetection));
00846 d->m_bufferForDefferedEncDetection.clear();
00847 #ifdef DECODE_DEBUG
00848 kWarning() << "KEncodingDetector:flush() "<< d->m_bufferForDefferedEncDetection.length()<<" bytes "<< d->m_codec->name();
00849 #endif
00850 return result;
00851 }
00852
00853 bool KEncodingDetector::analyze(const char *data, int len)
00854 {
00855
00856
00857
00858 if (len >= 10 && ((d->m_source != UserChosenEncoding) || is16Bit(d->m_codec)))
00859 {
00860
00861 const uchar *udata = (const uchar *)data;
00862 uchar c1 = *udata++;
00863 uchar c2 = *udata++;
00864 uchar c3 = *udata++;
00865
00866
00867 const char *autoDetectedEncoding;
00868 if ((c1 == 0xFE && c2 == 0xFF) || (c1 == 0xFF && c2 == 0xFE))
00869 {
00870 autoDetectedEncoding = "ISO-10646-UCS-2";
00871 }
00872 else if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF)
00873 {
00874 autoDetectedEncoding = "UTF-8";
00875 }
00876 else if (c1 == 0x00 || c2 == 0x00)
00877 {
00878 uchar c4 = *udata++;
00879 uchar c5 = *udata++;
00880 uchar c6 = *udata++;
00881 uchar c7 = *udata++;
00882 uchar c8 = *udata++;
00883 uchar c9 = *udata++;
00884 uchar c10 = *udata++;
00885
00886 int nul_count_even = (c2 != 0) + (c4 != 0) + (c6 != 0) + (c8 != 0) + (c10 != 0);
00887 int nul_count_odd = (c1 != 0) + (c3 != 0) + (c5 != 0) + (c7 != 0) + (c9 != 0);
00888 if ((nul_count_even==0 && nul_count_odd==5) || (nul_count_even==5 && nul_count_odd==0))
00889 autoDetectedEncoding = "ISO-10646-UCS-2";
00890 else
00891 autoDetectedEncoding = 0;
00892 }
00893 else
00894 {
00895 autoDetectedEncoding = 0;
00896 }
00897
00898
00899 if (autoDetectedEncoding != 0)
00900 {
00901 d->m_source = BOM;
00902 d->m_codec = QTextCodec::codecForName(autoDetectedEncoding);
00903 assert(d->m_codec);
00904
00905 delete d->m_decoder;
00906 d->m_decoder = d->m_codec->makeDecoder();
00907 #ifdef DECODE_DEBUG
00908 kWarning() << "Detection by BOM";
00909 #endif
00910 if (is16Bit(d->m_codec) && c2==0x00)
00911 {
00912
00913 char reverseUtf16[3] = {(char)0xFF, (char)0xFE, 0x00};
00914 d->m_decoder->toUnicode(reverseUtf16, 2);
00915 }
00916 return true;
00917 }
00918 }
00919
00920
00921 if (d->m_source==UserChosenEncoding)
00922 {
00923 #ifdef DECODE_DEBUG
00924 kWarning() << "KEncodingDetector: UserChosenEncoding exit ";
00925 #endif
00926
00927 if (errorsIfUtf8(data, len))
00928 setEncoding("",DefaultEncoding);
00929 return true;
00930 }
00931
00932 if (!d->m_seenBody)
00933 {
00934
00935
00936
00937 const char *ptr = data;
00938 const char *pEnd = data+len;
00939
00940 while(ptr != pEnd)
00941 {
00942 if(*ptr!='<')
00943 {
00944 ++ptr;
00945 continue;
00946 }
00947 ++ptr;
00948
00949 if (ptr[0] == '!' && ptr[1] == '-' && ptr[2] == '-')
00950 {
00951 ptr += 3;
00952 skipComment(ptr, pEnd);
00953 continue;
00954 }
00955
00956
00957 if (ptr[0]=='?' && ptr[1]=='x' && ptr[2]=='m' && ptr[3]=='l')
00958 {
00959 const char *end = ptr;
00960 while (*end != '>' && end < pEnd)
00961 end++;
00962 if (*end == '\0' || end == pEnd)
00963 break;
00964 QByteArray str(ptr, end - ptr);
00965 int length;
00966 int pos = findXMLEncoding(str, length);
00967
00968 if (pos!=-1 && setEncoding(str.mid(pos, length), EncodingFromXMLHeader))
00969 {
00970 return true;
00971 }
00972 }
00973
00974
00975 while (
00976 !((*ptr >= 'a') && (*ptr <= 'z') ||
00977 (*ptr >= 'A') && (*ptr <= 'Z'))
00978 && ptr < pEnd
00979 )
00980 ++ptr;
00981
00982 char tmp[5];
00983 int length=0;
00984 const char* max=ptr+4;
00985 if (pEnd<max)
00986 max=pEnd;
00987 while (
00988 ((*ptr >= 'a') && (*ptr <= 'z') ||
00989 (*ptr >= 'A') && (*ptr <= 'Z') ||
00990 (*ptr >= '0') && (*ptr <= '9'))
00991 && ptr < max
00992 )
00993 {
00994 tmp[length] = tolower( *ptr );
00995 ++ptr;
00996 ++length;
00997 }
00998 tmp[length] = 0;
00999 if (tmp[0]=='m'&&tmp[1]=='e'&&tmp[2]=='t'&&tmp[3]=='a')
01000 {
01001
01002 const char* end = ptr;
01003 while(*end != '>' && *end != '\0' && end<pEnd)
01004 end++;
01005
01006 QByteArray str( ptr, (end-ptr)+1);
01007 str = str.toLower();
01008 int pos=0;
01009
01010
01011 if( (pos = str.indexOf("charset")) == -1)
01012 continue;
01013 pos+=6;
01014
01015 if( (pos = str.indexOf("=", pos)) == -1)
01016 continue;
01017
01018
01019 while (pos < (int)str.length() && str[pos] <= ' ')
01020 ++pos;
01021 if ( pos == (int)str.length())
01022 continue;
01023
01024 int endpos = pos;
01025 while( endpos < str.length() &&
01026 (str[endpos] != ' ' && str[endpos] != '"' && str[endpos] != '\''
01027 && str[endpos] != ';' && str[endpos] != '>') )
01028 ++endpos;
01029 #ifdef DECODE_DEBUG
01030 kDebug( 6005 ) << "KEncodingDetector: found charset in <meta>: " << str.mid(pos,endpos-pos).data();
01031 #endif
01032 if (setEncoding(str.mid(pos,endpos-pos), EncodingFromMetaTag))
01033 return true;
01034 }
01035 else if (tmp[0]=='b'&&tmp[1]=='o'&&tmp[2]=='d'&&tmp[3]=='y')
01036 {
01037 d->m_seenBody=true;
01038 break;
01039 }
01040 }
01041 }
01042
01043 if (d->m_source==EncodingFromHTTPHeader)
01044 return true;
01045
01046 if (len<20)
01047 {
01048 setEncoding("",DefaultEncoding);
01049 return false;
01050 }
01051 #ifdef DECODE_DEBUG
01052 kDebug( 6005 ) << "KEncodingDetector: using heuristics (" << strlen(data) << ")";
01053 #endif
01054
01055 switch ( d->m_autoDetectLanguage)
01056 {
01057 case KEncodingDetector::Arabic:
01058 return setEncoding(automaticDetectionForArabic( (const unsigned char*) data, len ), AutoDetectedEncoding);
01059
01060 case KEncodingDetector::Baltic:
01061 return setEncoding(automaticDetectionForBaltic( (const unsigned char*) data, len ), AutoDetectedEncoding);
01062
01063 case KEncodingDetector::CentralEuropean:
01064 return setEncoding(automaticDetectionForCentralEuropean( (const unsigned char*) data, len ), AutoDetectedEncoding);
01065 break;
01066 case KEncodingDetector::Cyrillic:
01067 return setEncoding(automaticDetectionForCyrillic( (const unsigned char*) data, len), AutoDetectedEncoding);
01068
01069 case KEncodingDetector::Greek:
01070 return setEncoding(automaticDetectionForGreek( (const unsigned char*) data, len ), AutoDetectedEncoding);
01071
01072 case KEncodingDetector::Hebrew:
01073 return setEncoding(automaticDetectionForHebrew( (const unsigned char*) data, len ), AutoDetectedEncoding);
01074
01075 case KEncodingDetector::Japanese:
01076 return setEncoding(automaticDetectionForJapanese( (const unsigned char*) data, len ), AutoDetectedEncoding);
01077
01078 case KEncodingDetector::Turkish:
01079 return setEncoding(automaticDetectionForTurkish( (const unsigned char*) data, len ), AutoDetectedEncoding);
01080
01081 case KEncodingDetector::WesternEuropean:
01082 if (setEncoding(automaticDetectionForWesternEuropean( (const unsigned char*) data, len ), AutoDetectedEncoding))
01083 return true;
01084 else if (d->m_defaultCodec->mibEnum()==MibLatin1)
01085 {
01086 return setEncoding("iso-8859-15",AutoDetectedEncoding);
01087 }
01088 else
01089 {
01090 return setEncoding("",DefaultEncoding);
01091 }
01092
01093 case KEncodingDetector::SemiautomaticDetection:
01094 case KEncodingDetector::ChineseSimplified:
01095 case KEncodingDetector::ChineseTraditional:
01096 case KEncodingDetector::Korean:
01097 case KEncodingDetector::Thai:
01098 case KEncodingDetector::Unicode:
01099 case KEncodingDetector::NorthernSaami:
01100 case KEncodingDetector::SouthEasternEurope:
01101 case KEncodingDetector::None:
01102
01103
01104 break;
01105 }
01106
01107 setEncoding("",DefaultEncoding);
01108 return true;
01109 }
01110
01111
01112 KEncodingDetector::AutoDetectScript KEncodingDetector::scriptForName(const QString& lang)
01113 {
01114 if (lang.isEmpty())
01115 return KEncodingDetector::None;
01116 else if (lang==i18nc("@item Text character set", "Unicode"))
01117 return KEncodingDetector::Unicode;
01118 else if (lang==i18nc("@item Text character set", "Cyrillic"))
01119 return KEncodingDetector::Cyrillic;
01120 else if (lang==i18nc("@item Text character set", "Western European"))
01121 return KEncodingDetector::WesternEuropean;
01122 else if (lang==i18nc("@item Text character set", "Central European"))
01123 return KEncodingDetector::CentralEuropean;
01124 else if (lang==i18nc("@item Text character set", "Greek"))
01125 return KEncodingDetector::Greek;
01126 else if (lang==i18nc("@item Text character set", "Hebrew"))
01127 return KEncodingDetector::Hebrew;
01128 else if (lang==i18nc("@item Text character set", "Turkish"))
01129 return KEncodingDetector::Turkish;
01130 else if (lang==i18nc("@item Text character set", "Japanese"))
01131 return KEncodingDetector::Japanese;
01132 else if (lang==i18nc("@item Text character set", "Baltic"))
01133 return KEncodingDetector::Baltic;
01134 else if (lang==i18nc("@item Text character set", "Arabic"))
01135 return KEncodingDetector::Arabic;
01136
01137 return KEncodingDetector::None;
01138 }
01139
01140 bool KEncodingDetector::hasAutoDetectionForScript(KEncodingDetector::AutoDetectScript script)
01141 {
01142 switch (script)
01143 {
01144 case KEncodingDetector::Arabic:
01145 return true;
01146 case KEncodingDetector::Baltic:
01147 return true;
01148 case KEncodingDetector::CentralEuropean:
01149 return true;
01150 case KEncodingDetector::Cyrillic:
01151 return true;
01152 case KEncodingDetector::Greek:
01153 return true;
01154 case KEncodingDetector::Hebrew:
01155 return true;
01156 case KEncodingDetector::Japanese:
01157 return true;
01158 case KEncodingDetector::Turkish:
01159 return true;
01160 case KEncodingDetector::WesternEuropean:
01161 return true;
01162 case KEncodingDetector::ChineseTraditional:
01163 return true;
01164 case KEncodingDetector::ChineseSimplified:
01165 return true;
01166 case KEncodingDetector::Unicode:
01167 return true;
01168 break;
01169 default:
01170 return false;
01171 }
01172 }
01173
01174 QString KEncodingDetector::nameForScript(KEncodingDetector::AutoDetectScript script)
01175 {
01176 switch (script)
01177 {
01178 case KEncodingDetector::Arabic:
01179 return i18nc("@item Text character set", "Arabic");
01180 break;
01181 case KEncodingDetector::Baltic:
01182 return i18nc("@item Text character set", "Baltic");
01183 break;
01184 case KEncodingDetector::CentralEuropean:
01185 return i18nc("@item Text character set", "Central European");
01186 break;
01187 case KEncodingDetector::Cyrillic:
01188 return i18nc("@item Text character set", "Cyrillic");
01189 break;
01190 case KEncodingDetector::Greek:
01191 return i18nc("@item Text character set", "Greek");
01192 break;
01193 case KEncodingDetector::Hebrew:
01194 return i18nc("@item Text character set", "Hebrew");
01195 break;
01196 case KEncodingDetector::Japanese:
01197 return i18nc("@item Text character set", "Japanese");
01198 break;
01199 case KEncodingDetector::Turkish:
01200 return i18nc("@item Text character set", "Turkish");
01201 break;
01202 case KEncodingDetector::WesternEuropean:
01203 return i18nc("@item Text character set", "Western European");
01204 break;
01205 case KEncodingDetector::ChineseTraditional:
01206 return i18nc("@item Text character set", "Chinese Traditional");
01207 break;
01208 case KEncodingDetector::ChineseSimplified:
01209 return i18nc("@item Text character set", "Chinese Simplified");
01210 break;
01211 case KEncodingDetector::Korean:
01212 return i18nc("@item Text character set", "Korean");
01213 break;
01214 case KEncodingDetector::Thai:
01215 return i18nc("@item Text character set", "Thai");
01216 break;
01217 case KEncodingDetector::Unicode:
01218 return i18nc("@item Text character set", "Unicode");
01219 break;
01220
01221 default:
01222 return QString();
01223
01224 }
01225 }
01226
01227 #undef DECODE_DEBUG
01228