/*
 * Copyright (C) 2006, 2007, 2011 Apple Inc. All rights reserved.
 * Copyright (C) 2007-2009 Torch Mobile, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#include "config.h"
#include "TextEncodingRegistry.h"

#include "TextCodecLatin1.h"
#include "TextCodecUserDefined.h"
#include "TextCodecUTF16.h"
#include "TextCodecUTF8.h"
#include "TextEncoding.h"
#include <wtf/ASCIICType.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/MainThread.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/StdLibExtras.h>
#include <wtf/StringExtras.h>
#include <wtf/text/StringHash.h>

#if USE(ICU_UNICODE)
#include "TextCodecICU.h"
#endif
#if PLATFORM(MAC)
#include "TextCodecMac.h"
#endif
#if USE(QT4_UNICODE)
#include "qt/TextCodecQt.h"
#endif
#if USE(GLIB_UNICODE)
#include "gtk/TextCodecGtk.h"
#endif
#if USE(WINCE_UNICODE)
#include "win/TextCodecWin.h"
#endif

#include <wtf/CurrentTime.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringBuilder.h>

using namespace WTF;

namespace WebCore {

const size_t maxEncodingNameLength = 63;

// Hash for all-ASCII strings that does case folding.
struct TextEncodingNameHash {
    static bool equal(const char* s1, const char* s2)
    {
        char c1;
        char c2;
        do {
            c1 = *s1++;
            c2 = *s2++;
            if (toASCIILower(c1) != toASCIILower(c2))
                return false;
        } while (c1 && c2);
        return !c1 && !c2;
    }

    // This algorithm is the one-at-a-time hash from:
    // http://burtleburtle.net/bob/hash/hashfaq.html
    // http://burtleburtle.net/bob/hash/doobs.html
    static unsigned hash(const char* s)
    {
        unsigned h = WTF::stringHashingStartValue;
        for (;;) {
            char c = *s++;
            if (!c) {
                h += (h << 3);
                h ^= (h >> 11);
                h += (h << 15);
                return h;
            }
            h += toASCIILower(c);
            h += (h << 10); 
            h ^= (h >> 6); 
        }
    }

    static const bool safeToCompareToEmptyOrDeleted = false;
};

struct TextCodecFactory {
    NewTextCodecFunction function;
    const void* additionalData;
    TextCodecFactory(NewTextCodecFunction f = 0, const void* d = 0) : function(f), additionalData(d) { }
};

struct HashTranslatorTextEncodingName {
    static unsigned hash(const char* literal)
    {
        return TextEncodingNameHash::hash(literal);
    }

    static bool equal(const ASCIILiteral& a, const char* b)
    {
        return TextEncodingNameHash::equal(a.characters(), b);
    }
};

using TextEncodingNameMap = HashMap<ASCIILiteral, ASCIILiteral, TextEncodingNameHash>;
using TextCodecMap = HashMap<ASCIILiteral, TextCodecFactory>;

static Mutex& encodingRegistryMutex()
{
    // We don't have to use AtomicallyInitializedStatic here because
    // this function is called on the main thread for any page before
    // it is used in worker threads.
	static NeverDestroyed<Mutex> mutex;
    return mutex;
}

static TextEncodingNameMap* textEncodingNameMap;
static TextCodecMap* textCodecMap;
static bool didExtendTextCodecMaps;
static HashSet<ASCIILiteral>* japaneseEncodings;
static HashSet<ASCIILiteral>* nonBackslashEncodings;

static constexpr ASCIILiteral textEncodingNameBlacklist[] = { ASCIILiteral("UTF-7"), ASCIILiteral("BOCU-1"), ASCIILiteral("SCSU") };

#if ERROR_DISABLED

static inline void checkExistingName(ASCIILiteral, ASCIILiteral) { }

#else

static void checkExistingName(ASCIILiteral alias, ASCIILiteral atomicName)
{
	ASCIILiteral oldAtomicName = textEncodingNameMap->get(alias);
    if (!oldAtomicName)
        return;
    if (oldAtomicName == atomicName)
        return;
    // Keep the warning silent about one case where we know this will happen.
    if (strcmp(alias, "ISO-8859-8-I") == 0
            && strcmp(oldAtomicName, "ISO-8859-8-I") == 0
            && strcasecmp(atomicName, "iso-8859-8") == 0)
        return;
    LOG_ERROR("alias %s maps to %s already, but someone is trying to make it map to %s", alias, oldAtomicName, atomicName);
}

#endif

static bool isUndesiredAlias(ASCIILiteral alias)
{
    // Reject aliases with version numbers that are supported by some back-ends (such as "ISO_2022,locale=ja,version=0" in ICU).
	if (strchr(alias.characters(), ','))
		return true;
    // 8859_1 is known to (at least) ICU, but other browsers don't support this name - and having it caused a compatibility
    // problem, see bug 43554.
    if (alias == ASCIILiteral("8859_1"))
        return true;
    return false;
}

static void addToTextEncodingNameMap(ASCIILiteral alias, ASCIILiteral name)
{
    ASSERT(strlen(alias) <= maxEncodingNameLength);
    if (isUndesiredAlias(alias))
        return;
    ASCIILiteral atomicName = textEncodingNameMap->get(name);
    ASSERT((alias == name) || !atomicName.isNull());
    if (atomicName.isNull())
        atomicName = name;
    checkExistingName(alias, atomicName);
    textEncodingNameMap->add(alias, atomicName);
}

static void addToTextCodecMap(ASCIILiteral name, NewTextCodecFunction function, const void* additionalData)
{
	ASCIILiteral atomicName = textEncodingNameMap->get(name);
    ASSERT(!atomName.isNull());
    textCodecMap->add(atomicName, TextCodecFactory(function, additionalData));
}

static void pruneBlacklistedCodecs()
{
    for (size_t i = 0; i < WTF_ARRAY_LENGTH(textEncodingNameBlacklist); ++i) {
    	ASCIILiteral atomicName = textEncodingNameMap->get(textEncodingNameBlacklist[i]);
    	if (atomicName.isNull())
			continue;

        Vector<ASCIILiteral> names;
        for (auto& entry : *textEncodingNameMap) {
            if (entry.second == atomicName)
                names.append(entry.first);
        }

        for (auto& name : names)
            textEncodingNameMap->remove(name);

        textCodecMap->remove(atomicName);
    }
}

static void buildBaseTextCodecMaps()
{
    ASSERT(isMainThread());
    ASSERT(!textCodecMap);
    ASSERT(!textEncodingNameMap);

    textCodecMap = new TextCodecMap;
    textEncodingNameMap = new TextEncodingNameMap;

    TextCodecLatin1::registerEncodingNames(addToTextEncodingNameMap);
    TextCodecLatin1::registerCodecs(addToTextCodecMap);

    TextCodecUTF8::registerEncodingNames(addToTextEncodingNameMap);
    TextCodecUTF8::registerCodecs(addToTextCodecMap);

    TextCodecUTF16::registerEncodingNames(addToTextEncodingNameMap);
    TextCodecUTF16::registerCodecs(addToTextCodecMap);

    TextCodecUserDefined::registerEncodingNames(addToTextEncodingNameMap);
    TextCodecUserDefined::registerCodecs(addToTextCodecMap);

#if USE(GLIB_UNICODE)
    // FIXME: This is not needed. The code above covers all the base codecs.
    TextCodecGtk::registerBaseEncodingNames(addToTextEncodingNameMap);
    TextCodecGtk::registerBaseCodecs(addToTextCodecMap);
#endif
}

static void addEncodingName(HashSet<ASCIILiteral>& set, ASCIILiteral name)
{
    // We must not use atomicCanonicalTextEncodingName() because this function is called in it.
	ASCIILiteral atomicName = textEncodingNameMap->get(name);
	if (!atomicName.isNull())
		set.add(atomicName);
}

static void buildQuirksSets()
{
    // FIXME: Having isJapaneseEncoding() and shouldShowBackslashAsCurrencySymbolIn()
    // and initializing the sets for them in TextEncodingRegistry.cpp look strange.

    ASSERT(!japaneseEncodings);
    ASSERT(!nonBackslashEncodings);

    japaneseEncodings = new HashSet<ASCIILiteral>;
    addEncodingName(*japaneseEncodings, ASCIILiteral("EUC-JP"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("ISO-2022-JP"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("ISO-2022-JP-1"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("ISO-2022-JP-2"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("ISO-2022-JP-3"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("JIS_C6226-1978"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("JIS_X0201"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("JIS_X0208-1983"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("JIS_X0208-1990"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("JIS_X0212-1990"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("Shift_JIS"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("Shift_JIS_X0213-2000"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("cp932"));
    addEncodingName(*japaneseEncodings, ASCIILiteral("x-mac-japanese"));

    nonBackslashEncodings = new HashSet<ASCIILiteral>;
    // The text encodings below treat backslash as a currency symbol for IE compatibility.
    // See http://blogs.msdn.com/michkap/archive/2005/09/17/469941.aspx for more information.
    addEncodingName(*nonBackslashEncodings, ASCIILiteral("x-mac-japanese"));
    addEncodingName(*nonBackslashEncodings, ASCIILiteral("ISO-2022-JP"));
    addEncodingName(*nonBackslashEncodings, ASCIILiteral("EUC-JP"));
    // Shift_JIS_X0213-2000 is not the same encoding as Shift_JIS on Mac. We need to register both of them.
    addEncodingName(*nonBackslashEncodings, ASCIILiteral("Shift_JIS"));
    addEncodingName(*nonBackslashEncodings, ASCIILiteral("Shift_JIS_X0213-2000"));
}

bool isJapaneseEncoding(ASCIILiteral canonicalEncodingName)
{
    return !canonicalEncodingName.isNull() && japaneseEncodings && japaneseEncodings->contains(canonicalEncodingName);
}

bool shouldShowBackslashAsCurrencySymbolIn(ASCIILiteral canonicalEncodingName)
{
    return !canonicalEncodingName.isNull() && nonBackslashEncodings && nonBackslashEncodings->contains(canonicalEncodingName);
}

static void extendTextCodecMaps()
{
#if USE(ICU_UNICODE)
    TextCodecICU::registerEncodingNames(addToTextEncodingNameMap);
    TextCodecICU::registerCodecs(addToTextCodecMap);
#endif

#if USE(QT4_UNICODE)
    TextCodecQt::registerEncodingNames(addToTextEncodingNameMap);
    TextCodecQt::registerCodecs(addToTextCodecMap);
#endif

#if PLATFORM(MAC)
    TextCodecMac::registerEncodingNames(addToTextEncodingNameMap);
    TextCodecMac::registerCodecs(addToTextCodecMap);
#endif

#if USE(GLIB_UNICODE)
    TextCodecGtk::registerExtendedEncodingNames(addToTextEncodingNameMap);
    TextCodecGtk::registerExtendedCodecs(addToTextCodecMap);
#endif

#if USE(WINCE_UNICODE)
    TextCodecWin::registerExtendedEncodingNames(addToTextEncodingNameMap);
    TextCodecWin::registerExtendedCodecs(addToTextCodecMap);
#endif

    pruneBlacklistedCodecs();
    buildQuirksSets();
}

#if ENABLE(BML_DRCS)
namespace {
class BMLTextCodec : public TextCodec {
public:
	BMLTextCodec()
	: savedByte(0)
	, savedSecond(0)
	{
	}

	virtual ~BMLTextCodec()
	{
	}

	virtual String decode(const char*, size_t length, bool flush, bool stopOnError, bool& sawError);
	virtual CString encode(const UChar*, size_t length, UnencodableHandling);

private:
	unsigned char savedByte;
	unsigned char savedSecond;
};

static const UChar CHARs_0xADxx[] = {
	/*A0*/ 0xFFFD,0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,
	/*A8*/ 0x2467,0x2468,0x2469,0x246A,0x246B,0x246C,0x246D,0x246E,
	/*B0*/ 0x246F,0x2470,0x2471,0x2472,0x2473,0x2160,0x2161,0x2162,
	/*B8*/ 0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0xFFFD,
	/*C0*/ 0x3349,0x3314,0x3322,0x334D,0x3318,0x3327,0x3303,0x3336,
	/*C8*/ 0x3351,0x3357,0x330D,0x3326,0x3323,0x332B,0x334A,0x332C,
	/*D0*/ 0x339C,0x339D,0x339E,0x338E,0x338F,0x33C4,0x33A1,0xFFFD,
	/*D8*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0x337B,
	/*E0*/ 0x301D,0x301F,0x2116,0x33CD,0x2121,0x32A4,0x32A5,0x32A6,
	/*E8*/ 0x32A7,0x32A8,0x3231,0x3232,0x3239,0x337E,0x337D,0x337C,
	/*F0*/ 0x2252,0x2261,0x22B2,0x222E,0x2211,0x22A1,0x22A5,0x2220,
	/*F8*/ 0x221F,0x22BF,0x2235,0x2229,0x222A,0xFFFD,0xFFFD,0xFFFD
};

/**
 * ARIB STD-B24_V5_0-E1_VOL_1.pdf
 *
 * Table 7-19 Code Values for Added Symbols Set
 */
static const UChar CHARs_0xF9xx[] = {
	/*F9XX - 89/01*/
	/*A0*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*A8*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*B0*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*B8*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*C0*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*C8*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*D0*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*D8*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*E0*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*E8*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*F0*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*F8*/ 0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,0xFFFD,
	/*FAxx - 90/01*/
	/*A0*/ 0xFFFD,0xE0C9,0xE0CA,0xE0CB,0xE0CC,0xE0CD,0xE0CE,0xE0CF,
	/*A8*/ 0xE0D0,0xE0D1,0xE0D2,0xE0D3,0xE0D4,0xE0D5,0xE0D6,0xE0D7,
	/*B0*/ 0xE0D8,0xE0D9,0xE0DA,0xE0DB,0xE0DC,0xE0DD,0xE0DE,0xE0DF,
	/*B8*/ 0xE0E0,0xE0E1,0xE0E2,0xE0E3,0xE0E4,0xE0E5,0xE0E6,0xE0E7,
	/*C0*/ 0xE0E8,0xE0E9,0xE0EA,0xE0EB,0xE0EC,0xE0ED,0xE0EE,0xE0EF,
	/*C8*/ 0xE0F0,0xE0F1,0xE0F2,0xE0F3,0xE0F4,0xE0F5,0xE0F6,0xE0F7,
	/*D0*/ 0xE0F8,0xE0F9,0xE0FA,0xE0FB,0xE0FC,0xE0FD,0xE0FE,0xE0FF,
	/*D8*/ 0xE180,0xE181,0xE182,0xE183,0xE184,0xE185,0xE186,0xE187,
	/*E0*/ 0xE188,0xE189,0xE18A,0xE18B,0xE18C,0xE18D,0xE18E,0xE18F,
	/*E8*/ 0xE190,0xE191,0xE192,0xE193,0xE194,0xE195,0xE196,0xE197,
	/*F0*/ 0xE198,0xE199,0xE19A,0xE19B,0xE19C,0xE19D,0xE19E,0xE19F,
	/*F8*/ 0xE1A0,0xE1A1,0xE1A2,0xE1A3,0xE1A4,0xE1A5,0xE1A6,0xFFFD,
	/*FBxx - 91/01*/
	/*A0*/ 0xFFFD,0xE1A7,0xE1A8,0xE1A9,0xE1AA,0xE1AB,0xE1AC,0xE1AD,
	/*A8*/ 0xE1AE,0xE1AF,0xE1B0,0xE1B1,0xE1B2,0xE1B3,0xE1B4,0xE1B5,
	/*B0*/ 0xE1B6,0xE1B7,0xE1B8,0xE1B9,0xE1BA,0xE1BB,0xE1BC,0xE1BD,
	/*B8*/ 0xE1BE,0xE1BF,0xE1C0,0xE1C1,0xE1C2,0xE1C3,0xE1C4,0xE1C5,
	/*C0*/ 0xE1C6,0xE1C7,0xE1C8,0xE1C9,0xE1CA,0xE1CB,0xE1CC,0xE1CD,
	/*C8*/ 0xE1CE,0xE1CF,0xE1D0,0xE1D1,0xE1D2,0xE1D3,0xE1D4,0xE1D5,
	/*D0*/ 0xE1D6,0xE1D7,0xE1D8,0xE1D9,0xE1DA,0xE1DB,0xE1DC,0xE1DD,
	/*D8*/ 0xE1DE,0xE1DF,0xE1E0,0xE1E1,0xE1E2,0xE1E3,0xE1E4,0xE1E5,
	/*E0*/ 0xE1E6,0xE1E7,0xE1E8,0xE1E9,0xE1EA,0xE1EB,0xE1EC,0xE1ED,
	/*E8*/ 0xE1EE,0xE1EF,0xE1F0,0xE1F1,0xE1F2,0xE1F3,0xE1F4,0xE1F5,
	/*F0*/ 0xE1F6,0xE1F7,0xE1F8,0xE1F9,0xE1FA,0xE1FB,0xE1FC,0xE1FD,
	/*F8*/ 0xE1FE,0xE1FF,0xE280,0xE281,0xE282,0xE283,0xE284,0xFFFD,
	/*FCxx - 92/01*/
	/*A0*/ 0xFFFD,0xE285,0xE286,0xE287,0xE288,0xE289,0xE28A,0xE28B,
	/*A8*/ 0xE28C,0xE28D,0xE28E,0x33A1,0x33A5,0x339D,0x33A0,0x33A4,
	/*B0*/ 0xE28F,0x2488,0x2489,0x248A,0x248B,0x248C,0x248D,0x248E,
	/*B8*/ 0x248F,0x2490,0xE290,0xE291,0xE292,0xE293,0xE294,0xE295,
	/*C0*/ 0xE296,0xE297,0xE298,0xE299,0xE29A,0xE29B,0xE29C,0xE29D,
	/*C8*/ 0xE29E,0xE29F,0x3233,0x3236,0x3232,0x3231,0x3239,0xE2A0,
	/*D0*/ 0x25B6,0x25C0,0x3016,0x3017,0xE2A1,0xE2A2,0xE2A3,0xE2A4,
	/*D8*/ 0xE2A5,0xE2A6,0xE2A7,0xE2A8,0xE2A9,0xE2AA,0xE2AB,0xE2AC,
	/*E0*/ 0xE2AD,0xE2AE,0xE2AF,0xE2B0,0xE2B1,0xE2B2,0xE2B3,0xE2B4,
	/*E8*/ 0xE2B5,0xE2B6,0xE2B7,0xE2B8,0xE2B9,0xE2BA,0xE2BB,0xE2BC,
	/*F0*/ 0xE2BD,0xE2BE,0xE2BF,0xE2C0,0xE2C1,0xE2C2,0x00AE,0x00A9,
	/*F8*/ 0xE2C3,0xE2C4,0xE2C5,0xE2C6,0xE2C7,0xE2C8,0xE2C9,0xFFFD,
	/*FDxx - 93/01*/
	/*A0*/ 0xFFFD,0x322A,0x322B,0x322C,0x322D,0x322E,0x322F,0x3230,
	/*A8*/ 0x3237,0x337E,0x337D,0x337C,0x337B,0xE2CA,0xE2CB,0x3036,
	/*B0*/ 0xE2CC,0xE2CD,0xE2CE,0xE2CF,0xE2D0,0xE2D1,0xE2D2,0xE2D3,
	/*B8*/ 0xE2D4,0xE2D5,0xE2D6,0xE2D7,0xE2D8,0xE2D9,0xE2DA,0xE2DB,
	/*C0*/ 0xE2DC,0xE2DD,0xE2DE,0xE2DF,0xE2E0,0xE2E1,0xE2E2,0x2113,
	/*C8*/ 0x338F,0x3390,0x33CA,0x339E,0x33A2,0x3371,0xE2E3,0xE2E4,
	/*D0*/ 0x00BD,0xE2E5,0x2153,0x2154,0x00BC,0x00BE,0x2155,0x2156,
	/*D8*/ 0x2157,0x2158,0x2159,0x215A,0xE2E6,0x215B,0xE2E7,0xE2E8,
	/*E0*/ 0x2600,0x2601,0x2602,0xE2E9,0xE2EA,0xE2EB,0xE2EC,0xE2ED,
	/*E8*/ 0x2666,0x2665,0x2663,0x2660,0xE2EE,0xE2EF,0x203C,0xE2F0,
	/*F0*/ 0xE2F1,0xE2F2,0xE2F3,0xE2F4,0xE2F5,0xE2F6,0xE2F7,0xE2F8,
	/*F8*/ 0xE2F9,0xE2FA,0x266C,0xE2FB,0xE2FC,0xE2FD,0xE2FE,0xFFFD,
	/*FExx - 94/01*/
	/*A0*/ 0xFFFD,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166, //00
	/*A8*/ 0x2167,0x2168,0x2169,0x216A,0x216B,0x2470,0x2471,0x2472, //08
	/*B0*/ 0x2473,0x2474,0x2475,0x2476,0x2477,0x2478,0x2479,0x247A, //16
	/*B8*/ 0x247B,0x247C,0x247D,0x247E,0x247F,0xE2FF,0xE380,0xE381, //24
	/*C0*/ 0xE382,0xE383,0xE384,0xE385,0xE386,0xE387,0xE388,0xE389, //32
	/*C8*/ 0xE38A,0xE38B,0xE38C,0xE38D,0xE38E,0xE38F,0xE390,0xE391, //40
	/*D0*/ 0xE392,0xE393,0xE394,0xE395,0xE396,0xE397,0xE398,0xE399, //48
	/*D8*/ 0xE39A,0xE39B,0xE39C,0xE39D,0xE39E,0xE39F,0xE3A0,0xE3A1, //56
	/*E0*/ 0xE3A2,0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466, //64
	/*E8*/ 0x2467,0x2468,0x2469,0x246A,0x246B,0x246C,0x246D,0x246E, //72
	/*F0*/ 0x246F,0x2776,0x2777,0x2778,0x2779,0x277A,0x277B,0x277C, //80
	/*F8*/ 0x277D,0x277E,0x277F,0xE3A3,0xE3A4,0xE3A5,0xE3A6,0xFFFD, //88
};

WTF::CString BMLTextCodec::encode(const UChar* characters, size_t length, UnencodableHandling)
{
	return TextEncoding("EUC-JP").encode(StringView(characters, length), QuestionMarksForUnencodables);
}

/* iconv_t is an opaque type. This is the real iconv_t type. */
typedef struct conv_struct * conv_t;

/* Our own notion of wide character, as UCS-4, according to ISO-10646-1. */
typedef unsigned int ucs4_t;

/* Return code if invalid input after a shift sequence of n bytes was read.
   (xxx_mbtowc) */
/* Return code if invalid. (xxx_mbtowc) */
#define RET_ILSEQ           -1
/* Return code if only a shift sequence of n bytes was read. (xxx_mbtowc) */
#define RET_TOOFEW(n)       -2

/* Return code if invalid. (xxx_wctomb) */
#define RET_ILUNI      -1
/* Return code if output buffer is too small. (xxx_wctomb, xxx_reset) */
#define RET_TOOSMALL   -2

/* CJK character sets [CCS = coded character set] [CJKV.INF chapter 3] */

typedef struct {
  unsigned short indx; /* index into big table */
  unsigned short used; /* bitmask of used entries */
} Summary16;

#include "iconv/jisx0201.h"
#include "iconv/jisx0208.h"
#include "iconv/jisx0212.h"
#include "iconv/euc_jp.h"

static int BML_euc_jp_mbtowc(ucs4_t *pwc, const char *s, int n)
{
	return euc_jp_mbtowc(0, pwc, (const unsigned char*)s, n);
}

String BMLTextCodec::decode(const char* str, size_t length, bool flush, bool stopOnError, bool& sawError)
{
	sawError = false;

	if(savedByte != 0){
		Vector<char> cbuf;

		cbuf.reserveCapacity(length + 2);

		cbuf.append(savedByte);

		if(savedSecond != 0)
			cbuf.append(savedSecond);

		cbuf.append(str, length);

		savedByte = 0;
		savedSecond = 0;

		return decode(cbuf.data(), cbuf.size(), flush, stopOnError, sawError);
	}

	StringBuilder builder;

    for(size_t off = 0; off < length; /**/) {
        unsigned char k1 = str[off];

        if(k1 == 0){
            ++off;
        }
        else if(k1 < 0x80){
        	builder.append(k1);
        	++off;
        }
        else if((off + 1) >= length){
        	savedByte = k1;
            break;
        }
        else{
        	ucs4_t pwc;

        	unsigned char i2 = str[off + 1];

            if(k1==0xAD && (i2>=0xA0 && i2<=0xFF)){
            	pwc = CHARs_0xADxx[i2 - 0xA0];
            	off += 2;
            }
            else if((k1>=0xF9 && k1<=0xFE) && (i2>=0xA0 && i2<=0xFF)){
            	pwc = CHARs_0xF9xx[(k1 - 0xF9) * (0xFF - 0XA0 + 1) + (i2 - 0xA0)];
            	off += 2;
            }
            else if (k1==0xF7 || k1==0xF8) {
            	pwc = (((k1 & 0xFF) << 8) | (i2 & 0xFF));
            	off += 2;
            }
            else{
            	int result = BML_euc_jp_mbtowc(&pwc, str + off, length - off);

            	if(result > 0){
            		off += result;
            	}
            	else if(result == RET_TOOFEW(0)){
            		if((length - off) == 1){
            			savedByte= k1;
            		}
            		else if((length - off) == 2){
            			savedByte= k1;
            			savedSecond = i2;
            		}
            		else{
            			fprintf(stderr, "++++>BMLTextCodecPrivate::decode(0x%2x%2x) invalid TOOLFEW(%i).\n", k1, i2, (length - off));

            			sawError = true;
            		}
            		break;
            	}
            	else{
            		fprintf(stderr, "++++>BMLTextCodecPrivate::decode(0x%2x%2x) invalid return (%i).\n", k1, i2, result);

            		pwc = 0xfffd;
            		off += 2;
            	}
            }

            builder.append((UChar)pwc);
	    }
    }

    return builder.toString();
}

}
#endif

PassOwnPtr<TextCodec> newTextCodec(const TextEncoding& encoding)
{
#if ENABLE(BML_DRCS)
	return adoptPtr(new BMLTextCodec());
#else
    MutexLocker lock(encodingRegistryMutex());

    ASSERT(textCodecMap);

    auto it = textCodecMap->find(encoding.name());

    if(it == textCodecMap->end())
    	it = textCodecMap->find(UTF8Encoding().name());

    return it->second.function(encoding, it->second.additionalData);
#endif
}

ASCIILiteral atomicCanonicalTextEncodingName(const char* name)
{
    if (!name || !name[0])
        return ASCIILiteral();
    if (!textEncodingNameMap)
        buildBaseTextCodecMaps();

    MutexLocker lock(encodingRegistryMutex());

    if (ASCIILiteral atomicName = textEncodingNameMap->get<HashTranslatorTextEncodingName>(name))
        return atomicName;
    if (didExtendTextCodecMaps)
        return ASCIILiteral();
    extendTextCodecMaps();
    didExtendTextCodecMaps = true;
    return textEncodingNameMap->get<HashTranslatorTextEncodingName>(name);
}

template <typename CharacterType>
static ASCIILiteral atomicCanonicalTextEncodingName(const CharacterType* characters, size_t length)
{
    char buffer[maxEncodingNameLength + 1];
    size_t j = 0;
    for (size_t i = 0; i < length; ++i) {
    	CharacterType c = characters[i];
        if (j == maxEncodingNameLength)
            return ASCIILiteral();
        buffer[j++] = c;
    }
    buffer[j] = 0;
    return atomicCanonicalTextEncodingName(buffer);
}

ASCIILiteral atomicCanonicalTextEncodingName(const String& alias)
{
    if (!alias.length())
        return ASCIILiteral();

    if (alias.is8Bit())
        return atomicCanonicalTextEncodingName(alias.characters8(), alias.length());

    return atomicCanonicalTextEncodingName(alias.characters16(), alias.length());
}

bool noExtendedTextEncodingNameUsed()
{
    // If the calling thread did not use extended encoding names, it is fine for it to use a stale false value.
    return !didExtendTextCodecMaps;
}

#ifndef NDEBUG
void dumpTextEncodingNameMap()
{
    unsigned size = textEncodingNameMap->size();
    fprintf(stderr, "Dumping %u entries in WebCore::textEncodingNameMap...\n", size);

    MutexLocker lock(encodingRegistryMutex());

    TextEncodingNameMap::const_iterator it = textEncodingNameMap->begin();
    TextEncodingNameMap::const_iterator end = textEncodingNameMap->end();
    for (; it != end; ++it)
        fprintf(stderr, "'%s' => '%s'\n", it->first, it->second);
}
#endif

} // namespace WebCore
