Move TextCodec classes to std::unique_ptr
[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 "DOMImplementation.h"
27 #include "HTMLMetaCharsetParser.h"
28 #include "HTMLNames.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 (equalIgnoringCase(mimeType, "text/css"))
306         return CSS;
307     if (equalIgnoringCase(mimeType, "text/html"))
308         return HTML;
309     if (DOMImplementation::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(0)
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 // Returns the position of the encoding string.
363 static int findXMLEncoding(const char* str, int len, int& encodingLength)
364 {
365     int pos = find(str, len, "encoding");
366     if (pos == -1)
367         return -1;
368     pos += 8;
369     
370     // Skip spaces and stray control characters.
371     while (pos < len && str[pos] <= ' ')
372         ++pos;
373
374     // Skip equals sign.
375     if (pos >= len || str[pos] != '=')
376         return -1;
377     ++pos;
378
379     // Skip spaces and stray control characters.
380     while (pos < len && str[pos] <= ' ')
381         ++pos;
382
383     // Skip quotation mark.
384     if (pos >= len)
385         return - 1;
386     char quoteMark = str[pos];
387     if (quoteMark != '"' && quoteMark != '\'')
388         return -1;
389     ++pos;
390
391     // Find the trailing quotation mark.
392     int end = pos;
393     while (end < len && str[end] != quoteMark)
394         ++end;
395     if (end >= len)
396         return -1;
397
398     encodingLength = end - pos;
399     return pos;
400 }
401
402 size_t TextResourceDecoder::checkForBOM(const char* data, size_t len)
403 {
404     // Check for UTF-16/32 or UTF-8 BOM mark at the beginning, which is a sure sign of a Unicode encoding.
405     // We let it override even a user-chosen encoding.
406     ASSERT(!m_checkedForBOM);
407
408     size_t lengthOfBOM = 0;
409
410     size_t bufferLength = m_buffer.size();
411
412     size_t buf1Len = bufferLength;
413     size_t buf2Len = len;
414     const unsigned char* buf1 = reinterpret_cast<const unsigned char*>(m_buffer.data());
415     const unsigned char* buf2 = reinterpret_cast<const unsigned char*>(data);
416     unsigned char c1 = buf1Len ? (--buf1Len, *buf1++) : buf2Len ? (--buf2Len, *buf2++) : 0;
417     unsigned char c2 = buf1Len ? (--buf1Len, *buf1++) : buf2Len ? (--buf2Len, *buf2++) : 0;
418     unsigned char c3 = buf1Len ? (--buf1Len, *buf1++) : buf2Len ? (--buf2Len, *buf2++) : 0;
419     unsigned char c4 = buf2Len ? (--buf2Len, *buf2++) : 0;
420
421     // Check for the BOM.
422     if (c1 == 0xFF && c2 == 0xFE) {
423         if (c3 != 0 || c4 != 0) {
424             setEncoding(UTF16LittleEndianEncoding(), AutoDetectedEncoding);
425             lengthOfBOM = 2;
426         } else {
427             setEncoding(UTF32LittleEndianEncoding(), AutoDetectedEncoding);
428             lengthOfBOM = 4;
429         }
430     } else if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF) {
431         setEncoding(UTF8Encoding(), AutoDetectedEncoding);
432         lengthOfBOM = 3;
433     } else if (c1 == 0xFE && c2 == 0xFF) {
434         setEncoding(UTF16BigEndianEncoding(), AutoDetectedEncoding);
435         lengthOfBOM = 2;
436     } else if (c1 == 0 && c2 == 0 && c3 == 0xFE && c4 == 0xFF) {
437         setEncoding(UTF32BigEndianEncoding(), AutoDetectedEncoding);
438         lengthOfBOM = 4;
439     }
440
441     if (lengthOfBOM || bufferLength + len >= 4)
442         m_checkedForBOM = true;
443
444     return lengthOfBOM;
445 }
446
447 bool TextResourceDecoder::checkForCSSCharset(const char* data, size_t len, bool& movedDataToBuffer)
448 {
449     if (m_source != DefaultEncoding && m_source != EncodingFromParentFrame) {
450         m_checkedForCSSCharset = true;
451         return true;
452     }
453
454     size_t oldSize = m_buffer.size();
455     m_buffer.grow(oldSize + len);
456     memcpy(m_buffer.data() + oldSize, data, len);
457
458     movedDataToBuffer = true;
459
460     if (m_buffer.size() <= 13) // strlen('@charset "x";') == 13
461         return false;
462
463     const char* dataStart = m_buffer.data();
464     const char* dataEnd = dataStart + m_buffer.size();
465
466     if (bytesEqual(dataStart, '@', 'c', 'h', 'a', 'r', 's', 'e', 't', ' ', '"')) {
467         dataStart += 10;
468         const char* pos = dataStart;
469
470         while (pos < dataEnd && *pos != '"')
471             ++pos;
472         if (pos == dataEnd)
473             return false;
474
475         int encodingNameLength = pos - dataStart;
476         
477         ++pos;
478         if (pos == dataEnd)
479             return false;
480
481         if (*pos == ';')
482             setEncoding(findTextEncoding(dataStart, encodingNameLength), EncodingFromCSSCharset);
483     }
484
485     m_checkedForCSSCharset = true;
486     return true;
487 }
488
489 bool TextResourceDecoder::checkForHeadCharset(const char* data, size_t len, bool& movedDataToBuffer)
490 {
491     if (m_source != DefaultEncoding && m_source != EncodingFromParentFrame) {
492         m_checkedForHeadCharset = true;
493         return true;
494     }
495
496     // This is not completely efficient, since the function might go
497     // through the HTML head several times.
498
499     size_t oldSize = m_buffer.size();
500     m_buffer.grow(oldSize + len);
501     memcpy(m_buffer.data() + oldSize, data, len);
502
503     movedDataToBuffer = true;
504
505     // Continue with checking for an HTML meta tag if we were already doing so.
506     if (m_charsetParser)
507         return checkForMetaCharset(data, len);
508
509     const char* ptr = m_buffer.data();
510     const char* pEnd = ptr + m_buffer.size();
511
512     // Is there enough data available to check for XML declaration?
513     if (m_buffer.size() < 8)
514         return false;
515
516     // Handle XML declaration, which can have encoding in it. This encoding is honored even for HTML documents.
517     // 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.
518     if (bytesEqual(ptr, '<', '?', 'x', 'm', 'l')) {
519         const char* xmlDeclarationEnd = ptr;
520         while (xmlDeclarationEnd != pEnd && *xmlDeclarationEnd != '>')
521             ++xmlDeclarationEnd;
522         if (xmlDeclarationEnd == pEnd)
523             return false;
524         // No need for +1, because we have an extra "?" to lose at the end of XML declaration.
525         int len = 0;
526         int pos = findXMLEncoding(ptr, xmlDeclarationEnd - ptr, len);
527         if (pos != -1)
528             setEncoding(findTextEncoding(ptr + pos, len), EncodingFromXMLHeader);
529         // continue looking for a charset - it may be specified in an HTTP-Equiv meta
530     } else if (bytesEqual(ptr, '<', 0, '?', 0, 'x', 0)) {
531         setEncoding(UTF16LittleEndianEncoding(), AutoDetectedEncoding);
532         return true;
533     } else if (bytesEqual(ptr, 0, '<', 0, '?', 0, 'x')) {
534         setEncoding(UTF16BigEndianEncoding(), AutoDetectedEncoding);
535         return true;
536     } else if (bytesEqual(ptr, '<', 0, 0, 0, '?', 0, 0, 0)) {
537         setEncoding(UTF32LittleEndianEncoding(), AutoDetectedEncoding);
538         return true;
539     } else if (bytesEqual(ptr, 0, 0, 0, '<', 0, 0, 0, '?')) {
540         setEncoding(UTF32BigEndianEncoding(), AutoDetectedEncoding);
541         return true;
542     }
543
544     // The HTTP-EQUIV meta has no effect on XHTML.
545     if (m_contentType == XML)
546         return true;
547
548     m_charsetParser = std::make_unique<HTMLMetaCharsetParser>();
549     return checkForMetaCharset(data, len);
550 }
551
552 bool TextResourceDecoder::checkForMetaCharset(const char* data, size_t length)
553 {
554     if (!m_charsetParser->checkForMetaCharset(data, length))
555         return false;
556
557     setEncoding(m_charsetParser->encoding(), EncodingFromMetaTag);
558     m_charsetParser = nullptr;
559     m_checkedForHeadCharset = true;
560     return true;
561 }
562
563 void TextResourceDecoder::detectJapaneseEncoding(const char* data, size_t len)
564 {
565     switch (KanjiCode::judge(data, len)) {
566         case KanjiCode::JIS:
567             setEncoding("ISO-2022-JP", AutoDetectedEncoding);
568             break;
569         case KanjiCode::EUC:
570             setEncoding("EUC-JP", AutoDetectedEncoding);
571             break;
572         case KanjiCode::SJIS:
573             setEncoding("Shift_JIS", AutoDetectedEncoding);
574             break;
575         case KanjiCode::ASCII:
576         case KanjiCode::UTF16:
577         case KanjiCode::UTF8:
578             break;
579     }
580 }
581
582 // We use the encoding detector in two cases:
583 //   1. Encoding detector is turned ON and no other encoding source is
584 //      available (that is, it's DefaultEncoding).
585 //   2. Encoding detector is turned ON and the encoding is set to
586 //      the encoding of the parent frame, which is also auto-detected.
587 //   Note that condition #2 is NOT satisfied unless parent-child frame
588 //   relationship is compliant to the same-origin policy. If they're from
589 //   different domains, |m_source| would not be set to EncodingFromParentFrame
590 //   in the first place. 
591 bool TextResourceDecoder::shouldAutoDetect() const
592 {
593     // Just checking m_hintEncoding suffices here because it's only set
594     // in setHintEncoding when the source is AutoDetectedEncoding.
595     return m_usesEncodingDetector
596         && (m_source == DefaultEncoding || (m_source == EncodingFromParentFrame && m_hintEncoding)); 
597 }
598
599 String TextResourceDecoder::decode(const char* data, size_t len)
600 {
601     size_t lengthOfBOM = 0;
602     if (!m_checkedForBOM)
603         lengthOfBOM = checkForBOM(data, len);
604
605     bool movedDataToBuffer = false;
606
607     if (m_contentType == CSS && !m_checkedForCSSCharset)
608         if (!checkForCSSCharset(data, len, movedDataToBuffer))
609             return emptyString();
610
611     if ((m_contentType == HTML || m_contentType == XML) && !m_checkedForHeadCharset) // HTML and XML
612         if (!checkForHeadCharset(data, len, movedDataToBuffer))
613             return emptyString();
614
615     // FIXME: It is wrong to change the encoding downstream after we have already done some decoding.
616     if (shouldAutoDetect()) {
617         if (m_encoding.isJapanese())
618             detectJapaneseEncoding(data, len); // FIXME: We should use detectTextEncoding() for all languages.
619         else {
620             TextEncoding detectedEncoding;
621             if (detectTextEncoding(data, len, m_hintEncoding, &detectedEncoding))
622                 setEncoding(detectedEncoding, AutoDetectedEncoding);
623         }
624     }
625
626     ASSERT(m_encoding.isValid());
627
628     if (!m_codec)
629         m_codec = newTextCodec(m_encoding);
630
631     if (m_buffer.isEmpty())
632         return m_codec->decode(data + lengthOfBOM, len - lengthOfBOM, false, m_contentType == XML, m_sawError);
633
634     if (!movedDataToBuffer) {
635         size_t oldSize = m_buffer.size();
636         m_buffer.grow(oldSize + len);
637         memcpy(m_buffer.data() + oldSize, data, len);
638     }
639
640     String result = m_codec->decode(m_buffer.data() + lengthOfBOM, m_buffer.size() - lengthOfBOM, false, m_contentType == XML && !m_useLenientXMLDecoding, m_sawError);
641     m_buffer.clear();
642     return result;
643 }
644
645 String TextResourceDecoder::flush()
646 {
647    // If we can not identify the encoding even after a document is completely
648    // loaded, we need to detect the encoding if other conditions for
649    // autodetection is satisfied.
650     if (m_buffer.size() && shouldAutoDetect()
651         && ((!m_checkedForHeadCharset && (m_contentType == HTML || m_contentType == XML)) || (!m_checkedForCSSCharset && (m_contentType == CSS)))) {
652          TextEncoding detectedEncoding;
653          if (detectTextEncoding(m_buffer.data(), m_buffer.size(),
654                                 m_hintEncoding, &detectedEncoding))
655              setEncoding(detectedEncoding, AutoDetectedEncoding);
656     }
657
658     if (!m_codec)
659         m_codec = newTextCodec(m_encoding);
660
661     String result = m_codec->decode(m_buffer.data(), m_buffer.size(), true, m_contentType == XML && !m_useLenientXMLDecoding, m_sawError);
662     m_buffer.clear();
663     m_codec = nullptr;
664     m_checkedForBOM = false; // Skip BOM again when re-decoding.
665     return result;
666 }
667
668 String TextResourceDecoder::decodeAndFlush(const char* data, size_t length)
669 {
670     String decoded = decode(data, length);
671     return decoded + flush();
672 }
673
674 }