Back to index

lightning-sunbird  0.9+nobinonly
UMacUnicode.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla browser.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications, Inc.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Conrad Carlen <ccarlen@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * 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 "UMacUnicode.h"
00041 
00042 #include <TextCommon.h>
00043 #include <Script.h>
00044 
00045 #include "nsString.h"
00046 
00047 static TextEncoding getSystemEncoding()
00048 {
00049     OSStatus err;
00050     TextEncoding theEncoding;
00051     
00052     err = ::UpgradeScriptInfoToTextEncoding(smSystemScript, kTextLanguageDontCare,
00053         kTextRegionDontCare, NULL, &theEncoding);
00054     
00055     if (err != noErr)
00056         theEncoding = kTextEncodingMacRoman;
00057     
00058     return theEncoding;
00059 }
00060 
00061 CPlatformUCSConversion *CPlatformUCSConversion::mgInstance = nsnull; 
00062 UnicodeToTextInfo CPlatformUCSConversion::sEncoderInfo = nsnull;
00063 TextToUnicodeInfo CPlatformUCSConversion::sDecoderInfo = nsnull;
00064 
00065 CPlatformUCSConversion::CPlatformUCSConversion()
00066 {
00067 }
00068 
00069 
00070 CPlatformUCSConversion*
00071 CPlatformUCSConversion::GetInstance()
00072 {
00073     if (!mgInstance)
00074         mgInstance = new CPlatformUCSConversion;
00075         
00076     return mgInstance;
00077 }
00078 
00079 
00080 NS_IMETHODIMP 
00081 CPlatformUCSConversion::PrepareEncoder()
00082 {
00083     nsresult rv = NS_OK;
00084     if (!sEncoderInfo) {
00085         OSStatus err;
00086         err = ::CreateUnicodeToTextInfoByEncoding(getSystemEncoding(), &sEncoderInfo);
00087         if (err)
00088             rv = NS_ERROR_FAILURE;
00089     }
00090     return rv;
00091 }
00092 
00093 
00094 NS_IMETHODIMP 
00095 CPlatformUCSConversion::PrepareDecoder()
00096 {
00097     nsresult rv = NS_OK;
00098     if (!sDecoderInfo) {
00099         OSStatus err;
00100         err = ::CreateTextToUnicodeInfoByEncoding(getSystemEncoding(), &sDecoderInfo);
00101         if (err)
00102             rv = NS_ERROR_FAILURE;
00103     }
00104     return rv;
00105 }
00106 
00107 
00108 NS_IMETHODIMP 
00109 CPlatformUCSConversion::UCSToPlatform(const nsAString& aIn, nsACString& aOut)
00110 {
00111     nsresult rv = PrepareEncoder();
00112     if (NS_FAILED(rv)) return rv;
00113     
00114     OSStatus err = noErr;
00115     char stackBuffer[512];
00116 
00117     aOut.Truncate(0);
00118     nsReadingIterator<PRUnichar> done_reading;
00119     aIn.EndReading(done_reading);
00120 
00121     // for each chunk of |aIn|...
00122     PRUint32 fragmentLength = 0;
00123     nsReadingIterator<PRUnichar> iter;
00124     for (aIn.BeginReading(iter); iter != done_reading && err == noErr; iter.advance(PRInt32(fragmentLength)))
00125     {
00126         fragmentLength = PRUint32(iter.size_forward());        
00127         UInt32 bytesLeft = fragmentLength * sizeof(UniChar);
00128         nsReadingIterator<PRUnichar> sub_iter(iter);
00129         
00130         do {
00131             UInt32 bytesRead = 0, bytesWritten = 0;
00132             err = ::ConvertFromUnicodeToText(sEncoderInfo,
00133                                              bytesLeft,
00134                                              (const UniChar*)sub_iter.get(),
00135                                              kUnicodeUseFallbacksMask | kUnicodeLooseMappingsMask,
00136                                              0, nsnull, nsnull, nsnull,
00137                                              sizeof(stackBuffer),
00138                                              &bytesRead,
00139                                              &bytesWritten,
00140                                              stackBuffer);
00141             if (err == kTECUsedFallbacksStatus)
00142                 err = noErr;
00143             else if (err == kTECOutputBufferFullStatus) {
00144                 bytesLeft -= bytesRead;
00145                 sub_iter.advance(bytesRead / sizeof(UniChar));
00146             }
00147             aOut.Append(stackBuffer, bytesWritten);
00148         }
00149         while (err == kTECOutputBufferFullStatus);
00150     }
00151     return (err == noErr) ? NS_OK : NS_ERROR_FAILURE;
00152 }
00153 
00154 
00155 NS_IMETHODIMP
00156 CPlatformUCSConversion::UCSToPlatform(const nsAString& aIn, Str255& aOut)
00157 {
00158     nsresult res;
00159     nsCAutoString cStr;
00160     
00161     res = UCSToPlatform(aIn, cStr);
00162     if (NS_SUCCEEDED(res))
00163     {
00164         PRUint32 outLength = cStr.Length();
00165         if (outLength > 255)
00166             outLength = 255;
00167         memcpy(&aOut[1], cStr.get(), outLength);
00168         aOut[0] = outLength;
00169     }
00170     return res;
00171 }
00172 
00173 
00174 NS_IMETHODIMP 
00175 CPlatformUCSConversion::PlatformToUCS(const nsACString& aIn, nsAString& aOut)
00176 {
00177     nsresult rv = PrepareDecoder();
00178     if (NS_FAILED(rv)) return rv;
00179     
00180     OSStatus err = noErr;
00181     UniChar stackBuffer[512];
00182 
00183     aOut.Truncate(0);
00184     nsReadingIterator<char> done_reading;
00185     aIn.EndReading(done_reading);
00186 
00187     // for each chunk of |aIn|...
00188     PRUint32 fragmentLength = 0;
00189     nsReadingIterator<char> iter;
00190     for (aIn.BeginReading(iter); iter != done_reading && err == noErr; iter.advance(PRInt32(fragmentLength)))
00191     {
00192         fragmentLength = PRUint32(iter.size_forward());        
00193         UInt32 bytesLeft = fragmentLength;
00194         nsReadingIterator<char> sub_iter(iter);
00195         
00196         do {
00197             UInt32 bytesRead = 0, bytesWritten = 0;
00198             err = ::ConvertFromTextToUnicode(sDecoderInfo,
00199                                              bytesLeft,
00200                                              sub_iter.get(),
00201                                              kUnicodeUseFallbacksMask | kUnicodeLooseMappingsMask,
00202                                              0, nsnull, nsnull, nsnull,
00203                                              sizeof(stackBuffer),
00204                                              &bytesRead,
00205                                              &bytesWritten,
00206                                              stackBuffer);
00207             if (err == kTECUsedFallbacksStatus)
00208                 err = noErr;
00209             else if (err == kTECOutputBufferFullStatus) {
00210                 bytesLeft -= bytesRead;
00211                 sub_iter.advance(bytesRead);
00212             }
00213             aOut.Append((PRUnichar *)stackBuffer, bytesWritten / sizeof(PRUnichar));
00214         }
00215         while (err == kTECOutputBufferFullStatus);
00216     }
00217     return (err == noErr) ? NS_OK : NS_ERROR_FAILURE;
00218 }
00219 
00220 NS_IMETHODIMP 
00221 CPlatformUCSConversion::PlatformToUCS(const Str255& aIn, nsAString& aOut)
00222 {
00223     char charBuf[256];
00224     
00225     memcpy(charBuf, &aIn[1], aIn[0]);
00226     charBuf[aIn[0]] = '\0';
00227     return PlatformToUCS(nsDependentCString(charBuf, aIn[0]), aOut);
00228 }