/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape 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/NPL/ * * 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): * Pierre Phaneuf * * * Alternatively, the contents of this file may be used under the terms of * either 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 NPL, 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 NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include "nsIFactory.h" #include "nsISupports.h" #include "nsNativeCharDetDll.h" #include "pratom.h" #include "nsReadableUtils.h" #include "nsICharsetDetector.h" #include "nsICharsetDetectionObserver.h" #include "nsIStringCharsetDetector.h" //========================================================== // By using DoConversion to unicode with from codepage set to auto detection, // we can get input codepage then charset name. // static HRESULT DetectCharsetUsingMLang(IMultiLanguage *aMultiLanguage, IMLangConvertCharset *aMLangConvertCharset, char* charset, nsDetectionConfident& aConfidence, BYTE* inBuf, UINT* inSize) { if (NULL == charset) { return E_FAIL; } if (*inSize > 4096) { return E_FAIL; // Or we could allocate memory on heap } aConfidence = eNoAnswerYet; BYTE outBuf[4096]; UINT outSize = 0; HRESULT hr = aMLangConvertCharset->DoConversion(inBuf, inSize, outBuf, &outSize); if (SUCCEEDED(hr)) { DWORD dwProperty = 0; UINT sourceCP; hr = aMLangConvertCharset->GetProperty(&dwProperty); if (SUCCEEDED(hr)) { if (dwProperty & MLCONVCHARF_AUTODETECT) { hr = aMLangConvertCharset->GetSourceCodePage(&sourceCP); if (SUCCEEDED(hr)) { MIMECPINFO aCodePageInfo; hr = aMultiLanguage->GetCodePageInfo(sourceCP, &aCodePageInfo); if (SUCCEEDED(hr)) { // convert WCHAR* to char* nsString aCharset(aCodePageInfo.wszWebCharset); char *cstr = ToNewCString(aCharset); PL_strcpy(charset, cstr); delete [] cstr; aConfidence = eSureAnswer; } } } else { charset[0] = '\0'; aConfidence = eNoAnswerMatch; } } } return hr; } //========================================================== class nsNativeDetector : public nsICharsetDetector // Implement the interface { public: NS_DECL_ISUPPORTS nsNativeDetector(PRUint32 aCodePage); virtual ~nsNativeDetector(); NS_IMETHOD Init(nsICharsetDetectionObserver* aObserver); NS_IMETHOD DoIt(const char* aBuf, PRUint32 aLen, PRBool* oDontFeedMe); NS_IMETHOD Done(); private: nsICharsetDetectionObserver* mObserver; IMultiLanguage *mMultiLanguage; IMLangConvertCharset *mMLangConvertCharset; PRUint32 mCodePage; char mCharset[65]; }; NS_IMPL_ISUPPORTS1(nsNativeDetector, nsICharsetDetector) //---------------------------------------------------------- nsNativeDetector::nsNativeDetector(PRUint32 aCodePage) { HRESULT hr = CoInitialize(NULL); mObserver = nsnull; mCodePage = aCodePage; mMultiLanguage = NULL; mMLangConvertCharset = NULL; } //---------------------------------------------------------- nsNativeDetector::~nsNativeDetector() { NS_IF_RELEASE(mObserver); if (NULL != mMultiLanguage) mMultiLanguage->Release(); if (NULL != mMLangConvertCharset) mMLangConvertCharset->Release(); CoUninitialize(); } //---------------------------------------------------------- NS_IMETHODIMP nsNativeDetector::Init( nsICharsetDetectionObserver* aObserver) { NS_ASSERTION(mObserver == nsnull , "Init twice"); if(nsnull == aObserver) return NS_ERROR_ILLEGAL_VALUE; mObserver = aObserver; HRESULT hr = CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (LPVOID *)&mMultiLanguage); if (SUCCEEDED(hr)) { DWORD dwProperty = 0; hr = mMultiLanguage->CreateConvertCharset(mCodePage, 1200, dwProperty, &mMLangConvertCharset); } return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE; } //---------------------------------------------------------- NS_IMETHODIMP nsNativeDetector::DoIt( const char* aBuf, PRUint32 aLen, PRBool* oDontFeedMe) { NS_ASSERTION(mObserver != nsnull , "have not init yet"); if((nsnull == aBuf) || (nsnull == oDontFeedMe)) return NS_ERROR_ILLEGAL_VALUE; UINT theSize = (UINT) aLen; nsDetectionConfident aConfidence; if (SUCCEEDED(DetectCharsetUsingMLang(mMultiLanguage, mMLangConvertCharset, mCharset, aConfidence, (BYTE *) aBuf, &theSize))) { if (eNoAnswerMatch != aConfidence) { mObserver->Notify(mCharset, aConfidence); } } else { mObserver->Notify("", eNoAnswerMatch); } *oDontFeedMe = PR_TRUE; return NS_OK; } //---------------------------------------------------------- NS_IMETHODIMP nsNativeDetector::Done() { NS_ASSERTION(mObserver != nsnull , "have not init yet"); return NS_OK; } //========================================================== class nsNativeStringDetector : public nsIStringCharsetDetector // Implement the interface { public: NS_DECL_ISUPPORTS nsNativeStringDetector(PRUint32 aCodePage); virtual ~nsNativeStringDetector(); NS_IMETHOD DoIt(const char* aBuf, PRUint32 aLen, const char** oCharset, nsDetectionConfident &oConfident); protected: PRUint32 mCodePage; IMultiLanguage *mMultiLanguage; char mCharset[65]; }; NS_IMPL_ISUPPORTS1(nsNativeStringDetector, nsIStringCharsetDetector) //---------------------------------------------------------- nsNativeStringDetector::nsNativeStringDetector(PRUint32 aCodePage) { HRESULT hr = CoInitialize(NULL); mCodePage = aCodePage; mMultiLanguage = NULL; } //---------------------------------------------------------- nsNativeStringDetector::~nsNativeStringDetector() { if (NULL != mMultiLanguage) mMultiLanguage->Release(); CoUninitialize(); } //---------------------------------------------------------- NS_IMETHODIMP nsNativeStringDetector::DoIt(const char* aBuf, PRUint32 aLen, const char** oCharset, nsDetectionConfident &oConfident) { HRESULT hr = S_OK; oConfident = eNoAnswerMatch; *oCharset = ""; if (NULL == mMultiLanguage) { hr = CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (LPVOID *)&mMultiLanguage); } if (SUCCEEDED(hr)) { IMLangConvertCharset *aMLangConvertCharset; DWORD dwProperty = 0; hr = mMultiLanguage->CreateConvertCharset(mCodePage, 1200, dwProperty, &aMLangConvertCharset); if (SUCCEEDED(hr)) { UINT theSize = (UINT) aLen; nsDetectionConfident aConfidence; hr = DetectCharsetUsingMLang(mMultiLanguage, aMLangConvertCharset, mCharset, aConfidence, (BYTE *) aBuf, &theSize); if (SUCCEEDED(hr)) { *oCharset = mCharset; oConfident = aConfidence; } aMLangConvertCharset->Release(); } } return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE; } //========================================================== class nsNativeDetectorFactory : public nsIFactory { NS_DECL_ISUPPORTS public: nsNativeDetectorFactory(PRUint32 aCodePage, PRBool stringBase) { mCodePage = aCodePage; mStringBase = stringBase; } virtual ~nsNativeDetectorFactory() { } NS_IMETHOD CreateInstance(nsISupports* aDelegate, const nsIID& aIID, void** aResult); NS_IMETHOD LockFactory(PRBool aLock); private: PRUint32 mCodePage; PRBool mStringBase; }; //-------------------------------------------------------------- NS_IMPL_ISUPPORTS1(nsNativeDetectorFactory, nsIFactory) NS_IMETHODIMP nsNativeDetectorFactory::CreateInstance( nsISupports* aDelegate, const nsIID &aIID, void** aResult) { if(NULL == aResult) return NS_ERROR_NULL_POINTER; if(NULL != aDelegate) return NS_ERROR_NO_AGGREGATION; *aResult = NULL; nsISupports *inst = nsnull; if (mStringBase) inst = (nsISupports *) new nsNativeStringDetector(mCodePage); else inst = (nsISupports *) new nsNativeDetector(mCodePage); if(NULL == inst) { return NS_ERROR_OUT_OF_MEMORY; } NS_ADDREF(inst); // Stabilize nsresult res =inst->QueryInterface(aIID, aResult); NS_RELEASE(inst); // Destabilize and avoid leaks. Avoid calling delete return res; } //-------------------------------------------------------------- NS_IMETHODIMP nsNativeDetectorFactory::LockFactory(PRBool aLock) { return NS_OK; } //========================================================== nsIFactory* NEW_JA_NATIVEDETECTOR_FACTORY() { return new nsNativeDetectorFactory(50932, PR_FALSE); } nsIFactory* NEW_JA_STRING_NATIVEDETECTOR_FACTORY() { return new nsNativeDetectorFactory(50932, PR_TRUE); } nsIFactory* NEW_KO_NATIVEDETECTOR_FACTORY() { return new nsNativeDetectorFactory(50949, PR_FALSE); } nsIFactory* NEW_KO_STRING_NATIVEDETECTOR_FACTORY() { return new nsNativeDetectorFactory(50949, PR_TRUE); }