1/* 2 * Copyright (C) 2010 Company 100, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "TextCodecBrew.h" 28 29#include "AEEAppGen.h" 30#include "AEEICharsetConv.h" 31#include "NotImplemented.h" 32#include "PlatformString.h" 33#include <wtf/Assertions.h> 34#include <wtf/text/CString.h> 35 36namespace WebCore { 37 38// FIXME: Not sure if there are Brew MP devices which use big endian. 39const char* WebCore::TextCodecBrew::m_internalEncodingName = "UTF-16LE"; 40 41static PassOwnPtr<TextCodec> newTextCodecBrew(const TextEncoding& encoding, const void*) 42{ 43 return new TextCodecBrew(encoding); 44} 45 46void TextCodecBrew::registerExtendedEncodingNames(EncodingNameRegistrar registrar) 47{ 48 // FIXME: Not sure how to enumerate all available encodings. 49 notImplemented(); 50} 51 52void TextCodecBrew::registerExtendedCodecs(TextCodecRegistrar registrar) 53{ 54 notImplemented(); 55} 56 57TextCodecBrew::TextCodecBrew(const TextEncoding& encoding) 58 : m_charsetConverter(0) 59 , m_encoding(encoding) 60 , m_numBufferedBytes(0) 61{ 62 String format = String::format("%s>%s", encoding.name(), m_internalEncodingName); 63 64 IShell* shell = reinterpret_cast<AEEApplet*>(GETAPPINSTANCE())->m_pIShell; 65 AEECLSID classID = ISHELL_GetHandler(shell, AEEIID_ICharsetConv, format.latin1().data()); 66 ISHELL_CreateInstance(shell, classID, reinterpret_cast<void**>(&m_charsetConverter)); 67 68 ASSERT(m_charsetConverter); 69} 70 71TextCodecBrew::~TextCodecBrew() 72{ 73 if (m_charsetConverter) 74 ICharsetConv_Release(m_charsetConverter); 75} 76 77String TextCodecBrew::decode(const char* bytes, size_t length, bool flush, bool stopOnError, bool& sawError) 78{ 79 int code = ICharsetConv_Initialize(m_charsetConverter, m_encoding.name(), m_internalEncodingName, 0); 80 ASSERT(code == AEE_SUCCESS); 81 82 Vector<UChar> result; 83 Vector<unsigned char> prefixedBytes(length); 84 85 int srcSize; 86 unsigned char* srcBegin; 87 88 if (m_numBufferedBytes) { 89 srcSize = length + m_numBufferedBytes; 90 prefixedBytes.grow(srcSize); 91 memcpy(prefixedBytes.data(), m_bufferedBytes, m_numBufferedBytes); 92 memcpy(prefixedBytes.data() + m_numBufferedBytes, bytes, length); 93 94 srcBegin = prefixedBytes.data(); 95 96 // all buffered bytes are consumed now 97 m_numBufferedBytes = 0; 98 } else { 99 srcSize = length; 100 srcBegin = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(bytes)); 101 } 102 103 unsigned char* src = srcBegin; 104 unsigned char* srcEnd = srcBegin + srcSize; 105 106 Vector<UChar> dstBuffer(srcSize); 107 108 while (src < srcEnd) { 109 int numCharsConverted; 110 unsigned char* dstBegin = reinterpret_cast<unsigned char*>(dstBuffer.data()); 111 unsigned char* dst = dstBegin; 112 int dstSize = dstBuffer.size() * sizeof(UChar); 113 114 code = ICharsetConv_CharsetConvert(m_charsetConverter, &src, &srcSize, &dst, &dstSize, &numCharsConverted); 115 ASSERT(code != AEE_ENOSUCH); 116 117 if (code == AEE_EBUFFERTOOSMALL) { 118 // Increase the buffer and try it again. 119 dstBuffer.grow(dstBuffer.size() * 2); 120 continue; 121 } 122 123 if (code == AEE_EBADITEM) { 124 sawError = true; 125 if (stopOnError) { 126 result.append(L'?'); 127 break; 128 } 129 130 src++; 131 } 132 133 if (code == AEE_EINCOMPLETEITEM) { 134 if (flush) { 135 LOG_ERROR("Partial bytes at end of input while flush requested."); 136 sawError = true; 137 return String(); 138 } 139 140 m_numBufferedBytes = srcEnd - src; 141 memcpy(m_bufferedBytes, src, m_numBufferedBytes); 142 break; 143 } 144 145 int numChars = (dst - dstBegin) / sizeof(UChar); 146 if (numChars > 0) 147 result.append(dstBuffer.data(), numChars); 148 } 149 150 return String::adopt(result); 151} 152 153CString TextCodecBrew::encode(const UChar* characters, size_t length, UnencodableHandling handling) 154{ 155 if (!length) 156 return ""; 157 158 unsigned int replacementCharacter = '?'; 159 160 // FIXME: Impossible to handle EntitiesForUnencodables or URLEncodedEntitiesForUnencodables with ICharsetConv. 161 int code = ICharsetConv_Initialize(m_charsetConverter, m_internalEncodingName, m_encoding.name(), replacementCharacter); 162 ASSERT(code == AEE_SUCCESS); 163 164 Vector<char> result; 165 166 int srcSize = length * sizeof(UChar); 167 unsigned char* srcBegin = const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(characters)); 168 unsigned char* src = srcBegin; 169 unsigned char* srcEnd = srcBegin + srcSize; 170 171 Vector<unsigned char> dstBuffer(length * sizeof(UChar)); 172 173 while (src < srcEnd) { 174 int numCharsConverted; 175 unsigned char* dstBegin = dstBuffer.data(); 176 unsigned char* dst = dstBegin; 177 int dstSize = dstBuffer.size(); 178 179 code = ICharsetConv_CharsetConvert(m_charsetConverter, &src, &srcSize, &dst, &dstSize, &numCharsConverted); 180 ASSERT(code != AEE_EINCOMPLETEITEM); 181 182 if (code == AEE_ENOSUCH) { 183 LOG_ERROR("Conversion error, Code=%d", code); 184 return CString(); 185 } 186 187 if (code == AEE_EBUFFERTOOSMALL) { 188 // Increase the buffer and try it again. 189 dstBuffer.grow(dstBuffer.size() * 2); 190 continue; 191 } 192 193 if (code == AEE_EBADITEM) 194 src += sizeof(UChar); // Skip the invalid character 195 196 int numBytes = dst - dstBegin; 197 if (numBytes > 0) 198 result.append(dstBuffer.data(), numBytes); 199 } 200 201 return CString(result.data(), result.size()); 202} 203 204} // namespace WebCore 205