/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsIServiceManager.h" #include "nsICharsetConverterManager.h" #include "nsUCSupport.h" #include "nsString.h" #include "nsIStringEnumerator.h" #include "nsVoidArray.h" //---------------------------------------------------------------------------- // Global functions and data [declaration] #define ARRAY_SIZE(_array) (sizeof(_array) / sizeof(_array[0])) #define SMALL_BUFFER_SIZE 512 #define MED_BUFFER_SIZE 1024 #define BIG_BUFFER_SIZE 2048 static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID); //---------------------------------------------------------------------------- // Class nsTestLog [declaration] /** * A Logging class for test programs. * * This simple test program will not trigger a component registration. So * Mozilla has to be run once before running this, so that the necessary * components will be registered. Also, please observe that the ContractID's are * case sensitive now! * * @created 28/Mar/2000 * @author Catalin Rotaru [CATA] */ class nsTestLog { private: static const char * kTraceDelimiter; nsCAutoString mTrace; public: void AddTrace(char * aTrace); void DelTrace(char * aTrace); void PrintError(char * aCall, int aError); void PrintError(char * aCall, char * aMessage); }; //---------------------------------------------------------------------------- // Class nsTestUConv [declaration] /** * The main class of the program. * * XXX Create a very general set of "bug and regression" test cases and the * one in TestTempBug() * XXX Apply the new argument style (pointers) to the converters interfaces * * @created 28/Mar/2000 * @author Catalin Rotaru [CATA] */ class nsTestUConv { private: nsTestLog mLog; /** * Run the built-in set of self tests for encoders. */ nsresult TestEncoders(); /** * Run the built-in set of self tests for decoders. */ nsresult TestDecoders(); /** * Run the built-in set of self tests for the CharsetManager. */ nsresult TestCharsetManager(); /** * Display charset detectors and their attributes. */ nsresult DisplayDetectors(); /** * Display charsets and their attributes. */ nsresult DisplayCharsets(); /** * Run a temporary debug test. This method is ment as a placeholder when some * quick debugging is needed. */ nsresult TestTempBug(); nsresult Encode(PRUnichar ** aSrc, PRUnichar * aSrcEnd, char ** aDest, char * aDestEnd, const nsAFlatCString& aCharset); /** * Bridge methods between the new argument style (poiters) and the old one * (lengths). To be removed when the converter interfaces will switch to the * new style. * * This wraps an encoder Convert() call. */ nsresult ConvertEncode(PRUnichar ** aSrc, PRUnichar * aSrcEnd, char ** aDest, char * aDestEnd, nsIUnicodeEncoder * aEncoder); /** * This wraps an encoder Finish() call. */ nsresult FinishEncode(char ** aDest, char * aDestEnd, nsIUnicodeEncoder * aEncoder); void PrintSpaces(int aCount); public: /** * Main method of the program. */ nsresult Main(int aArgC, char ** aArgV); }; //---------------------------------------------------------------------------- // Global functions and data [implementation] int main(int argc, char ** argv) { nsTestUConv testObj; nsresult res; res = testObj.Main(argc, argv); return (NS_FAILED(res)); } //---------------------------------------------------------------------------- // Class nsTestLog [implementation] const char * nsTestLog::kTraceDelimiter = "."; void nsTestLog::AddTrace(char * aTrace) { mTrace.Append(aTrace); mTrace.Append(kTraceDelimiter); } void nsTestLog::DelTrace(char * aTrace) { mTrace.Truncate(mTrace.Length() - strlen(aTrace) - strlen(kTraceDelimiter)); } void nsTestLog::PrintError(char * aCall, int aError) { const char * trace = mTrace.get(); printf("ERROR at %s%s code=0x%x.\n", trace, aCall, aError); } void nsTestLog::PrintError(char * aCall, char * aMessage) { const char * trace = mTrace.get(); printf("ERROR at %s%s reason: %s.\n", trace, aCall, aMessage); } //---------------------------------------------------------------------------- // Class nsTestUConv [implementation] nsresult nsTestUConv::TestEncoders() { char * trace = "TestEncoders"; mLog.AddTrace(trace); nsresult res = NS_OK; nsCOMPtr ccMan = do_GetService(kCharsetConverterManagerCID, &res); if (NS_FAILED(res)) return res; nsCOMPtr encoders; res = ccMan->GetEncoderList(getter_AddRefs(encoders)); if (NS_FAILED(res)) return res; PRUint32 encoderCount=0; PRBool hasMore; encoders->HasMore(&hasMore); nsCAutoString charset; while (hasMore) { encoders->GetNext(charset); encoders->HasMore(&hasMore); } mLog.DelTrace(trace); return res; } nsresult nsTestUConv::TestDecoders() { char * trace = "TestDecoders"; mLog.AddTrace(trace); nsresult res = NS_OK; // XXX write me mLog.DelTrace(trace); return res; } nsresult nsTestUConv::TestCharsetManager() { char * trace = "TestCharsetManager"; mLog.AddTrace(trace); nsresult res = NS_OK; nsAutoString name; nsCOMPtr csAtom; nsCOMPtr ccMan = do_GetService(kCharsetConverterManagerCID, &res); if (NS_FAILED(res)) { mLog.PrintError("NS_WITH_SERVICE", res); return res; } mLog.DelTrace(trace); return res; } nsresult nsTestUConv::DisplayDetectors() { char * trace = "DisplayDetectors"; mLog.AddTrace(trace); nsresult res = NS_OK; nsCOMPtr ccMan = do_GetService(kCharsetConverterManagerCID, &res); if (NS_FAILED(res)) { mLog.PrintError("NS_WITH_SERVICE", res); return res; } // charset detectors nsCOMPtr detectors; res = ccMan->GetCharsetDetectorList(getter_AddRefs(detectors)); if (NS_FAILED(res)) { mLog.PrintError("GetCharsetDetectorList()", res); return res; } printf("***** Character Set Detectors *****\n"); PRBool hasMore; detectors->HasMore(&hasMore); while (hasMore) { nsCAutoString detectorName; res = detectors->GetNext(detectorName); if (NS_FAILED(res)) { mLog.PrintError("GetNext()", res); return res; } printf("%s", detectorName.get()); PrintSpaces(36 - detectorName.Length()); // align to hard coded column number nsAutoString title; res = ccMan->GetCharsetTitle(detectorName.get(), title); if (NS_FAILED(res)) title.SetLength(0); printf("\"%s\"\n", NS_LossyConvertUCS2toASCII(title).get()); } mLog.DelTrace(trace); return NS_OK; } nsresult nsTestUConv::DisplayCharsets() { char * trace = "DisplayCharsets"; mLog.AddTrace(trace); nsresult res = NS_OK; nsCOMPtr ccMan = do_GetService(kCharsetConverterManagerCID, &res); if (NS_FAILED(res)) { mLog.PrintError("NS_WITH_SERVICE", res); return res; } nsCOMPtr decoders; nsCOMPtr encoders; res = ccMan->GetDecoderList(getter_AddRefs(decoders)); if (NS_FAILED(res)) { mLog.PrintError("GetDecoderList()", res); return res; } res = ccMan->GetEncoderList(getter_AddRefs(encoders)); if (NS_FAILED(res)) { mLog.PrintError("GetEncoderList()", res); return res; } printf("***** Character Sets *****\n"); PRUint32 encCount = 0, decCount = 0; PRUint32 basicEncCount = 0, basicDecCount = 0; nsCStringArray allCharsets; nsCAutoString charset; PRBool hasMore; encoders->HasMore(&hasMore); while (hasMore) { res = encoders->GetNext(charset); if (NS_SUCCEEDED(res)) allCharsets.AppendCString(charset); encoders->HasMore(&hasMore); } nsAutoString prop, str; PRUint32 count = allCharsets.Count(); for (PRUint32 i = 0; i < count; i++) { const nsCString* charset = allCharsets[i]; printf("%s", charset->get()); PrintSpaces(24 - charset->Length()); // align to hard coded column number nsCOMPtr dec = NULL; res = ccMan->GetUnicodeDecoder(charset->get(), getter_AddRefs(dec)); if (NS_FAILED(res)) printf (" "); else { printf("D"); decCount++; } #ifdef NS_DEBUG // show the "basic" decoder classes if (dec) { nsCOMPtr isBasic = do_QueryInterface(dec); if (isBasic) { basicDecCount++; printf("b"); } else printf(" "); } else printf(" "); #endif nsCOMPtr enc = NULL; res = ccMan->GetUnicodeEncoder(charset->get(), getter_AddRefs(enc)); if (NS_FAILED(res)) printf (" "); else { printf("E"); encCount++; } #ifdef NS_DEBUG if (enc) { nsCOMPtr isBasic = do_QueryInterface(enc); if (isBasic) { basicEncCount++; printf("b"); } else printf(" "); } else printf(" "); #endif printf(" "); prop.AssignLiteral(".notForBrowser"); res = ccMan->GetCharsetData(charset->get(), prop.get(), str); if ((dec != NULL) && (NS_FAILED(res))) printf ("B"); else printf("X"); prop.AssignLiteral(".notForComposer"); res = ccMan->GetCharsetData(charset->get(), prop.get(), str); if ((enc != NULL) && (NS_FAILED(res))) printf ("C"); else printf("X"); prop.AssignLiteral(".notForMailView"); res = ccMan->GetCharsetData(charset->get(), prop.get(), str); if ((dec != NULL) && (NS_FAILED(res))) printf ("V"); else printf("X"); prop.AssignLiteral(".notForMailEdit"); res = ccMan->GetCharsetData(charset->get(), prop.get(), str); if ((enc != NULL) && (NS_FAILED(res))) printf ("E"); else printf("X"); printf("(%3d, %3d) ", encCount, decCount); res = ccMan->GetCharsetTitle(charset->get(), str); if (NS_FAILED(res)) str.SetLength(0); NS_LossyConvertUCS2toASCII buff2(str); printf(" \"%s\"\n", buff2.get()); } printf("%u of %u decoders are basic (%d%%)\n", basicDecCount, decCount, (basicDecCount * 100) / decCount); printf("%u of %u encoders are basic (%d%%)\n", basicEncCount, encCount, (basicEncCount * 100) / encCount); mLog.DelTrace(trace); return NS_OK; } nsresult nsTestUConv::TestTempBug() { char * trace = "TestTempBug"; mLog.AddTrace(trace); nsresult res = NS_OK; NS_NAMED_LITERAL_CSTRING(charset, "ISO-2022-JP"); PRUnichar src[] = {0x0043, 0x004e, 0x0045, 0x0054, 0x0020, 0x004A, 0x0061, 0x0070, 0x0061, 0x006E, 0x0020, 0x7DE8, 0x96C6, 0x5C40}; PRUnichar * srcEnd = src + ARRAY_SIZE(src); char dest[BIG_BUFFER_SIZE]; char * destEnd = dest + BIG_BUFFER_SIZE; PRUnichar * p = src; char * q = dest; res = Encode(&p, srcEnd, &q, destEnd, charset); mLog.DelTrace(trace); return res; } nsresult nsTestUConv::Encode(PRUnichar ** aSrc, PRUnichar * aSrcEnd, char ** aDest, char * aDestEnd, const nsAFlatCString& aCharset) { char * trace = "Encode"; mLog.AddTrace(trace); nsresult res = NS_OK; nsCOMPtr ccMan = do_GetService(kCharsetConverterManagerCID, &res); if (NS_FAILED(res)) { mLog.PrintError("NS_WITH_SERVICE", res); return res; } nsCOMPtr enc; res = ccMan->GetUnicodeEncoder(aCharset.get(), getter_AddRefs(enc)); if (NS_FAILED(res)) { mLog.PrintError("GetUnicodeEncoder()", res); return res; } res = ConvertEncode(aSrc, aSrcEnd, aDest, aDestEnd, enc); if (NS_FAILED(res)) { mLog.PrintError("Convert()", res); return res; } res = FinishEncode(aDest, aDestEnd, enc); if (NS_FAILED(res)) { mLog.PrintError("Finish()", res); return res; } mLog.DelTrace(trace); return res; } nsresult nsTestUConv::ConvertEncode(PRUnichar ** aSrc, PRUnichar * aSrcEnd, char ** aDest, char * aDestEnd, nsIUnicodeEncoder * aEncoder) { PRUnichar * src = (*aSrc); char * dest = (*aDest); PRInt32 srcLen = aSrcEnd - src; PRInt32 destLen = aDestEnd - dest; nsresult res = aEncoder->Convert(src, &srcLen, dest, &destLen); (*aSrc) = src + srcLen; (*aDest) = dest + destLen; return res; } nsresult nsTestUConv::FinishEncode(char ** aDest, char * aDestEnd, nsIUnicodeEncoder * aEncoder) { char * dest = (*aDest); PRInt32 destLen = aDestEnd - dest; nsresult res = aEncoder->Finish(dest, &destLen); (*aDest) = dest + destLen; return res; } void nsTestUConv::PrintSpaces(int aCount) { for (int i = 0; i < aCount; i++) printf(" "); } nsresult nsTestUConv::Main(int aArgC, char ** aArgV) { char * trace = "Main"; mLog.AddTrace(trace); nsresult res = NS_OK; if (aArgC < 2) { // no arguments were passed to the program, so we just run the self tests res = TestCharsetManager(); if (NS_SUCCEEDED(res)) res = TestEncoders(); if (NS_SUCCEEDED(res)) res = TestDecoders(); } else if (!strcmp(aArgV[1], "-tempbug")) { // we are testing a temporary bug res = TestTempBug(); } else if (!strcmp(aArgV[1], "-display")) { // display all the available data res = DisplayDetectors(); if (NS_SUCCEEDED(res)) res = DisplayCharsets(); } mLog.DelTrace(trace); return res; }