Back to index

lightning-sunbird  0.9+nobinonly
nsScriptableUConv.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Makoto Kato <m_kato@ga2.so-net.ne.jp >
00024  *   Ryoichi Furukawa <oliver@1000cp.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "pratom.h"
00041 #include "nsString.h"
00042 #include "nsReadableUtils.h"
00043 #include "nsIServiceManager.h"
00044 #include "nsICharsetConverterManager.h"
00045 #include "nsIScriptableUConv.h"
00046 #include "nsScriptableUConv.h"
00047 #include "nsIStringStream.h"
00048 #include "nsCRT.h"
00049 
00050 #include "nsIPlatformCharset.h"
00051 
00052 static PRInt32          gInstanceCount = 0;
00053 
00054 /* Implementation file */
00055 NS_IMPL_ISUPPORTS1(nsScriptableUnicodeConverter, nsIScriptableUnicodeConverter)
00056 
00057 nsScriptableUnicodeConverter::nsScriptableUnicodeConverter()
00058 {
00059   PR_AtomicIncrement(&gInstanceCount);
00060 }
00061 
00062 nsScriptableUnicodeConverter::~nsScriptableUnicodeConverter()
00063 {
00064   PR_AtomicDecrement(&gInstanceCount);
00065 }
00066 
00067 nsresult
00068 nsScriptableUnicodeConverter::ConvertFromUnicodeWithLength(const nsAString& aSrc,
00069                                                            PRInt32* aOutLen,
00070                                                            char **_retval)
00071 {
00072   if (!mEncoder)
00073     return NS_ERROR_FAILURE;
00074 
00075   nsresult rv = NS_OK;
00076   PRInt32 inLength = aSrc.Length();
00077   const nsAFlatString& flatSrc = PromiseFlatString(aSrc);
00078   rv = mEncoder->GetMaxLength(flatSrc.get(), inLength, aOutLen);
00079   if (NS_SUCCEEDED(rv)) {
00080     *_retval = (char*) nsMemory::Alloc(*aOutLen+1);
00081     if (!*_retval)
00082       return NS_ERROR_OUT_OF_MEMORY;
00083 
00084     rv = mEncoder->Convert(flatSrc.get(), &inLength, *_retval, aOutLen);
00085     if (NS_SUCCEEDED(rv))
00086     {
00087       (*_retval)[*aOutLen] = '\0';
00088       return NS_OK;
00089     }
00090     nsMemory::Free(*_retval);
00091   }
00092   *_retval = nsnull;
00093   return NS_ERROR_FAILURE;
00094 }
00095 
00096 /* ACString ConvertFromUnicode (in AString src); */
00097 NS_IMETHODIMP
00098 nsScriptableUnicodeConverter::ConvertFromUnicode(const nsAString& aSrc,
00099                                                  nsACString& _retval)
00100 {
00101   PRInt32 len;
00102   char* str;
00103   nsresult rv = ConvertFromUnicodeWithLength(aSrc, &len, &str);
00104   if (NS_SUCCEEDED(rv)) {
00105     // No Adopt on nsACString :(
00106     _retval.Assign(str, len);
00107     nsMemory::Free(str);
00108   }
00109   return rv;
00110 }
00111 
00112 nsresult
00113 nsScriptableUnicodeConverter::FinishWithLength(char **_retval, PRInt32* aLength)
00114 {
00115   if (!mEncoder)
00116     return NS_ERROR_FAILURE;
00117 
00118   PRInt32 finLength = 32;
00119 
00120   *_retval = (char *) nsMemory::Alloc(finLength);
00121   if (!*_retval)
00122     return NS_ERROR_OUT_OF_MEMORY;
00123 
00124   nsresult rv = mEncoder->Finish(*_retval, &finLength);
00125   if (NS_SUCCEEDED(rv))
00126     (*_retval)[finLength] = '\0';
00127   else
00128     nsMemory::Free(*_retval);
00129 
00130   *aLength = finLength;
00131 
00132   return rv;
00133 
00134 }
00135 
00136 /* ACString Finish(); */
00137 NS_IMETHODIMP
00138 nsScriptableUnicodeConverter::Finish(nsACString& _retval)
00139 {
00140   PRInt32 len;
00141   char* str;
00142   nsresult rv = FinishWithLength(&str, &len);
00143   if (NS_SUCCEEDED(rv)) {
00144     // No Adopt on nsACString :(
00145     _retval.Assign(str, len);
00146     nsMemory::Free(str);
00147   }
00148   return rv;
00149 }
00150 
00151 /* AString ConvertToUnicode (in ACString src); */
00152 NS_IMETHODIMP
00153 nsScriptableUnicodeConverter::ConvertToUnicode(const nsACString& aSrc, nsAString& _retval)
00154 {
00155   nsACString::const_iterator i;
00156   aSrc.BeginReading(i);
00157   return ConvertFromByteArray(NS_REINTERPRET_CAST(const PRUint8*, i.get()),
00158                               aSrc.Length(),
00159                               _retval);
00160 }
00161 
00162 /* AString convertFromByteArray([const,array,size_is(aCount)] in octet aData,
00163                                 in unsigned long aCount);
00164  */
00165 NS_IMETHODIMP
00166 nsScriptableUnicodeConverter::ConvertFromByteArray(const PRUint8* aData,
00167                                                    PRUint32 aCount,
00168                                                    nsAString& _retval)
00169 {
00170   if (!mDecoder)
00171     return NS_ERROR_FAILURE;
00172 
00173   nsresult rv = NS_OK;
00174   PRInt32 inLength = aCount;
00175   PRInt32 outLength;
00176   rv = mDecoder->GetMaxLength(NS_REINTERPRET_CAST(const char*, aData),
00177                               inLength, &outLength);
00178   if (NS_SUCCEEDED(rv))
00179   {
00180     PRUnichar* buf = (PRUnichar*) nsMemory::Alloc((outLength+1)*sizeof(PRUnichar));
00181     if (!buf)
00182       return NS_ERROR_OUT_OF_MEMORY;
00183 
00184     rv = mDecoder->Convert(NS_REINTERPRET_CAST(const char*, aData),
00185                            &inLength, buf, &outLength);
00186     if (NS_SUCCEEDED(rv))
00187     {
00188       buf[outLength] = 0;
00189       _retval.Assign(buf, outLength);
00190     }
00191     nsMemory::Free(buf);
00192     return rv;
00193   }
00194   return NS_ERROR_FAILURE;
00195 
00196 }
00197 
00198 /* void convertToByteArray(in AString aString,
00199                           out unsigned long aLen,
00200                           [array, size_is(aLen),retval] out octet aData);
00201  */
00202 NS_IMETHODIMP
00203 nsScriptableUnicodeConverter::ConvertToByteArray(const nsAString& aString,
00204                                                  PRUint32* aLen,
00205                                                  PRUint8** _aData)
00206 {
00207   char* data;
00208   PRInt32 len;
00209   nsresult rv = ConvertFromUnicodeWithLength(aString, &len, &data);
00210   if (NS_FAILED(rv))
00211     return rv;
00212   nsXPIDLCString str;
00213   str.Adopt(data, len); // NOTE: This uses the XPIDLCString as a byte array
00214 
00215   rv = FinishWithLength(&data, &len);
00216   if (NS_FAILED(rv))
00217     return rv;
00218 
00219   str.Append(data, len);
00220   // NOTE: this being a byte array, it needs no null termination
00221   *_aData = NS_REINTERPRET_CAST(PRUint8*,
00222                                 nsMemory::Clone(str.get(), str.Length()));
00223   if (!*_aData)
00224     return NS_ERROR_OUT_OF_MEMORY;
00225   *aLen = str.Length();
00226   return NS_OK;
00227 }
00228 
00229 /* nsIInputStream convertToInputStream(in AString aString); */
00230 NS_IMETHODIMP
00231 nsScriptableUnicodeConverter::ConvertToInputStream(const nsAString& aString,
00232                                                    nsIInputStream** _retval)
00233 {
00234   nsresult rv;
00235   nsCOMPtr<nsIStringInputStream> inputStream =
00236     do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
00237   if (NS_FAILED(rv))
00238     return rv;
00239 
00240   PRUint8* data;
00241   PRUint32 dataLen;
00242   rv = ConvertToByteArray(aString, &dataLen, &data);
00243   if (NS_FAILED(rv))
00244     return rv;
00245 
00246   rv = inputStream->AdoptData(NS_REINTERPRET_CAST(char*, data), dataLen);
00247   if (NS_FAILED(rv)) {
00248     nsMemory::Free(data);
00249     return rv;
00250   }
00251 
00252   NS_ADDREF(*_retval = inputStream);
00253   return rv;
00254 }
00255 
00256 /* attribute string charset; */
00257 NS_IMETHODIMP
00258 nsScriptableUnicodeConverter::GetCharset(char * *aCharset)
00259 {
00260   *aCharset = ToNewCString(mCharset);
00261   if (!*aCharset)
00262     return NS_ERROR_OUT_OF_MEMORY;
00263 
00264   return NS_OK;
00265 }
00266 
00267 NS_IMETHODIMP
00268 nsScriptableUnicodeConverter::SetCharset(const char * aCharset)
00269 {
00270   mCharset.Assign(aCharset);
00271   return InitConverter();
00272 }
00273 
00274 nsresult
00275 nsScriptableUnicodeConverter::InitConverter()
00276 {
00277   nsresult rv = NS_OK;
00278   mEncoder = NULL ;
00279 
00280   nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
00281 
00282   if (NS_SUCCEEDED( rv) && (nsnull != ccm)) {
00283     // get charset atom due to getting unicode converter
00284     
00285     // get an unicode converter
00286     rv = ccm->GetUnicodeEncoder(mCharset.get(), getter_AddRefs(mEncoder));
00287     if(NS_SUCCEEDED(rv)) {
00288       rv = mEncoder->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace, nsnull, (PRUnichar)'?');
00289       if(NS_SUCCEEDED(rv)) {
00290         rv = ccm->GetUnicodeDecoder(mCharset.get(), getter_AddRefs(mDecoder));
00291       }
00292     }
00293   }
00294 
00295   return rv ;
00296 }