Back to index

lightning-sunbird  0.9+nobinonly
nsNativeCharsetUtils.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2002
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Darin Fisher <darin@netscape.com>
00023  *   Brian Stell <bstell@ix.netcom.com>
00024  *   Frank Tang <ftang@netscape.com>
00025  *   Brendan Eich <brendan@mozilla.org>
00026  *   Sergei Dolgov <sergei_d@fi.fi.tartu.ee>
00027  *   Jungshik Shin <jshin@i18nl10n.com>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either the GNU General Public License Version 2 or later (the "GPL"), or
00031  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 #include "xpcom-private.h"
00044 
00045 //-----------------------------------------------------------------------------
00046 // XP_MACOSX or XP_BEOS
00047 //-----------------------------------------------------------------------------
00048 #if defined(XP_BEOS) || defined(XP_MACOSX)
00049 
00050 #include "nsAString.h"
00051 #include "nsReadableUtils.h"
00052 #include "nsString.h"
00053 
00054 NS_COM nsresult
00055 NS_CopyNativeToUnicode(const nsACString &input, nsAString  &output)
00056 {
00057     CopyUTF8toUTF16(input, output);
00058     return NS_OK;
00059 }
00060 
00061 NS_COM nsresult
00062 NS_CopyUnicodeToNative(const nsAString  &input, nsACString &output)
00063 {
00064     CopyUTF16toUTF8(input, output);
00065     return NS_OK;
00066 }
00067 
00068 NS_COM PRBool
00069 NS_IsNativeUTF8()
00070 {
00071     return PR_TRUE;
00072 }
00073 
00074 void
00075 NS_StartupNativeCharsetUtils()
00076 {
00077 }
00078 
00079 void
00080 NS_ShutdownNativeCharsetUtils()
00081 {
00082 }
00083 
00084 
00085 //-----------------------------------------------------------------------------
00086 // XP_UNIX
00087 //-----------------------------------------------------------------------------
00088 #elif defined(XP_UNIX)
00089 
00090 #include <stdlib.h>   // mbtowc, wctomb
00091 #include <locale.h>   // setlocale
00092 #include "nscore.h"
00093 #include "prlock.h"
00094 #include "nsAString.h"
00095 #include "nsReadableUtils.h"
00096 
00097 //
00098 // choose a conversion library.  we used to use mbrtowc/wcrtomb under Linux,
00099 // but that doesn't work for non-BMP characters whether we use '-fshort-wchar'
00100 // or not (see bug 206811 and 
00101 // news://news.mozilla.org:119/bajml3$fvr1@ripley.netscape.com). we now use
00102 // iconv for all platforms where nltypes.h and nllanginfo.h are present 
00103 // along with iconv.
00104 //
00105 #if defined(HAVE_ICONV) && defined(HAVE_NL_TYPES_H) && defined(HAVE_LANGINFO_CODESET)
00106 #define USE_ICONV 1
00107 #else
00108 #define USE_STDCONV 1
00109 #endif
00110 
00111 static void
00112 isolatin1_to_utf16(const char **input, PRUint32 *inputLeft, PRUnichar **output, PRUint32 *outputLeft)
00113 {
00114     while (*inputLeft && *outputLeft) {
00115         **output = (unsigned char) **input;
00116         (*input)++;
00117         (*inputLeft)--;
00118         (*output)++;
00119         (*outputLeft)--;
00120     }
00121 }
00122 
00123 static void
00124 utf16_to_isolatin1(const PRUnichar **input, PRUint32 *inputLeft, char **output, PRUint32 *outputLeft)
00125 {
00126     while (*inputLeft && *outputLeft) {
00127         **output = (unsigned char) **input;
00128         (*input)++;
00129         (*inputLeft)--;
00130         (*output)++;
00131         (*outputLeft)--;
00132     }
00133 }
00134 
00135 //-----------------------------------------------------------------------------
00136 // conversion using iconv
00137 //-----------------------------------------------------------------------------
00138 #if defined(USE_ICONV)
00139 #include <nl_types.h> // CODESET
00140 #include <langinfo.h> // nl_langinfo
00141 #include <iconv.h>    // iconv_open, iconv, iconv_close
00142 #include <errno.h>
00143 #include "plstr.h"
00144 
00145 #if defined(HAVE_ICONV_WITH_CONST_INPUT)
00146 #define ICONV_INPUT(x) (x)
00147 #else
00148 #define ICONV_INPUT(x) ((char **)x)
00149 #endif
00150 
00151 // solaris definitely needs this, but we'll enable it by default
00152 // just in case... but we know for sure that iconv(3) in glibc
00153 // doesn't need this.
00154 #if !defined(__GLIBC__)
00155 #define ENABLE_UTF8_FALLBACK_SUPPORT
00156 #endif
00157 
00158 #define INVALID_ICONV_T ((iconv_t) -1)
00159 
00160 static inline size_t
00161 xp_iconv(iconv_t converter,
00162          const char **input,
00163          size_t      *inputLeft,
00164          char       **output,
00165          size_t      *outputLeft)
00166 {
00167     size_t res, outputAvail = outputLeft ? *outputLeft : 0;
00168     res = iconv(converter, ICONV_INPUT(input), inputLeft, output, outputLeft);
00169     if (res == (size_t) -1) {
00170         // on some platforms (e.g., linux) iconv will fail with
00171         // E2BIG if it cannot convert _all_ of its input.  it'll
00172         // still adjust all of the in/out params correctly, so we
00173         // can ignore this error.  the assumption is that we will
00174         // be called again to complete the conversion.
00175         if ((errno == E2BIG) && (*outputLeft < outputAvail))
00176             res = 0;
00177     }
00178     return res;
00179 }
00180 
00181 static inline void
00182 xp_iconv_reset(iconv_t converter)
00183 {
00184     // NOTE: the man pages on Solaris claim that you can pass NULL
00185     // for all parameter to reset the converter, but beware the 
00186     // evil Solaris crash if you go down this route >:-)
00187     
00188     const char *zero_char_in_ptr  = NULL;
00189     char       *zero_char_out_ptr = NULL;
00190     size_t      zero_size_in      = 0,
00191                 zero_size_out     = 0;
00192 
00193     xp_iconv(converter, &zero_char_in_ptr,
00194                         &zero_size_in,
00195                         &zero_char_out_ptr,
00196                         &zero_size_out);
00197 }
00198 
00199 static inline iconv_t
00200 xp_iconv_open(const char **to_list, const char **from_list)
00201 {
00202     iconv_t res;
00203     const char **from_name;
00204     const char **to_name;
00205 
00206     // try all possible combinations to locate a converter.
00207     to_name = to_list;
00208     while (*to_name) {
00209         if (**to_name) {
00210             from_name = from_list;
00211             while (*from_name) {
00212                 if (**from_name) {
00213                     res = iconv_open(*to_name, *from_name);
00214                     if (res != INVALID_ICONV_T)
00215                         return res;
00216                 }
00217                 from_name++;
00218             }
00219         }
00220         to_name++;
00221     }
00222 
00223     return INVALID_ICONV_T;
00224 }
00225 
00226 /* 
00227  * PRUnichar[] is NOT a UCS-2 array BUT a UTF-16 string. Therefore, we
00228  * have to use UTF-16 with iconv(3) on platforms where it's supported.
00229  * However, the way UTF-16 and UCS-2 are interpreted varies across platforms 
00230  * and implementations of iconv(3). On Tru64, it also depends on the environment
00231  * variable. To avoid the trouble arising from byte-swapping 
00232  * (bug 208809), we have to try UTF-16LE/BE and UCS-2LE/BE before falling 
00233  * back to UTF-16 and UCS-2 and variants. We assume that UTF-16 and UCS-2 
00234  * on systems without UTF-16LE/BE and UCS-2LE/BE have the native endianness,
00235  * which isn't the case of glibc 2.1.x, for which we use 'UNICODELITTLE'
00236  * and 'UNICODEBIG'. It's also not true of Tru64 V4 when the environment
00237  * variable ICONV_BYTEORDER is set to 'big-endian', about which not much 
00238  * can be done other than adding a note in the release notes. (bug 206811)
00239  */
00240 static const char *UTF_16_NAMES[] = {
00241 #if defined(IS_LITTLE_ENDIAN)
00242     "UTF-16LE",
00243 #if defined(__GLIBC__)
00244     "UNICODELITTLE",
00245 #endif
00246     "UCS-2LE",
00247 #else
00248     "UTF-16BE",
00249 #if defined(__GLIBC__)
00250     "UNICODEBIG",
00251 #endif
00252     "UCS-2BE",
00253 #endif
00254     "UTF-16",
00255     "UCS-2",
00256     "UCS2",
00257     "UCS_2",
00258     "ucs-2",
00259     "ucs2",
00260     "ucs_2",
00261     NULL
00262 };
00263 
00264 #if defined(ENABLE_UTF8_FALLBACK_SUPPORT)
00265 static const char *UTF_8_NAMES[] = {
00266     "UTF-8",
00267     "UTF8",
00268     "UTF_8",
00269     "utf-8",
00270     "utf8",
00271     "utf_8",
00272     NULL
00273 };
00274 #endif
00275 
00276 static const char *ISO_8859_1_NAMES[] = {
00277     "ISO-8859-1",
00278 #if !defined(__GLIBC__)
00279     "ISO8859-1",
00280     "ISO88591",
00281     "ISO_8859_1",
00282     "ISO8859_1",
00283     "iso-8859-1",
00284     "iso8859-1",
00285     "iso88591",
00286     "iso_8859_1",
00287     "iso8859_1",
00288 #endif
00289     NULL
00290 };
00291 
00292 class nsNativeCharsetConverter
00293 {
00294 public:
00295     nsNativeCharsetConverter();
00296    ~nsNativeCharsetConverter();
00297 
00298     nsresult NativeToUnicode(const char      **input , PRUint32 *inputLeft,
00299                              PRUnichar       **output, PRUint32 *outputLeft);
00300     nsresult UnicodeToNative(const PRUnichar **input , PRUint32 *inputLeft,
00301                              char            **output, PRUint32 *outputLeft);
00302 
00303     static void GlobalInit();
00304     static void GlobalShutdown();
00305     static PRBool IsNativeUTF8();
00306 
00307 private:
00308     static iconv_t gNativeToUnicode;
00309     static iconv_t gUnicodeToNative;
00310 #if defined(ENABLE_UTF8_FALLBACK_SUPPORT)
00311     static iconv_t gNativeToUTF8;
00312     static iconv_t gUTF8ToNative;
00313     static iconv_t gUnicodeToUTF8;
00314     static iconv_t gUTF8ToUnicode;
00315 #endif
00316     static PRLock *gLock;
00317     static PRBool  gInitialized;
00318     static PRBool  gIsNativeUTF8;
00319 
00320     static void LazyInit();
00321 
00322     static void Lock()   { if (gLock) PR_Lock(gLock);   }
00323     static void Unlock() { if (gLock) PR_Unlock(gLock); }
00324 };
00325 
00326 iconv_t nsNativeCharsetConverter::gNativeToUnicode = INVALID_ICONV_T;
00327 iconv_t nsNativeCharsetConverter::gUnicodeToNative = INVALID_ICONV_T;
00328 #if defined(ENABLE_UTF8_FALLBACK_SUPPORT)
00329 iconv_t nsNativeCharsetConverter::gNativeToUTF8    = INVALID_ICONV_T;
00330 iconv_t nsNativeCharsetConverter::gUTF8ToNative    = INVALID_ICONV_T;
00331 iconv_t nsNativeCharsetConverter::gUnicodeToUTF8   = INVALID_ICONV_T;
00332 iconv_t nsNativeCharsetConverter::gUTF8ToUnicode   = INVALID_ICONV_T;
00333 #endif
00334 PRLock *nsNativeCharsetConverter::gLock            = nsnull;
00335 PRBool  nsNativeCharsetConverter::gInitialized     = PR_FALSE;
00336 PRBool  nsNativeCharsetConverter::gIsNativeUTF8    = PR_FALSE;
00337 
00338 void
00339 nsNativeCharsetConverter::LazyInit()
00340 {
00341     const char  *blank_list[] = { "", NULL };
00342     const char **native_charset_list = blank_list;
00343     const char  *native_charset = nl_langinfo(CODESET);
00344     if (native_charset == nsnull) {
00345         NS_ERROR("native charset is unknown");
00346         // fallback to ISO-8859-1
00347         native_charset_list = ISO_8859_1_NAMES;
00348     }
00349     else
00350         native_charset_list[0] = native_charset;
00351 
00352     // Most, if not all, Unixen supporting UTF-8 and nl_langinfo(CODESET) 
00353     // return 'UTF-8' (or 'utf-8')
00354     if (!PL_strcasecmp(native_charset, "UTF-8"))
00355         gIsNativeUTF8 = PR_TRUE;
00356 
00357     gNativeToUnicode = xp_iconv_open(UTF_16_NAMES, native_charset_list);
00358     gUnicodeToNative = xp_iconv_open(native_charset_list, UTF_16_NAMES);
00359 
00360 #if defined(ENABLE_UTF8_FALLBACK_SUPPORT)
00361     if (gNativeToUnicode == INVALID_ICONV_T) {
00362         gNativeToUTF8 = xp_iconv_open(UTF_8_NAMES, native_charset_list);
00363         gUTF8ToUnicode = xp_iconv_open(UTF_16_NAMES, UTF_8_NAMES);
00364         NS_ASSERTION(gNativeToUTF8 != INVALID_ICONV_T, "no native to utf-8 converter");
00365         NS_ASSERTION(gUTF8ToUnicode != INVALID_ICONV_T, "no utf-8 to utf-16 converter");
00366     }
00367     if (gUnicodeToNative == INVALID_ICONV_T) {
00368         gUnicodeToUTF8 = xp_iconv_open(UTF_8_NAMES, UTF_16_NAMES);
00369         gUTF8ToNative = xp_iconv_open(native_charset_list, UTF_8_NAMES);
00370         NS_ASSERTION(gUnicodeToUTF8 != INVALID_ICONV_T, "no utf-16 to utf-8 converter");
00371         NS_ASSERTION(gUTF8ToNative != INVALID_ICONV_T, "no utf-8 to native converter");
00372     }
00373 #else
00374     NS_ASSERTION(gNativeToUnicode != INVALID_ICONV_T, "no native to utf-16 converter");
00375     NS_ASSERTION(gUnicodeToNative != INVALID_ICONV_T, "no utf-16 to native converter");
00376 #endif
00377 
00378     /*
00379      * On Solaris 8 (and newer?), the iconv modules converting to UCS-2
00380      * prepend a byte order mark unicode character (BOM, u+FEFF) during
00381      * the first use of the iconv converter. The same is the case of 
00382      * glibc 2.2.9x and Tru64 V5 (see bug 208809) when 'UTF-16' is used. 
00383      * However, we use 'UTF-16LE/BE' in both cases, instead so that we 
00384      * should be safe. But just in case...
00385      *
00386      * This dummy conversion gets rid of the BOMs and fixes bug 153562.
00387      */
00388     char dummy_input[1] = { ' ' };
00389     char dummy_output[4];
00390 
00391     if (gNativeToUnicode != INVALID_ICONV_T) {
00392        const char *input = dummy_input;
00393        size_t input_left = sizeof(dummy_input);
00394        char *output = dummy_output;
00395        size_t output_left = sizeof(dummy_output);
00396 
00397        xp_iconv(gNativeToUnicode, &input, &input_left, &output, &output_left);
00398     }
00399 #if defined(ENABLE_UTF8_FALLBACK_SUPPORT)
00400     if (gUTF8ToUnicode != INVALID_ICONV_T) {
00401        const char *input = dummy_input;
00402        size_t input_left = sizeof(dummy_input);
00403        char *output = dummy_output;
00404        size_t output_left = sizeof(dummy_output);
00405 
00406        xp_iconv(gUTF8ToUnicode, &input, &input_left, &output, &output_left);
00407     }
00408 #endif
00409 
00410     gInitialized = PR_TRUE;
00411 }
00412 
00413 void
00414 nsNativeCharsetConverter::GlobalInit()
00415 {
00416     gLock = PR_NewLock();
00417     NS_ASSERTION(gLock, "lock creation failed");
00418 }
00419 
00420 void
00421 nsNativeCharsetConverter::GlobalShutdown()
00422 {
00423     if (gLock) {
00424         PR_DestroyLock(gLock);
00425         gLock = nsnull;
00426     }
00427 
00428     if (gNativeToUnicode != INVALID_ICONV_T) {
00429         iconv_close(gNativeToUnicode);
00430         gNativeToUnicode = INVALID_ICONV_T;
00431     }
00432 
00433     if (gUnicodeToNative != INVALID_ICONV_T) {
00434         iconv_close(gUnicodeToNative);
00435         gUnicodeToNative = INVALID_ICONV_T;
00436     }
00437 
00438 #if defined(ENABLE_UTF8_FALLBACK_SUPPORT)
00439     if (gNativeToUTF8 != INVALID_ICONV_T) {
00440         iconv_close(gNativeToUTF8);
00441         gNativeToUTF8 = INVALID_ICONV_T;
00442     }
00443     if (gUTF8ToNative != INVALID_ICONV_T) {
00444         iconv_close(gUTF8ToNative);
00445         gUTF8ToNative = INVALID_ICONV_T;
00446     }
00447     if (gUnicodeToUTF8 != INVALID_ICONV_T) {
00448         iconv_close(gUnicodeToUTF8);
00449         gUnicodeToUTF8 = INVALID_ICONV_T;
00450     }
00451     if (gUTF8ToUnicode != INVALID_ICONV_T) {
00452         iconv_close(gUTF8ToUnicode);
00453         gUTF8ToUnicode = INVALID_ICONV_T;
00454     }
00455 #endif
00456 
00457     gInitialized = PR_FALSE;
00458 }
00459 
00460 nsNativeCharsetConverter::nsNativeCharsetConverter()
00461 {
00462     Lock();
00463     if (!gInitialized)
00464         LazyInit();
00465 }
00466 
00467 nsNativeCharsetConverter::~nsNativeCharsetConverter()
00468 {
00469     // reset converters for next time
00470     if (gNativeToUnicode != INVALID_ICONV_T)
00471         xp_iconv_reset(gNativeToUnicode);
00472     if (gUnicodeToNative != INVALID_ICONV_T)
00473         xp_iconv_reset(gUnicodeToNative);
00474 #if defined(ENABLE_UTF8_FALLBACK_SUPPORT)
00475     if (gNativeToUTF8 != INVALID_ICONV_T)
00476         xp_iconv_reset(gNativeToUTF8);
00477     if (gUTF8ToNative != INVALID_ICONV_T)
00478         xp_iconv_reset(gUTF8ToNative);
00479     if (gUnicodeToUTF8 != INVALID_ICONV_T)
00480         xp_iconv_reset(gUnicodeToUTF8);
00481     if (gUTF8ToUnicode != INVALID_ICONV_T)
00482         xp_iconv_reset(gUTF8ToUnicode);
00483 #endif
00484     Unlock();
00485 }
00486 
00487 nsresult
00488 nsNativeCharsetConverter::NativeToUnicode(const char **input,
00489                                           PRUint32    *inputLeft,
00490                                           PRUnichar  **output,
00491                                           PRUint32    *outputLeft)
00492 {
00493     size_t res = 0;
00494     size_t inLeft = (size_t) *inputLeft;
00495     size_t outLeft = (size_t) *outputLeft * 2;
00496 
00497     if (gNativeToUnicode != INVALID_ICONV_T) {
00498 
00499         res = xp_iconv(gNativeToUnicode, input, &inLeft, (char **) output, &outLeft);
00500 
00501         *inputLeft = inLeft;
00502         *outputLeft = outLeft / 2;
00503         if (res != (size_t) -1) 
00504             return NS_OK;
00505 
00506         NS_WARNING("conversion from native to utf-16 failed");
00507 
00508         // reset converter
00509         xp_iconv_reset(gNativeToUnicode);
00510     }
00511 #if defined(ENABLE_UTF8_FALLBACK_SUPPORT)
00512     else if ((gNativeToUTF8 != INVALID_ICONV_T) &&
00513              (gUTF8ToUnicode != INVALID_ICONV_T)) {
00514         // convert first to UTF8, then from UTF8 to UCS2
00515         const char *in = *input;
00516 
00517         char ubuf[1024];
00518 
00519         // we assume we're always called with enough space in |output|,
00520         // so convert many chars at a time...
00521         while (inLeft) {
00522             char *p = ubuf;
00523             size_t n = sizeof(ubuf);
00524             res = xp_iconv(gNativeToUTF8, &in, &inLeft, &p, &n);
00525             if (res == (size_t) -1) {
00526                 NS_ERROR("conversion from native to utf-8 failed");
00527                 break;
00528             }
00529             NS_ASSERTION(outLeft > 0, "bad assumption");
00530             p = ubuf;
00531             n = sizeof(ubuf) - n;
00532             res = xp_iconv(gUTF8ToUnicode, (const char **) &p, &n, (char **) output, &outLeft);
00533             if (res == (size_t) -1) {
00534                 NS_ERROR("conversion from utf-8 to utf-16 failed");
00535                 break;
00536             }
00537         }
00538 
00539         (*input) += (*inputLeft - inLeft);
00540         *inputLeft = inLeft;
00541         *outputLeft = outLeft / 2;
00542 
00543         if (res != (size_t) -1) 
00544             return NS_OK;
00545 
00546         // reset converters
00547         xp_iconv_reset(gNativeToUTF8);
00548         xp_iconv_reset(gUTF8ToUnicode);
00549     }
00550 #endif
00551 
00552     // fallback: zero-pad and hope for the best
00553     // XXX This is lame and we have to do better.
00554     isolatin1_to_utf16(input, inputLeft, output, outputLeft);
00555 
00556     return NS_OK;
00557 }
00558 
00559 nsresult
00560 nsNativeCharsetConverter::UnicodeToNative(const PRUnichar **input,
00561                                           PRUint32         *inputLeft,
00562                                           char            **output,
00563                                           PRUint32         *outputLeft)
00564 {
00565     size_t res = 0;
00566     size_t inLeft = (size_t) *inputLeft * 2;
00567     size_t outLeft = (size_t) *outputLeft;
00568 
00569     if (gUnicodeToNative != INVALID_ICONV_T) {
00570         res = xp_iconv(gUnicodeToNative, (const char **) input, &inLeft, output, &outLeft);
00571 
00572         if (res != (size_t) -1) {
00573             *inputLeft = inLeft / 2;
00574             *outputLeft = outLeft;
00575             return NS_OK;
00576         }
00577 
00578         NS_ERROR("iconv failed");
00579 
00580         // reset converter
00581         xp_iconv_reset(gUnicodeToNative);
00582     }
00583 #if defined(ENABLE_UTF8_FALLBACK_SUPPORT)
00584     else if ((gUnicodeToUTF8 != INVALID_ICONV_T) &&
00585              (gUTF8ToNative != INVALID_ICONV_T)) {
00586         const char *in = (const char *) *input;
00587 
00588         char ubuf[6]; // max utf-8 char length (really only needs to be 4 bytes)
00589 
00590         // convert one uchar at a time...
00591         while (inLeft && outLeft) {
00592             char *p = ubuf;
00593             size_t n = sizeof(ubuf), one_uchar = sizeof(PRUnichar);
00594             res = xp_iconv(gUnicodeToUTF8, &in, &one_uchar, &p, &n);
00595             if (res == (size_t) -1) {
00596                 NS_ERROR("conversion from utf-16 to utf-8 failed");
00597                 break;
00598             }
00599             p = ubuf;
00600             n = sizeof(ubuf) - n;
00601             res = xp_iconv(gUTF8ToNative, (const char **) &p, &n, output, &outLeft);
00602             if (res == (size_t) -1) {
00603                 if (errno == E2BIG) {
00604                     // not enough room for last uchar... back up and return.
00605                     in -= sizeof(PRUnichar);
00606                     res = 0;
00607                 }
00608                 else
00609                     NS_ERROR("conversion from utf-8 to native failed");
00610                 break;
00611             }
00612             inLeft -= sizeof(PRUnichar);
00613         }
00614 
00615         if (res != (size_t) -1) {
00616             (*input) += (*inputLeft - inLeft/2);
00617             *inputLeft = inLeft/2;
00618             *outputLeft = outLeft;
00619             return NS_OK;
00620         }
00621 
00622         // reset converters
00623         xp_iconv_reset(gUnicodeToUTF8);
00624         xp_iconv_reset(gUTF8ToNative);
00625     }
00626 #endif
00627 
00628     // fallback: truncate and hope for the best
00629     utf16_to_isolatin1(input, inputLeft, output, outputLeft);
00630 
00631     return NS_OK;
00632 }
00633 
00634 PRBool
00635 nsNativeCharsetConverter::IsNativeUTF8()
00636 {
00637     if (!gInitialized) {
00638         Lock();
00639         if (!gInitialized)
00640            LazyInit();
00641         Unlock();
00642     }
00643     return gIsNativeUTF8; 
00644 }
00645 
00646 #endif // USE_ICONV
00647 
00648 //-----------------------------------------------------------------------------
00649 // conversion using mb[r]towc/wc[r]tomb
00650 //-----------------------------------------------------------------------------
00651 #if defined(USE_STDCONV)
00652 #if defined(HAVE_WCRTOMB) || defined(HAVE_MBRTOWC)
00653 #include <wchar.h>    // mbrtowc, wcrtomb
00654 #endif
00655 
00656 class nsNativeCharsetConverter
00657 {
00658 public:
00659     nsNativeCharsetConverter();
00660 
00661     nsresult NativeToUnicode(const char      **input , PRUint32 *inputLeft,
00662                              PRUnichar       **output, PRUint32 *outputLeft);
00663     nsresult UnicodeToNative(const PRUnichar **input , PRUint32 *inputLeft,
00664                              char            **output, PRUint32 *outputLeft);
00665 
00666     static void GlobalInit();
00667     static void GlobalShutdown() { }
00668     static PRBool IsNativeUTF8();
00669 
00670 private:
00671     static PRBool gWCharIsUnicode;
00672 
00673 #if defined(HAVE_WCRTOMB) || defined(HAVE_MBRTOWC)
00674     mbstate_t ps;
00675 #endif
00676 };
00677 
00678 PRBool nsNativeCharsetConverter::gWCharIsUnicode = PR_FALSE;
00679 
00680 nsNativeCharsetConverter::nsNativeCharsetConverter()
00681 {
00682 #if defined(HAVE_WCRTOMB) || defined(HAVE_MBRTOWC)
00683     memset(&ps, 0, sizeof(ps));
00684 #endif
00685 }
00686 
00687 void
00688 nsNativeCharsetConverter::GlobalInit()
00689 {
00690     // verify that wchar_t for the current locale is actually unicode.
00691     // if it is not, then we should avoid calling mbtowc/wctomb and
00692     // just fallback on zero-pad/truncation conversion.
00693     //
00694     // this test cannot be done at build time because the encoding of
00695     // wchar_t may depend on the runtime locale.  sad, but true!!
00696     //
00697     // so, if wchar_t is unicode then converting an ASCII character
00698     // to wchar_t should not change its numeric value.  we'll just
00699     // check what happens with the ASCII 'a' character.
00700     //
00701     // this test is not perfect... obviously, it could yield false
00702     // positives, but then at least ASCII text would be converted
00703     // properly (or maybe just the 'a' character) -- oh well :(
00704 
00705     char a = 'a';
00706     unsigned int w = 0;
00707 
00708     int res = mbtowc((wchar_t *) &w, &a, 1);
00709 
00710     gWCharIsUnicode = (res != -1 && w == 'a');
00711 
00712 #ifdef DEBUG
00713     if (!gWCharIsUnicode)
00714         NS_WARNING("wchar_t is not unicode (unicode conversion will be lossy)");
00715 #endif
00716 }
00717 
00718 nsresult
00719 nsNativeCharsetConverter::NativeToUnicode(const char **input,
00720                                           PRUint32    *inputLeft,
00721                                           PRUnichar  **output,
00722                                           PRUint32    *outputLeft)
00723 {
00724     if (gWCharIsUnicode) {
00725         int incr;
00726 
00727         // cannot use wchar_t here since it may have been redefined (e.g.,
00728         // via -fshort-wchar).  hopefully, sizeof(tmp) is sufficient XP.
00729         unsigned int tmp = 0;
00730         while (*inputLeft && *outputLeft) {
00731 #ifdef HAVE_MBRTOWC
00732             incr = (int) mbrtowc((wchar_t *) &tmp, *input, *inputLeft, &ps);
00733 #else
00734             // XXX is this thread-safe?
00735             incr = (int) mbtowc((wchar_t *) &tmp, *input, *inputLeft);
00736 #endif
00737             if (incr < 0) {
00738                 NS_WARNING("mbtowc failed: possible charset mismatch");
00739                 // zero-pad and hope for the best
00740                 tmp = (unsigned char) **input;
00741                 incr = 1;
00742             }
00743             **output = (PRUnichar) tmp;
00744             (*input) += incr;
00745             (*inputLeft) -= incr;
00746             (*output)++;
00747             (*outputLeft)--;
00748         }
00749     }
00750     else {
00751         // wchar_t isn't unicode, so the best we can do is treat the
00752         // input as if it is isolatin1 :(
00753         isolatin1_to_utf16(input, inputLeft, output, outputLeft);
00754     }
00755 
00756     return NS_OK;
00757 }
00758 
00759 nsresult
00760 nsNativeCharsetConverter::UnicodeToNative(const PRUnichar **input,
00761                                           PRUint32         *inputLeft,
00762                                           char            **output,
00763                                           PRUint32         *outputLeft)
00764 {
00765     if (gWCharIsUnicode) {
00766         int incr;
00767 
00768         while (*inputLeft && *outputLeft >= MB_CUR_MAX) {
00769 #ifdef HAVE_WCRTOMB
00770             incr = (int) wcrtomb(*output, (wchar_t) **input, &ps);
00771 #else
00772             // XXX is this thread-safe?
00773             incr = (int) wctomb(*output, (wchar_t) **input);
00774 #endif
00775             if (incr < 0) {
00776                 NS_WARNING("mbtowc failed: possible charset mismatch");
00777                 **output = (unsigned char) **input; // truncate
00778                 incr = 1;
00779             }
00780             // most likely we're dead anyways if this assertion should fire
00781             NS_ASSERTION(PRUint32(incr) <= *outputLeft, "wrote beyond end of string");
00782             (*output) += incr;
00783             (*outputLeft) -= incr;
00784             (*input)++;
00785             (*inputLeft)--;
00786         }
00787     }
00788     else {
00789         // wchar_t isn't unicode, so the best we can do is treat the
00790         // input as if it is isolatin1 :(
00791         utf16_to_isolatin1(input, inputLeft, output, outputLeft);
00792     }
00793 
00794     return NS_OK;
00795 }
00796 
00797 // XXX : for now, return false
00798 PRBool
00799 nsNativeCharsetConverter::IsNativeUTF8()
00800 {
00801     return PR_FALSE;
00802 }
00803 
00804 #endif // USE_STDCONV
00805 
00806 //-----------------------------------------------------------------------------
00807 // API implementation
00808 //-----------------------------------------------------------------------------
00809 
00810 NS_COM nsresult
00811 NS_CopyNativeToUnicode(const nsACString &input, nsAString &output)
00812 {
00813     output.Truncate();
00814 
00815     PRUint32 inputLen = input.Length();
00816 
00817     nsACString::const_iterator iter;
00818     input.BeginReading(iter);
00819 
00820     //
00821     // OPTIMIZATION: preallocate space for largest possible result; convert
00822     // directly into the result buffer to avoid intermediate buffer copy.
00823     //
00824     // this will generally result in a larger allocation, but that seems
00825     // better than an extra buffer copy.
00826     //
00827     if (!EnsureStringLength(output, inputLen))
00828         return NS_ERROR_OUT_OF_MEMORY;
00829     nsAString::iterator out_iter;
00830     output.BeginWriting(out_iter);
00831 
00832     PRUnichar *result = out_iter.get();
00833     PRUint32 resultLeft = inputLen;
00834 
00835     const char *buf = iter.get();
00836     PRUint32 bufLeft = inputLen;
00837 
00838     nsNativeCharsetConverter conv;
00839     nsresult rv = conv.NativeToUnicode(&buf, &bufLeft, &result, &resultLeft);
00840     if (NS_SUCCEEDED(rv)) {
00841         NS_ASSERTION(bufLeft == 0, "did not consume entire input buffer");
00842         output.SetLength(inputLen - resultLeft);
00843     }
00844     return rv;
00845 }
00846 
00847 NS_COM nsresult
00848 NS_CopyUnicodeToNative(const nsAString &input, nsACString &output)
00849 {
00850     output.Truncate();
00851 
00852     nsAString::const_iterator iter, end;
00853     input.BeginReading(iter);
00854     input.EndReading(end);
00855 
00856     // cannot easily avoid intermediate buffer copy.
00857     char temp[4096];
00858 
00859     nsNativeCharsetConverter conv;
00860 
00861     const PRUnichar *buf = iter.get();
00862     PRUint32 bufLeft = Distance(iter, end);
00863     while (bufLeft) {
00864         char *p = temp;
00865         PRUint32 tempLeft = sizeof(temp);
00866 
00867         nsresult rv = conv.UnicodeToNative(&buf, &bufLeft, &p, &tempLeft);
00868         if (NS_FAILED(rv)) return rv;
00869 
00870         if (tempLeft < sizeof(temp))
00871             output.Append(temp, sizeof(temp) - tempLeft);
00872     }
00873     return NS_OK;
00874 }
00875 
00876 NS_COM PRBool
00877 NS_IsNativeUTF8()
00878 {
00879     return nsNativeCharsetConverter::IsNativeUTF8();
00880 }
00881 
00882 void
00883 NS_StartupNativeCharsetUtils()
00884 {
00885     //
00886     // need to initialize the locale or else charset conversion will fail.
00887     // better not delay this in case some other component alters the locale
00888     // settings.
00889     //
00890     // XXX we assume that we are called early enough that we should
00891     // always be the first to care about the locale's charset.
00892     //
00893     setlocale(LC_CTYPE, "");
00894 
00895     nsNativeCharsetConverter::GlobalInit();
00896 }
00897 
00898 void
00899 NS_ShutdownNativeCharsetUtils()
00900 {
00901     nsNativeCharsetConverter::GlobalShutdown();
00902 }
00903 
00904 //-----------------------------------------------------------------------------
00905 // XP_WIN
00906 //-----------------------------------------------------------------------------
00907 #elif defined(XP_WIN)
00908 
00909 #include <windows.h>
00910 #include "nsAString.h"
00911 #include "nsReadableUtils.h"
00912 
00913 NS_COM nsresult
00914 NS_CopyNativeToUnicode(const nsACString &input, nsAString &output)
00915 {
00916     PRUint32 inputLen = input.Length();
00917 
00918     nsACString::const_iterator iter;
00919     input.BeginReading(iter);
00920 
00921     const char *buf = iter.get();
00922 
00923     // determine length of result
00924     PRUint32 resultLen = 0;
00925     int n = ::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, NULL, 0);
00926     if (n > 0)
00927         resultLen += n;
00928 
00929     // allocate sufficient space
00930     if (!EnsureStringLength(output, resultLen))
00931         return NS_ERROR_OUT_OF_MEMORY;
00932     if (resultLen > 0) {
00933         nsAString::iterator out_iter;
00934         output.BeginWriting(out_iter);
00935 
00936         PRUnichar *result = out_iter.get();
00937 
00938         ::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, result, resultLen);
00939     }
00940     return NS_OK;
00941 }
00942 
00943 NS_COM nsresult
00944 NS_CopyUnicodeToNative(const nsAString  &input, nsACString &output)
00945 {
00946     PRUint32 inputLen = input.Length();
00947 
00948     nsAString::const_iterator iter;
00949     input.BeginReading(iter);
00950 
00951     const PRUnichar *buf = iter.get();
00952 
00953     // determine length of result
00954     PRUint32 resultLen = 0;
00955 
00956     int n = ::WideCharToMultiByte(CP_ACP, 0, buf, inputLen, NULL, 0, NULL, NULL);
00957     if (n > 0)
00958         resultLen += n;
00959 
00960     // allocate sufficient space
00961     if (!EnsureStringLength(output, resultLen))
00962         return NS_ERROR_OUT_OF_MEMORY;
00963     if (resultLen > 0) {
00964         nsACString::iterator out_iter;
00965         output.BeginWriting(out_iter);
00966 
00967         // default "defaultChar" is '?', which is an illegal character on windows
00968         // file system.  That will cause file uncreatable. Change it to '_'
00969         const char defaultChar = '_';
00970 
00971         char *result = out_iter.get();
00972 
00973         ::WideCharToMultiByte(CP_ACP, 0, buf, inputLen, result, resultLen,
00974                               &defaultChar, NULL);
00975     }
00976     return NS_OK;
00977 }
00978 
00979 NS_COM PRBool
00980 NS_IsNativeUTF8()
00981 {
00982     return PR_FALSE;
00983 }
00984 
00985 // moved from widget/src/windows/nsToolkit.cpp
00986 NS_COM PRInt32 
00987 NS_ConvertAtoW(const char *aStrInA, int aBufferSize, PRUnichar *aStrOutW)
00988 {
00989     return MultiByteToWideChar(CP_ACP, 0, aStrInA, -1, aStrOutW, aBufferSize);
00990 }
00991 
00992 NS_COM PRInt32 
00993 NS_ConvertWtoA(const PRUnichar *aStrInW, int aBufferSizeOut, char *aStrOutA,
00994                const char *aDefault)
00995 {
00996     if ((!aStrInW) || (!aStrOutA) || (aBufferSizeOut <= 0))
00997         return 0;
00998 
00999     int numCharsConverted = WideCharToMultiByte(CP_ACP, 0, aStrInW, -1, 
01000                                                 aStrOutA, aBufferSizeOut,
01001                                                 aDefault, NULL);
01002 
01003     if (!numCharsConverted) {
01004         if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
01005             // Overflow, add missing null termination but return 0
01006             aStrOutA[aBufferSizeOut-1] = '\0';
01007         }
01008         else {
01009             // Other error, clear string and return 0
01010             aStrOutA[0] = '\0';
01011         }
01012     }
01013     else if (numCharsConverted < aBufferSizeOut) {
01014         // Add 2nd null (really necessary?)
01015         aStrOutA[numCharsConverted] = '\0';
01016     }
01017 
01018     return numCharsConverted;
01019 }
01020 
01021 //-----------------------------------------------------------------------------
01022 // XP_OS2
01023 //-----------------------------------------------------------------------------
01024 #elif defined(XP_OS2)
01025 
01026 #define INCL_DOS
01027 #include <os2.h>
01028 #include <uconv.h>
01029 #include "nsAString.h"
01030 #include "nsReadableUtils.h"
01031 #include <ulserrno.h>
01032 #include "nsNativeCharsetUtils.h"
01033 
01034 static UconvObject UnicodeConverter = NULL;
01035 
01036 NS_COM nsresult
01037 NS_CopyNativeToUnicode(const nsACString &input, nsAString  &output)
01038 {
01039     PRUint32 inputLen = input.Length();
01040 
01041     nsACString::const_iterator iter;
01042     input.BeginReading(iter);
01043     const char *inputStr = iter.get();
01044 
01045     // determine length of result
01046     PRUint32 resultLen = inputLen;
01047     if (!EnsureStringLength(output, resultLen))
01048         return NS_ERROR_OUT_OF_MEMORY;
01049 
01050     nsAString::iterator out_iter;
01051     output.BeginWriting(out_iter);
01052     UniChar *result = (UniChar*)out_iter.get();
01053 
01054     size_t cSubs = 0;
01055     size_t resultLeft = resultLen;
01056 
01057     if (!UnicodeConverter)
01058       NS_StartupNativeCharsetUtils();
01059 
01060     int unirc = ::UniUconvToUcs(UnicodeConverter, (void**)&inputStr, &inputLen,
01061                                 &result, &resultLeft, &cSubs);
01062 
01063     NS_ASSERTION(unirc != UCONV_E2BIG, "Path too big");
01064 
01065     if (unirc != ULS_SUCCESS) {
01066         output.Truncate();
01067         return NS_ERROR_FAILURE;
01068     }
01069 
01070     // Need to update string length to reflect how many bytes were actually
01071     // written.
01072     output.Truncate(resultLen - resultLeft);
01073     return NS_OK;
01074 }
01075 
01076 NS_COM nsresult
01077 NS_CopyUnicodeToNative(const nsAString &input, nsACString &output)
01078 {
01079     size_t inputLen = input.Length();
01080 
01081     nsAString::const_iterator iter;
01082     input.BeginReading(iter);
01083     UniChar* inputStr = (UniChar*) NS_CONST_CAST(PRUnichar*, iter.get());
01084 
01085     // maximum length of unicode string of length x converted to native
01086     // codepage is x*2
01087     size_t resultLen = inputLen * 2;
01088     if (!EnsureStringLength(output, resultLen))
01089         return NS_ERROR_OUT_OF_MEMORY;
01090 
01091     nsACString::iterator out_iter;
01092     output.BeginWriting(out_iter);
01093     char *result = out_iter.get();
01094 
01095     size_t cSubs = 0;
01096     size_t resultLeft = resultLen;
01097 
01098     if (!UnicodeConverter)
01099       NS_StartupNativeCharsetUtils();
01100   
01101     int unirc = ::UniUconvFromUcs(UnicodeConverter, &inputStr, &inputLen,
01102                                   (void**)&result, &resultLeft, &cSubs);
01103 
01104     NS_ASSERTION(unirc != UCONV_E2BIG, "Path too big");
01105   
01106     if (unirc != ULS_SUCCESS) {
01107         output.Truncate();
01108         return NS_ERROR_FAILURE;
01109     }
01110 
01111     // Need to update string length to reflect how many bytes were actually
01112     // written.
01113     output.Truncate(resultLen - resultLeft);
01114     return NS_OK;
01115 }
01116 
01117 NS_COM PRBool
01118 NS_IsNativeUTF8()
01119 {
01120     return PR_FALSE;
01121 }
01122 
01123 void
01124 NS_StartupNativeCharsetUtils()
01125 {
01126     ULONG ulLength;
01127     ULONG ulCodePage;
01128     DosQueryCp(sizeof(ULONG), &ulCodePage, &ulLength);
01129 
01130     UniChar codepage[20];
01131     int unirc = ::UniMapCpToUcsCp(ulCodePage, codepage, 20);
01132     if (unirc == ULS_SUCCESS) {
01133         unirc = ::UniCreateUconvObject(codepage, &UnicodeConverter);
01134         if (unirc == ULS_SUCCESS) {
01135             uconv_attribute_t attr;
01136             ::UniQueryUconvObject(UnicodeConverter, &attr, sizeof(uconv_attribute_t), 
01137                                   NULL, NULL, NULL);
01138             attr.options = UCONV_OPTION_SUBSTITUTE_BOTH;
01139             attr.subchar_len=1;
01140             attr.subchar[0]='_';
01141             ::UniSetUconvObject(UnicodeConverter, &attr);
01142         }
01143     }
01144 }
01145 
01146 void
01147 NS_ShutdownNativeCharsetUtils()
01148 {
01149     ::UniFreeUconvObject(UnicodeConverter);
01150 }
01151 
01152 //-----------------------------------------------------------------------------
01153 // XP_MAC
01154 //-----------------------------------------------------------------------------
01155 #elif defined(XP_MAC)
01156 
01157 #include <UnicodeConverter.h>
01158 #include <TextCommon.h>
01159 #include <Script.h>
01160 #include <MacErrors.h>
01161 #include "nsAString.h"
01162 #include "nsReadableUtils.h"
01163 
01164 class nsFSStringConversionMac {
01165 public:
01166      static nsresult UCSToFS(const nsAString& aIn, nsACString& aOut);  
01167      static nsresult FSToUCS(const nsACString& ain, nsAString& aOut);  
01168 
01169      static void CleanUp();
01170 
01171 private:
01172      static TextEncoding GetSystemEncoding();
01173      static nsresult PrepareEncoder();
01174      static nsresult PrepareDecoder();
01175      
01176      static UnicodeToTextInfo sEncoderInfo;
01177      static TextToUnicodeInfo sDecoderInfo;
01178 };
01179 
01180 UnicodeToTextInfo nsFSStringConversionMac::sEncoderInfo = nsnull;
01181 TextToUnicodeInfo nsFSStringConversionMac::sDecoderInfo = nsnull;
01182 
01183 nsresult nsFSStringConversionMac::UCSToFS(const nsAString& aIn, nsACString& aOut)
01184 {
01185     nsresult rv = PrepareEncoder();
01186     if (NS_FAILED(rv)) return rv;
01187     
01188     OSStatus err = noErr;
01189     char stackBuffer[512];
01190 
01191     aOut.Truncate();
01192 
01193     // for each chunk of |aIn|...
01194     nsReadingIterator<PRUnichar> iter;
01195     aIn.BeginReading(iter);
01196 
01197     PRUint32 fragmentLength = PRUint32(iter.size_forward());        
01198     UInt32 bytesLeft = fragmentLength * sizeof(UniChar);
01199         
01200     do {
01201         UInt32 bytesRead = 0, bytesWritten = 0;
01202         err = ::ConvertFromUnicodeToText(sEncoderInfo,
01203                                          bytesLeft,
01204                                          (const UniChar*)iter.get(),
01205                                          kUnicodeUseFallbacksMask | kUnicodeLooseMappingsMask,
01206                                          0, nsnull, nsnull, nsnull,
01207                                          sizeof(stackBuffer),
01208                                          &bytesRead,
01209                                          &bytesWritten,
01210                                          stackBuffer);
01211         if (err == kTECUsedFallbacksStatus)
01212             err = noErr;
01213         else if (err == kTECOutputBufferFullStatus) {
01214             bytesLeft -= bytesRead;
01215             iter.advance(bytesRead / sizeof(UniChar));
01216         }
01217         aOut.Append(stackBuffer, bytesWritten);
01218     }
01219     while (err == kTECOutputBufferFullStatus);
01220 
01221     return (err == noErr) ? NS_OK : NS_ERROR_FAILURE;
01222 }
01223 
01224 nsresult nsFSStringConversionMac::FSToUCS(const nsACString& aIn, nsAString& aOut)
01225 {
01226     nsresult rv = PrepareDecoder();
01227     if (NS_FAILED(rv)) return rv;
01228     
01229     OSStatus err = noErr;
01230     UniChar stackBuffer[512];
01231 
01232     aOut.Truncate(0);
01233 
01234     // for each chunk of |aIn|...
01235     nsReadingIterator<char> iter;
01236     aIn.BeginReading(iter);
01237 
01238     PRUint32 fragmentLength = PRUint32(iter.size_forward());        
01239     UInt32 bytesLeft = fragmentLength;
01240     
01241     do {
01242         UInt32 bytesRead = 0, bytesWritten = 0;
01243         err = ::ConvertFromTextToUnicode(sDecoderInfo,
01244                                          bytesLeft,
01245                                          iter.get(),
01246                                          kUnicodeUseFallbacksMask | kUnicodeLooseMappingsMask,
01247                                          0, nsnull, nsnull, nsnull,
01248                                          sizeof(stackBuffer),
01249                                          &bytesRead,
01250                                          &bytesWritten,
01251                                          stackBuffer);
01252         if (err == kTECUsedFallbacksStatus)
01253             err = noErr;
01254         else if (err == kTECOutputBufferFullStatus) {
01255             bytesLeft -= bytesRead;
01256             iter.advance(bytesRead);
01257         }
01258         aOut.Append((PRUnichar *)stackBuffer, bytesWritten / sizeof(PRUnichar));
01259     }
01260     while (err == kTECOutputBufferFullStatus);
01261 
01262     return (err == noErr) ? NS_OK : NS_ERROR_FAILURE;
01263 }
01264 
01265 void nsFSStringConversionMac::CleanUp()
01266 {
01267     if (sDecoderInfo) {
01268         ::DisposeTextToUnicodeInfo(&sDecoderInfo);
01269         sDecoderInfo = nsnull;
01270     }
01271     if (sEncoderInfo) {
01272         ::DisposeUnicodeToTextInfo(&sEncoderInfo);
01273         sEncoderInfo = nsnull;
01274     }  
01275 }
01276 
01277 TextEncoding nsFSStringConversionMac::GetSystemEncoding()
01278 {
01279     OSStatus err;
01280     TextEncoding theEncoding;
01281     
01282     err = ::UpgradeScriptInfoToTextEncoding(smSystemScript, kTextLanguageDontCare,
01283         kTextRegionDontCare, NULL, &theEncoding);
01284     
01285     if (err != noErr)
01286         theEncoding = kTextEncodingMacRoman;
01287     
01288     return theEncoding;
01289 }
01290 
01291 nsresult nsFSStringConversionMac::PrepareEncoder()
01292 {
01293     nsresult rv = NS_OK;
01294     if (!sEncoderInfo) {
01295         OSStatus err;
01296         err = ::CreateUnicodeToTextInfoByEncoding(GetSystemEncoding(), &sEncoderInfo);
01297         if (err)
01298             rv = NS_ERROR_FAILURE;
01299     }
01300     return rv;
01301 }
01302 
01303 nsresult nsFSStringConversionMac::PrepareDecoder()
01304 {
01305     nsresult rv = NS_OK;
01306     if (!sDecoderInfo) {
01307         OSStatus err;
01308         err = ::CreateTextToUnicodeInfoByEncoding(GetSystemEncoding(), &sDecoderInfo);
01309         if (err)
01310             rv = NS_ERROR_FAILURE;
01311     }
01312     return rv;
01313 }
01314 
01315 NS_COM nsresult
01316 NS_CopyNativeToUnicode(const nsACString &input, nsAString  &output)
01317 {
01318     return nsFSStringConversionMac::FSToUCS(input, output);
01319 }
01320 
01321 NS_COM nsresult
01322 NS_CopyUnicodeToNative(const nsAString  &input, nsACString &output)
01323 {
01324     return nsFSStringConversionMac::UCSToFS(input, output);
01325 }
01326 
01327 NS_COM PRBool
01328 NS_IsNativeUTF8()
01329 {
01330     return PR_FALSE;
01331 }
01332 
01333 void
01334 NS_StartupNativeCharsetUtils()
01335 {
01336 }
01337 
01338 void
01339 NS_ShutdownNativeCharsetUtils()
01340 {
01341     nsFSStringConversionMac::CleanUp();
01342 }
01343 
01344 //-----------------------------------------------------------------------------
01345 // default : truncate/zeropad
01346 //-----------------------------------------------------------------------------
01347 #else
01348 
01349 #include "nsReadableUtils.h"
01350 
01351 NS_COM nsresult
01352 NS_CopyNativeToUnicode(const nsACString &input, nsAString  &output)
01353 {
01354     CopyASCIItoUCS2(input, output);
01355     return NS_OK;
01356 }
01357 
01358 NS_COM nsresult
01359 NS_CopyUnicodeToNative(const nsAString  &input, nsACString &output)
01360 {
01361     CopyUCS2toASCII(input, output);
01362     return NS_OK;
01363 }
01364 
01365 NS_COM PRBool
01366 NS_IsNativeUTF8()
01367 {
01368     return PR_FALSE;
01369 }
01370 
01371 void
01372 NS_StartupNativeCharsetUtils()
01373 {
01374 }
01375 
01376 void
01377 NS_ShutdownNativeCharsetUtils()
01378 {
01379 }
01380 
01381 #endif