fe94b7f818746e3d2e7ab30b467fa09e13b12492
[WebKit-https.git] / Source / WebCore / loader / TextResourceDecoder.cpp
1 /*
2     Copyright (C) 1999 Lars Knoll (knoll@mpi-hd.mpg.de)
3     Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
4     Copyright (C) 2005, 2006, 2007 Alexey Proskuryakov (ap@nypop.com)
5
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Library General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Library General Public License for more details.
15
16     You should have received a copy of the GNU Library General Public License
17     along with this library; see the file COPYING.LIB.  If not, write to
18     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19     Boston, MA 02110-1301, USA.
20 */
21
22
23 #include "config.h"
24 #include "TextResourceDecoder.h"
25
26 #include "HTMLMetaCharsetParser.h"
27 #include "HTMLNames.h"
28 #include "MIMETypeRegistry.h"
29 #include "TextCodec.h"
30 #include "TextEncoding.h"
31 #include "TextEncodingDetector.h"
32 #include "TextEncodingRegistry.h"
33 #include <wtf/ASCIICType.h>
34 #include <wtf/StringExtras.h>
35
36 using namespace WTF;
37
38 namespace WebCore {
39
40 using namespace HTMLNames;
41
42 static inline bool bytesEqual(const char* p, char b0, char b1)
43 {
44     return p[0] == b0 && p[1] == b1;
45 }
46
47 static inline bool bytesEqual(const char* p, char b0, char b1, char b2, char b3, char b4)
48 {
49     return p[0] == b0 && p[1] == b1 && p[2] == b2 && p[3] == b3 && p[4] == b4;
50 }
51
52 static inline bool bytesEqual(const char* p, char b0, char b1, char b2, char b3, char b4, char b5)
53 {
54     return p[0] == b0 && p[1] == b1 && p[2] == b2 && p[3] == b3 && p[4] == b4 && p[5] == b5;
55 }
56
57 static inline bool bytesEqual(const char* p, char b0, char b1, char b2, char b3, char b4, char b5, char b6, char b7)
58 {
59     return p[0] == b0 && p[1] == b1 && p[2] == b2 && p[3] == b3 && p[4] == b4 && p[5] == b5 && p[6] == b6 && p[7] == b7;
60 }
61
62 static inline bool bytesEqual(const char* p, char b0, char b1, char b2, char b3, char b4, char b5, char b6, char b7, char b8, char b9)
63 {
64     return p[0] == b0 && p[1] == b1 && p[2] == b2 && p[3] == b3 && p[4] == b4 && p[5] == b5 && p[6] == b6 && p[7] == b7 && p[8] == b8 && p[9] == b9;
65 }
66
67 // You might think we should put these find functions elsewhere, perhaps with the
68 // similar functions that operate on UChar, but arguably only the decoder has
69 // a reason to process strings of char rather than UChar.
70
71 static int find(const char* subject, size_t subjectLength, const char* target)
72 {
73     size_t targetLength = strlen(target);
74     if (targetLength > subjectLength)
75         return -1;
76     for (size_t i = 0; i <= subjectLength - targetLength; ++i) {
77         bool match = true;
78         for (size_t j = 0; j < targetLength; ++j) {
79             if (subject[i + j] != target[j]) {
80                 match = false;
81                 break;
82             }
83         }
84         if (match)
85             return i;
86     }
87     return -1;
88 }
89
90 static TextEncoding findTextEncoding(const char* encodingName, int length)
91 {
92     Vector<char, 64> buffer(length + 1);
93     memcpy(buffer.data(), encodingName, length);
94     buffer[length] = '\0';
95     return buffer.data();
96 }
97
98 class KanjiCode {
99 public:
100     enum Type { ASCII, JIS, EUC, SJIS, UTF16, UTF8 };
101     static enum Type judge(const char* str, int length);
102     static const int ESC = 0x1b;
103     static const unsigned char sjisMap[256];
104     static int ISkanji(int code)
105     {
106         if (code >= 0x100)
107             return 0;
108         return sjisMap[code & 0xff] & 1;
109     }
110     static int ISkana(int code)
111     {
112         if (code >= 0x100)
113             return 0;
114         return sjisMap[code & 0xff] & 2;
115     }
116 };
117
118 const unsigned char KanjiCode::sjisMap[256] = {
119     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
128     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
129     0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
130     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
131     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
132     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
133     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
134     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0
135 };
136
137 /*
138  * EUC-JP is
139  *     [0xa1 - 0xfe][0xa1 - 0xfe]
140  *     0x8e[0xa1 - 0xfe](SS2)
141  *     0x8f[0xa1 - 0xfe][0xa1 - 0xfe](SS3)
142  *
143  * Shift_Jis is
144  *     [0x81 - 0x9f, 0xe0 - 0xef(0xfe?)][0x40 - 0x7e, 0x80 - 0xfc]
145  *
146  * Shift_Jis Hankaku Kana is
147  *     [0xa1 - 0xdf]
148  */
149
150 /*
151  * KanjiCode::judge() is based on judge_jcode() from jvim
152  *     http://hp.vector.co.jp/authors/VA003457/vim/
153  *
154  * Special Thanks to Kenichi Tsuchida
155  */
156
157 enum KanjiCode::Type KanjiCode::judge(const char* str, int size)
158 {
159     enum Type code;
160     int i;
161     int bfr = false;            /* Kana Moji */
162     int bfk = 0;                /* EUC Kana */
163     int sjis = 0;
164     int euc = 0;
165
166     const unsigned char* ptr = reinterpret_cast<const unsigned char*>(str);
167
168     code = ASCII;
169
170     i = 0;
171     while (i < size) {
172         if (ptr[i] == ESC && (size - i >= 3)) {
173             if (bytesEqual(str + i + 1, '$', 'B')
174                     || bytesEqual(str + i + 1, '(', 'B')
175                     || bytesEqual(str + i + 1, '$', '@')
176                     || bytesEqual(str + i + 1, '(', 'J')) {
177                 code = JIS;
178                 goto breakBreak;
179             }
180             if (bytesEqual(str + i + 1, '(', 'I') || bytesEqual(str + i + 1, ')', 'I')) {
181                 code = JIS;
182                 i += 3;
183             } else {
184                 i++;
185             }
186             bfr = false;
187             bfk = 0;
188         } else {
189             if (ptr[i] < 0x20) {
190                 bfr = false;
191                 bfk = 0;
192                 /* ?? check kudokuten ?? && ?? hiragana ?? */
193                 if ((i >= 2) && (ptr[i - 2] == 0x81)
194                         && (0x41 <= ptr[i - 1] && ptr[i - 1] <= 0x49)) {
195                     code = SJIS;
196                     sjis += 100;        /* kudokuten */
197                 } else if ((i >= 2) && (ptr[i - 2] == 0xa1)
198                         && (0xa2 <= ptr[i - 1] && ptr[i - 1] <= 0xaa)) {
199                     code = EUC;
200                     euc += 100;         /* kudokuten */
201                 } else if ((i >= 2) && (ptr[i - 2] == 0x82) && (0xa0 <= ptr[i - 1])) {
202                     sjis += 40;         /* hiragana */
203                 } else if ((i >= 2) && (ptr[i - 2] == 0xa4) && (0xa0 <= ptr[i - 1])) {
204                     euc += 40;          /* hiragana */
205                 }
206             } else {
207                 /* ?? check hiragana or katana ?? */
208                 if ((size - i > 1) && (ptr[i] == 0x82) && (0xa0 <= ptr[i + 1])) {
209                     sjis++;     /* hiragana */
210                 } else if ((size - i > 1) && (ptr[i] == 0x83)
211                          && (0x40 <= ptr[i + 1] && ptr[i + 1] <= 0x9f)) {
212                     sjis++;     /* katakana */
213                 } else if ((size - i > 1) && (ptr[i] == 0xa4) && (0xa0 <= ptr[i + 1])) {
214                     euc++;      /* hiragana */
215                 } else if ((size - i > 1) && (ptr[i] == 0xa5) && (0xa0 <= ptr[i + 1])) {
216                     euc++;      /* katakana */
217                 }
218                 if (bfr) {
219                     if ((i >= 1) && (0x40 <= ptr[i] && ptr[i] <= 0xa0) && ISkanji(ptr[i - 1])) {
220                         code = SJIS;
221                         goto breakBreak;
222                     } else if ((i >= 1) && (0x81 <= ptr[i - 1] && ptr[i - 1] <= 0x9f) && ((0x40 <= ptr[i] && ptr[i] < 0x7e) || (0x7e < ptr[i] && ptr[i] <= 0xfc))) {
223                         code = SJIS;
224                         goto breakBreak;
225                     } else if ((i >= 1) && (0xfd <= ptr[i] && ptr[i] <= 0xfe) && (0xa1 <= ptr[i - 1] && ptr[i - 1] <= 0xfe)) {
226                         code = EUC;
227                         goto breakBreak;
228                     } else if ((i >= 1) && (0xfd <= ptr[i - 1] && ptr[i - 1] <= 0xfe) && (0xa1 <= ptr[i] && ptr[i] <= 0xfe)) {
229                         code = EUC;
230                         goto breakBreak;
231                     } else if ((i >= 1) && (ptr[i] < 0xa0 || 0xdf < ptr[i]) && (0x8e == ptr[i - 1])) {
232                         code = SJIS;
233                         goto breakBreak;
234                     } else if (ptr[i] <= 0x7f) {
235                         code = SJIS;
236                         goto breakBreak;
237                     } else {
238                         if (0xa1 <= ptr[i] && ptr[i] <= 0xa6) {
239                             euc++;      /* sjis hankaku kana kigo */
240                         } else if (0xa1 <= ptr[i] && ptr[i] <= 0xdf) {
241                             ;           /* sjis hankaku kana */
242                         } else if (0xa1 <= ptr[i] && ptr[i] <= 0xfe) {
243                             euc++;
244                         } else if (0x8e == ptr[i]) {
245                             euc++;
246                         } else if (0x20 <= ptr[i] && ptr[i] <= 0x7f) {
247                             sjis++;
248                         }
249                         bfr = false;
250                         bfk = 0;
251                     }
252                 } else if (0x8e == ptr[i]) {
253                     if (size - i <= 1) {
254                         ;
255                     } else if (0xa1 <= ptr[i + 1] && ptr[i + 1] <= 0xdf) {
256                         /* EUC KANA or SJIS KANJI */
257                         if (bfk == 1) {
258                             euc += 100;
259                         }
260                         bfk++;
261                         i++;
262                     } else {
263                         /* SJIS only */
264                         code = SJIS;
265                         goto breakBreak;
266                     }
267                 } else if (0x81 <= ptr[i] && ptr[i] <= 0x9f) {
268                     /* SJIS only */
269                     code = SJIS;
270                     if ((size - i >= 1)
271                             && ((0x40 <= ptr[i + 1] && ptr[i + 1] <= 0x7e)
272                             || (0x80 <= ptr[i + 1] && ptr[i + 1] <= 0xfc))) {
273                         goto breakBreak;
274                     }
275                 } else if (0xfd <= ptr[i] && ptr[i] <= 0xfe) {
276                     /* EUC only */
277                     code = EUC;
278                     if ((size - i >= 1)
279                             && (0xa1 <= ptr[i + 1] && ptr[i + 1] <= 0xfe)) {
280                         goto breakBreak;
281                     }
282                 } else if (ptr[i] <= 0x7f) {
283                     ;
284                 } else {
285                     bfr = true;
286                     bfk = 0;
287                 }
288             }
289             i++;
290         }
291     }
292     if (code == ASCII) {
293         if (sjis > euc) {
294             code = SJIS;
295         } else if (sjis < euc) {
296             code = EUC;
297         }
298     }
299 breakBreak:
300     return (code);
301 }
302
303 TextResourceDecoder::ContentType TextResourceDecoder::determineContentType(const String& mimeType)
304 {
305     if (equalLettersIgnoringASCIICase(mimeType, "text/css"))
306         return CSS;
307     if (equalLettersIgnoringASCIICase(mimeType, "text/html"))
308         return HTML;
309     if (MIMETypeRegistry::isXMLMIMEType(mimeType))
310         return XML;
311     return PlainText;
312 }
313
314 const TextEncoding& TextResourceDecoder::defaultEncoding(ContentType contentType, const TextEncoding& specifiedDefaultEncoding)
315 {
316     // Despite 8.5 "Text/xml with Omitted Charset" of RFC 3023, we assume UTF-8 instead of US-ASCII 
317     // for text/xml. This matches Firefox.
318     if (contentType == XML)
319         return UTF8Encoding();
320     if (!specifiedDefaultEncoding.isValid())
321         return Latin1Encoding();
322     return specifiedDefaultEncoding;
323 }
324
325 TextResourceDecoder::TextResourceDecoder(const String& mimeType, const TextEncoding& specifiedDefaultEncoding, bool usesEncodingDetector)
326     : m_contentType(determineContentType(mimeType))
327     , m_encoding(defaultEncoding(m_contentType, specifiedDefaultEncoding))
328     , m_source(DefaultEncoding)
329     , m_hintEncoding(nullptr)
330     , m_checkedForBOM(false)
331     , m_checkedForCSSCharset(false)
332     , m_checkedForHeadCharset(false)
333     , m_useLenientXMLDecoding(false)
334     , m_sawError(false)
335     , m_usesEncodingDetector(usesEncodingDetector)
336 {
337 }
338
339 TextResourceDecoder::~TextResourceDecoder()
340 {
341 }
342
343 void TextResourceDecoder::setEncoding(const TextEncoding& encoding, EncodingSource source)
344 {
345     // In case the encoding didn't exist, we keep the old one (helps some sites specifying invalid encodings).
346     if (!encoding.isValid())
347         return;
348
349     // When encoding comes from meta tag (i.e. it cannot be XML files sent via XHR),
350     // treat x-user-defined as windows-1252 (bug 18270)
351     if (source == EncodingFromMetaTag && strcasecmp(encoding.name(), "x-user-defined") == 0)
352         m_encoding = "windows-1252";
353     else if (source == EncodingFromMetaTag || source == EncodingFromXMLHeader || source == EncodingFromCSSCharset)        
354         m_encoding = encoding.closestByteBasedEquivalent();
355     else
356         m_encoding = encoding;
357
358     m_codec = nullptr;
359     m_source = source;
360 }
361
362 bool TextResourceDecoder::hasEqualEncodingForCharset(const String& charset) const
363 {
364     return defaultEncoding(m_contentType, charset) == m_encoding;
365 }
366
367 // Returns the position of the encoding string.
368 static int findXMLEncoding(const char* str, int len, int& encodingLength)
369 {
370     int pos = find(str, len, "encoding");
371     if (pos == -1)
372         return -1;
373     pos += 8;
374     
375     // Skip spaces and stray control characters.
376     while (pos < len && str[pos] <= ' ')
377         ++pos;
378
379     // Skip equals sign.
380     if (pos >= len || str[pos] != '=')
381         return -1;
382     ++pos;
383
384     // Skip spaces and stray control characters.
385     while (pos < len && str[pos] <= ' ')
386         ++pos;
387
388     // Skip quotation mark.
389     if (pos >= len)
390         return - 1;
391     char quoteMark = str[pos];
392     if (quoteMark != '"' && quoteMark != '\'')
393         return -1;
394     ++pos;
395
396     // Find the trailing quotation mark.
397     int end = pos;
398     while (end < len && str[end] != quoteMark)
399         ++end;
400     if (end >= len)
401         return -1;
402
403     encodingLength = end - pos;
404     return pos;
405 }
406
407 size_t TextResourceDecoder::checkForBOM(const char* data, size_t len)
408 {
409     // Check for UTF-16/32 or UTF-8 BOM mark at the beginning, which is a sure sign of a Unicode encoding.
410     // We let it override even a user-chosen encoding.
411     ASSERT(!m_checkedForBOM);
412
413     size_t lengthOfBOM = 0;
414
415     size_t bufferLength = m_buffer.size();
416
417     size_t buf1Len = bufferLength;
418     size_t buf2Len = len;
419     const unsigned char* buf1 = reinterpret_cast<const unsigned char*>(m_buffer.data());
420     const unsigned char* buf2 = reinterpret_cast<const unsigned char*>(data);
421     unsigned char c1 = buf1Len ? (--buf1Len, *buf1++) : buf2Len ? (--buf2Len, *buf2++) : 0;
422     unsigned char c2 = buf1Len ? (--buf1Len, *buf1++) : buf2Len ? (--buf2Len, *buf2++) : 0;
423     unsigned char c3 = buf1Len ? (--buf1Len, *buf1++) : buf2Len ? (--buf2Len, *buf2++) : 0;
424     unsigned char c4 = buf2Len ? (--buf2Len, *buf2++) : 0;
425
426     // Check for the BOM.
427     if (c1 == 0xFF && c2 == 0xFE) {
428         if (c3 != 0 || c4 != 0) {
429             setEncoding(UTF16LittleEndianEncoding(), AutoDetectedEncoding);
430             lengthOfBOM = 2;
431         } else {
432             setEncoding(UTF32LittleEndianEncoding(), AutoDetectedEncoding);
433             lengthOfBOM = 4;
434         }
435     } else if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) {
436         setEncoding(UTF8Encoding(), AutoDetectedEncoding);
437         lengthOfBOM = 3;
438     } else if (c1 == 0xFE && c2 == 0xFF) {
439         setEncoding(UTF16BigEndianEncoding(), AutoDetectedEncoding);
440         lengthOfBOM = 2;
441     } else if (c1 == 0 && c2 == 0 && c3 == 0xFE && c4 == 0xFF) {
442         setEncoding(UTF32BigEndianEncoding(), AutoDetectedEncoding);
443         lengthOfBOM = 4;
444     }
445
446     if (lengthOfBOM || bufferLength + len >= 4)
447         m_checkedForBOM = true;
448
449     return lengthOfBOM;
450 }
451
452 bool TextResourceDecoder::checkForCSSCharset(const char* data, size_t len, bool& movedDataToBuffer)
453 {
454     if (m_source != DefaultEncoding && m_source != EncodingFromParentFrame) {
455         m_checkedForCSSCharset = true;
456         return true;
457     }
458
459     size_t oldSize = m_buffer.size();
460     m_buffer.grow(oldSize + len);
461     memcpy(m_buffer.data() + oldSize, data, len);
462
463     movedDataToBuffer = true;
464
465     if (m_buffer.size() <= 13) // strlen('@charset "x";') == 13
466         return false;
467
468     const char* dataStart = m_buffer.data();
469     const char* dataEnd = dataStart + m_buffer.size();
470
471     if (bytesEqual(dataStart, '@', 'c', 'h', 'a', 'r', 's', 'e', 't', ' ', '"')) {
472         dataStart += 10;
473         const char* pos = dataStart;
474
475         while (pos < dataEnd && *pos != '"')
476             ++pos;
477         if (pos == dataEnd)
478             return false;
479
480         int encodingNameLength = pos - dataStart;
481         
482         ++pos;
483         if (pos == dataEnd)
484             return false;
485
486         if (*pos == ';')
487             setEncoding(findTextEncoding(dataStart, encodingNameLength), EncodingFromCSSCharset);
488     }
489
490     m_checkedForCSSCharset = true;
491     return true;
492 }
493
494 bool TextResourceDecoder::checkForHeadCharset(const char* data, size_t len, bool& movedDataToBuffer)
495 {
496     if (m_source != DefaultEncoding && m_source != EncodingFromParentFrame) {
497         m_checkedForHeadCharset = true;
498         return true;
499     }
500
501     // This is not completely efficient, since the function might go
502     // through the HTML head several times.
503
504     size_t oldSize = m_buffer.size();
505     m_buffer.grow(oldSize + len);
506     memcpy(m_buffer.data() + oldSize, data, len);
507
508     movedDataToBuffer = true;
509
510     // Continue with checking for an HTML meta tag if we were already doing so.
511     if (m_charsetParser)
512         return checkForMetaCharset(data, len);
513
514     const char* ptr = m_buffer.data();
515     const char* pEnd = ptr + m_buffer.size();
516
517     // Is there enough data available to check for XML declaration?
518     if (m_buffer.size() < 8)
519         return false;
520
521     // Handle XML declaration, which can have encoding in it. This encoding is honored even for HTML documents.
522     // It is an error for an XML declaration not to be at the start of an XML document, and it is ignored in HTML documents in such case.
523     if (bytesEqual(ptr, '<', '?', 'x', 'm', 'l')) {
524         const char* xmlDeclarationEnd = ptr;
525         while (xmlDeclarationEnd != pEnd && *xmlDeclarationEnd != '>')
526             ++xmlDeclarationEnd;
527         if (xmlDeclarationEnd == pEnd)
528             return false;
529         // No need for +1, because we have an extra "?" to lose at the end of XML declaration.
530         int len = 0;
531         int pos = findXMLEncoding(ptr, xmlDeclarationEnd - ptr, len);
532         if (pos != -1)
533             setEncoding(findTextEncoding(ptr + pos, len), EncodingFromXMLHeader);
534         // continue looking for a charset - it may be specified in an HTTP-Equiv meta
535     } else if (bytesEqual(ptr, '<', 0, '?', 0, 'x', 0)) {
536         setEncoding(UTF16LittleEndianEncoding(), AutoDetectedEncoding);
537         return true;
538     } else if (bytesEqual(ptr, 0, '<', 0, '?', 0, 'x')) {
539         setEncoding(UTF16BigEndianEncoding(), AutoDetectedEncoding);
540         return true;
541     } else if (bytesEqual(ptr, '<', 0, 0, 0, '?', 0, 0, 0)) {
542         setEncoding(UTF32LittleEndianEncoding(), AutoDetectedEncoding);
543         return true;
544     } else if (bytesEqual(ptr, 0, 0, 0, '<', 0, 0, 0, '?')) {
545         setEncoding(UTF32BigEndianEncoding(), AutoDetectedEncoding);
546         return true;
547     }
548
549     // The HTTP-EQUIV meta has no effect on XHTML.
550     if (m_contentType == XML)
551         return true;
552
553     m_charsetParser = std::make_unique<HTMLMetaCharsetParser>();
554     return checkForMetaCharset(data, len);
555 }
556
557 bool TextResourceDecoder::checkForMetaCharset(const char* data, size_t length)
558 {
559     if (!m_charsetParser->checkForMetaCharset(data, length))
560         return false;
561
562     setEncoding(m_charsetParser->encoding(), EncodingFromMetaTag);
563     m_charsetParser = nullptr;
564     m_checkedForHeadCharset = true;
565     return true;
566 }
567
568 void TextResourceDecoder::detectJapaneseEncoding(const char* data, size_t len)
569 {
570     switch (KanjiCode::judge(data, len)) {
571         case KanjiCode::JIS:
572             setEncoding("ISO-2022-JP", AutoDetectedEncoding);
573             break;
574         case KanjiCode::EUC:
575             setEncoding("EUC-JP", AutoDetectedEncoding);
576             break;
577         case KanjiCode::SJIS:
578             setEncoding("Shift_JIS", AutoDetectedEncoding);
579             break;
580         case KanjiCode::ASCII:
581         case KanjiCode::UTF16:
582         case KanjiCode::UTF8:
583             break;
584     }
585 }
586
587 // We use the encoding detector in two cases:
588 //   1. Encoding detector is turned ON and no other encoding source is
589 //      available (that is, it's DefaultEncoding).
590 //   2. Encoding detector is turned ON and the encoding is set to
591 //      the encoding of the parent frame, which is also auto-detected.
592 //   Note that condition #2 is NOT satisfied unless parent-child frame
593 //   relationship is compliant to the same-origin policy. If they're from
594 //   different domains, |m_source| would not be set to EncodingFromParentFrame
595 //   in the first place. 
596 bool TextResourceDecoder::shouldAutoDetect() const
597 {
598     // Just checking m_hintEncoding suffices here because it's only set
599     // in setHintEncoding when the source is AutoDetectedEncoding.
600     return m_usesEncodingDetector
601         && (m_source == DefaultEncoding || (m_source == EncodingFromParentFrame && m_hintEncoding)); 
602 }
603
604 String TextResourceDecoder::decode(const char* data, size_t len)
605 {
606     size_t lengthOfBOM = 0;
607     if (!m_checkedForBOM)
608         lengthOfBOM = checkForBOM(data, len);
609
610     bool movedDataToBuffer = false;
611
612     if (m_contentType == CSS && !m_checkedForCSSCharset)
613         if (!checkForCSSCharset(data, len, movedDataToBuffer))
614             return emptyString();
615
616     if ((m_contentType == HTML || m_contentType == XML) && !m_checkedForHeadCharset) // HTML and XML
617         if (!checkForHeadCharset(data, len, movedDataToBuffer))
618             return emptyString();
619
620     // FIXME: It is wrong to change the encoding downstream after we have already done some decoding.
621     if (shouldAutoDetect()) {
622         if (m_encoding.isJapanese())
623             detectJapaneseEncoding(data, len); // FIXME: We should use detectTextEncoding() for all languages.
624         else {
625             TextEncoding detectedEncoding;
626             if (detectTextEncoding(data, len, m_hintEncoding, &detectedEncoding))
627                 setEncoding(detectedEncoding, AutoDetectedEncoding);
628         }
629     }
630
631     ASSERT(m_encoding.isValid());
632
633     if (!m_codec)
634         m_codec = newTextCodec(m_encoding);
635
636     if (m_buffer.isEmpty())
637         return m_codec->decode(data + lengthOfBOM, len - lengthOfBOM, false, m_contentType == XML, m_sawError);
638
639     if (!movedDataToBuffer) {
640         size_t oldSize = m_buffer.size();
641         m_buffer.grow(oldSize + len);
642         memcpy(m_buffer.data() + oldSize, data, len);
643     }
644
645     String result = m_codec->decode(m_buffer.data() + lengthOfBOM, m_buffer.size() - lengthOfBOM, false, m_contentType == XML && !m_useLenientXMLDecoding, m_sawError);
646     m_buffer.clear();
647     return result;
648 }
649
650 String TextResourceDecoder::flush()
651 {
652    // If we can not identify the encoding even after a document is completely
653    // loaded, we need to detect the encoding if other conditions for
654    // autodetection is satisfied.
655     if (m_buffer.size() && shouldAutoDetect()
656         && ((!m_checkedForHeadCharset && (m_contentType == HTML || m_contentType == XML)) || (!m_checkedForCSSCharset && (m_contentType == CSS)))) {
657          TextEncoding detectedEncoding;
658          if (detectTextEncoding(m_buffer.data(), m_buffer.size(),
659                                 m_hintEncoding, &detectedEncoding))
660              setEncoding(detectedEncoding, AutoDetectedEncoding);
661     }
662
663     if (!m_codec)
664         m_codec = newTextCodec(m_encoding);
665
666     String result = m_codec->decode(m_buffer.data(), m_buffer.size(), true, m_contentType == XML && !m_useLenientXMLDecoding, m_sawError);
667     m_buffer.clear();
668     m_codec = nullptr;
669     m_checkedForBOM = false; // Skip BOM again when re-decoding.
670     return result;
671 }
672
673 String TextResourceDecoder::decodeAndFlush(const char* data, size_t length)
674 {
675     String decoded = decode(data, length);
676     return decoded + flush();
677 }
678
679 }