• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 namespace WebCore {
37 
38 // FIXME: Not sure if there are Brew MP devices which use big endian.
39 const char* WebCore::TextCodecBrew::m_internalEncodingName = "UTF-16LE";
40 
newTextCodecBrew(const TextEncoding & encoding,const void *)41 static PassOwnPtr<TextCodec> newTextCodecBrew(const TextEncoding& encoding, const void*)
42 {
43     return new TextCodecBrew(encoding);
44 }
45 
registerExtendedEncodingNames(EncodingNameRegistrar registrar)46 void TextCodecBrew::registerExtendedEncodingNames(EncodingNameRegistrar registrar)
47 {
48     // FIXME: Not sure how to enumerate all available encodings.
49     notImplemented();
50 }
51 
registerExtendedCodecs(TextCodecRegistrar registrar)52 void TextCodecBrew::registerExtendedCodecs(TextCodecRegistrar registrar)
53 {
54     notImplemented();
55 }
56 
TextCodecBrew(const TextEncoding & encoding)57 TextCodecBrew::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 
~TextCodecBrew()71 TextCodecBrew::~TextCodecBrew()
72 {
73     if (m_charsetConverter)
74         ICharsetConv_Release(m_charsetConverter);
75 }
76 
decode(const char * bytes,size_t length,bool flush,bool stopOnError,bool & sawError)77 String 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 
encode(const UChar * characters,size_t length,UnencodableHandling handling)153 CString 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