1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Makoto Kato <m_kato@ga2.so-net.ne.jp >
24 : * Ryoichi Furukawa <oliver@1000cp.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "nsAtomicRefcnt.h"
41 : #include "nsString.h"
42 : #include "nsReadableUtils.h"
43 : #include "nsIServiceManager.h"
44 : #include "nsICharsetConverterManager.h"
45 : #include "nsIScriptableUConv.h"
46 : #include "nsScriptableUConv.h"
47 : #include "nsIStringStream.h"
48 : #include "nsCRT.h"
49 : #include "nsComponentManagerUtils.h"
50 :
51 : static PRInt32 gInstanceCount = 0;
52 :
53 : /* Implementation file */
54 13023 : NS_IMPL_ISUPPORTS1(nsScriptableUnicodeConverter, nsIScriptableUnicodeConverter)
55 :
56 616 : nsScriptableUnicodeConverter::nsScriptableUnicodeConverter()
57 616 : : mIsInternal(false)
58 : {
59 616 : PR_ATOMIC_INCREMENT(&gInstanceCount);
60 616 : }
61 :
62 1848 : nsScriptableUnicodeConverter::~nsScriptableUnicodeConverter()
63 : {
64 616 : PR_ATOMIC_DECREMENT(&gInstanceCount);
65 2464 : }
66 :
67 : nsresult
68 3968 : nsScriptableUnicodeConverter::ConvertFromUnicodeWithLength(const nsAString& aSrc,
69 : PRInt32* aOutLen,
70 : char **_retval)
71 : {
72 3968 : if (!mEncoder)
73 0 : return NS_ERROR_FAILURE;
74 :
75 3968 : nsresult rv = NS_OK;
76 3968 : PRInt32 inLength = aSrc.Length();
77 7936 : const nsAFlatString& flatSrc = PromiseFlatString(aSrc);
78 3968 : rv = mEncoder->GetMaxLength(flatSrc.get(), inLength, aOutLen);
79 3968 : if (NS_SUCCEEDED(rv)) {
80 3968 : *_retval = (char*)moz_malloc(*aOutLen+1);
81 3968 : if (!*_retval)
82 0 : return NS_ERROR_OUT_OF_MEMORY;
83 :
84 3968 : rv = mEncoder->Convert(flatSrc.get(), &inLength, *_retval, aOutLen);
85 3968 : if (NS_SUCCEEDED(rv))
86 : {
87 3968 : (*_retval)[*aOutLen] = '\0';
88 3968 : return NS_OK;
89 : }
90 0 : moz_free(*_retval);
91 : }
92 0 : *_retval = nsnull;
93 0 : return NS_ERROR_FAILURE;
94 : }
95 :
96 : /* ACString ConvertFromUnicode (in AString src); */
97 : NS_IMETHODIMP
98 3150 : nsScriptableUnicodeConverter::ConvertFromUnicode(const nsAString& aSrc,
99 : nsACString& _retval)
100 : {
101 : PRInt32 len;
102 : char* str;
103 3150 : nsresult rv = ConvertFromUnicodeWithLength(aSrc, &len, &str);
104 3150 : if (NS_SUCCEEDED(rv)) {
105 : // No Adopt on nsACString :(
106 3150 : _retval.Assign(str, len);
107 3150 : moz_free(str);
108 : }
109 3150 : return rv;
110 : }
111 :
112 : nsresult
113 606175 : nsScriptableUnicodeConverter::FinishWithLength(char **_retval, PRInt32* aLength)
114 : {
115 606175 : if (!mEncoder)
116 0 : return NS_ERROR_FAILURE;
117 :
118 606175 : PRInt32 finLength = 32;
119 :
120 606175 : *_retval = (char *)moz_malloc(finLength);
121 606175 : if (!*_retval)
122 0 : return NS_ERROR_OUT_OF_MEMORY;
123 :
124 606175 : nsresult rv = mEncoder->Finish(*_retval, &finLength);
125 606175 : if (NS_SUCCEEDED(rv))
126 606175 : *aLength = finLength;
127 : else
128 0 : moz_free(*_retval);
129 :
130 606175 : return rv;
131 :
132 : }
133 :
134 : /* ACString Finish(); */
135 : NS_IMETHODIMP
136 605357 : nsScriptableUnicodeConverter::Finish(nsACString& _retval)
137 : {
138 : PRInt32 len;
139 : char* str;
140 605357 : nsresult rv = FinishWithLength(&str, &len);
141 605357 : if (NS_SUCCEEDED(rv)) {
142 : // No Adopt on nsACString :(
143 605357 : _retval.Assign(str, len);
144 605357 : moz_free(str);
145 : }
146 605357 : return rv;
147 : }
148 :
149 : /* AString ConvertToUnicode (in ACString src); */
150 : NS_IMETHODIMP
151 615576 : nsScriptableUnicodeConverter::ConvertToUnicode(const nsACString& aSrc, nsAString& _retval)
152 : {
153 615576 : nsACString::const_iterator i;
154 615576 : aSrc.BeginReading(i);
155 615576 : return ConvertFromByteArray(reinterpret_cast<const PRUint8*>(i.get()),
156 : aSrc.Length(),
157 1231152 : _retval);
158 : }
159 :
160 : /* AString convertFromByteArray([const,array,size_is(aCount)] in octet aData,
161 : in unsigned long aCount);
162 : */
163 : NS_IMETHODIMP
164 615576 : nsScriptableUnicodeConverter::ConvertFromByteArray(const PRUint8* aData,
165 : PRUint32 aCount,
166 : nsAString& _retval)
167 : {
168 615576 : if (!mDecoder)
169 0 : return NS_ERROR_FAILURE;
170 :
171 615576 : nsresult rv = NS_OK;
172 615576 : PRInt32 inLength = aCount;
173 : PRInt32 outLength;
174 615576 : rv = mDecoder->GetMaxLength(reinterpret_cast<const char*>(aData),
175 615576 : inLength, &outLength);
176 615576 : if (NS_SUCCEEDED(rv))
177 : {
178 615576 : PRUnichar* buf = (PRUnichar*)moz_malloc((outLength+1)*sizeof(PRUnichar));
179 615576 : if (!buf)
180 0 : return NS_ERROR_OUT_OF_MEMORY;
181 :
182 615576 : rv = mDecoder->Convert(reinterpret_cast<const char*>(aData),
183 615576 : &inLength, buf, &outLength);
184 615576 : if (NS_SUCCEEDED(rv))
185 : {
186 614924 : buf[outLength] = 0;
187 614924 : _retval.Assign(buf, outLength);
188 : }
189 615576 : moz_free(buf);
190 615576 : return rv;
191 : }
192 0 : return NS_ERROR_FAILURE;
193 :
194 : }
195 :
196 : /* void convertToByteArray(in AString aString,
197 : [optional] out unsigned long aLen,
198 : [array, size_is(aLen),retval] out octet aData);
199 : */
200 : NS_IMETHODIMP
201 818 : nsScriptableUnicodeConverter::ConvertToByteArray(const nsAString& aString,
202 : PRUint32* aLen,
203 : PRUint8** _aData)
204 : {
205 : char* data;
206 : PRInt32 len;
207 818 : nsresult rv = ConvertFromUnicodeWithLength(aString, &len, &data);
208 818 : if (NS_FAILED(rv))
209 0 : return rv;
210 1636 : nsXPIDLCString str;
211 818 : str.Adopt(data, len); // NOTE: This uses the XPIDLCString as a byte array
212 :
213 818 : rv = FinishWithLength(&data, &len);
214 818 : if (NS_FAILED(rv))
215 0 : return rv;
216 :
217 818 : str.Append(data, len);
218 818 : moz_free(data);
219 : // NOTE: this being a byte array, it needs no null termination
220 818 : *_aData = reinterpret_cast<PRUint8*>(moz_malloc(str.Length()));
221 818 : if (!*_aData)
222 0 : return NS_ERROR_OUT_OF_MEMORY;
223 818 : memcpy(*_aData, str.get(), str.Length());
224 818 : *aLen = str.Length();
225 818 : return NS_OK;
226 : }
227 :
228 : /* nsIInputStream convertToInputStream(in AString aString); */
229 : NS_IMETHODIMP
230 276 : nsScriptableUnicodeConverter::ConvertToInputStream(const nsAString& aString,
231 : nsIInputStream** _retval)
232 : {
233 : nsresult rv;
234 : nsCOMPtr<nsIStringInputStream> inputStream =
235 552 : do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
236 276 : if (NS_FAILED(rv))
237 0 : return rv;
238 :
239 : PRUint8* data;
240 : PRUint32 dataLen;
241 276 : rv = ConvertToByteArray(aString, &dataLen, &data);
242 276 : if (NS_FAILED(rv))
243 0 : return rv;
244 :
245 276 : rv = inputStream->AdoptData(reinterpret_cast<char*>(data), dataLen);
246 276 : if (NS_FAILED(rv)) {
247 0 : moz_free(data);
248 0 : return rv;
249 : }
250 :
251 276 : NS_ADDREF(*_retval = inputStream);
252 276 : return rv;
253 : }
254 :
255 : /* attribute string charset; */
256 : NS_IMETHODIMP
257 0 : nsScriptableUnicodeConverter::GetCharset(char * *aCharset)
258 : {
259 0 : *aCharset = ToNewCString(mCharset);
260 0 : if (!*aCharset)
261 0 : return NS_ERROR_OUT_OF_MEMORY;
262 :
263 0 : return NS_OK;
264 : }
265 :
266 : NS_IMETHODIMP
267 9941 : nsScriptableUnicodeConverter::SetCharset(const char * aCharset)
268 : {
269 9941 : mCharset.Assign(aCharset);
270 9941 : return InitConverter();
271 : }
272 :
273 : NS_IMETHODIMP
274 0 : nsScriptableUnicodeConverter::GetIsInternal(bool *aIsInternal)
275 : {
276 0 : *aIsInternal = mIsInternal;
277 0 : return NS_OK;
278 : }
279 :
280 : NS_IMETHODIMP
281 8 : nsScriptableUnicodeConverter::SetIsInternal(const bool aIsInternal)
282 : {
283 8 : mIsInternal = aIsInternal;
284 8 : return NS_OK;
285 : }
286 :
287 : nsresult
288 9941 : nsScriptableUnicodeConverter::InitConverter()
289 : {
290 9941 : nsresult rv = NS_OK;
291 9941 : mEncoder = NULL ;
292 :
293 19882 : nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
294 :
295 9941 : if (NS_SUCCEEDED( rv) && (nsnull != ccm)) {
296 : // get charset atom due to getting unicode converter
297 :
298 : // get an unicode converter
299 9941 : rv = ccm->GetUnicodeEncoder(mCharset.get(), getter_AddRefs(mEncoder));
300 9941 : if(NS_SUCCEEDED(rv)) {
301 9937 : rv = mEncoder->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace, nsnull, (PRUnichar)'?');
302 9937 : if(NS_SUCCEEDED(rv)) {
303 : rv = mIsInternal ?
304 18 : ccm->GetUnicodeDecoderInternal(mCharset.get(),
305 9973 : getter_AddRefs(mDecoder)) :
306 9919 : ccm->GetUnicodeDecoder(mCharset.get(),
307 19892 : getter_AddRefs(mDecoder));
308 : }
309 : }
310 : }
311 :
312 9941 : return rv ;
313 : }
|