Back to index

lightning-sunbird  0.9+nobinonly
nsNativeDetectors.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  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 
00040 #include <objbase.h>
00041 #include <mlang.h>
00042 
00043 #include "nsIFactory.h"
00044 #include "nsISupports.h"
00045 #include "nsNativeCharDetDll.h"
00046 #include "pratom.h"
00047 #include "nsReadableUtils.h"
00048 
00049 #include "nsICharsetDetector.h"
00050 #include "nsICharsetDetectionObserver.h"
00051 #include "nsIStringCharsetDetector.h"
00052 
00053 
00054 //==========================================================
00055 
00056 // By using DoConversion to unicode with from codepage set to auto detection,
00057 // we can get input codepage then charset name.
00058 //
00059 static HRESULT DetectCharsetUsingMLang(IMultiLanguage *aMultiLanguage, IMLangConvertCharset *aMLangConvertCharset, 
00060                                        char* charset, nsDetectionConfident& aConfidence, BYTE* inBuf, UINT* inSize)
00061 {
00062   if (NULL == charset) {
00063     return E_FAIL;
00064   }
00065   if (*inSize > 4096) {
00066     return E_FAIL;  // Or we could allocate memory on heap
00067   }
00068   aConfidence = eNoAnswerYet;
00069 
00070   BYTE outBuf[4096];
00071   UINT outSize = 0;
00072 
00073   HRESULT hr = aMLangConvertCharset->DoConversion(inBuf, inSize, outBuf, &outSize);
00074   if (SUCCEEDED(hr)) {
00075     DWORD dwProperty = 0;
00076     UINT sourceCP;
00077     hr = aMLangConvertCharset->GetProperty(&dwProperty);
00078     if (SUCCEEDED(hr)) {
00079       if (dwProperty & MLCONVCHARF_AUTODETECT) {
00080         hr = aMLangConvertCharset->GetSourceCodePage(&sourceCP);
00081         if (SUCCEEDED(hr)) {
00082           MIMECPINFO aCodePageInfo;
00083           hr = aMultiLanguage->GetCodePageInfo(sourceCP, &aCodePageInfo);
00084           if (SUCCEEDED(hr)) {
00085             // convert WCHAR* to char*
00086             nsString aCharset(aCodePageInfo.wszWebCharset);
00087             char *cstr = ToNewCString(aCharset);
00088             PL_strcpy(charset, cstr);
00089             delete [] cstr;
00090             aConfidence = eSureAnswer;
00091           }
00092         }
00093       }
00094       else {
00095         charset[0] = '\0';
00096         aConfidence = eNoAnswerMatch;
00097       }
00098     }
00099   }
00100   return hr;
00101 }
00102 
00103 //==========================================================
00104 
00105 class nsNativeDetector : 
00106       public nsICharsetDetector // Implement the interface 
00107 {
00108 public:
00109   NS_DECL_ISUPPORTS
00110 
00111   nsNativeDetector(PRUint32 aCodePage);
00112   virtual ~nsNativeDetector();
00113   NS_IMETHOD Init(nsICharsetDetectionObserver* aObserver);
00114   NS_IMETHOD DoIt(const char* aBuf, PRUint32 aLen, PRBool* oDontFeedMe);
00115   NS_IMETHOD Done();
00116  
00117 private:
00118   nsICharsetDetectionObserver* mObserver;
00119   IMultiLanguage *mMultiLanguage;
00120   IMLangConvertCharset *mMLangConvertCharset;
00121   PRUint32  mCodePage;
00122   char mCharset[65];
00123 };
00124 
00125 NS_IMPL_ISUPPORTS1(nsNativeDetector, nsICharsetDetector)
00126 
00127 //----------------------------------------------------------
00128 nsNativeDetector::nsNativeDetector(PRUint32 aCodePage)
00129 {
00130   HRESULT hr = CoInitialize(NULL);
00131   mObserver = nsnull;
00132   mCodePage = aCodePage;
00133   mMultiLanguage = NULL;
00134   mMLangConvertCharset = NULL;
00135 }
00136 //----------------------------------------------------------
00137 nsNativeDetector::~nsNativeDetector()
00138 {
00139   NS_IF_RELEASE(mObserver);
00140   if (NULL != mMultiLanguage)
00141     mMultiLanguage->Release();
00142   if (NULL != mMLangConvertCharset)
00143     mMLangConvertCharset->Release();
00144   CoUninitialize();
00145 }
00146 //----------------------------------------------------------
00147 NS_IMETHODIMP nsNativeDetector::Init(
00148   nsICharsetDetectionObserver* aObserver)
00149 {
00150   NS_ASSERTION(mObserver == nsnull , "Init twice");
00151   if(nsnull == aObserver)
00152      return NS_ERROR_ILLEGAL_VALUE;
00153 
00154   mObserver = aObserver;
00155 
00156   HRESULT hr = CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, 
00157                                 IID_IMultiLanguage, (LPVOID *)&mMultiLanguage);
00158   if (SUCCEEDED(hr)) {
00159     DWORD dwProperty = 0;
00160     hr = mMultiLanguage->CreateConvertCharset(mCodePage, 1200, dwProperty, &mMLangConvertCharset);
00161   }
00162 
00163   return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
00164 }
00165 //----------------------------------------------------------
00166 NS_IMETHODIMP nsNativeDetector::DoIt(
00167   const char* aBuf, PRUint32 aLen, PRBool* oDontFeedMe)
00168 {
00169   NS_ASSERTION(mObserver != nsnull , "have not init yet");
00170 
00171   if((nsnull == aBuf) || (nsnull == oDontFeedMe))
00172      return NS_ERROR_ILLEGAL_VALUE;
00173 
00174   UINT theSize = (UINT) aLen;
00175   nsDetectionConfident aConfidence;
00176   if (SUCCEEDED(DetectCharsetUsingMLang(mMultiLanguage, mMLangConvertCharset, 
00177                                         mCharset, aConfidence, (BYTE *) aBuf, &theSize))) {
00178     if (eNoAnswerMatch != aConfidence) {
00179       mObserver->Notify(mCharset, aConfidence);
00180     }
00181   }
00182   else {
00183     mObserver->Notify("", eNoAnswerMatch);
00184   }
00185 
00186   *oDontFeedMe = PR_TRUE;
00187 
00188   return NS_OK;
00189 }
00190 //----------------------------------------------------------
00191 NS_IMETHODIMP nsNativeDetector::Done()
00192 {
00193   NS_ASSERTION(mObserver != nsnull , "have not init yet");
00194   return NS_OK;
00195 }
00196 
00197 //==========================================================
00198 class nsNativeStringDetector : 
00199       public nsIStringCharsetDetector // Implement the interface 
00200 {
00201 public:
00202   NS_DECL_ISUPPORTS
00203 
00204   nsNativeStringDetector(PRUint32 aCodePage);
00205   virtual ~nsNativeStringDetector();
00206   NS_IMETHOD DoIt(const char* aBuf, PRUint32 aLen, 
00207                   const char** oCharset, 
00208                   nsDetectionConfident &oConfident);
00209 protected:
00210   PRUint32  mCodePage;
00211   IMultiLanguage *mMultiLanguage;
00212   char mCharset[65];
00213 };
00214 
00215 NS_IMPL_ISUPPORTS1(nsNativeStringDetector, nsIStringCharsetDetector)
00216 
00217 //----------------------------------------------------------
00218 nsNativeStringDetector::nsNativeStringDetector(PRUint32 aCodePage)
00219 {
00220   HRESULT hr = CoInitialize(NULL);
00221   mCodePage = aCodePage;
00222   mMultiLanguage = NULL;
00223 }
00224 //----------------------------------------------------------
00225 nsNativeStringDetector::~nsNativeStringDetector()
00226 {
00227   if (NULL != mMultiLanguage)
00228     mMultiLanguage->Release();
00229   CoUninitialize();
00230 }
00231 
00232 //----------------------------------------------------------
00233 NS_IMETHODIMP nsNativeStringDetector::DoIt(const char* aBuf, PRUint32 aLen, 
00234                                            const char** oCharset, 
00235                                            nsDetectionConfident &oConfident)
00236 {
00237        HRESULT hr = S_OK;
00238 
00239   oConfident = eNoAnswerMatch;
00240   *oCharset = "";
00241 
00242   if (NULL == mMultiLanguage) {
00243     hr = CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, 
00244                           IID_IMultiLanguage, (LPVOID *)&mMultiLanguage);
00245   }
00246 
00247   if (SUCCEEDED(hr)) {
00248     IMLangConvertCharset *aMLangConvertCharset;
00249     DWORD dwProperty = 0;
00250     hr = mMultiLanguage->CreateConvertCharset(mCodePage, 1200, dwProperty, &aMLangConvertCharset);
00251     if (SUCCEEDED(hr)) {
00252       UINT theSize = (UINT) aLen;
00253       nsDetectionConfident aConfidence;
00254 
00255       hr = DetectCharsetUsingMLang(mMultiLanguage, aMLangConvertCharset, 
00256                                    mCharset, aConfidence, (BYTE *) aBuf, &theSize);
00257       if (SUCCEEDED(hr)) {
00258         *oCharset = mCharset;
00259         oConfident = aConfidence;
00260       }
00261 
00262       aMLangConvertCharset->Release();
00263     }
00264   }
00265 
00266   return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
00267 }
00268 
00269 //==========================================================
00270 class nsNativeDetectorFactory : public nsIFactory {
00271    NS_DECL_ISUPPORTS
00272 
00273 public:
00274    nsNativeDetectorFactory(PRUint32 aCodePage, PRBool stringBase) {
00275      mCodePage = aCodePage;
00276      mStringBase = stringBase;
00277    }
00278    virtual ~nsNativeDetectorFactory() {
00279    }
00280 
00281    NS_IMETHOD CreateInstance(nsISupports* aDelegate, const nsIID& aIID, void** aResult);
00282    NS_IMETHOD LockFactory(PRBool aLock);
00283 private:
00284    PRUint32 mCodePage;
00285    PRBool mStringBase;
00286 };
00287 
00288 //--------------------------------------------------------------
00289 NS_IMPL_ISUPPORTS1(nsNativeDetectorFactory, nsIFactory)
00290 
00291 NS_IMETHODIMP nsNativeDetectorFactory::CreateInstance(
00292     nsISupports* aDelegate, const nsIID &aIID, void** aResult)
00293 {
00294   if(NULL == aResult)
00295         return NS_ERROR_NULL_POINTER;
00296   if(NULL != aDelegate)
00297         return NS_ERROR_NO_AGGREGATION;
00298 
00299   *aResult = NULL;
00300 
00301   nsISupports *inst = nsnull;
00302   if (mStringBase)
00303     inst = (nsISupports *) new nsNativeStringDetector(mCodePage);
00304    else
00305     inst = (nsISupports *) new nsNativeDetector(mCodePage);
00306   if(NULL == inst) {
00307     return NS_ERROR_OUT_OF_MEMORY;
00308   }
00309   NS_ADDREF(inst);  // Stabilize
00310   nsresult res =inst->QueryInterface(aIID, aResult);
00311   NS_RELEASE(inst); // Destabilize and avoid leaks. Avoid calling delete <interface pointer>
00312 
00313   return res;
00314 }
00315 //--------------------------------------------------------------
00316 NS_IMETHODIMP nsNativeDetectorFactory::LockFactory(PRBool aLock)
00317 {
00318   return NS_OK;
00319 }
00320 
00321 //==========================================================
00322 nsIFactory* NEW_JA_NATIVEDETECTOR_FACTORY() {
00323   return new nsNativeDetectorFactory(50932, PR_FALSE);
00324 }
00325 nsIFactory* NEW_JA_STRING_NATIVEDETECTOR_FACTORY() {
00326   return new nsNativeDetectorFactory(50932, PR_TRUE);
00327 }
00328 nsIFactory* NEW_KO_NATIVEDETECTOR_FACTORY() {
00329   return new nsNativeDetectorFactory(50949, PR_FALSE);
00330 }
00331 nsIFactory* NEW_KO_STRING_NATIVEDETECTOR_FACTORY() {
00332   return new nsNativeDetectorFactory(50949, PR_TRUE);
00333 }