90d34046937aafe69f0fc50dc10aee81a0575f1d
[WebKit-https.git] / WebCore / loader / Decoder.cpp
1 /*
2     This file is part of the KDE libraries
3
4     Copyright (C) 1999 Lars Knoll (knoll@mpi-hd.mpg.de)
5     Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
6     Copyright (C) 2005, 2006 Alexey Proskuryakov (ap@nypop.com)
7
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Library General Public
10     License as published by the Free Software Foundation; either
11     version 2 of the License, or (at your option) any later version.
12
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Library General Public License for more details.
17
18     You should have received a copy of the GNU Library General Public License
19     along with this library; see the file COPYING.LIB.  If not, write to
20     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21     Boston, MA 02111-1307, USA.
22 */
23
24
25 #include "config.h"
26 #include "Decoder.h"
27
28 #include "CString.h"
29 #include "DOMImplementation.h"
30 #include "DeprecatedCString.h"
31 #include "DeprecatedString.h"
32 #include "HTMLNames.h"
33 #include "StreamingTextDecoder.h"
34
35 namespace WebCore {
36
37 using namespace HTMLNames;
38
39 class KanjiCode {
40 public:
41     enum Type { ASCII, JIS, EUC, SJIS, UTF16, UTF8 };
42     static enum Type judge(const char* str, int length);
43     static const int ESC = 0x1b;
44     static const unsigned char sjisMap[256];
45     static int ISkanji(int code)
46     {
47         if (code >= 0x100)
48             return 0;
49         return sjisMap[code & 0xff] & 1;
50     }
51     static int ISkana(int code)
52     {
53         if (code >= 0x100)
54             return 0;
55         return sjisMap[code & 0xff] & 2;
56     }
57 };
58
59 const unsigned char KanjiCode::sjisMap[256] = {
60     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
68     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
69     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
70     0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
71     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
72     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
73     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
74     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
75     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0
76 };
77
78 /*
79  * EUC-JP is
80  *     [0xa1 - 0xfe][0xa1 - 0xfe]
81  *     0x8e[0xa1 - 0xfe](SS2)
82  *     0x8f[0xa1 - 0xfe][0xa1 - 0xfe](SS3)
83  *
84  * Shift_Jis is
85  *     [0x81 - 0x9f, 0xe0 - 0xef(0xfe?)][0x40 - 0x7e, 0x80 - 0xfc]
86  *
87  * Shift_Jis Hankaku Kana is
88  *     [0xa1 - 0xdf]
89  */
90
91 /*
92  * KanjiCode::judge() is based on judge_jcode() from jvim
93  *     http://hp.vector.co.jp/authors/VA003457/vim/
94  *
95  * Special Thanks to Kenichi Tsuchida
96  */
97
98 enum KanjiCode::Type KanjiCode::judge(const char* str, int size)
99 {
100     enum Type code;
101     int i;
102     int bfr = false;            /* Kana Moji */
103     int bfk = 0;                /* EUC Kana */
104     int sjis = 0;
105     int euc = 0;
106
107     const unsigned char* ptr = reinterpret_cast<const unsigned char*>(str);
108
109     code = ASCII;
110
111     i = 0;
112     while (i < size) {
113         if (ptr[i] == ESC && (size - i >= 3)) {
114             if ((ptr[i + 1] == '$' && ptr[i + 2] == 'B')
115             || (ptr[i + 1] == '(' && ptr[i + 2] == 'B')) {
116                 code = JIS;
117                 goto breakBreak;
118             } else if ((ptr[i + 1] == '$' && ptr[i + 2] == '@')
119                     || (ptr[i + 1] == '(' && ptr[i + 2] == 'J')) {
120                 code = JIS;
121                 goto breakBreak;
122             } else if (ptr[i + 1] == '(' && ptr[i + 2] == 'I') {
123                 code = JIS;
124                 i += 3;
125             } else if (ptr[i + 1] == ')' && ptr[i + 2] == 'I') {
126                 code = JIS;
127                 i += 3;
128             } else {
129                 i++;
130             }
131             bfr = false;
132             bfk = 0;
133         } else {
134             if (ptr[i] < 0x20) {
135                 bfr = false;
136                 bfk = 0;
137                 /* ?? check kudokuten ?? && ?? hiragana ?? */
138                 if ((i >= 2) && (ptr[i - 2] == 0x81)
139                         && (0x41 <= ptr[i - 1] && ptr[i - 1] <= 0x49)) {
140                     code = SJIS;
141                     sjis += 100;        /* kudokuten */
142                 } else if ((i >= 2) && (ptr[i - 2] == 0xa1)
143                         && (0xa2 <= ptr[i - 1] && ptr[i - 1] <= 0xaa)) {
144                     code = EUC;
145                     euc += 100;         /* kudokuten */
146                 } else if ((i >= 2) && (ptr[i - 2] == 0x82) && (0xa0 <= ptr[i - 1])) {
147                     sjis += 40;         /* hiragana */
148                 } else if ((i >= 2) && (ptr[i - 2] == 0xa4) && (0xa0 <= ptr[i - 1])) {
149                     euc += 40;          /* hiragana */
150                 }
151             } else {
152                 /* ?? check hiragana or katana ?? */
153                 if ((size - i > 1) && (ptr[i] == 0x82) && (0xa0 <= ptr[i + 1])) {
154                     sjis++;     /* hiragana */
155                 } else if ((size - i > 1) && (ptr[i] == 0x83)
156                          && (0x40 <= ptr[i + 1] && ptr[i + 1] <= 0x9f)) {
157                     sjis++;     /* katakana */
158                 } else if ((size - i > 1) && (ptr[i] == 0xa4) && (0xa0 <= ptr[i + 1])) {
159                     euc++;      /* hiragana */
160                 } else if ((size - i > 1) && (ptr[i] == 0xa5) && (0xa0 <= ptr[i + 1])) {
161                     euc++;      /* katakana */
162                 }
163                 if (bfr) {
164                     if ((i >= 1) && (0x40 <= ptr[i] && ptr[i] <= 0xa0) && ISkanji(ptr[i - 1])) {
165                         code = SJIS;
166                         goto breakBreak;
167                     } else if ((i >= 1) && (0x81 <= ptr[i - 1] && ptr[i - 1] <= 0x9f) && ((0x40 <= ptr[i] && ptr[i] < 0x7e) || (0x7e < ptr[i] && ptr[i] <= 0xfc))) {
168                         code = SJIS;
169                         goto breakBreak;
170                     } else if ((i >= 1) && (0xfd <= ptr[i] && ptr[i] <= 0xfe) && (0xa1 <= ptr[i - 1] && ptr[i - 1] <= 0xfe)) {
171                         code = EUC;
172                         goto breakBreak;
173                     } else if ((i >= 1) && (0xfd <= ptr[i - 1] && ptr[i - 1] <= 0xfe) && (0xa1 <= ptr[i] && ptr[i] <= 0xfe)) {
174                         code = EUC;
175                         goto breakBreak;
176                     } else if ((i >= 1) && (ptr[i] < 0xa0 || 0xdf < ptr[i]) && (0x8e == ptr[i - 1])) {
177                         code = SJIS;
178                         goto breakBreak;
179                     } else if (ptr[i] <= 0x7f) {
180                         code = SJIS;
181                         goto breakBreak;
182                     } else {
183                         if (0xa1 <= ptr[i] && ptr[i] <= 0xa6) {
184                             euc++;      /* sjis hankaku kana kigo */
185                         } else if (0xa1 <= ptr[i] && ptr[i] <= 0xdf) {
186                             ;           /* sjis hankaku kana */
187                         } else if (0xa1 <= ptr[i] && ptr[i] <= 0xfe) {
188                             euc++;
189                         } else if (0x8e == ptr[i]) {
190                             euc++;
191                         } else if (0x20 <= ptr[i] && ptr[i] <= 0x7f) {
192                             sjis++;
193                         }
194                         bfr = false;
195                         bfk = 0;
196                     }
197                 } else if (0x8e == ptr[i]) {
198                     if (size - i <= 1) {
199                         ;
200                     } else if (0xa1 <= ptr[i + 1] && ptr[i + 1] <= 0xdf) {
201                         /* EUC KANA or SJIS KANJI */
202                         if (bfk == 1) {
203                             euc += 100;
204                         }
205                         bfk++;
206                         i++;
207                     } else {
208                         /* SJIS only */
209                         code = SJIS;
210                         goto breakBreak;
211                     }
212                 } else if (0x81 <= ptr[i] && ptr[i] <= 0x9f) {
213                     /* SJIS only */
214                     code = SJIS;
215                     if ((size - i >= 1)
216                             && ((0x40 <= ptr[i + 1] && ptr[i + 1] <= 0x7e)
217                             || (0x80 <= ptr[i + 1] && ptr[i + 1] <= 0xfc))) {
218                         goto breakBreak;
219                     }
220                 } else if (0xfd <= ptr[i] && ptr[i] <= 0xfe) {
221                     /* EUC only */
222                     code = EUC;
223                     if ((size - i >= 1)
224                             && (0xa1 <= ptr[i + 1] && ptr[i + 1] <= 0xfe)) {
225                         goto breakBreak;
226                     }
227                 } else if (ptr[i] <= 0x7f) {
228                     ;
229                 } else {
230                     bfr = true;
231                     bfk = 0;
232                 }
233             }
234             i++;
235         }
236     }
237     if (code == ASCII) {
238         if (sjis > euc) {
239             code = SJIS;
240         } else if (sjis < euc) {
241             code = EUC;
242         }
243     }
244 breakBreak:
245     return (code);
246 }
247
248 Decoder::ContentType Decoder::determineContentType(const String& mimeType)
249 {
250     if (equalIgnoringCase(mimeType, "text/css"))
251         return CSS;
252     if (equalIgnoringCase(mimeType, "text/html"))
253         return HTML;
254     if (DOMImplementation::isXMLMIMEType(mimeType))
255         return XML;
256     return PlainText;
257 }
258
259 const TextEncoding& Decoder::defaultEncoding(ContentType contentType, const TextEncoding& specifiedDefaultEncoding)
260 {
261     // Despite 8.5 "Text/xml with Omitted Charset" of RFC 3023, we assume UTF-8 instead of US-ASCII 
262     // for text/xml. This matches Firefox.
263     if (contentType == XML)
264         return UTF8Encoding();
265     if (!specifiedDefaultEncoding.isValid())
266         return Latin1Encoding();
267     return specifiedDefaultEncoding;
268 }
269
270 Decoder::Decoder(const String& mimeType, const TextEncoding& specifiedDefaultEncoding)
271     : m_contentType(determineContentType(mimeType))
272     , m_decoder(defaultEncoding(m_contentType, specifiedDefaultEncoding))
273     , m_source(DefaultEncoding)
274     , m_checkedForBOM(false)
275     , m_checkedForCSSCharset(false)
276     , m_checkedForHeadCharset(false)
277 {
278 }
279
280 Decoder::~Decoder()
281 {
282 }
283
284 void Decoder::setEncoding(const TextEncoding& encoding, EncodingSource source)
285 {
286     // In case the encoding didn't exist, we keep the old one (helps some sites specifying invalid encodings).
287     if (!encoding.isValid())
288         return;
289
290     if (source == EncodingFromMetaTag || source == EncodingFromXMLHeader || source == EncodingFromCSSCharset)        
291         m_decoder.reset(encoding.closest8BitEquivalent());
292     else
293         m_decoder.reset(encoding);
294
295     m_source = source;
296 }
297
298 // Returns the position of the encoding string.
299 static int findXMLEncoding(const DeprecatedCString &str, int &encodingLength)
300 {
301     int len = str.length();
302
303     int pos = str.find("encoding");
304     if (pos == -1)
305         return -1;
306     pos += 8;
307     
308     // Skip spaces and stray control characters.
309     while (str[pos] <= ' ' && pos != len)
310         ++pos;
311
312     // Skip equals sign.
313     if (str[pos] != '=')
314         return -1;
315     ++pos;
316
317     // Skip spaces and stray control characters.
318     while (str[pos] <= ' ' && pos != len)
319         ++pos;
320
321     // Skip quotation mark.
322     char quoteMark = str[pos];
323     if (quoteMark != '"' && quoteMark != '\'')
324         return -1;
325     ++pos;
326
327     // Find the trailing quotation mark.
328     int end = pos;
329     while (str[end] != quoteMark)
330         ++end;
331
332     if (end == len)
333         return -1;
334     
335     encodingLength = end - pos;
336     return pos;
337 }
338
339 // true if there is more to parse
340 static inline bool skipWhitespace(const char*& pos, const char* dataEnd)
341 {
342     while (pos < dataEnd && (*pos == '\t' || *pos == ' '))
343         ++pos;
344     return pos != dataEnd;
345 }
346
347 void Decoder::checkForBOM(const char* data, size_t len)
348 {
349     // Check for UTF-16 or UTF-8 BOM mark at the beginning, which is a sure sign of a Unicode encoding.
350
351     if (m_source == UserChosenEncoding) {
352         // FIXME: Maybe a BOM should override even a user-chosen encoding.
353         m_checkedForBOM = true;
354         return;
355     }
356
357     // Check if we have enough data.
358     size_t bufferLength = m_buffer.size();
359     if (bufferLength + len < 3)
360         return;
361
362     m_checkedForBOM = true;
363
364     // Extract the first three bytes.
365     // Handle the case where some of bytes are already in the buffer.
366     // The last byte is always guaranteed to not be in the buffer.
367     const unsigned char* udata = reinterpret_cast<const unsigned char*>(data);
368     unsigned char c1 = bufferLength >= 1 ? m_buffer[0] : *udata++;
369     unsigned char c2 = bufferLength >= 2 ? m_buffer[1] : *udata++;
370     ASSERT(bufferLength < 3);
371     unsigned char c3 = *udata;
372
373     // Check for the BOM.
374     if (c1 == 0xFE && c2 == 0xFF)
375         setEncoding(UTF16BigEndianEncoding(), AutoDetectedEncoding);
376     else if (c1 == 0xFF && c2 == 0xFE)
377         setEncoding(UTF16LittleEndianEncoding(), AutoDetectedEncoding);
378     else if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF)
379         setEncoding(UTF8Encoding(), AutoDetectedEncoding);
380 }
381
382 void Decoder::checkForCSSCharset(const char* data, size_t len)
383 {
384     if (m_source != DefaultEncoding) {
385         m_checkedForCSSCharset = true;
386         return;
387     }
388
389     size_t oldSize = m_buffer.size();
390     m_buffer.resize(oldSize + len);
391     memcpy(m_buffer.data() + oldSize, data, len);
392
393     if (m_buffer.size() > 8) { // strlen("@charset") == 8
394         const char* dataStart = m_buffer.data();
395         const char* dataEnd = dataStart + m_buffer.size();
396
397         if (dataStart[0] == '@' && dataStart[1] == 'c' && dataStart[2] == 'h' && dataStart[3] == 'a' && dataStart[4] == 'r' && 
398             dataStart[5] == 's' && dataStart[6] == 'e' && dataStart[7] == 't') {
399     
400             dataStart += 8;
401             const char* pos = dataStart;
402             if (!skipWhitespace(pos, dataEnd))
403                 return;
404
405             if (*pos == '"' || *pos == '\'') {
406                 char quotationMark = *pos;
407                 ++pos;
408                 dataStart = pos;
409             
410                 while (pos < dataEnd && *pos != quotationMark)
411                     ++pos;
412                 if (pos == dataEnd)
413                     return;
414
415                 DeprecatedCString encodingName(dataStart, pos - dataStart + 1);
416                 
417                 ++pos;
418                 if (!skipWhitespace(pos, dataEnd))
419                     return;
420
421                 if (*pos == ';')
422                     setEncoding(TextEncoding(encodingName), EncodingFromCSSCharset);
423             }
424         }
425         m_checkedForCSSCharset = true;
426     }
427 }
428
429 // Other browsers allow comments in the head section, so we need to also.
430 // It's important not to look for tags inside the comments.
431 static inline void skipComment(const char*& ptr, const char* pEnd)
432 {
433     const char* p = ptr;
434     // Allow <!-->; other browsers do.
435     if (*p == '>') {
436         p++;
437     } else {
438         while (p != pEnd) {
439             if (*p == '-') {
440                 // This is the real end of comment, "-->".
441                 if (p[1] == '-' && p[2] == '>') {
442                     p += 3;
443                     break;
444                 }
445                 // This is the incorrect end of comment that other browsers allow, "--!>".
446                 if (p[1] == '-' && p[2] == '!' && p[3] == '>') {
447                     p += 4;
448                     break;
449                 }
450             }
451             p++;
452         }
453     }
454     ptr = p;
455 }
456
457 bool Decoder::checkForHeadCharset(const char* data, size_t len, bool& movedDataToBuffer)
458 {
459     if (m_source != DefaultEncoding) {
460         m_checkedForHeadCharset = true;
461         return true;
462     }
463
464     // This is not completely efficient, since the function might go
465     // through the HTML head several times.
466
467     size_t oldSize = m_buffer.size();
468     m_buffer.resize(oldSize + len);
469     memcpy(m_buffer.data() + oldSize, data, len);
470
471     movedDataToBuffer = true;
472     
473     // we still don't have an encoding, and are in the head
474     // the following tags are allowed in <head>:
475     // SCRIPT|STYLE|META|LINK|OBJECT|TITLE|BASE
476     
477     // We stop scanning when a tag that is not permitted in <head>
478     // is seen, rather when </head> is seen, because that more closely
479     // matches behavior in other browsers; more details in
480     // <http://bugzilla.opendarwin.org/show_bug.cgi?id=3590>.
481     
482     // Additionally, we ignore things that looks like tags in <title>; see
483     // <http://bugzilla.opendarwin.org/show_bug.cgi?id=4560>.
484     
485     bool withinTitle = false;
486
487     const char* ptr = m_buffer.data();
488     const char* pEnd = ptr + m_buffer.size();
489     while (ptr != pEnd) {
490         if (*ptr == '<') {
491             bool end = false;
492             ptr++;
493
494             // Handle comments.
495             if (ptr[0] == '!' && ptr[1] == '-' && ptr[2] == '-') {
496                 ptr += 3;
497                 skipComment(ptr, pEnd);
498                 continue;
499             }
500
501             // Handle XML declaration, which can have encoding in it.
502             // This encoding is honored even for HTML documents.
503             if (ptr[0] == '?' && ptr[1] == 'x' && ptr[2] == 'm' && ptr[3] == 'l') {
504                 const char* end = ptr;
505                 while (*end != '>' && *end != '\0')
506                     end++;
507                 if (*end == '\0')
508                     break;
509                 DeprecatedCString str(ptr, end - ptr);
510                 int len;
511                 int pos = findXMLEncoding(str, len);
512                 if (pos != -1)
513                     setEncoding(TextEncoding(str.mid(pos, len)), EncodingFromXMLHeader);
514                 // continue looking for a charset - it may be specified in an HTTP-Equiv meta
515             } else if (ptr[0] == 0 && ptr[1] == '?' && ptr[2] == 0 && ptr[3] == 'x' && ptr[4] == 0 && ptr[5] == 'm' && ptr[6] == 0 && ptr[7] == 'l') {
516                 // UTF-16 without BOM
517                 setEncoding(((ptr - m_buffer.data()) % 2) ? "UTF-16LE" : "UTF-16BE", AutoDetectedEncoding);
518                 return true;
519             }
520
521             // the HTTP-EQUIV meta has no effect on XHTML
522             if (m_contentType == XML)
523                 return true;
524
525             if (*ptr == '/') {
526                 ++ptr;
527                 end = true;
528             }
529
530             char tmp[20];
531             int len = 0;
532             while (
533                 ((*ptr >= 'a') && (*ptr <= 'z') ||
534                  (*ptr >= 'A') && (*ptr <= 'Z') ||
535                  (*ptr >= '0') && (*ptr <= '9'))
536                 && len < 19 )
537             {
538                 tmp[len] = tolower(*ptr);
539                 ptr++;
540                 len++;
541             }
542             tmp[len] = 0;
543             AtomicString tag(tmp);
544             
545             if (tag == titleTag)
546                 withinTitle = !end;
547             
548             if (!end && tag == metaTag) {
549                 const char* end = ptr;
550                 while (*end != '>' && *end != '\0')
551                     end++;
552                 if (*end == '\0')
553                     break;
554                 DeprecatedCString str(ptr, (end-ptr)+1);
555                 str = str.lower();
556                 int pos = 0;
557                 while (pos < (int)str.length()) {
558                     if ((pos = str.find("charset", pos, false)) == -1)
559                         break;
560                     pos += 7;
561                     // skip whitespace..
562                     while (pos < (int)str.length() && str[pos] <= ' ')
563                         pos++;
564                     if (pos == (int)str.length())
565                         break;
566                     if (str[pos++] != '=')
567                         continue;
568                     while (pos < (int)str.length() &&
569                             (str[pos] <= ' ') || str[pos] == '=' || str[pos] == '"' || str[pos] == '\'')
570                         pos++;
571
572                     // end ?
573                     if (pos == (int)str.length())
574                         break;
575                     unsigned endpos = pos;
576                     while (endpos < str.length() &&
577                            str[endpos] != ' ' && str[endpos] != '"' && str[endpos] != '\'' &&
578                            str[endpos] != ';' && str[endpos] != '>')
579                         endpos++;
580                     setEncoding(TextEncoding(str.mid(pos, endpos - pos)), EncodingFromMetaTag);
581                     if (m_source == EncodingFromMetaTag)
582                         return true;
583
584                     if (endpos >= str.length() || str[endpos] == '/' || str[endpos] == '>')
585                         break;
586
587                     pos = endpos + 1;
588                 }
589             } else if (tag != scriptTag && tag != noscriptTag && tag != styleTag &&
590                        tag != linkTag && tag != metaTag && tag != objectTag &&
591                        tag != titleTag && tag != baseTag && 
592                        (end || tag != htmlTag) && !withinTitle &&
593                        (tag != headTag) && isalpha(tmp[0])) {
594                 m_checkedForHeadCharset = true;
595                 return true;
596             }
597         }
598         else
599             ptr++;
600     }
601     return false;
602 }
603
604 void Decoder::detectJapaneseEncoding(const char* data, size_t len)
605 {
606     switch (KanjiCode::judge(data, len)) {
607         case KanjiCode::JIS:
608             setEncoding("ISO-2022-JP", AutoDetectedEncoding);
609             break;
610         case KanjiCode::EUC:
611             setEncoding("EUC-JP", AutoDetectedEncoding);
612             break;
613         case KanjiCode::SJIS:
614             setEncoding("Shift_JIS", AutoDetectedEncoding);
615             break;
616         case KanjiCode::ASCII:
617         case KanjiCode::UTF16:
618         case KanjiCode::UTF8:
619             break;
620     }
621 }
622
623 String Decoder::decode(const char* data, size_t len)
624 {
625     if (!m_checkedForBOM)
626         checkForBOM(data, len);
627
628     if (m_contentType == CSS && !m_checkedForCSSCharset) {
629         checkForCSSCharset(data, len);
630         return "";
631     }
632
633     bool movedDataToBuffer = false;
634
635     if ((m_contentType == HTML || m_contentType == XML) && !m_checkedForHeadCharset) { // HTML and XML
636         if (!checkForHeadCharset(data, len, movedDataToBuffer))
637             return "";
638     }
639
640     // Do the auto-detect if our default encoding is one of the Japanese ones.
641     // FIXME: It seems wrong to change our encoding downstream after we have already done some decoding.
642     if (m_source != UserChosenEncoding && m_source != AutoDetectedEncoding && encoding().isJapanese())
643         detectJapaneseEncoding(data, len);
644
645     ASSERT(encoding().isValid());
646
647     if (m_buffer.isEmpty())
648         return m_decoder.decode(data, len);
649
650     if (!movedDataToBuffer) {
651         size_t oldSize = m_buffer.size();
652         m_buffer.resize(oldSize + len);
653         memcpy(m_buffer.data() + oldSize, data, len);
654     }
655
656     String result = m_decoder.decode(m_buffer.data(), m_buffer.size());
657     m_buffer.resize(0);
658     return result;
659 }
660
661 String Decoder::flush()
662 {
663     String result = m_decoder.decode(m_buffer.data(), m_buffer.size(), true);
664     m_buffer.resize(0);
665     return result;
666 }
667
668 }