Back to index

lightning-sunbird  0.9+nobinonly
nsHTMLFormatConverter.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.org 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 the GNU General Public License Version 2 or later (the "GPL"), or
00027  * 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 #include "nsString.h"
00040 #include "nsCRT.h"
00041 #include "nsISupportsArray.h"
00042 #include "nsIComponentManager.h"
00043 #include "nsCOMPtr.h"
00044 #include "nsXPCOM.h"
00045 #include "nsISupportsPrimitives.h"
00046 #include "nsXPIDLString.h"
00047 
00048 #include "nsITransferable.h" // for mime defs, this is BAD
00049 
00050 // HTML convertor stuff
00051 #include "nsIParser.h"
00052 #include "nsIDTD.h"
00053 #include "nsParserCIID.h"
00054 #include "nsIContentSink.h"
00055 
00056 #include "nsString.h"
00057 #include "nsWidgetsCID.h"
00058 #include "nsHTMLFormatConverter.h"
00059 #include "nsPrimitiveHelpers.h"
00060 #include "nsIDocumentEncoder.h"
00061 #include "nsIHTMLToTextSink.h"
00062 
00063 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
00064 
00065 NS_IMPL_ADDREF(nsHTMLFormatConverter)
00066 NS_IMPL_RELEASE(nsHTMLFormatConverter)
00067 NS_IMPL_QUERY_INTERFACE1(nsHTMLFormatConverter, nsIFormatConverter)
00068 
00069 
00070 //-------------------------------------------------------------------------
00071 //
00072 // HTMLFormatConverter constructor
00073 //
00074 //-------------------------------------------------------------------------
00075 nsHTMLFormatConverter::nsHTMLFormatConverter()
00076 {
00077 }
00078 
00079 //-------------------------------------------------------------------------
00080 //
00081 // HTMLFormatConverter destructor
00082 //
00083 //-------------------------------------------------------------------------
00084 nsHTMLFormatConverter::~nsHTMLFormatConverter()
00085 {
00086 }
00087 
00088 
00089 //
00090 // GetInputDataFlavors
00091 //
00092 // Creates a new list and returns the list of all the flavors this converter
00093 // knows how to import. In this case, it's just HTML.
00094 //
00095 // Flavors (strings) are wrapped in a primitive object so that JavaScript can
00096 // access them easily via XPConnect.
00097 //
00098 NS_IMETHODIMP
00099 nsHTMLFormatConverter::GetInputDataFlavors(nsISupportsArray **_retval)
00100 {
00101   if ( !_retval )
00102     return NS_ERROR_INVALID_ARG;
00103   
00104   nsresult rv = NS_NewISupportsArray ( _retval );  // addrefs for us
00105   if ( NS_SUCCEEDED(rv) )
00106     rv = AddFlavorToList ( *_retval, kHTMLMime );
00107   
00108   return rv;
00109   
00110 } // GetInputDataFlavors
00111 
00112 
00113 //
00114 // GetOutputDataFlavors
00115 //
00116 // Creates a new list and returns the list of all the flavors this converter
00117 // knows how to export (convert). In this case, it's all sorts of things that HTML can be
00118 // converted to.
00119 //
00120 // Flavors (strings) are wrapped in a primitive object so that JavaScript can
00121 // access them easily via XPConnect.
00122 //
00123 NS_IMETHODIMP
00124 nsHTMLFormatConverter::GetOutputDataFlavors(nsISupportsArray **_retval)
00125 {
00126   if ( !_retval )
00127     return NS_ERROR_INVALID_ARG;
00128   
00129   nsresult rv = NS_NewISupportsArray ( _retval );  // addrefs for us
00130   if ( NS_SUCCEEDED(rv) ) {
00131     rv = AddFlavorToList ( *_retval, kHTMLMime );
00132     if ( NS_FAILED(rv) )
00133       return rv;
00134 #if NOT_NOW
00135 // pinkerton
00136 // no one uses this flavor right now, so it's just slowing things down. If anyone cares I
00137 // can put it back in.
00138     rv = AddFlavorToList ( *_retval, kAOLMailMime );
00139     if ( NS_FAILED(rv) )
00140       return rv;
00141 #endif
00142     rv = AddFlavorToList ( *_retval, kUnicodeMime );
00143     if ( NS_FAILED(rv) )
00144       return rv;
00145   }
00146   return rv;
00147 
00148 } // GetOutputDataFlavors
00149 
00150 
00151 //
00152 // AddFlavorToList
00153 //
00154 // Convenience routine for adding a flavor wrapped in an nsISupportsCString object
00155 // to a list
00156 //
00157 nsresult
00158 nsHTMLFormatConverter :: AddFlavorToList ( nsISupportsArray* inList, const char* inFlavor )
00159 {
00160   nsresult rv;
00161   
00162   nsCOMPtr<nsISupportsCString> dataFlavor =
00163       do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
00164   if ( dataFlavor ) {
00165     dataFlavor->SetData ( nsDependentCString(inFlavor) );
00166     // add to list as an nsISupports so the correct interface gets the addref
00167     // in AppendElement()
00168     nsCOMPtr<nsISupports> genericFlavor ( do_QueryInterface(dataFlavor) );
00169     inList->AppendElement ( genericFlavor);
00170   }
00171   return rv;
00172 
00173 } // AddFlavorToList
00174 
00175 
00176 //
00177 // CanConvert
00178 //
00179 // Determines if we support the given conversion. Currently, this method only
00180 // converts from HTML to others.
00181 //
00182 NS_IMETHODIMP
00183 nsHTMLFormatConverter::CanConvert(const char *aFromDataFlavor, const char *aToDataFlavor, PRBool *_retval)
00184 {
00185   if ( !_retval )
00186     return NS_ERROR_INVALID_ARG;
00187 
00188     // STRING USE WARNING: reduce conversions here?
00189   
00190   *_retval = PR_FALSE;
00191   nsAutoString fromFlavor; fromFlavor.AssignWithConversion( aFromDataFlavor );
00192   if ( !nsCRT::strcmp(aFromDataFlavor, kHTMLMime) ) {
00193     if ( !nsCRT::strcmp(aToDataFlavor, kHTMLMime) )
00194       *_retval = PR_TRUE;
00195     else if ( !nsCRT::strcmp(aToDataFlavor, kUnicodeMime) )
00196       *_retval = PR_TRUE;
00197 #if NOT_NOW
00198 // pinkerton
00199 // no one uses this flavor right now, so it's just slowing things down. If anyone cares I
00200 // can put it back in.
00201     else if ( toFlavor.Equals(kAOLMailMime) )
00202       *_retval = PR_TRUE;
00203 #endif
00204   }
00205   return NS_OK;
00206 
00207 } // CanConvert
00208 
00209 
00210 
00211 //
00212 // Convert
00213 //
00214 // Convert data from one flavor to another. The data is wrapped in primitive objects so that it is
00215 // accessable from JS. Currently, this only accepts HTML input, so anything else is invalid.
00216 //
00217 //XXX This method copies the data WAAAAY too many time for my liking. Grrrrrr. Mostly it's because
00218 //XXX we _must_ put things into nsStrings so that the parser will accept it. Lame lame lame lame. We
00219 //XXX also can't just get raw unicode out of the nsString, so we have to allocate heap to get
00220 //XXX unicode out of the string. Lame lame lame.
00221 //
00222 NS_IMETHODIMP
00223 nsHTMLFormatConverter::Convert(const char *aFromDataFlavor, nsISupports *aFromData, PRUint32 aDataLen, 
00224                                const char *aToDataFlavor, nsISupports **aToData, PRUint32 *aDataToLen)
00225 {
00226   if ( !aToData || !aDataToLen )
00227     return NS_ERROR_INVALID_ARG;
00228 
00229   nsresult rv = NS_OK;
00230 
00231   if ( !nsCRT::strcmp(aFromDataFlavor, kHTMLMime) ) {
00232     nsCAutoString toFlavor ( aToDataFlavor );
00233 
00234     // HTML on clipboard is going to always be double byte so it will be in a primitive
00235     // class of nsISupportsString. Also, since the data is in two byte chunks the 
00236     // length represents the length in 1-byte chars, so we need to divide by two.
00237     nsCOMPtr<nsISupportsString> dataWrapper0 ( do_QueryInterface(aFromData) );
00238     if (!dataWrapper0) {
00239       return NS_ERROR_INVALID_ARG;
00240     }
00241 
00242     nsAutoString dataStr;
00243     dataWrapper0->GetData ( dataStr );  //еее COPY #1
00244     // note: conversion to text/plain is done inside the clipboard. we do not need to worry 
00245     // about it here.
00246     if ( toFlavor.Equals(kHTMLMime) || toFlavor.Equals(kUnicodeMime) ) {
00247       nsresult res;
00248       if (toFlavor.Equals(kHTMLMime)) {
00249         PRInt32 dataLen = dataStr.Length() * 2;
00250         nsPrimitiveHelpers::CreatePrimitiveForData ( toFlavor.get(), (void*)dataStr.get(), dataLen, aToData );
00251         if ( *aToData )
00252           *aDataToLen = dataLen;
00253       } else {
00254         nsAutoString outStr;
00255         res = ConvertFromHTMLToUnicode(dataStr, outStr);
00256         if (NS_SUCCEEDED(res)) {
00257           PRInt32 dataLen = outStr.Length() * 2;
00258           nsPrimitiveHelpers::CreatePrimitiveForData ( toFlavor.get(), (void*)outStr.get(), dataLen, aToData );
00259           if ( *aToData ) 
00260             *aDataToLen = dataLen;
00261         }
00262       }
00263     } // else if HTML or Unicode
00264     else if ( toFlavor.Equals(kAOLMailMime) ) {
00265       nsAutoString outStr;
00266       if ( NS_SUCCEEDED(ConvertFromHTMLToAOLMail(dataStr, outStr)) ) {
00267         PRInt32 dataLen = outStr.Length() * 2;
00268         nsPrimitiveHelpers::CreatePrimitiveForData ( toFlavor.get(), (void*)outStr.get(), dataLen, aToData );
00269         if ( *aToData ) 
00270           *aDataToLen = dataLen;
00271       }
00272     } // else if AOL mail
00273     else {
00274       *aToData = nsnull;
00275       *aDataToLen = 0;
00276       rv = NS_ERROR_FAILURE;
00277     }
00278   } // if we got html mime
00279   else
00280     rv = NS_ERROR_FAILURE;      
00281     
00282   return rv;
00283   
00284 } // Convert
00285 
00286 
00287 //
00288 // ConvertFromHTMLToUnicode
00289 //
00290 // Takes HTML and converts it to plain text but in unicode.
00291 //
00292 NS_IMETHODIMP
00293 nsHTMLFormatConverter::ConvertFromHTMLToUnicode(const nsAutoString & aFromStr, nsAutoString & aToStr)
00294 {
00295   // create the parser to do the conversion.
00296   aToStr.SetLength(0);
00297   nsresult rv;
00298   nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID, &rv);
00299   if ( !parser )
00300     return rv;
00301 
00302   // convert it!
00303   nsCOMPtr<nsIContentSink> sink;
00304 
00305   sink = do_CreateInstance(NS_PLAINTEXTSINK_CONTRACTID);
00306   NS_ENSURE_TRUE(sink, NS_ERROR_FAILURE);
00307 
00308   nsCOMPtr<nsIHTMLToTextSink> textSink(do_QueryInterface(sink));
00309   NS_ENSURE_TRUE(textSink, NS_ERROR_FAILURE);
00310 
00311   textSink->Initialize(&aToStr, nsIDocumentEncoder::OutputSelectionOnly
00312                        | nsIDocumentEncoder::OutputAbsoluteLinks, 0);
00313 
00314   parser->SetContentSink(sink);
00315 
00316   parser->Parse(aFromStr, 0, NS_LITERAL_CSTRING("text/html"), PR_FALSE, PR_TRUE, eDTDMode_fragment);
00317   
00318   return NS_OK;
00319 } // ConvertFromHTMLToUnicode
00320 
00321 
00326 NS_IMETHODIMP
00327 nsHTMLFormatConverter::ConvertFromHTMLToAOLMail(const nsAutoString & aFromStr,
00328                                                 nsAutoString & aToStr)
00329 {
00330   aToStr.AssignLiteral("<HTML>");
00331   aToStr.Append(aFromStr);
00332   aToStr.AppendLiteral("</HTML>");
00333 
00334   return NS_OK;
00335 }
00336