LCOV - code coverage report
Current view: directory - embedding/components/webbrowserpersist/src - nsWebBrowserPersist.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1898 376 19.8 %
Date: 2012-06-02 Functions: 99 37 37.4 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is the Mozilla browser.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications, Inc.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1999
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Adam Lock <adamlock@netscape.com>
      24                 :  *   Kathleen Brade <brade@netscape.com>
      25                 :  *   Ryan Jones <sciguyryan@gmail.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "mozilla/Util.h"
      42                 : 
      43                 : #include "nspr.h"
      44                 : 
      45                 : #include "nsIFileStreams.h"       // New Necko file streams
      46                 : 
      47                 : #ifdef XP_OS2
      48                 : #include "nsILocalFileOS2.h"
      49                 : #endif
      50                 : 
      51                 : #include "nsNetUtil.h"
      52                 : #include "nsComponentManagerUtils.h"
      53                 : #include "nsIComponentRegistrar.h"
      54                 : #include "nsIStorageStream.h"
      55                 : #include "nsISeekableStream.h"
      56                 : #include "nsIHttpChannel.h"
      57                 : #include "nsIHttpChannelInternal.h"
      58                 : #include "nsIEncodedChannel.h"
      59                 : #include "nsIUploadChannel.h"
      60                 : #include "nsICachingChannel.h"
      61                 : #include "nsIFileChannel.h"
      62                 : #include "nsEscape.h"
      63                 : #include "nsUnicharUtils.h"
      64                 : #include "nsIStringEnumerator.h"
      65                 : #include "nsCRT.h"
      66                 : #include "nsSupportsArray.h"
      67                 : #include "nsContentCID.h"
      68                 : #include "nsStreamUtils.h"
      69                 : 
      70                 : #include "nsCExternalHandlerService.h"
      71                 : 
      72                 : #include "nsIURL.h"
      73                 : #include "nsIFileURL.h"
      74                 : #include "nsIDocument.h"
      75                 : #include "nsIDOMDocument.h"
      76                 : #include "nsIDOMXMLDocument.h"
      77                 : #include "nsIDOMTreeWalker.h"
      78                 : #include "nsIDOMNode.h"
      79                 : #include "nsIDOMComment.h"
      80                 : #include "nsIDOMNamedNodeMap.h"
      81                 : #include "nsIDOMNodeList.h"
      82                 : #include "nsIWebProgressListener.h"
      83                 : #include "nsIAuthPrompt.h"
      84                 : #include "nsIPrompt.h"
      85                 : #include "nsISHEntry.h"
      86                 : #include "nsIWebPageDescriptor.h"
      87                 : #include "nsIFormControl.h"
      88                 : #include "nsContentUtils.h"
      89                 : 
      90                 : #include "nsIDOMNodeFilter.h"
      91                 : #include "nsIDOMProcessingInstruction.h"
      92                 : #include "nsIDOMHTMLBodyElement.h"
      93                 : #include "nsIDOMHTMLTableElement.h"
      94                 : #include "nsIDOMHTMLTableRowElement.h"
      95                 : #include "nsIDOMHTMLTableCellElement.h"
      96                 : #include "nsIDOMHTMLAnchorElement.h"
      97                 : #include "nsIDOMHTMLAreaElement.h"
      98                 : #include "nsIDOMHTMLImageElement.h"
      99                 : #include "nsIDOMHTMLScriptElement.h"
     100                 : #include "nsIDOMHTMLLinkElement.h"
     101                 : #include "nsIDOMHTMLBaseElement.h"
     102                 : #include "nsIDOMHTMLFrameElement.h"
     103                 : #include "nsIDOMHTMLIFrameElement.h"
     104                 : #include "nsIDOMHTMLInputElement.h"
     105                 : #include "nsIDOMHTMLEmbedElement.h"
     106                 : #include "nsIDOMHTMLObjectElement.h"
     107                 : #include "nsIDOMHTMLAppletElement.h"
     108                 : #include "nsIDOMHTMLOptionElement.h"
     109                 : #include "nsIDOMHTMLTextAreaElement.h"
     110                 : #include "nsIDOMHTMLDocument.h"
     111                 : #include "nsIDOMSVGImageElement.h"
     112                 : #include "nsIDOMSVGScriptElement.h"
     113                 : #ifdef MOZ_MEDIA
     114                 : #include "nsIDOMHTMLSourceElement.h"
     115                 : #include "nsIDOMHTMLMediaElement.h"
     116                 : #endif // MOZ_MEDIA
     117                 :  
     118                 : #include "nsIImageLoadingContent.h"
     119                 : 
     120                 : #include "ftpCore.h"
     121                 : #include "nsITransport.h"
     122                 : #include "nsISocketTransport.h"
     123                 : #include "nsIStringBundle.h"
     124                 : #include "nsIProtocolHandler.h"
     125                 : 
     126                 : #include "nsWebBrowserPersist.h"
     127                 : 
     128                 : using namespace mozilla;
     129                 : 
     130                 : // Buffer file writes in 32kb chunks
     131                 : #define BUFFERED_OUTPUT_SIZE (1024 * 32)
     132                 : 
     133                 : #define NS_SUCCESS_DONT_FIXUP NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 1)
     134                 : 
     135                 : // Information about a DOM document
     136                 : struct DocData
     137               0 : {
     138                 :     nsCOMPtr<nsIURI> mBaseURI;
     139                 :     nsCOMPtr<nsIDOMDocument> mDocument;
     140                 :     nsCOMPtr<nsIURI> mFile;
     141                 :     nsCOMPtr<nsIURI> mDataPath;
     142                 :     bool mDataPathIsRelative;
     143                 :     nsCString mRelativePathToData;
     144                 :     nsCString mCharset;
     145                 : };
     146                 : 
     147                 : // Information about a URI
     148                 : struct URIData
     149               0 : {
     150                 :     bool mNeedsPersisting;
     151                 :     bool mSaved;
     152                 :     bool mIsSubFrame;
     153                 :     bool mDataPathIsRelative;
     154                 :     bool mNeedsFixup;
     155                 :     nsString mFilename;
     156                 :     nsString mSubFrameExt;
     157                 :     nsCOMPtr<nsIURI> mFile;
     158                 :     nsCOMPtr<nsIURI> mDataPath;
     159                 :     nsCString mRelativePathToData;
     160                 :     nsCString mCharset;
     161                 : };
     162                 : 
     163                 : // Information about the output stream
     164                 : struct OutputData
     165                 : {
     166                 :     nsCOMPtr<nsIURI> mFile;
     167                 :     nsCOMPtr<nsIURI> mOriginalLocation;
     168                 :     nsCOMPtr<nsIOutputStream> mStream;
     169                 :     PRInt64 mSelfProgress;
     170                 :     PRInt64 mSelfProgressMax;
     171                 :     bool mCalcFileExt;
     172                 : 
     173             344 :     OutputData(nsIURI *aFile, nsIURI *aOriginalLocation, bool aCalcFileExt) :
     174                 :         mFile(aFile),
     175                 :         mOriginalLocation(aOriginalLocation),
     176                 :         mSelfProgress(0),
     177                 :         mSelfProgressMax(10000),
     178             344 :         mCalcFileExt(aCalcFileExt)
     179                 :     {
     180             344 :     }
     181              82 :     ~OutputData()
     182              82 :     {
     183              82 :         if (mStream)
     184                 :         {
     185              20 :             mStream->Close();
     186                 :         }
     187              82 :     }
     188                 : };
     189                 : 
     190                 : struct UploadData
     191               0 : {
     192                 :     nsCOMPtr<nsIURI> mFile;
     193                 :     PRInt64 mSelfProgress;
     194                 :     PRInt64 mSelfProgressMax;
     195                 : 
     196               0 :     UploadData(nsIURI *aFile) :
     197                 :         mFile(aFile),
     198                 :         mSelfProgress(0),
     199               0 :         mSelfProgressMax(10000)
     200                 :     {
     201               0 :     }
     202                 : };
     203                 : 
     204                 : struct CleanupData
     205               0 : {
     206                 :     nsCOMPtr<nsILocalFile> mFile;
     207                 :     // Snapshot of what the file actually is at the time of creation so that if
     208                 :     // it transmutes into something else later on it can be ignored. For example,
     209                 :     // catch files that turn into dirs or vice versa.
     210                 :     bool mIsDirectory;
     211                 : };
     212                 : 
     213                 : // Maximum file length constant. The max file name length is
     214                 : // volume / server dependent but it is difficult to obtain
     215                 : // that information. Instead this constant is a reasonable value that
     216                 : // modern systems should able to cope with.
     217                 : const PRUint32 kDefaultMaxFilenameLength = 64;
     218                 : 
     219                 : // Default flags for persistence
     220                 : const PRUint32 kDefaultPersistFlags = 
     221                 :     nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION |
     222                 :     nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES;
     223                 : 
     224                 : // String bundle where error messages come from
     225                 : const char *kWebBrowserPersistStringBundle =
     226                 :     "chrome://global/locale/nsWebBrowserPersist.properties";
     227                 : 
     228             344 : nsWebBrowserPersist::nsWebBrowserPersist() :
     229                 :     mCurrentThingsToPersist(0),
     230                 :     mFirstAndOnlyUse(true),
     231                 :     mCancel(false),
     232                 :     mJustStartedLoading(true),
     233                 :     mCompleted(false),
     234                 :     mStartSaving(false),
     235                 :     mReplaceExisting(true),
     236                 :     mSerializingOutput(false),
     237                 :     mPersistFlags(kDefaultPersistFlags),
     238                 :     mPersistResult(NS_OK),
     239                 :     mTotalCurrentProgress(0),
     240                 :     mTotalMaxProgress(0),
     241                 :     mWrapColumn(72),
     242             344 :     mEncodingFlags(0)
     243                 : {
     244             344 : }
     245                 : 
     246             210 : nsWebBrowserPersist::~nsWebBrowserPersist()
     247                 : {
     248              70 :     Cleanup();
     249             280 : }
     250                 : 
     251                 : //*****************************************************************************
     252                 : // nsWebBrowserPersist::nsISupports
     253                 : //*****************************************************************************
     254                 : 
     255            3128 : NS_IMPL_ADDREF(nsWebBrowserPersist)
     256            2592 : NS_IMPL_RELEASE(nsWebBrowserPersist)
     257                 : 
     258            4322 : NS_INTERFACE_MAP_BEGIN(nsWebBrowserPersist)
     259            4322 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserPersist)
     260            3987 :     NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPersist)
     261            3299 :     NS_INTERFACE_MAP_ENTRY(nsICancelable)
     262            3262 :     NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
     263            2835 :     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     264            2835 :     NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
     265            2472 :     NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
     266            2472 :     NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
     267            2344 : NS_INTERFACE_MAP_END
     268                 : 
     269                 : 
     270                 : //*****************************************************************************
     271                 : // nsWebBrowserPersist::nsIInterfaceRequestor
     272                 : //*****************************************************************************
     273                 : 
     274             398 : NS_IMETHODIMP nsWebBrowserPersist::GetInterface(const nsIID & aIID, void **aIFace)
     275                 : {
     276             398 :     NS_ENSURE_ARG_POINTER(aIFace);
     277                 : 
     278             398 :     *aIFace = nsnull;
     279                 : 
     280             398 :     nsresult rv = QueryInterface(aIID, aIFace);
     281             398 :     if (NS_SUCCEEDED(rv))
     282                 :     {
     283              64 :         return rv;
     284                 :     }
     285                 :     
     286             668 :     if (mProgressListener && (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) 
     287             668 :                              || aIID.Equals(NS_GET_IID(nsIPrompt))))
     288                 :     {
     289               0 :         mProgressListener->QueryInterface(aIID, aIFace);
     290               0 :         if (*aIFace)
     291               0 :             return NS_OK;
     292                 :     }
     293                 : 
     294             668 :     nsCOMPtr<nsIInterfaceRequestor> req = do_QueryInterface(mProgressListener);
     295             334 :     if (req)
     296                 :     {
     297               0 :         return req->GetInterface(aIID, aIFace);
     298                 :     }
     299                 : 
     300             334 :     return NS_ERROR_NO_INTERFACE;
     301                 : }
     302                 : 
     303                 : 
     304                 : //*****************************************************************************
     305                 : // nsWebBrowserPersist::nsIWebBrowserPersist
     306                 : //*****************************************************************************
     307                 : 
     308                 : /* attribute unsigned long persistFlags; */
     309               0 : NS_IMETHODIMP nsWebBrowserPersist::GetPersistFlags(PRUint32 *aPersistFlags)
     310                 : {
     311               0 :     NS_ENSURE_ARG_POINTER(aPersistFlags);
     312               0 :     *aPersistFlags = mPersistFlags;
     313               0 :     return NS_OK;
     314                 : }
     315             344 : NS_IMETHODIMP nsWebBrowserPersist::SetPersistFlags(PRUint32 aPersistFlags)
     316                 : {
     317             344 :     mPersistFlags = aPersistFlags;
     318             344 :     mReplaceExisting = (mPersistFlags & PERSIST_FLAGS_REPLACE_EXISTING_FILES) ? true : false;
     319             344 :     mSerializingOutput = (mPersistFlags & PERSIST_FLAGS_SERIALIZE_OUTPUT) ? true : false;
     320             344 :     return NS_OK;
     321                 : }
     322                 : 
     323                 : /* readonly attribute unsigned long currentState; */
     324               0 : NS_IMETHODIMP nsWebBrowserPersist::GetCurrentState(PRUint32 *aCurrentState)
     325                 : {
     326               0 :     NS_ENSURE_ARG_POINTER(aCurrentState);
     327               0 :     if (mCompleted)
     328                 :     {
     329               0 :         *aCurrentState = PERSIST_STATE_FINISHED;
     330                 :     }
     331               0 :     else if (mFirstAndOnlyUse)
     332                 :     {
     333               0 :         *aCurrentState = PERSIST_STATE_SAVING;
     334                 :     }
     335                 :     else
     336                 :     {
     337               0 :         *aCurrentState = PERSIST_STATE_READY;
     338                 :     }
     339               0 :     return NS_OK;
     340                 : }
     341                 : 
     342                 : /* readonly attribute unsigned long result; */
     343               0 : NS_IMETHODIMP nsWebBrowserPersist::GetResult(PRUint32 *aResult)
     344                 : {
     345               0 :     NS_ENSURE_ARG_POINTER(aResult);
     346               0 :     *aResult = mPersistResult;
     347               0 :     return NS_OK;
     348                 : }
     349                 : 
     350                 : /* attribute nsIWebBrowserPersistProgress progressListener; */
     351               0 : NS_IMETHODIMP nsWebBrowserPersist::GetProgressListener(
     352                 :     nsIWebProgressListener * *aProgressListener)
     353                 : {
     354               0 :     NS_ENSURE_ARG_POINTER(aProgressListener);
     355               0 :     *aProgressListener = mProgressListener;
     356               0 :     NS_IF_ADDREF(*aProgressListener);
     357               0 :     return NS_OK;
     358                 : }
     359                 : 
     360             344 : NS_IMETHODIMP nsWebBrowserPersist::SetProgressListener(
     361                 :     nsIWebProgressListener * aProgressListener)
     362                 : {
     363             344 :     mProgressListener = aProgressListener;
     364             344 :     mProgressListener2 = do_QueryInterface(aProgressListener);
     365             344 :     mEventSink = do_GetInterface(aProgressListener);
     366             344 :     return NS_OK;
     367                 : }
     368                 : 
     369                 : /* void saveURI (in nsIURI aURI, in nsISupports aCacheKey, in nsIURI aReferrer,
     370                 :    in nsIInputStream aPostData, in wstring aExtraHeaders,
     371                 :    in nsISupports aFile); */
     372             337 : NS_IMETHODIMP nsWebBrowserPersist::SaveURI(
     373                 :     nsIURI *aURI, nsISupports *aCacheKey, nsIURI *aReferrer, nsIInputStream *aPostData, const char *aExtraHeaders, nsISupports *aFile)
     374                 : {
     375             337 :     NS_ENSURE_TRUE(mFirstAndOnlyUse, NS_ERROR_FAILURE);
     376             337 :     mFirstAndOnlyUse = false; // Stop people from reusing this object!
     377                 : 
     378             674 :     nsCOMPtr<nsIURI> fileAsURI;
     379                 :     nsresult rv;
     380             337 :     rv = GetValidURIFromObject(aFile, getter_AddRefs(fileAsURI));
     381             337 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
     382                 : 
     383                 :     // SaveURI doesn't like broken uris.
     384             337 :     mPersistFlags |= PERSIST_FLAGS_FAIL_ON_BROKEN_LINKS;
     385             337 :     rv = SaveURIInternal(aURI, aCacheKey, aReferrer, aPostData, aExtraHeaders, fileAsURI, false);
     386             337 :     return NS_FAILED(rv) ? rv : NS_OK;
     387                 : }
     388                 : 
     389                 : /* void saveChannel (in nsIChannel aChannel, in nsISupports aFile); */
     390               7 : NS_IMETHODIMP nsWebBrowserPersist::SaveChannel(
     391                 :     nsIChannel *aChannel, nsISupports *aFile)
     392                 : {
     393               7 :     NS_ENSURE_TRUE(mFirstAndOnlyUse, NS_ERROR_FAILURE);
     394               7 :     mFirstAndOnlyUse = false; // Stop people from reusing this object!
     395                 : 
     396              14 :     nsCOMPtr<nsIURI> fileAsURI;
     397                 :     nsresult rv;
     398               7 :     rv = GetValidURIFromObject(aFile, getter_AddRefs(fileAsURI));
     399               7 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
     400                 : 
     401               7 :     rv = aChannel->GetURI(getter_AddRefs(mURI));
     402               7 :     NS_ENSURE_SUCCESS(rv, rv);
     403                 : 
     404                 :     // SaveURI doesn't like broken uris.
     405               7 :     mPersistFlags |= PERSIST_FLAGS_FAIL_ON_BROKEN_LINKS;
     406               7 :     rv = SaveChannelInternal(aChannel, fileAsURI, false);
     407               7 :     return NS_FAILED(rv) ? rv : NS_OK;
     408                 : }
     409                 : 
     410                 : 
     411                 : /* void saveDocument (in nsIDOMDocument aDocument, in nsIURI aFileURI,
     412                 :    in nsIURI aDataPathURI, in string aOutputContentType,
     413                 :    in unsigned long aEncodingFlags, in unsigned long aWrapColumn); */
     414               0 : NS_IMETHODIMP nsWebBrowserPersist::SaveDocument(
     415                 :     nsIDOMDocument *aDocument, nsISupports *aFile, nsISupports *aDataPath,
     416                 :     const char *aOutputContentType, PRUint32 aEncodingFlags, PRUint32 aWrapColumn)
     417                 : {
     418               0 :     NS_ENSURE_TRUE(mFirstAndOnlyUse, NS_ERROR_FAILURE);
     419               0 :     mFirstAndOnlyUse = false; // Stop people from reusing this object!
     420                 : 
     421               0 :     nsCOMPtr<nsIURI> fileAsURI;
     422               0 :     nsCOMPtr<nsIURI> datapathAsURI;
     423                 :     nsresult rv;
     424                 : 
     425               0 :     rv = GetValidURIFromObject(aFile, getter_AddRefs(fileAsURI));
     426               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
     427               0 :     if (aDataPath)
     428                 :     {
     429               0 :         rv = GetValidURIFromObject(aDataPath, getter_AddRefs(datapathAsURI));
     430               0 :         NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
     431                 :     }
     432                 : 
     433               0 :     mWrapColumn = aWrapColumn;
     434                 : 
     435                 :     // Produce nsIDocumentEncoder encoding flags
     436               0 :     mEncodingFlags = 0;
     437               0 :     if (aEncodingFlags & ENCODE_FLAGS_SELECTION_ONLY)
     438               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputSelectionOnly;
     439               0 :     if (aEncodingFlags & ENCODE_FLAGS_FORMATTED)
     440               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputFormatted;
     441               0 :     if (aEncodingFlags & ENCODE_FLAGS_RAW)
     442               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputRaw;
     443               0 :     if (aEncodingFlags & ENCODE_FLAGS_BODY_ONLY)
     444               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputBodyOnly;
     445               0 :     if (aEncodingFlags & ENCODE_FLAGS_PREFORMATTED)
     446               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputPreformatted;
     447               0 :     if (aEncodingFlags & ENCODE_FLAGS_WRAP)
     448               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputWrap;
     449               0 :     if (aEncodingFlags & ENCODE_FLAGS_FORMAT_FLOWED)
     450               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputFormatFlowed;
     451               0 :     if (aEncodingFlags & ENCODE_FLAGS_ABSOLUTE_LINKS)
     452               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputAbsoluteLinks;
     453               0 :     if (aEncodingFlags & ENCODE_FLAGS_ENCODE_BASIC_ENTITIES)
     454               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputEncodeBasicEntities;
     455               0 :     if (aEncodingFlags & ENCODE_FLAGS_ENCODE_LATIN1_ENTITIES)
     456               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputEncodeLatin1Entities;
     457               0 :     if (aEncodingFlags & ENCODE_FLAGS_ENCODE_HTML_ENTITIES)
     458               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputEncodeHTMLEntities;
     459               0 :     if (aEncodingFlags & ENCODE_FLAGS_ENCODE_W3C_ENTITIES)
     460               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputEncodeW3CEntities;
     461               0 :     if (aEncodingFlags & ENCODE_FLAGS_CR_LINEBREAKS)
     462               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputCRLineBreak;
     463               0 :     if (aEncodingFlags & ENCODE_FLAGS_LF_LINEBREAKS)
     464               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputLFLineBreak;
     465               0 :     if (aEncodingFlags & ENCODE_FLAGS_NOSCRIPT_CONTENT)
     466               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputNoScriptContent;
     467               0 :     if (aEncodingFlags & ENCODE_FLAGS_NOFRAMES_CONTENT)
     468               0 :         mEncodingFlags |= nsIDocumentEncoder::OutputNoFramesContent;
     469                 :     
     470               0 :     if (aOutputContentType)
     471                 :     {
     472               0 :         mContentType.AssignASCII(aOutputContentType);
     473                 :     }
     474                 : 
     475               0 :     rv = SaveDocumentInternal(aDocument, fileAsURI, datapathAsURI);
     476                 : 
     477                 :     // Now save the URIs that have been gathered
     478                 : 
     479               0 :     if (NS_SUCCEEDED(rv) && datapathAsURI)
     480                 :     {
     481               0 :         rv = SaveGatheredURIs(fileAsURI);
     482                 :     }
     483               0 :     else if (mProgressListener)
     484                 :     {
     485                 :         // tell the listener we're done
     486               0 :         mProgressListener->OnStateChange(nsnull, nsnull,
     487                 :                                          nsIWebProgressListener::STATE_START |
     488                 :                                          nsIWebProgressListener::STATE_IS_NETWORK,
     489               0 :                                          NS_OK);
     490               0 :         mProgressListener->OnStateChange(nsnull, nsnull,
     491                 :                                          nsIWebProgressListener::STATE_STOP |
     492                 :                                          nsIWebProgressListener::STATE_IS_NETWORK,
     493               0 :                                          rv);
     494                 :     }
     495                 : 
     496               0 :     return rv;
     497                 : }
     498                 : 
     499                 : /* void cancel(nsresult aReason); */
     500              11 : NS_IMETHODIMP nsWebBrowserPersist::Cancel(nsresult aReason)
     501                 : {
     502              11 :     mCancel = true;
     503              11 :     EndDownload(aReason);
     504              11 :     return NS_OK;
     505                 : }
     506                 : 
     507                 : 
     508                 : /* void cancelSave(); */
     509               0 : NS_IMETHODIMP nsWebBrowserPersist::CancelSave()
     510                 : {
     511               0 :     return Cancel(NS_BINDING_ABORTED);
     512                 : }
     513                 : 
     514                 : 
     515                 : nsresult
     516               0 : nsWebBrowserPersist::StartUpload(nsIStorageStream *storStream, 
     517                 :     nsIURI *aDestinationURI, const nsACString &aContentType)
     518                 : {
     519                 :      // setup the upload channel if the destination is not local
     520               0 :     nsCOMPtr<nsIInputStream> inputstream;
     521               0 :     nsresult rv = storStream->NewInputStream(0, getter_AddRefs(inputstream));
     522               0 :     NS_ENSURE_TRUE(inputstream, NS_ERROR_FAILURE);
     523               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
     524               0 :     return StartUpload(inputstream, aDestinationURI, aContentType);
     525                 : }
     526                 : 
     527                 : nsresult
     528               0 : nsWebBrowserPersist::StartUpload(nsIInputStream *aInputStream,
     529                 :     nsIURI *aDestinationURI, const nsACString &aContentType)
     530                 : {
     531               0 :     nsCOMPtr<nsIChannel> destChannel;
     532               0 :     CreateChannelFromURI(aDestinationURI, getter_AddRefs(destChannel));
     533               0 :     nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(destChannel));
     534               0 :     NS_ENSURE_TRUE(uploadChannel, NS_ERROR_FAILURE);
     535                 : 
     536                 :     // Set the upload stream
     537                 :     // NOTE: ALL data must be available in "inputstream"
     538               0 :     nsresult rv = uploadChannel->SetUploadStream(aInputStream, aContentType, -1);
     539               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
     540               0 :     rv = destChannel->AsyncOpen(this, nsnull);
     541               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
     542                 : 
     543                 :     // add this to the upload list
     544               0 :     nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(destChannel);
     545               0 :     nsISupportsKey key(keyPtr);
     546               0 :     mUploadList.Put(&key, new UploadData(aDestinationURI));
     547                 : 
     548               0 :     return NS_OK;
     549                 : }
     550                 : 
     551                 : nsresult
     552               0 : nsWebBrowserPersist::SaveGatheredURIs(nsIURI *aFileAsURI)
     553                 : {
     554               0 :     nsresult rv = NS_OK;
     555                 : 
     556                 :     // Count how many URIs in the URI map require persisting
     557               0 :     PRUint32 urisToPersist = 0;
     558               0 :     if (mURIMap.Count() > 0)
     559                 :     {
     560               0 :         mURIMap.Enumerate(EnumCountURIsToPersist, &urisToPersist);
     561                 :     }
     562                 : 
     563               0 :     if (urisToPersist > 0)
     564                 :     {
     565                 :         // Persist each file in the uri map. The document(s)
     566                 :         // will be saved after the last one of these is saved.
     567               0 :         mURIMap.Enumerate(EnumPersistURIs, this);
     568                 :     }
     569                 : 
     570                 :     // if we don't have anything in mOutputMap (added from above enumeration)
     571                 :     // then we build the doc list (SaveDocuments)
     572               0 :     if (mOutputMap.Count() == 0)
     573                 :     {
     574                 :         // There are no URIs to save, so just save the document(s)
     575                 : 
     576                 :         // State start notification
     577               0 :         PRUint32 addToStateFlags = 0;
     578               0 :         if (mProgressListener)
     579                 :         {
     580               0 :             if (mJustStartedLoading)
     581                 :             {
     582               0 :                 addToStateFlags |= nsIWebProgressListener::STATE_IS_NETWORK;
     583                 :             }
     584               0 :             mProgressListener->OnStateChange(nsnull, nsnull,
     585               0 :                 nsIWebProgressListener::STATE_START | addToStateFlags, NS_OK);
     586                 :         }
     587                 : 
     588               0 :         rv = SaveDocuments();
     589               0 :         if (NS_FAILED(rv))
     590               0 :             EndDownload(rv);
     591               0 :         else if (aFileAsURI)
     592                 :         {
     593                 :             // local files won't trigger OnStopRequest so we call EndDownload here
     594               0 :             bool isFile = false;
     595               0 :             aFileAsURI->SchemeIs("file", &isFile);
     596               0 :             if (isFile)
     597               0 :                 EndDownload(NS_OK);
     598                 :         }
     599                 : 
     600                 :         // State stop notification
     601               0 :         if (mProgressListener)
     602                 :         {
     603               0 :             mProgressListener->OnStateChange(nsnull, nsnull,
     604               0 :                 nsIWebProgressListener::STATE_STOP | addToStateFlags, rv);
     605                 :         }
     606                 :     }
     607                 : 
     608               0 :     return rv;
     609                 : }
     610                 : 
     611                 : // this method returns true if there is another file to persist and false if not
     612                 : bool
     613               0 : nsWebBrowserPersist::SerializeNextFile()
     614                 : {
     615               0 :     if (!mSerializingOutput)
     616                 :     {
     617               0 :         return false;
     618                 :     }
     619                 : 
     620               0 :     nsresult rv = SaveGatheredURIs(nsnull);
     621               0 :     if (NS_FAILED(rv))
     622                 :     {
     623               0 :         return false;
     624                 :     }
     625                 : 
     626               0 :     return (mURIMap.Count() 
     627               0 :         || mUploadList.Count()
     628               0 :         || mDocList.Length()
     629               0 :         || mOutputMap.Count());
     630                 : }
     631                 : 
     632                 : 
     633                 : //*****************************************************************************
     634                 : // nsWebBrowserPersist::nsIRequestObserver
     635                 : //*****************************************************************************
     636                 : 
     637              82 : NS_IMETHODIMP nsWebBrowserPersist::OnStartRequest(
     638                 :     nsIRequest* request, nsISupports *ctxt)
     639                 : {
     640              82 :     if (mProgressListener)
     641                 :     {
     642                 :         PRUint32 stateFlags = nsIWebProgressListener::STATE_START |
     643              82 :                               nsIWebProgressListener::STATE_IS_REQUEST;
     644              82 :         if (mJustStartedLoading)
     645                 :         {
     646              82 :             stateFlags |= nsIWebProgressListener::STATE_IS_NETWORK;
     647                 :         }
     648              82 :         mProgressListener->OnStateChange(nsnull, request, stateFlags, NS_OK);
     649                 :     }
     650                 : 
     651              82 :     mJustStartedLoading = false;
     652                 : 
     653             164 :     nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
     654              82 :     NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);
     655                 : 
     656             164 :     nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(request);
     657             164 :     nsISupportsKey key(keyPtr);
     658              82 :     OutputData *data = (OutputData *) mOutputMap.Get(&key);
     659                 : 
     660                 :     // NOTE: This code uses the channel as a hash key so it will not
     661                 :     //       recognize redirected channels because the key is not the same.
     662                 :     //       When that happens we remove and add the data entry to use the
     663                 :     //       new channel as the hash key.
     664              82 :     if (!data)
     665                 :     {
     666               4 :         UploadData *upData = (UploadData *) mUploadList.Get(&key);
     667               4 :         if (!upData)
     668                 :         {
     669                 :             // Redirect? Try and fixup the output table
     670               4 :             nsresult rv = FixRedirectedChannelEntry(channel);
     671               4 :             NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
     672                 : 
     673                 :             // Should be able to find the data after fixup unless redirects
     674                 :             // are disabled.
     675               4 :             data = (OutputData *) mOutputMap.Get(&key);
     676               4 :             if (!data)
     677                 :             {
     678               4 :                 return NS_ERROR_FAILURE;
     679                 :             }
     680                 :         }
     681                 :     }
     682                 : 
     683              78 :     if (data && data->mFile)
     684                 :     {
     685                 :         // If PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION is set in mPersistFlags,
     686                 :         // try to determine whether this channel needs to apply Content-Encoding
     687                 :         // conversions.
     688              78 :         NS_ASSERTION(!((mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION) &&
     689                 :                       (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION)),
     690                 :                      "Conflict in persist flags: both AUTODETECT and NO_CONVERSION set");
     691              78 :         if (mPersistFlags & PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION)
     692              78 :             SetApplyConversionIfNeeded(channel);
     693                 : 
     694              78 :         if (data->mCalcFileExt && !(mPersistFlags & PERSIST_FLAGS_DONT_CHANGE_FILENAMES))
     695                 :         {
     696                 :             // this is the first point at which the server can tell us the mimetype
     697               0 :             CalculateAndAppendFileExt(data->mFile, channel, data->mOriginalLocation);
     698                 : 
     699                 :             // now make filename conformant and unique
     700               0 :             CalculateUniqueFilename(data->mFile);
     701                 :         }
     702                 : 
     703                 :         // compare uris and bail before we add to output map if they are equal
     704              78 :         bool isEqual = false;
     705              78 :         if (NS_SUCCEEDED(data->mFile->Equals(data->mOriginalLocation, &isEqual))
     706                 :             && isEqual)
     707                 :         {
     708                 :             // remove from output map
     709               0 :             delete data;
     710               0 :             mOutputMap.Remove(&key);
     711                 : 
     712                 :             // cancel; we don't need to know any more
     713                 :             // stop request will get called
     714               0 :             request->Cancel(NS_BINDING_ABORTED);
     715                 :         }
     716                 :     }
     717                 : 
     718              78 :     return NS_OK;
     719                 : }
     720                 :  
     721              82 : NS_IMETHODIMP nsWebBrowserPersist::OnStopRequest(
     722                 :     nsIRequest* request, nsISupports *ctxt, nsresult status)
     723                 : {
     724             164 :     nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(request);
     725             164 :     nsISupportsKey key(keyPtr);
     726              82 :     OutputData *data = (OutputData *) mOutputMap.Get(&key);
     727              82 :     if (data)
     728                 :     {
     729              71 :         if (NS_SUCCEEDED(mPersistResult) && NS_FAILED(status))
     730              51 :             SendErrorStatusChange(true, status, request, data->mFile);
     731                 : 
     732                 : #if defined(XP_OS2)
     733                 :         // delete 'data';  this will close the stream and let
     734                 :         // us tag the file it created with its source URI
     735                 :         nsCOMPtr<nsIURI> uriSource = data->mOriginalLocation;
     736                 :         nsCOMPtr<nsILocalFile> localFile;
     737                 :         GetLocalFileFromURI(data->mFile, getter_AddRefs(localFile));
     738                 :         delete data;
     739                 :         mOutputMap.Remove(&key);
     740                 :         if (localFile)
     741                 :         {
     742                 :             nsCOMPtr<nsILocalFileOS2> localFileOS2 = do_QueryInterface(localFile);
     743                 :             if (localFileOS2)
     744                 :             {
     745                 :                 nsCAutoString url;
     746                 :                 uriSource->GetSpec(url);
     747                 :                 localFileOS2->SetFileSource(url);
     748                 :             }
     749                 :         }
     750                 : #else
     751                 :         // This will close automatically close the output stream
     752              71 :         delete data;
     753              71 :         mOutputMap.Remove(&key);
     754                 : #endif
     755                 :     }
     756                 :     else
     757                 :     {
     758                 :         // if we didn't find the data in mOutputMap, try mUploadList
     759              11 :         UploadData *upData = (UploadData *) mUploadList.Get(&key);
     760              11 :         if (upData)
     761                 :         {
     762               0 :             delete upData;
     763               0 :             mUploadList.Remove(&key);
     764                 :         }
     765                 :     }
     766                 : 
     767                 :     // ensure we call SaveDocuments if we:
     768                 :     // 1) aren't canceling
     769                 :     // 2) we haven't triggered the save (which we only want to trigger once)
     770                 :     // 3) we aren't serializing (which will call it inside SerializeNextFile)
     771              82 :     if (mOutputMap.Count() == 0 && !mCancel && !mStartSaving && !mSerializingOutput)
     772                 :     {
     773              71 :         nsresult rv = SaveDocuments();
     774              71 :         NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
     775                 :     }
     776                 : 
     777              82 :     bool completed = false;
     778              82 :     if (mOutputMap.Count() == 0 && mUploadList.Count() == 0 && !mCancel)
     779                 :     {
     780                 :         // if no documents left in mDocList, --> done
     781                 :         // if we have no files left to serialize and no error result, --> done
     782              71 :         if (mDocList.Length() == 0
     783               0 :             || (!SerializeNextFile() && NS_SUCCEEDED(mPersistResult)))
     784                 :         {
     785              71 :             completed = true;
     786                 :         }
     787                 :     }
     788                 : 
     789              82 :     if (completed)
     790                 :     {
     791                 :         // we're all done, do our cleanup
     792              71 :         EndDownload(status);
     793                 :     }
     794                 : 
     795              82 :     if (mProgressListener)
     796                 :     {
     797                 :         PRUint32 stateFlags = nsIWebProgressListener::STATE_STOP |
     798              82 :                               nsIWebProgressListener::STATE_IS_REQUEST;
     799              82 :         if (completed)
     800                 :         {
     801              71 :             stateFlags |= nsIWebProgressListener::STATE_IS_NETWORK;
     802                 :         }
     803              82 :         mProgressListener->OnStateChange(nsnull, request, stateFlags, status);
     804                 :     }
     805              82 :     if (completed)
     806                 :     {
     807              71 :         mProgressListener = nsnull;
     808              71 :         mProgressListener2 = nsnull;
     809              71 :         mEventSink = nsnull;
     810                 :     }
     811                 : 
     812              82 :     return NS_OK;
     813                 : }
     814                 : 
     815                 : //*****************************************************************************
     816                 : // nsWebBrowserPersist::nsIStreamListener
     817                 : //*****************************************************************************
     818                 : 
     819              63 : NS_IMETHODIMP nsWebBrowserPersist::OnDataAvailable(
     820                 :     nsIRequest* request, nsISupports *aContext, nsIInputStream *aIStream,
     821                 :     PRUint32 aOffset, PRUint32 aLength)
     822                 : {
     823              63 :     bool cancel = mCancel;
     824              63 :     if (!cancel)
     825                 :     {
     826              56 :         nsresult rv = NS_OK;
     827              56 :         PRUint32 bytesRemaining = aLength;
     828                 : 
     829             112 :         nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
     830              56 :         NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);
     831                 : 
     832             112 :         nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(request);
     833             112 :         nsISupportsKey key(keyPtr);
     834              56 :         OutputData *data = (OutputData *) mOutputMap.Get(&key);
     835              56 :         if (!data) {
     836                 :             // might be uploadData; consume necko's buffer and bail...
     837                 :             PRUint32 n;
     838               0 :             return aIStream->ReadSegments(NS_DiscardSegment, nsnull, aLength, &n);
     839                 :         }
     840                 : 
     841              56 :         bool readError = true;
     842                 : 
     843                 :         // Make the output stream
     844              56 :         if (!data->mStream)
     845                 :         {
     846              20 :             rv = MakeOutputStream(data->mFile, getter_AddRefs(data->mStream));
     847              20 :             if (NS_FAILED(rv))
     848                 :             {
     849               0 :                 readError = false;
     850               0 :                 cancel = true;
     851                 :             }
     852                 :         }
     853                 : 
     854                 :         // Read data from the input and write to the output
     855                 :         char buffer[8192];
     856                 :         PRUint32 bytesRead;
     857             168 :         while (!cancel && bytesRemaining)
     858                 :         {
     859              56 :             readError = true;
     860                 :             rv = aIStream->Read(buffer,
     861              56 :                                 NS_MIN(PRUint32(sizeof(buffer)), bytesRemaining),
     862             112 :                                 &bytesRead);
     863              56 :             if (NS_SUCCEEDED(rv))
     864                 :             {
     865              56 :                 readError = false;
     866                 :                 // Write out the data until something goes wrong, or, it is
     867                 :                 // all written.  We loop because for some errors (e.g., disk
     868                 :                 // full), we get NS_OK with some bytes written, then an error.
     869                 :                 // So, we want to write again in that case to get the actual
     870                 :                 // error code.
     871              56 :                 const char *bufPtr = buffer; // Where to write from.
     872             168 :                 while (NS_SUCCEEDED(rv) && bytesRead)
     873                 :                 {
     874              56 :                     PRUint32 bytesWritten = 0;
     875              56 :                     rv = data->mStream->Write(bufPtr, bytesRead, &bytesWritten);
     876              56 :                     if (NS_SUCCEEDED(rv))
     877                 :                     {
     878              56 :                         bytesRead -= bytesWritten;
     879              56 :                         bufPtr += bytesWritten;
     880              56 :                         bytesRemaining -= bytesWritten;
     881                 :                         // Force an error if (for some reason) we get NS_OK but
     882                 :                         // no bytes written.
     883              56 :                         if (!bytesWritten)
     884                 :                         {
     885               0 :                             rv = NS_ERROR_FAILURE;
     886               0 :                             cancel = true;
     887                 :                         }
     888                 :                     }
     889                 :                     else
     890                 :                     {
     891                 :                         // Disaster - can't write out the bytes - disk full / permission?
     892               0 :                         cancel = true;
     893                 :                     }
     894                 :                 }
     895                 :             }
     896                 :             else
     897                 :             {
     898                 :                 // Disaster - can't read the bytes - broken link / file error?
     899               0 :                 cancel = true;
     900                 :             }
     901                 :         }
     902                 : 
     903              56 :         PRInt32 channelContentLength = -1;
     904             112 :         if (!cancel &&
     905              56 :             NS_SUCCEEDED(channel->GetContentLength(&channelContentLength)))
     906                 :         {
     907                 :             // if we get -1 at this point, we didn't get content-length header
     908                 :             // assume that we got all of the data and push what we have; 
     909                 :             // that's the best we can do now
     910              56 :             if ((-1 == channelContentLength) ||
     911                 :                 ((channelContentLength - (aOffset + aLength)) == 0))
     912                 :             {
     913              20 :                 NS_WARN_IF_FALSE(channelContentLength != -1,
     914                 :                     "nsWebBrowserPersist::OnDataAvailable() no content length "
     915                 :                     "header, pushing what we have");
     916                 :                 // we're done with this pass; see if we need to do upload
     917              40 :                 nsCAutoString contentType;
     918              20 :                 channel->GetContentType(contentType);
     919                 :                 // if we don't have the right type of output stream then it's a local file
     920              40 :                 nsCOMPtr<nsIStorageStream> storStream(do_QueryInterface(data->mStream));
     921              20 :                 if (storStream)
     922                 :                 {
     923               0 :                     data->mStream->Close();
     924               0 :                     data->mStream = nsnull; // null out stream so we don't close it later
     925               0 :                     rv = StartUpload(storStream, data->mFile, contentType);
     926               0 :                     if (NS_FAILED(rv))
     927                 :                     {
     928               0 :                         readError = false;
     929               0 :                         cancel = true;
     930                 :                     }
     931                 :                 }
     932                 :             }
     933                 :         }
     934                 : 
     935                 :         // Notify listener if an error occurred.
     936              56 :         if (cancel)
     937                 :         {
     938                 :             SendErrorStatusChange(readError, rv,
     939               0 :                 readError ? request : nsnull, data->mFile);
     940                 :         }
     941                 :     }
     942                 : 
     943                 :     // Cancel reading?
     944              63 :     if (cancel)
     945                 :     {
     946               7 :         EndDownload(NS_BINDING_ABORTED);
     947                 :     }
     948                 : 
     949              63 :     return NS_OK;
     950                 : }
     951                 : 
     952                 : 
     953                 : //*****************************************************************************
     954                 : // nsWebBrowserPersist::nsIProgressEventSink
     955                 : //*****************************************************************************
     956                 : 
     957                 : /* void onProgress (in nsIRequest request, in nsISupports ctxt,
     958                 :     in unsigned long long aProgress, in unsigned long long aProgressMax); */
     959              60 : NS_IMETHODIMP nsWebBrowserPersist::OnProgress(
     960                 :     nsIRequest *request, nsISupports *ctxt, PRUint64 aProgress,
     961                 :     PRUint64 aProgressMax)
     962                 : {
     963              60 :     if (!mProgressListener)
     964                 :     {
     965               0 :         return NS_OK;
     966                 :     }
     967                 : 
     968                 :     // Store the progress of this request
     969             120 :     nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(request);
     970             120 :     nsISupportsKey key(keyPtr);
     971              60 :     OutputData *data = (OutputData *) mOutputMap.Get(&key);
     972              60 :     if (data)
     973                 :     {
     974              60 :         data->mSelfProgress = PRInt64(aProgress);
     975              60 :         data->mSelfProgressMax = PRInt64(aProgressMax);
     976                 :     }
     977                 :     else
     978                 :     {
     979               0 :         UploadData *upData = (UploadData *) mUploadList.Get(&key);
     980               0 :         if (upData)
     981                 :         {
     982               0 :             upData->mSelfProgress = PRInt64(aProgress);
     983               0 :             upData->mSelfProgressMax = PRInt64(aProgressMax);
     984                 :         }
     985                 :     }
     986                 : 
     987                 :     // Notify listener of total progress
     988              60 :     CalcTotalProgress();
     989              60 :     if (mProgressListener2)
     990                 :     {
     991              52 :       mProgressListener2->OnProgressChange64(nsnull, request, aProgress,
     992              52 :             aProgressMax, mTotalCurrentProgress, mTotalMaxProgress);
     993                 :     }
     994                 :     else
     995                 :     {
     996                 :       // have to truncate 64-bit to 32bit
     997               8 :       mProgressListener->OnProgressChange(nsnull, request, PRUint64(aProgress),
     998               8 :               PRUint64(aProgressMax), mTotalCurrentProgress, mTotalMaxProgress);
     999                 :     }
    1000                 : 
    1001                 :     // If our progress listener implements nsIProgressEventSink,
    1002                 :     // forward the notification
    1003              60 :     if (mEventSink)
    1004                 :     {
    1005               0 :         mEventSink->OnProgress(request, ctxt, aProgress, aProgressMax);
    1006                 :     }
    1007                 : 
    1008              60 :     return NS_OK;
    1009                 : }
    1010                 : 
    1011                 : /* void onStatus (in nsIRequest request, in nsISupports ctxt,
    1012                 :     in nsresult status, in wstring statusArg); */
    1013             148 : NS_IMETHODIMP nsWebBrowserPersist::OnStatus(
    1014                 :     nsIRequest *request, nsISupports *ctxt, nsresult status,
    1015                 :     const PRUnichar *statusArg)
    1016                 : {
    1017             148 :     if (mProgressListener)
    1018                 :     {
    1019                 :         // We need to filter out non-error error codes.
    1020                 :         // Is the only NS_SUCCEEDED value NS_OK?
    1021             148 :         switch ( status )
    1022                 :         {
    1023                 :         case NS_NET_STATUS_RESOLVING_HOST:
    1024                 :         case NS_NET_STATUS_RESOLVED_HOST:
    1025                 :         case NS_NET_STATUS_BEGIN_FTP_TRANSACTION:
    1026                 :         case NS_NET_STATUS_END_FTP_TRANSACTION:
    1027                 :         case NS_NET_STATUS_CONNECTING_TO:
    1028                 :         case NS_NET_STATUS_CONNECTED_TO:
    1029                 :         case NS_NET_STATUS_SENDING_TO:
    1030                 :         case NS_NET_STATUS_RECEIVING_FROM:
    1031                 :         case NS_NET_STATUS_WAITING_FOR:
    1032                 :         case nsITransport::STATUS_READING:
    1033                 :         case nsITransport::STATUS_WRITING:
    1034             148 :             break;
    1035                 : 
    1036                 :         default:
    1037                 :             // Pass other notifications (for legitimate errors) along.
    1038               0 :             mProgressListener->OnStatusChange(nsnull, request, status, statusArg);
    1039               0 :             break;
    1040                 :         }
    1041                 : 
    1042                 :     }
    1043                 : 
    1044                 :     // If our progress listener implements nsIProgressEventSink,
    1045                 :     // forward the notification
    1046             148 :     if (mEventSink)
    1047                 :     {
    1048               0 :         mEventSink->OnStatus(request, ctxt, status, statusArg);
    1049                 :     }
    1050                 : 
    1051             148 :     return NS_OK;
    1052                 : }
    1053                 : 
    1054                 : 
    1055                 : //*****************************************************************************
    1056                 : // nsWebBrowserPersist private methods
    1057                 : //*****************************************************************************
    1058                 : 
    1059                 : // Convert error info into proper message text and send OnStatusChange notification
    1060                 : // to the web progress listener.
    1061              51 : nsresult nsWebBrowserPersist::SendErrorStatusChange( 
    1062                 :     bool aIsReadError, nsresult aResult, nsIRequest *aRequest, nsIURI *aURI)
    1063                 : {
    1064              51 :     NS_ENSURE_ARG_POINTER(aURI);
    1065                 : 
    1066              51 :     if (!mProgressListener)
    1067                 :     {
    1068                 :         // Do nothing
    1069               0 :         return NS_OK;
    1070                 :     }
    1071                 : 
    1072                 :     // Get the file path or spec from the supplied URI
    1073             102 :     nsCOMPtr<nsILocalFile> file;
    1074              51 :     GetLocalFileFromURI(aURI, getter_AddRefs(file));
    1075             102 :     nsAutoString path;
    1076              51 :     if (file)
    1077                 :     {
    1078              51 :         file->GetPath(path);
    1079                 :     }
    1080                 :     else
    1081                 :     {
    1082               0 :         nsCAutoString fileurl;
    1083               0 :         aURI->GetSpec(fileurl);
    1084               0 :         AppendUTF8toUTF16(fileurl, path);
    1085                 :     }
    1086                 :     
    1087             102 :     nsAutoString msgId;
    1088              51 :     switch(aResult)
    1089                 :     {
    1090                 :     case NS_ERROR_FILE_NAME_TOO_LONG:
    1091                 :         // File name too long.
    1092               0 :         msgId.AssignLiteral("fileNameTooLongError");
    1093               0 :         break;
    1094                 :     case NS_ERROR_FILE_ALREADY_EXISTS:
    1095                 :         // File exists with same name as directory.
    1096               0 :         msgId.AssignLiteral("fileAlreadyExistsError");
    1097               0 :         break;
    1098                 :     case NS_ERROR_FILE_DISK_FULL:
    1099                 :     case NS_ERROR_FILE_NO_DEVICE_SPACE:
    1100                 :         // Out of space on target volume.
    1101               0 :         msgId.AssignLiteral("diskFull");
    1102               0 :         break;
    1103                 : 
    1104                 :     case NS_ERROR_FILE_READ_ONLY:
    1105                 :         // Attempt to write to read/only file.
    1106               0 :         msgId.AssignLiteral("readOnly");
    1107               0 :         break;
    1108                 : 
    1109                 :     case NS_ERROR_FILE_ACCESS_DENIED:
    1110                 :         // Attempt to write without sufficient permissions.
    1111               0 :         msgId.AssignLiteral("accessError");
    1112               0 :         break;
    1113                 : 
    1114                 :     default:
    1115                 :         // Generic read/write error message.
    1116              51 :         if (aIsReadError)
    1117              51 :             msgId.AssignLiteral("readError");
    1118                 :         else
    1119               0 :             msgId.AssignLiteral("writeError");
    1120              51 :         break;
    1121                 :     }
    1122                 :     // Get properties file bundle and extract status string.
    1123                 :     nsresult rv;
    1124             102 :     nsCOMPtr<nsIStringBundleService> s = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
    1125              51 :     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && s, NS_ERROR_FAILURE);
    1126                 : 
    1127             102 :     nsCOMPtr<nsIStringBundle> bundle;
    1128              51 :     rv = s->CreateBundle(kWebBrowserPersistStringBundle, getter_AddRefs(bundle));
    1129              51 :     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && bundle, NS_ERROR_FAILURE);
    1130                 :     
    1131             102 :     nsXPIDLString msgText;
    1132                 :     const PRUnichar *strings[1];
    1133              51 :     strings[0] = path.get();
    1134              51 :     rv = bundle->FormatStringFromName(msgId.get(), strings, 1, getter_Copies(msgText));
    1135              51 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    1136                 : 
    1137              51 :     mProgressListener->OnStatusChange(nsnull, aRequest, aResult, msgText);
    1138                 : 
    1139              51 :     return NS_OK;
    1140                 : }
    1141                 : 
    1142             344 : nsresult nsWebBrowserPersist::GetValidURIFromObject(nsISupports *aObject, nsIURI **aURI) const
    1143                 : {
    1144             344 :     NS_ENSURE_ARG_POINTER(aObject);
    1145             344 :     NS_ENSURE_ARG_POINTER(aURI);
    1146                 :     
    1147             688 :     nsCOMPtr<nsIFile> objAsFile = do_QueryInterface(aObject);
    1148             344 :     if (objAsFile)
    1149                 :     {
    1150              21 :         return NS_NewFileURI(aURI, objAsFile);
    1151                 :     }
    1152             646 :     nsCOMPtr<nsIURI> objAsURI = do_QueryInterface(aObject);
    1153             323 :     if (objAsURI)
    1154                 :     {
    1155             323 :         *aURI = objAsURI;
    1156             323 :         NS_ADDREF(*aURI);
    1157             323 :         return NS_OK;
    1158                 :     }
    1159                 : 
    1160               0 :     return NS_ERROR_FAILURE;
    1161                 : }
    1162                 : 
    1163              71 : nsresult nsWebBrowserPersist::GetLocalFileFromURI(nsIURI *aURI, nsILocalFile **aLocalFile) const
    1164                 : {
    1165                 :     nsresult rv;
    1166                 : 
    1167             142 :     nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
    1168              71 :     if (NS_FAILED(rv))
    1169               0 :         return rv;
    1170                 : 
    1171             142 :     nsCOMPtr<nsIFile> file;
    1172              71 :     rv = fileURL->GetFile(getter_AddRefs(file));
    1173              71 :     if (NS_SUCCEEDED(rv))
    1174              71 :         rv = CallQueryInterface(file, aLocalFile);
    1175                 : 
    1176              71 :     return rv;
    1177                 : }
    1178                 : 
    1179               0 : nsresult nsWebBrowserPersist::AppendPathToURI(nsIURI *aURI, const nsAString & aPath) const
    1180                 : {
    1181               0 :     NS_ENSURE_ARG_POINTER(aURI);
    1182                 : 
    1183               0 :     nsCAutoString newPath;
    1184               0 :     nsresult rv = aURI->GetPath(newPath);
    1185               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    1186                 : 
    1187                 :     // Append a forward slash if necessary
    1188               0 :     PRInt32 len = newPath.Length();
    1189               0 :     if (len > 0 && newPath.CharAt(len - 1) != '/')
    1190                 :     {
    1191               0 :         newPath.Append('/');
    1192                 :     }
    1193                 : 
    1194                 :     // Store the path back on the URI
    1195               0 :     AppendUTF16toUTF8(aPath, newPath);
    1196               0 :     aURI->SetPath(newPath);
    1197                 : 
    1198               0 :     return NS_OK;
    1199                 : }
    1200                 : 
    1201             337 : nsresult nsWebBrowserPersist::SaveURIInternal(
    1202                 :     nsIURI *aURI, nsISupports *aCacheKey, nsIURI *aReferrer,
    1203                 :     nsIInputStream *aPostData, const char *aExtraHeaders,
    1204                 :     nsIURI *aFile, bool aCalcFileExt)
    1205                 : {
    1206             337 :     NS_ENSURE_ARG_POINTER(aURI);
    1207             337 :     NS_ENSURE_ARG_POINTER(aFile);
    1208                 : 
    1209             337 :     nsresult rv = NS_OK;
    1210                 :     
    1211             337 :     mURI = aURI;
    1212                 : 
    1213             337 :     nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
    1214             337 :     if (mPersistFlags & PERSIST_FLAGS_BYPASS_CACHE)
    1215                 :     {
    1216              14 :         loadFlags |= nsIRequest::LOAD_BYPASS_CACHE;
    1217                 :     }
    1218             323 :     else if (mPersistFlags & PERSIST_FLAGS_FROM_CACHE)
    1219                 :     {
    1220             321 :         loadFlags |= nsIRequest::LOAD_FROM_CACHE;
    1221                 :     }
    1222                 : 
    1223                 :     // Extract the cache key
    1224             674 :     nsCOMPtr<nsISupports> cacheKey;
    1225             337 :     if (aCacheKey)
    1226                 :     {
    1227                 :         // Test if the cache key is actually a web page descriptor (docshell)
    1228                 :         // or session history entry.
    1229               0 :         nsCOMPtr<nsISHEntry> shEntry = do_QueryInterface(aCacheKey);
    1230               0 :         if (!shEntry)
    1231                 :         {
    1232                 :             nsCOMPtr<nsIWebPageDescriptor> webPageDescriptor =
    1233               0 :                 do_QueryInterface(aCacheKey);
    1234               0 :             if (webPageDescriptor)
    1235                 :             {
    1236               0 :                 nsCOMPtr<nsISupports> currentDescriptor;
    1237               0 :                 webPageDescriptor->GetCurrentDescriptor(getter_AddRefs(currentDescriptor));
    1238               0 :                 shEntry = do_QueryInterface(currentDescriptor);
    1239                 :             }
    1240                 :         }
    1241                 : 
    1242               0 :         if (shEntry)
    1243                 :         {
    1244               0 :             shEntry->GetCacheKey(getter_AddRefs(cacheKey));
    1245                 :         }
    1246                 :         else
    1247                 :         {
    1248                 :             // Assume a plain cache key
    1249               0 :             cacheKey = aCacheKey;
    1250                 :         }
    1251                 :     }
    1252                 : 
    1253                 :     // Open a channel to the URI
    1254             674 :     nsCOMPtr<nsIChannel> inputChannel;
    1255             337 :     rv = NS_NewChannel(getter_AddRefs(inputChannel), aURI,
    1256                 :             nsnull, nsnull, static_cast<nsIInterfaceRequestor *>(this),
    1257             337 :             loadFlags);
    1258                 :     
    1259             337 :     if (NS_FAILED(rv) || inputChannel == nsnull)
    1260                 :     {
    1261               0 :         EndDownload(NS_ERROR_FAILURE);
    1262               0 :         return NS_ERROR_FAILURE;
    1263                 :     }
    1264                 :     
    1265                 :     // Disable content conversion
    1266             337 :     if (mPersistFlags & PERSIST_FLAGS_NO_CONVERSION)
    1267                 :     {
    1268               0 :         nsCOMPtr<nsIEncodedChannel> encodedChannel(do_QueryInterface(inputChannel));
    1269               0 :         if (encodedChannel)
    1270                 :         {
    1271               0 :             encodedChannel->SetApplyConversion(false);
    1272                 :         }
    1273                 :     }
    1274                 : 
    1275             337 :     if (mPersistFlags & PERSIST_FLAGS_FORCE_ALLOW_COOKIES) 
    1276                 :     {
    1277                 :         nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
    1278               0 :                 do_QueryInterface(inputChannel);
    1279               0 :         if (httpChannelInternal)
    1280               0 :             httpChannelInternal->SetForceAllowThirdPartyCookie(true);
    1281                 :     }
    1282                 : 
    1283                 :     // Set the referrer, post data and headers if any
    1284             674 :     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(inputChannel));
    1285             337 :     if (httpChannel)
    1286                 :     {
    1287                 :         // Referrer
    1288             334 :         if (aReferrer)
    1289                 :         {
    1290               0 :             httpChannel->SetReferrer(aReferrer);
    1291                 :         }
    1292                 : 
    1293                 :         // Post data
    1294             334 :         if (aPostData)
    1295                 :         {
    1296               0 :             nsCOMPtr<nsISeekableStream> stream(do_QueryInterface(aPostData));
    1297               0 :             if (stream)
    1298                 :             {
    1299                 :                 // Rewind the postdata stream
    1300               0 :                 stream->Seek(nsISeekableStream::NS_SEEK_SET, 0);
    1301               0 :                 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
    1302               0 :                 NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
    1303                 :                 // Attach the postdata to the http channel
    1304               0 :                 uploadChannel->SetUploadStream(aPostData, EmptyCString(), -1);
    1305                 :             }
    1306                 :         }
    1307                 : 
    1308                 :         // Cache key
    1309             668 :         nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(httpChannel));
    1310             334 :         if (cacheChannel && cacheKey)
    1311                 :         {
    1312               0 :             cacheChannel->SetCacheKey(cacheKey);
    1313                 :         }
    1314                 : 
    1315                 :         // Headers
    1316             334 :         if (aExtraHeaders)
    1317                 :         {
    1318               0 :             nsCAutoString oneHeader;
    1319               0 :             nsCAutoString headerName;
    1320               0 :             nsCAutoString headerValue;
    1321               0 :             PRInt32 crlf = 0;
    1322               0 :             PRInt32 colon = 0;
    1323               0 :             const char *kWhitespace = "\b\t\r\n ";
    1324               0 :             nsCAutoString extraHeaders(aExtraHeaders);
    1325               0 :             while (true)
    1326                 :             {
    1327               0 :                 crlf = extraHeaders.Find("\r\n", true);
    1328               0 :                 if (crlf == -1)
    1329               0 :                     break;
    1330               0 :                 extraHeaders.Mid(oneHeader, 0, crlf);
    1331               0 :                 extraHeaders.Cut(0, crlf + 2);
    1332               0 :                 colon = oneHeader.Find(":");
    1333               0 :                 if (colon == -1)
    1334               0 :                     break; // Should have a colon
    1335               0 :                 oneHeader.Left(headerName, colon);
    1336               0 :                 colon++;
    1337               0 :                 oneHeader.Mid(headerValue, colon, oneHeader.Length() - colon);
    1338               0 :                 headerName.Trim(kWhitespace);
    1339               0 :                 headerValue.Trim(kWhitespace);
    1340                 :                 // Add the header (merging if required)
    1341               0 :                 rv = httpChannel->SetRequestHeader(headerName, headerValue, true);
    1342               0 :                 if (NS_FAILED(rv))
    1343                 :                 {
    1344               0 :                     EndDownload(NS_ERROR_FAILURE);
    1345               0 :                     return NS_ERROR_FAILURE;
    1346                 :                 }
    1347                 :             }
    1348                 :         }
    1349                 :     }
    1350             337 :     return SaveChannelInternal(inputChannel, aFile, aCalcFileExt);
    1351                 : }
    1352                 : 
    1353             344 : nsresult nsWebBrowserPersist::SaveChannelInternal(
    1354                 :     nsIChannel *aChannel, nsIURI *aFile, bool aCalcFileExt)
    1355                 : {
    1356             344 :     NS_ENSURE_ARG_POINTER(aChannel);
    1357             344 :     NS_ENSURE_ARG_POINTER(aFile);
    1358                 : 
    1359                 :     // The default behaviour of SaveChannelInternal is to download the source
    1360                 :     // into a storage stream and upload that to the target. MakeOutputStream
    1361                 :     // special-cases a file target and creates a file output stream directly.
    1362                 :     // We want to special-case a file source and create a file input stream,
    1363                 :     // but we don't need to do this in the case of a file target.
    1364             688 :     nsCOMPtr<nsIFileChannel> fc(do_QueryInterface(aChannel));
    1365             688 :     nsCOMPtr<nsIFileURL> fu(do_QueryInterface(aFile));
    1366             344 :     if (fc && !fu) {
    1367               0 :         nsCOMPtr<nsIInputStream> fileInputStream, bufferedInputStream;
    1368               0 :         nsresult rv = aChannel->Open(getter_AddRefs(fileInputStream));
    1369               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1370               0 :         rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedInputStream),
    1371               0 :                                        fileInputStream, BUFFERED_OUTPUT_SIZE);
    1372               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1373               0 :         nsCAutoString contentType;
    1374               0 :         aChannel->GetContentType(contentType);
    1375               0 :         return StartUpload(bufferedInputStream, aFile, contentType);
    1376                 :     }
    1377                 : 
    1378                 :     // Read from the input channel
    1379             344 :     nsresult rv = aChannel->AsyncOpen(this, nsnull);
    1380             344 :     if (rv == NS_ERROR_NO_CONTENT)
    1381                 :     {
    1382                 :         // Assume this is a protocol such as mailto: which does not feed out
    1383                 :         // data and just ignore it.
    1384               0 :         return NS_SUCCESS_DONT_FIXUP;
    1385                 :     }
    1386                 : 
    1387             344 :     if (NS_FAILED(rv))
    1388                 :     {
    1389                 :         // Opening failed, but do we care?
    1390               0 :         if (mPersistFlags & PERSIST_FLAGS_FAIL_ON_BROKEN_LINKS)
    1391                 :         {
    1392               0 :             SendErrorStatusChange(true, rv, aChannel, aFile);
    1393               0 :             EndDownload(NS_ERROR_FAILURE);
    1394               0 :             return NS_ERROR_FAILURE;
    1395                 :         }
    1396               0 :         return NS_SUCCESS_DONT_FIXUP;
    1397                 :     }
    1398                 : 
    1399                 :     // Add the output transport to the output map with the channel as the key
    1400             688 :     nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(aChannel);
    1401             688 :     nsISupportsKey key(keyPtr);
    1402             688 :     mOutputMap.Put(&key, new OutputData(aFile, mURI, aCalcFileExt));
    1403                 : 
    1404             344 :     return NS_OK;
    1405                 : }
    1406                 : 
    1407                 : nsresult
    1408               0 : nsWebBrowserPersist::GetExtensionForContentType(const PRUnichar *aContentType, PRUnichar **aExt)
    1409                 : {
    1410               0 :     NS_ENSURE_ARG_POINTER(aContentType);
    1411               0 :     NS_ENSURE_ARG_POINTER(aExt);
    1412                 : 
    1413               0 :     *aExt = nsnull;
    1414                 : 
    1415                 :     nsresult rv;
    1416               0 :     if (!mMIMEService)
    1417                 :     {
    1418               0 :         mMIMEService = do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
    1419               0 :         NS_ENSURE_TRUE(mMIMEService, NS_ERROR_FAILURE);
    1420                 :     }
    1421                 : 
    1422               0 :     nsCOMPtr<nsIMIMEInfo> mimeInfo;
    1423               0 :     nsCAutoString contentType;
    1424               0 :     contentType.AssignWithConversion(aContentType);
    1425               0 :     nsCAutoString ext;
    1426               0 :     rv = mMIMEService->GetPrimaryExtension(contentType, EmptyCString(), ext);
    1427               0 :     if (NS_SUCCEEDED(rv))
    1428                 :     {
    1429               0 :         *aExt = UTF8ToNewUnicode(ext);
    1430               0 :         NS_ENSURE_TRUE(*aExt, NS_ERROR_OUT_OF_MEMORY);
    1431               0 :         return NS_OK;
    1432                 :     }
    1433                 : 
    1434               0 :     return NS_ERROR_FAILURE;
    1435                 : }
    1436                 : 
    1437                 : nsresult
    1438               0 : nsWebBrowserPersist::GetDocumentExtension(nsIDOMDocument *aDocument, PRUnichar **aExt)
    1439                 : {
    1440               0 :     NS_ENSURE_ARG_POINTER(aDocument);
    1441               0 :     NS_ENSURE_ARG_POINTER(aExt);
    1442                 : 
    1443               0 :     nsXPIDLString contentType;
    1444               0 :     nsresult rv = GetDocEncoderContentType(aDocument, nsnull, getter_Copies(contentType));
    1445               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    1446               0 :     return GetExtensionForContentType(contentType.get(), aExt);
    1447                 : }
    1448                 : 
    1449                 : nsresult
    1450               0 : nsWebBrowserPersist::GetDocEncoderContentType(nsIDOMDocument *aDocument, const PRUnichar *aContentType, PRUnichar **aRealContentType)
    1451                 : {
    1452               0 :     NS_ENSURE_ARG_POINTER(aDocument);
    1453               0 :     NS_ENSURE_ARG_POINTER(aRealContentType);
    1454                 : 
    1455               0 :     *aRealContentType = nsnull;
    1456                 : 
    1457               0 :     nsAutoString defaultContentType(NS_LITERAL_STRING("text/html"));
    1458                 : 
    1459                 :     // Get the desired content type for the document, either by using the one
    1460                 :     // supplied or from the document itself.
    1461                 : 
    1462               0 :     nsAutoString contentType;
    1463               0 :     if (aContentType)
    1464                 :     {
    1465               0 :         contentType.Assign(aContentType);
    1466                 :     }
    1467                 :     else
    1468                 :     {
    1469                 :         // Get the content type from the document
    1470               0 :         nsAutoString type;
    1471               0 :         if (NS_SUCCEEDED(aDocument->GetContentType(type)) && !type.IsEmpty())
    1472               0 :             contentType.Assign(type);
    1473                 :     }
    1474                 : 
    1475                 :     // Check that an encoder actually exists for the desired output type. The
    1476                 :     // following content types will usually yield an encoder.
    1477                 :     //
    1478                 :     //   text/xml
    1479                 :     //   application/xml
    1480                 :     //   application/xhtml+xml
    1481                 :     //   image/svg+xml
    1482                 :     //   text/html
    1483                 :     //   text/plain
    1484                 : 
    1485               0 :     if (!contentType.IsEmpty() &&
    1486               0 :         !contentType.Equals(defaultContentType, nsCaseInsensitiveStringComparator()))
    1487                 :     {
    1488                 :         // Check if there is an encoder for the desired content type
    1489               0 :         nsCAutoString contractID(NS_DOC_ENCODER_CONTRACTID_BASE);
    1490               0 :         AppendUTF16toUTF8(contentType, contractID);
    1491                 : 
    1492               0 :         nsCOMPtr<nsIComponentRegistrar> registrar;
    1493               0 :         NS_GetComponentRegistrar(getter_AddRefs(registrar));
    1494               0 :         if (registrar)
    1495                 :         {
    1496                 :             bool result;
    1497               0 :             nsresult rv = registrar->IsContractIDRegistered(contractID.get(), &result);
    1498               0 :             if (NS_SUCCEEDED(rv) && result)
    1499                 :             {
    1500               0 :                 *aRealContentType = ToNewUnicode(contentType);
    1501                 :             }
    1502                 :         }
    1503                 :     }
    1504                 : 
    1505                 :     // Use the default if no encoder exists for the desired one
    1506               0 :     if (!*aRealContentType)
    1507                 :     {
    1508               0 :         *aRealContentType = ToNewUnicode(defaultContentType);
    1509                 :     }
    1510                 :     
    1511               0 :     NS_ENSURE_TRUE(*aRealContentType, NS_ERROR_OUT_OF_MEMORY);
    1512                 : 
    1513               0 :     return NS_OK;
    1514                 : }
    1515                 : 
    1516               0 : nsresult nsWebBrowserPersist::SaveDocumentInternal(
    1517                 :     nsIDOMDocument *aDocument, nsIURI *aFile, nsIURI *aDataPath)
    1518                 : {
    1519               0 :     NS_ENSURE_ARG_POINTER(aDocument);
    1520               0 :     NS_ENSURE_ARG_POINTER(aFile);
    1521                 : 
    1522                 :     // See if we can get the local file representation of this URI
    1523               0 :     nsCOMPtr<nsILocalFile> localFile;
    1524               0 :     nsresult rv = GetLocalFileFromURI(aFile, getter_AddRefs(localFile));
    1525                 : 
    1526               0 :     nsCOMPtr<nsILocalFile> localDataPath;
    1527               0 :     if (NS_SUCCEEDED(rv) && aDataPath)
    1528                 :     {
    1529                 :         // See if we can get the local file representation of this URI
    1530               0 :         rv = GetLocalFileFromURI(aDataPath, getter_AddRefs(localDataPath));
    1531               0 :         NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    1532                 :     }
    1533                 : 
    1534               0 :     nsCOMPtr<nsIDOMNode> docAsNode = do_QueryInterface(aDocument);
    1535                 : 
    1536                 :     // Persist the main document
    1537               0 :     nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDocument));
    1538               0 :     mURI = doc->GetDocumentURI();
    1539                 : 
    1540               0 :     nsCOMPtr<nsIURI> oldBaseURI = mCurrentBaseURI;
    1541               0 :     nsCAutoString oldCharset(mCurrentCharset);
    1542                 : 
    1543                 :     // Store the base URI and the charset
    1544               0 :     mCurrentBaseURI = doc->GetBaseURI();
    1545               0 :     mCurrentCharset = doc->GetDocumentCharacterSet();
    1546                 : 
    1547                 :     // Does the caller want to fixup the referenced URIs and save those too?
    1548               0 :     if (aDataPath)
    1549                 :     {
    1550                 :         // Basic steps are these.
    1551                 :         //
    1552                 :         // 1. Iterate through the document (and subdocuments) building a list
    1553                 :         //    of unique URIs.
    1554                 :         // 2. For each URI create an OutputData entry and open a channel to save
    1555                 :         //    it. As each URI is saved, discover the mime type and fix up the
    1556                 :         //    local filename with the correct extension.
    1557                 :         // 3. Store the document in a list and wait for URI persistence to finish
    1558                 :         // 4. After URI persistence completes save the list of documents,
    1559                 :         //    fixing it up as it goes out to file.
    1560                 : 
    1561               0 :         nsCOMPtr<nsIURI> oldDataPath = mCurrentDataPath;
    1562               0 :         bool oldDataPathIsRelative = mCurrentDataPathIsRelative;
    1563               0 :         nsCString oldCurrentRelativePathToData = mCurrentRelativePathToData;
    1564               0 :         PRUint32 oldThingsToPersist = mCurrentThingsToPersist;
    1565                 : 
    1566               0 :         mCurrentDataPathIsRelative = false;
    1567               0 :         mCurrentDataPath = aDataPath;
    1568               0 :         mCurrentRelativePathToData = "";
    1569               0 :         mCurrentThingsToPersist = 0;
    1570                 : 
    1571                 :         // Determine if the specified data path is relative to the
    1572                 :         // specified file, (e.g. c:\docs\htmldata is relative to
    1573                 :         // c:\docs\myfile.htm, but not to d:\foo\data.
    1574                 : 
    1575                 :         // Starting with the data dir work back through its parents
    1576                 :         // checking if one of them matches the base directory.
    1577                 : 
    1578               0 :         if (localDataPath && localFile)
    1579                 :         {
    1580               0 :             nsCOMPtr<nsIFile> baseDir;
    1581               0 :             localFile->GetParent(getter_AddRefs(baseDir));
    1582                 : 
    1583               0 :             nsCAutoString relativePathToData;
    1584               0 :             nsCOMPtr<nsIFile> dataDirParent;
    1585               0 :             dataDirParent = localDataPath;
    1586               0 :             while (dataDirParent)
    1587                 :             {
    1588               0 :                 bool sameDir = false;
    1589               0 :                 dataDirParent->Equals(baseDir, &sameDir);
    1590               0 :                 if (sameDir)
    1591                 :                 {
    1592               0 :                     mCurrentRelativePathToData = relativePathToData;
    1593               0 :                     mCurrentDataPathIsRelative = true;
    1594               0 :                     break;
    1595                 :                 }
    1596                 : 
    1597               0 :                 nsAutoString dirName;
    1598               0 :                 dataDirParent->GetLeafName(dirName);
    1599                 : 
    1600               0 :                 nsCAutoString newRelativePathToData;
    1601               0 :                 newRelativePathToData = NS_ConvertUTF16toUTF8(dirName)
    1602               0 :                                       + NS_LITERAL_CSTRING("/")
    1603               0 :                                       + relativePathToData;
    1604               0 :                 relativePathToData = newRelativePathToData;
    1605                 : 
    1606               0 :                 nsCOMPtr<nsIFile> newDataDirParent;
    1607               0 :                 rv = dataDirParent->GetParent(getter_AddRefs(newDataDirParent));
    1608               0 :                 dataDirParent = newDataDirParent;
    1609                 :             }
    1610                 :         }
    1611                 :         else
    1612                 :         {
    1613                 :             // generate a relative path if possible
    1614               0 :             nsCOMPtr<nsIURL> pathToBaseURL(do_QueryInterface(aFile));
    1615               0 :             if (pathToBaseURL)
    1616                 :             {
    1617               0 :                 nsCAutoString relativePath;  // nsACString
    1618               0 :                 if (NS_SUCCEEDED(pathToBaseURL->GetRelativeSpec(aDataPath, relativePath)))
    1619                 :                 {
    1620               0 :                     mCurrentDataPathIsRelative = true;
    1621               0 :                     mCurrentRelativePathToData = relativePath;
    1622                 :                 }
    1623                 :             }
    1624                 :         }
    1625                 : 
    1626                 :         // Store the document in a list so when URI persistence is done and the
    1627                 :         // filenames of saved URIs are known, the documents can be fixed up and
    1628                 :         // saved
    1629                 : 
    1630               0 :         DocData *docData = new DocData;
    1631               0 :         docData->mBaseURI = mCurrentBaseURI;
    1632               0 :         docData->mCharset = mCurrentCharset;
    1633               0 :         docData->mDocument = aDocument;
    1634               0 :         docData->mFile = aFile;
    1635               0 :         docData->mRelativePathToData = mCurrentRelativePathToData;
    1636               0 :         docData->mDataPath = mCurrentDataPath;
    1637               0 :         docData->mDataPathIsRelative = mCurrentDataPathIsRelative;
    1638               0 :         mDocList.AppendElement(docData);
    1639                 : 
    1640                 :         // Walk the DOM gathering a list of externally referenced URIs in the uri map
    1641               0 :         nsCOMPtr<nsIDOMTreeWalker> walker;
    1642                 :         rv = aDocument->CreateTreeWalker(docAsNode, 
    1643                 :             nsIDOMNodeFilter::SHOW_ELEMENT |
    1644                 :                 nsIDOMNodeFilter::SHOW_DOCUMENT |
    1645                 :                 nsIDOMNodeFilter::SHOW_PROCESSING_INSTRUCTION,
    1646               0 :             nsnull, true, getter_AddRefs(walker));
    1647               0 :         NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    1648                 : 
    1649               0 :         nsCOMPtr<nsIDOMNode> currentNode;
    1650               0 :         walker->GetCurrentNode(getter_AddRefs(currentNode));
    1651               0 :         while (currentNode)
    1652                 :         {
    1653               0 :             OnWalkDOMNode(currentNode);
    1654               0 :             walker->NextNode(getter_AddRefs(currentNode));
    1655                 :         }
    1656                 : 
    1657                 :         // If there are things to persist, create a directory to hold them
    1658               0 :         if (mCurrentThingsToPersist > 0)
    1659                 :         {
    1660               0 :             if (localDataPath)
    1661                 :             {
    1662               0 :                 bool exists = false;
    1663               0 :                 bool haveDir = false;
    1664                 : 
    1665               0 :                 localDataPath->Exists(&exists);
    1666               0 :                 if (exists)
    1667                 :                 {
    1668               0 :                     localDataPath->IsDirectory(&haveDir);
    1669                 :                 }
    1670               0 :                 if (!haveDir)
    1671                 :                 {
    1672               0 :                     rv = localDataPath->Create(nsILocalFile::DIRECTORY_TYPE, 0755);
    1673               0 :                     if (NS_SUCCEEDED(rv))
    1674               0 :                         haveDir = true;
    1675                 :                     else
    1676               0 :                         SendErrorStatusChange(false, rv, nsnull, aFile);
    1677                 :                 }
    1678               0 :                 if (!haveDir)
    1679                 :                 {
    1680               0 :                     EndDownload(NS_ERROR_FAILURE);
    1681               0 :                     mCurrentBaseURI = oldBaseURI;
    1682               0 :                     mCurrentCharset = oldCharset;
    1683               0 :                     return NS_ERROR_FAILURE;
    1684                 :                 }
    1685               0 :                 if (mPersistFlags & PERSIST_FLAGS_CLEANUP_ON_FAILURE)
    1686                 :                 {
    1687                 :                     // Add to list of things to delete later if all goes wrong
    1688               0 :                     CleanupData *cleanupData = new CleanupData;
    1689               0 :                     NS_ENSURE_TRUE(cleanupData, NS_ERROR_OUT_OF_MEMORY);
    1690               0 :                     cleanupData->mFile = localDataPath;
    1691               0 :                     cleanupData->mIsDirectory = true;
    1692               0 :                     mCleanupList.AppendElement(cleanupData);
    1693                 :                 }
    1694                 : #if defined(XP_OS2)
    1695                 :                 // tag the directory with the URI that originated its contents
    1696                 :                 nsCOMPtr<nsILocalFileOS2> localFileOS2 = do_QueryInterface(localDataPath);
    1697                 :                 if (localFileOS2)
    1698                 :                 {
    1699                 :                     nsCAutoString url;
    1700                 :                     mCurrentBaseURI->GetSpec(url);
    1701                 :                     localFileOS2->SetFileSource(url);
    1702                 :                 }
    1703                 : #endif
    1704                 :             }
    1705                 :         }
    1706                 : 
    1707               0 :         mCurrentThingsToPersist = oldThingsToPersist;
    1708               0 :         mCurrentDataPath = oldDataPath;
    1709               0 :         mCurrentDataPathIsRelative = oldDataPathIsRelative;
    1710               0 :         mCurrentRelativePathToData = oldCurrentRelativePathToData;
    1711                 :     }
    1712                 :     else
    1713                 :     {
    1714                 :         // Set the document base to ensure relative links still work
    1715               0 :         SetDocumentBase(aDocument, mCurrentBaseURI);
    1716                 : 
    1717                 :         // Get the content type to save with
    1718               0 :         nsXPIDLString realContentType;
    1719                 :         GetDocEncoderContentType(aDocument,
    1720               0 :             !mContentType.IsEmpty() ? mContentType.get() : nsnull,
    1721               0 :             getter_Copies(realContentType));
    1722                 : 
    1723               0 :         nsCAutoString contentType; contentType.AssignWithConversion(realContentType);
    1724               0 :         nsCAutoString charType; // Empty
    1725                 : 
    1726                 :         // Save the document
    1727                 :         rv = SaveDocumentWithFixup(
    1728                 :             aDocument,
    1729                 :             nsnull,  // no dom fixup
    1730                 :             aFile,
    1731                 :             mReplaceExisting,
    1732                 :             contentType,
    1733                 :             charType,
    1734               0 :             mEncodingFlags);
    1735               0 :         NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    1736                 :     }
    1737                 : 
    1738               0 :     mCurrentBaseURI = oldBaseURI;
    1739               0 :     mCurrentCharset = oldCharset;
    1740                 : 
    1741               0 :     return NS_OK;
    1742                 : }
    1743                 : 
    1744              71 : nsresult nsWebBrowserPersist::SaveDocuments()
    1745                 : {
    1746              71 :     nsresult rv = NS_OK;
    1747                 : 
    1748              71 :     mStartSaving = true;
    1749                 : 
    1750                 :     // Iterate through all queued documents, saving them to file and fixing
    1751                 :     // them up on the way.
    1752                 : 
    1753                 :     PRUint32 i;
    1754              71 :     for (i = 0; i < mDocList.Length(); i++)
    1755                 :     {
    1756               0 :         DocData *docData = mDocList.ElementAt(i);
    1757               0 :         if (!docData)
    1758                 :         {
    1759               0 :             rv = NS_ERROR_FAILURE;
    1760               0 :             break;
    1761                 :         }
    1762                 : 
    1763               0 :         mCurrentBaseURI = docData->mBaseURI;
    1764               0 :         mCurrentCharset = docData->mCharset;
    1765                 : 
    1766                 :         // Save the document, fixing it up with the new URIs as we do
    1767                 :         
    1768                 :         nsEncoderNodeFixup *nodeFixup;
    1769               0 :         nodeFixup = new nsEncoderNodeFixup;
    1770               0 :         if (nodeFixup)
    1771               0 :             nodeFixup->mWebBrowserPersist = this;
    1772                 : 
    1773                 :         // Get the content type
    1774               0 :         nsXPIDLString realContentType;
    1775                 :         GetDocEncoderContentType(docData->mDocument,
    1776               0 :             !mContentType.IsEmpty() ? mContentType.get() : nsnull,
    1777               0 :             getter_Copies(realContentType));
    1778                 : 
    1779               0 :         nsCAutoString contentType; contentType.AssignWithConversion(realContentType.get());
    1780               0 :         nsCAutoString charType; // Empty
    1781                 : 
    1782                 :         // Save the document, fixing up the links as it goes out
    1783                 :         rv = SaveDocumentWithFixup(
    1784                 :             docData->mDocument,
    1785                 :             nodeFixup,
    1786                 :             docData->mFile,
    1787                 :             mReplaceExisting,
    1788                 :             contentType,
    1789                 :             charType,
    1790               0 :             mEncodingFlags);
    1791                 : 
    1792               0 :         if (NS_FAILED(rv))
    1793                 :             break;
    1794                 : 
    1795                 :         // if we're serializing, bail after first iteration of loop
    1796               0 :         if (mSerializingOutput)
    1797                 :             break;
    1798                 :     }
    1799                 : 
    1800                 :     // delete, cleanup regardless of errors (bug 132417)
    1801              71 :     for (i = 0; i < mDocList.Length(); i++)
    1802                 :     {
    1803               0 :         DocData *docData = mDocList.ElementAt(i);
    1804               0 :         delete docData;
    1805               0 :         if (mSerializingOutput)
    1806                 :         {
    1807               0 :             mDocList.RemoveElementAt(i);
    1808               0 :             break;
    1809                 :         }
    1810                 :     }
    1811                 : 
    1812              71 :     if (!mSerializingOutput)
    1813                 :     {
    1814              71 :         mDocList.Clear();
    1815                 :     }
    1816                 : 
    1817              71 :     return rv;
    1818                 : }
    1819                 : 
    1820             159 : void nsWebBrowserPersist::Cleanup()
    1821                 : {
    1822             159 :     mURIMap.Enumerate(EnumCleanupURIMap, this);
    1823             159 :     mURIMap.Reset();
    1824             159 :     mOutputMap.Enumerate(EnumCleanupOutputMap, this);
    1825             159 :     mOutputMap.Reset();
    1826             159 :     mUploadList.Enumerate(EnumCleanupUploadList, this);
    1827             159 :     mUploadList.Reset();
    1828                 :     PRUint32 i;
    1829             159 :     for (i = 0; i < mDocList.Length(); i++)
    1830                 :     {
    1831               0 :         DocData *docData = mDocList.ElementAt(i);
    1832               0 :         delete docData;
    1833                 :     }
    1834             159 :     mDocList.Clear();
    1835             159 :     for (i = 0; i < mCleanupList.Length(); i++)
    1836                 :     {
    1837               0 :         CleanupData *cleanupData = mCleanupList.ElementAt(i);
    1838               0 :         delete cleanupData;
    1839                 :     }
    1840             159 :     mCleanupList.Clear();
    1841             159 :     mFilenameList.Clear();
    1842             159 : }
    1843                 : 
    1844               0 : void nsWebBrowserPersist::CleanupLocalFiles()
    1845                 : {
    1846                 :     // Two passes, the first pass cleans up files, the second pass tests
    1847                 :     // for and then deletes empty directories. Directories that are not
    1848                 :     // empty after the first pass must contain files from something else
    1849                 :     // and are not deleted.
    1850                 :     int pass;
    1851               0 :     for (pass = 0; pass < 2; pass++)
    1852                 :     {
    1853                 :         PRUint32 i;
    1854               0 :         for (i = 0; i < mCleanupList.Length(); i++)
    1855                 :         {
    1856               0 :             CleanupData *cleanupData = mCleanupList.ElementAt(i);
    1857               0 :             nsCOMPtr<nsILocalFile> file = cleanupData->mFile;
    1858                 : 
    1859                 :             // Test if the dir / file exists (something in an earlier loop
    1860                 :             // may have already removed it)
    1861               0 :             bool exists = false;
    1862               0 :             file->Exists(&exists);
    1863               0 :             if (!exists)
    1864               0 :                 continue;
    1865                 : 
    1866                 :             // Test if the file has changed in between creation and deletion
    1867                 :             // in some way that means it should be ignored
    1868               0 :             bool isDirectory = false;
    1869               0 :             file->IsDirectory(&isDirectory);
    1870               0 :             if (isDirectory != cleanupData->mIsDirectory)
    1871               0 :                 continue; // A file has become a dir or vice versa !
    1872                 : 
    1873               0 :             if (pass == 0 && !isDirectory)
    1874                 :             {
    1875               0 :                 file->Remove(false);
    1876                 :             }
    1877               0 :             else if (pass == 1 && isDirectory) // Directory
    1878                 :             {
    1879                 :                 // Directories are more complicated. Enumerate through
    1880                 :                 // children looking for files. Any files created by the
    1881                 :                 // persist object would have been deleted by the first
    1882                 :                 // pass so if there are any there at this stage, the dir
    1883                 :                 // cannot be deleted because it has someone else's files
    1884                 :                 // in it. Empty child dirs are deleted but they must be
    1885                 :                 // recursed through to ensure they are actually empty.
    1886                 : 
    1887               0 :                 bool isEmptyDirectory = true;
    1888               0 :                 nsCOMArray<nsISimpleEnumerator> dirStack;
    1889               0 :                 PRInt32 stackSize = 0;
    1890                 : 
    1891                 :                 // Push the top level enum onto the stack
    1892               0 :                 nsCOMPtr<nsISimpleEnumerator> pos;
    1893               0 :                 if (NS_SUCCEEDED(file->GetDirectoryEntries(getter_AddRefs(pos))))
    1894               0 :                     dirStack.AppendObject(pos);
    1895                 : 
    1896               0 :                 while (isEmptyDirectory && (stackSize = dirStack.Count()))
    1897                 :                 {
    1898                 :                     // Pop the last element
    1899               0 :                     nsCOMPtr<nsISimpleEnumerator> curPos;
    1900               0 :                     curPos = dirStack[stackSize-1];
    1901               0 :                     dirStack.RemoveObjectAt(stackSize - 1);
    1902                 :                     
    1903                 :                     // Test if the enumerator has any more files in it
    1904               0 :                     bool hasMoreElements = false;
    1905               0 :                     curPos->HasMoreElements(&hasMoreElements);
    1906               0 :                     if (!hasMoreElements)
    1907                 :                     {
    1908               0 :                         continue;
    1909                 :                     }
    1910                 : 
    1911                 :                     // Child files automatically make this code drop out,
    1912                 :                     // while child dirs keep the loop going.
    1913               0 :                     nsCOMPtr<nsISupports> child;
    1914               0 :                     curPos->GetNext(getter_AddRefs(child));
    1915               0 :                     NS_ASSERTION(child, "No child element, but hasMoreElements says otherwise");
    1916               0 :                     if (!child)
    1917               0 :                         continue;
    1918               0 :                     nsCOMPtr<nsILocalFile> childAsFile = do_QueryInterface(child);
    1919               0 :                     NS_ASSERTION(childAsFile, "This should be a file but isn't");
    1920                 : 
    1921               0 :                     bool childIsSymlink = false;
    1922               0 :                     childAsFile->IsSymlink(&childIsSymlink);
    1923               0 :                     bool childIsDir = false;
    1924               0 :                     childAsFile->IsDirectory(&childIsDir);                           
    1925               0 :                     if (!childIsDir || childIsSymlink)
    1926                 :                     {
    1927                 :                         // Some kind of file or symlink which means dir
    1928                 :                         // is not empty so just drop out.
    1929               0 :                         isEmptyDirectory = false;
    1930                 :                         break;
    1931                 :                     }
    1932                 :                     // Push parent enumerator followed by child enumerator
    1933               0 :                     nsCOMPtr<nsISimpleEnumerator> childPos;
    1934               0 :                     childAsFile->GetDirectoryEntries(getter_AddRefs(childPos));
    1935               0 :                     dirStack.AppendObject(curPos);
    1936               0 :                     if (childPos)
    1937               0 :                         dirStack.AppendObject(childPos);
    1938                 : 
    1939                 :                 }
    1940               0 :                 dirStack.Clear();
    1941                 : 
    1942                 :                 // If after all that walking the dir is deemed empty, delete it
    1943               0 :                 if (isEmptyDirectory)
    1944                 :                 {
    1945               0 :                     file->Remove(true);
    1946                 :                 }
    1947                 :             }
    1948                 :         }
    1949                 :     }
    1950               0 : }
    1951                 : 
    1952                 : nsresult
    1953               0 : nsWebBrowserPersist::CalculateUniqueFilename(nsIURI *aURI)
    1954                 : {
    1955               0 :     nsCOMPtr<nsIURL> url(do_QueryInterface(aURI));
    1956               0 :     NS_ENSURE_TRUE(url, NS_ERROR_FAILURE);
    1957                 : 
    1958               0 :     bool nameHasChanged = false;
    1959                 :     nsresult rv;
    1960                 : 
    1961                 :     // Get the old filename
    1962               0 :     nsCAutoString filename;
    1963               0 :     rv = url->GetFileName(filename);
    1964               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    1965               0 :     nsCAutoString directory;
    1966               0 :     rv = url->GetDirectory(directory);
    1967               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    1968                 : 
    1969                 :     // Split the filename into a base and an extension.
    1970                 :     // e.g. "foo.html" becomes "foo" & ".html"
    1971                 :     //
    1972                 :     // The nsIURL methods GetFileBaseName & GetFileExtension don't
    1973                 :     // preserve the dot whereas this code does to save some effort
    1974                 :     // later when everything is put back together.
    1975               0 :     PRInt32 lastDot = filename.RFind(".");
    1976               0 :     nsCAutoString base;
    1977               0 :     nsCAutoString ext;
    1978               0 :     if (lastDot >= 0)
    1979                 :     {
    1980               0 :         filename.Mid(base, 0, lastDot);
    1981               0 :         filename.Mid(ext, lastDot, filename.Length() - lastDot); // includes dot
    1982                 :     }
    1983                 :     else
    1984                 :     {
    1985                 :         // filename contains no dot
    1986               0 :         base = filename;
    1987                 :     }
    1988                 : 
    1989                 :     // Test if the filename is longer than allowed by the OS
    1990               0 :     PRInt32 needToChop = filename.Length() - kDefaultMaxFilenameLength;
    1991               0 :     if (needToChop > 0)
    1992                 :     {
    1993                 :         // Truncate the base first and then the ext if necessary
    1994               0 :         if (base.Length() > (PRUint32) needToChop)
    1995                 :         {
    1996               0 :             base.Truncate(base.Length() - needToChop);
    1997                 :         }
    1998                 :         else
    1999                 :         {
    2000               0 :             needToChop -= base.Length() - 1;
    2001               0 :             base.Truncate(1);
    2002               0 :             if (ext.Length() > (PRUint32) needToChop)
    2003                 :             {
    2004               0 :                 ext.Truncate(ext.Length() - needToChop);
    2005                 :             }
    2006                 :             else
    2007                 :             {
    2008               0 :                 ext.Truncate(0);
    2009                 :             }
    2010                 :             // If kDefaultMaxFilenameLength were 1 we'd be in trouble here,
    2011                 :             // but that won't happen because it will be set to a sensible
    2012                 :             // value.
    2013                 :         }
    2014                 : 
    2015               0 :         filename.Assign(base);
    2016               0 :         filename.Append(ext);
    2017               0 :         nameHasChanged = true;
    2018                 :     }
    2019                 : 
    2020                 :     // Ensure the filename is unique
    2021                 :     // Create a filename if it's empty, or if the filename / datapath is
    2022                 :     // already taken by another URI and create an alternate name.
    2023                 : 
    2024               0 :     if (base.IsEmpty() || !mFilenameList.IsEmpty())
    2025                 :     {
    2026               0 :         nsCAutoString tmpPath;
    2027               0 :         nsCAutoString tmpBase;
    2028               0 :         PRUint32 duplicateCounter = 1;
    2029               0 :         while (1)
    2030                 :         {
    2031                 :             // Make a file name,
    2032                 :             // Foo become foo_001, foo_002, etc.
    2033                 :             // Empty files become _001, _002 etc.
    2034                 : 
    2035               0 :             if (base.IsEmpty() || duplicateCounter > 1)
    2036                 :             {
    2037               0 :                 char * tmp = PR_smprintf("_%03d", duplicateCounter);
    2038               0 :                 NS_ENSURE_TRUE(tmp, NS_ERROR_OUT_OF_MEMORY);
    2039               0 :                 if (filename.Length() < kDefaultMaxFilenameLength - 4)
    2040                 :                 {
    2041               0 :                     tmpBase = base;
    2042                 :                 }
    2043                 :                 else
    2044                 :                 {
    2045               0 :                     base.Mid(tmpBase, 0, base.Length() - 4);
    2046                 :                 }
    2047               0 :                 tmpBase.Append(tmp);
    2048               0 :                 PR_smprintf_free(tmp);
    2049                 :             }
    2050                 :             else
    2051                 :             {
    2052               0 :                 tmpBase = base;
    2053                 :             }
    2054                 :         
    2055               0 :             tmpPath.Assign(directory);
    2056               0 :             tmpPath.Append(tmpBase);
    2057               0 :             tmpPath.Append(ext);
    2058                 : 
    2059                 :             // Test if the name is a duplicate
    2060               0 :             if (!mFilenameList.Contains(tmpPath))
    2061                 :             {
    2062               0 :                 if (!base.Equals(tmpBase))
    2063                 :                 {
    2064               0 :                     filename.Assign(tmpBase);
    2065               0 :                     filename.Append(ext);
    2066               0 :                     nameHasChanged = true;
    2067                 :                 }
    2068                 :                 break;
    2069                 :             }
    2070               0 :             duplicateCounter++;
    2071                 :         }
    2072                 :     }
    2073                 : 
    2074                 :     // Add name to list of those already used
    2075               0 :     nsCAutoString newFilepath(directory);
    2076               0 :     newFilepath.Append(filename);
    2077               0 :     mFilenameList.AppendElement(newFilepath);
    2078                 : 
    2079                 :     // Update the uri accordingly if the filename actually changed
    2080               0 :     if (nameHasChanged)
    2081                 :     {
    2082                 :         // Final sanity test
    2083               0 :         if (filename.Length() > kDefaultMaxFilenameLength)
    2084                 :         {
    2085               0 :             NS_WARNING("Filename wasn't truncated less than the max file length - how can that be?");
    2086               0 :             return NS_ERROR_FAILURE;
    2087                 :         }
    2088                 : 
    2089               0 :         nsCOMPtr<nsILocalFile> localFile;
    2090               0 :         GetLocalFileFromURI(aURI, getter_AddRefs(localFile));
    2091                 : 
    2092               0 :         if (localFile)
    2093                 :         {
    2094               0 :             nsAutoString filenameAsUnichar;
    2095               0 :             filenameAsUnichar.AssignWithConversion(filename.get());
    2096               0 :             localFile->SetLeafName(filenameAsUnichar);
    2097                 : 
    2098                 :             // Resync the URI with the file after the extension has been appended
    2099                 :             nsresult rv;
    2100               0 :             nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
    2101               0 :             NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    2102               0 :             fileURL->SetFile(localFile);  // this should recalculate uri
    2103                 :         }
    2104                 :         else
    2105                 :         {
    2106               0 :             url->SetFileName(filename);
    2107                 :         }
    2108                 :     }
    2109                 : 
    2110               0 :     return NS_OK;
    2111                 : }
    2112                 : 
    2113                 : 
    2114                 : nsresult
    2115               0 : nsWebBrowserPersist::MakeFilenameFromURI(nsIURI *aURI, nsString &aFilename)
    2116                 : {
    2117                 :     // Try to get filename from the URI.
    2118               0 :     nsAutoString fileName;
    2119                 : 
    2120                 :     // Get a suggested file name from the URL but strip it of characters
    2121                 :     // likely to cause the name to be illegal.
    2122                 : 
    2123               0 :     nsCOMPtr<nsIURL> url(do_QueryInterface(aURI));
    2124               0 :     if (url)
    2125                 :     {
    2126               0 :         nsCAutoString nameFromURL;
    2127               0 :         url->GetFileName(nameFromURL);
    2128               0 :         if (mPersistFlags & PERSIST_FLAGS_DONT_CHANGE_FILENAMES)
    2129                 :         {
    2130               0 :             fileName.AssignWithConversion(NS_UnescapeURL(nameFromURL).get());
    2131                 :             goto end;
    2132                 :         }
    2133               0 :         if (!nameFromURL.IsEmpty())
    2134                 :         {
    2135                 :             // Unescape the file name (GetFileName escapes it)
    2136               0 :             NS_UnescapeURL(nameFromURL);
    2137               0 :             PRUint32 nameLength = 0;
    2138               0 :             const char *p = nameFromURL.get();
    2139               0 :             for (;*p && *p != ';' && *p != '?' && *p != '#' && *p != '.'
    2140                 :                  ;p++)
    2141                 :             {
    2142               0 :                 if (nsCRT::IsAsciiAlpha(*p) || nsCRT::IsAsciiDigit(*p)
    2143                 :                     || *p == '.' || *p == '-' ||  *p == '_' || (*p == ' '))
    2144                 :                 {
    2145               0 :                     fileName.Append(PRUnichar(*p));
    2146               0 :                     if (++nameLength == kDefaultMaxFilenameLength)
    2147                 :                     {
    2148                 :                         // Note:
    2149                 :                         // There is no point going any further since it will be
    2150                 :                         // truncated in CalculateUniqueFilename anyway.
    2151                 :                         // More importantly, certain implementations of
    2152                 :                         // nsILocalFile (e.g. the Mac impl) might truncate
    2153                 :                         // names in undesirable ways, such as truncating from
    2154                 :                         // the middle, inserting ellipsis and so on.
    2155               0 :                         break;
    2156                 :                     }
    2157                 :                 }
    2158                 :             }
    2159                 :         }
    2160                 :     }
    2161                 : 
    2162                 :     // Empty filenames can confuse the local file object later 
    2163                 :     // when it attempts to set the leaf name in CalculateUniqueFilename
    2164                 :     // for duplicates and ends up replacing the parent dir. To avoid
    2165                 :     // the problem, all filenames are made at least one character long.
    2166               0 :     if (fileName.IsEmpty())
    2167                 :     {
    2168               0 :         fileName.Append(PRUnichar('a')); // 'a' is for arbitrary
    2169                 :     }
    2170                 :  
    2171                 : end:
    2172               0 :     aFilename = fileName;
    2173               0 :     return NS_OK;
    2174                 : }
    2175                 : 
    2176                 : 
    2177                 : nsresult
    2178               0 : nsWebBrowserPersist::CalculateAndAppendFileExt(nsIURI *aURI, nsIChannel *aChannel, nsIURI *aOriginalURIWithExtension)
    2179                 : {
    2180                 :     nsresult rv;
    2181                 : 
    2182               0 :     if (!mMIMEService)
    2183                 :     {
    2184               0 :         mMIMEService = do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
    2185               0 :         NS_ENSURE_TRUE(mMIMEService, NS_ERROR_FAILURE);
    2186                 :     }
    2187                 : 
    2188               0 :     nsCAutoString contentType;
    2189                 : 
    2190                 :     // Get the content type from the channel
    2191               0 :     aChannel->GetContentType(contentType);
    2192                 : 
    2193                 :     // Get the content type from the MIME service
    2194               0 :     if (contentType.IsEmpty())
    2195                 :     {
    2196               0 :         nsCOMPtr<nsIURI> uri;
    2197               0 :         aChannel->GetOriginalURI(getter_AddRefs(uri));
    2198               0 :         mMIMEService->GetTypeFromURI(uri, contentType);
    2199                 :     }
    2200                 : 
    2201                 :     // Append the extension onto the file
    2202               0 :     if (!contentType.IsEmpty())
    2203                 :     {
    2204               0 :         nsCOMPtr<nsIMIMEInfo> mimeInfo;
    2205               0 :         mMIMEService->GetFromTypeAndExtension(
    2206               0 :             contentType, EmptyCString(), getter_AddRefs(mimeInfo));
    2207                 : 
    2208               0 :         nsCOMPtr<nsILocalFile> localFile;
    2209               0 :         GetLocalFileFromURI(aURI, getter_AddRefs(localFile));
    2210                 : 
    2211               0 :         if (mimeInfo)
    2212                 :         {
    2213               0 :             nsCOMPtr<nsIURL> url(do_QueryInterface(aURI));
    2214               0 :             NS_ENSURE_TRUE(url, NS_ERROR_FAILURE);
    2215                 : 
    2216               0 :             nsCAutoString newFileName;
    2217               0 :             url->GetFileName(newFileName);
    2218                 : 
    2219                 :             // Test if the current extension is current for the mime type
    2220               0 :             bool hasExtension = false;
    2221               0 :             PRInt32 ext = newFileName.RFind(".");
    2222               0 :             if (ext != -1)
    2223                 :             {
    2224               0 :                 mimeInfo->ExtensionExists(Substring(newFileName, ext + 1), &hasExtension);
    2225                 :             }
    2226                 : 
    2227                 :             // Append the mime file extension
    2228               0 :             nsCAutoString fileExt;
    2229               0 :             if (!hasExtension)
    2230                 :             {
    2231                 :                 // Test if previous extension is acceptable
    2232               0 :                 nsCOMPtr<nsIURL> oldurl(do_QueryInterface(aOriginalURIWithExtension));
    2233               0 :                 NS_ENSURE_TRUE(oldurl, NS_ERROR_FAILURE);
    2234               0 :                 oldurl->GetFileExtension(fileExt);
    2235               0 :                 bool useOldExt = false;
    2236               0 :                 if (!fileExt.IsEmpty())
    2237                 :                 {
    2238               0 :                     mimeInfo->ExtensionExists(fileExt, &useOldExt);
    2239                 :                 }
    2240                 : 
    2241                 :                 // can't use old extension so use primary extension
    2242               0 :                 if (!useOldExt)
    2243                 :                 {
    2244               0 :                     mimeInfo->GetPrimaryExtension(fileExt);
    2245                 :                 } 
    2246                 : 
    2247               0 :                 if (!fileExt.IsEmpty())
    2248                 :                 {
    2249               0 :                     PRUint32 newLength = newFileName.Length() + fileExt.Length() + 1;
    2250               0 :                     if (newLength > kDefaultMaxFilenameLength)
    2251                 :                     {
    2252               0 :                         newFileName.Truncate(newFileName.Length() - (newLength - kDefaultMaxFilenameLength));
    2253                 :                     }
    2254               0 :                     newFileName.Append(".");
    2255               0 :                     newFileName.Append(fileExt);
    2256                 :                 }
    2257                 : 
    2258               0 :                 if (localFile)
    2259                 :                 {
    2260               0 :                     localFile->SetLeafName(NS_ConvertUTF8toUTF16(newFileName));
    2261                 : 
    2262                 :                     // Resync the URI with the file after the extension has been appended
    2263               0 :                     nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
    2264               0 :                     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    2265               0 :                     fileURL->SetFile(localFile);  // this should recalculate uri
    2266                 :                 }
    2267                 :                 else
    2268                 :                 {
    2269               0 :                     url->SetFileName(newFileName);
    2270                 :                 }
    2271                 :             }
    2272                 : 
    2273                 :         }
    2274                 :     }
    2275                 : 
    2276               0 :     return NS_OK;
    2277                 : }
    2278                 : 
    2279                 : nsresult
    2280              20 : nsWebBrowserPersist::MakeOutputStream(
    2281                 :     nsIURI *aURI, nsIOutputStream **aOutputStream)
    2282                 : {
    2283                 :     nsresult rv;
    2284                 : 
    2285              40 :     nsCOMPtr<nsILocalFile> localFile;
    2286              20 :     GetLocalFileFromURI(aURI, getter_AddRefs(localFile));
    2287              20 :     if (localFile)
    2288              20 :         rv = MakeOutputStreamFromFile(localFile, aOutputStream);
    2289                 :     else
    2290               0 :         rv = MakeOutputStreamFromURI(aURI, aOutputStream);
    2291                 : 
    2292              20 :     return rv;
    2293                 : }
    2294                 : 
    2295                 : nsresult
    2296              20 : nsWebBrowserPersist::MakeOutputStreamFromFile(
    2297                 :     nsILocalFile *aFile, nsIOutputStream **aOutputStream)
    2298                 : {
    2299              20 :     nsresult rv = NS_OK;
    2300                 : 
    2301                 :     nsCOMPtr<nsIFileOutputStream> fileOutputStream =
    2302              40 :         do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv);
    2303              20 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    2304                 : 
    2305                 :     // XXX brade:  get the right flags here!
    2306              20 :     PRInt32 ioFlags = -1;
    2307              20 :     if (mPersistFlags & nsIWebBrowserPersist::PERSIST_FLAGS_APPEND_TO_FILE)
    2308               5 :       ioFlags = PR_APPEND | PR_CREATE_FILE | PR_WRONLY; 
    2309              20 :     rv = fileOutputStream->Init(aFile, ioFlags, -1, 0);
    2310              20 :     NS_ENSURE_SUCCESS(rv, rv);
    2311                 : 
    2312                 :     *aOutputStream = NS_BufferOutputStream(fileOutputStream,
    2313              20 :                                            BUFFERED_OUTPUT_SIZE).get();
    2314                 : 
    2315              20 :     if (mPersistFlags & PERSIST_FLAGS_CLEANUP_ON_FAILURE)
    2316                 :     {
    2317                 :         // Add to cleanup list in event of failure
    2318               0 :         CleanupData *cleanupData = new CleanupData;
    2319               0 :         if (!cleanupData) {
    2320               0 :           NS_RELEASE(*aOutputStream);
    2321               0 :           return NS_ERROR_OUT_OF_MEMORY;
    2322                 :         }
    2323               0 :         cleanupData->mFile = aFile;
    2324               0 :         cleanupData->mIsDirectory = false;
    2325               0 :         mCleanupList.AppendElement(cleanupData);
    2326                 :     }
    2327                 : 
    2328              20 :     return NS_OK;
    2329                 : }
    2330                 : 
    2331                 : nsresult
    2332               0 : nsWebBrowserPersist::MakeOutputStreamFromURI(
    2333                 :     nsIURI *aURI, nsIOutputStream  **aOutputStream)
    2334                 : {
    2335               0 :     PRUint32 segsize = 8192;
    2336               0 :     PRUint32 maxsize = PRUint32(-1);
    2337               0 :     nsCOMPtr<nsIStorageStream> storStream;
    2338               0 :     nsresult rv = NS_NewStorageStream(segsize, maxsize, getter_AddRefs(storStream));
    2339               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2340                 :     
    2341               0 :     NS_ENSURE_SUCCESS(CallQueryInterface(storStream, aOutputStream), NS_ERROR_FAILURE);
    2342               0 :     return NS_OK;
    2343                 : }
    2344                 : 
    2345                 : void
    2346              89 : nsWebBrowserPersist::EndDownload(nsresult aResult)
    2347                 : {
    2348                 :     // Store the error code in the result if it is an error
    2349              89 :     if (NS_SUCCEEDED(mPersistResult) && NS_FAILED(aResult))
    2350                 :     {
    2351              62 :         mPersistResult = aResult;
    2352                 :     }
    2353                 : 
    2354                 :     // Do file cleanup if required
    2355              89 :     if (NS_FAILED(aResult) && (mPersistFlags & PERSIST_FLAGS_CLEANUP_ON_FAILURE))
    2356                 :     {
    2357               0 :         CleanupLocalFiles();
    2358                 :     }
    2359                 : 
    2360                 :     // Cleanup the channels
    2361              89 :     mCompleted = true;
    2362              89 :     Cleanup();
    2363              89 : }
    2364                 : 
    2365                 : /* Hack class to get access to nsISupportsKey's protected mKey member */
    2366                 : class nsMyISupportsKey : public nsISupportsKey
    2367                 : {
    2368                 : public:
    2369                 :     nsMyISupportsKey(nsISupports *key) : nsISupportsKey(key)
    2370                 :     {
    2371                 :     }
    2372                 : 
    2373              11 :     nsresult GetISupports(nsISupports **ret)
    2374                 :     {
    2375              11 :         *ret = mKey;
    2376              11 :         NS_IF_ADDREF(mKey);
    2377              11 :         return NS_OK;
    2378                 :     }
    2379                 : };
    2380                 : 
    2381                 : struct NS_STACK_CLASS FixRedirectData
    2382               8 : {
    2383                 :     nsCOMPtr<nsIChannel> mNewChannel;
    2384                 :     nsCOMPtr<nsIURI> mOriginalURI;
    2385                 :     nsISupportsKey *mMatchingKey;
    2386                 : };
    2387                 : 
    2388                 : nsresult
    2389               4 : nsWebBrowserPersist::FixRedirectedChannelEntry(nsIChannel *aNewChannel)
    2390                 : {
    2391               4 :     NS_ENSURE_ARG_POINTER(aNewChannel);
    2392               8 :     nsCOMPtr<nsIURI> originalURI;
    2393                 : 
    2394                 :     // Enumerate through existing open channels looking for one with
    2395                 :     // a URI matching the one specified.
    2396                 : 
    2397               8 :     FixRedirectData data;
    2398               4 :     data.mMatchingKey = nsnull;
    2399               4 :     data.mNewChannel = aNewChannel;
    2400               4 :     data.mNewChannel->GetOriginalURI(getter_AddRefs(data.mOriginalURI));
    2401               4 :     mOutputMap.Enumerate(EnumFixRedirect, (void *) &data);
    2402                 : 
    2403                 :     // If a match is found, remove the data entry with the old channel key
    2404                 :     // and re-add it with the new channel key.
    2405                 : 
    2406               4 :     if (data.mMatchingKey)
    2407                 :     {
    2408               0 :         OutputData *outputData = (OutputData *) mOutputMap.Get(data.mMatchingKey);
    2409               0 :         NS_ENSURE_TRUE(outputData, NS_ERROR_FAILURE);
    2410               0 :         mOutputMap.Remove(data.mMatchingKey);
    2411                 : 
    2412                 :         // Store data again with new channel unless told to ignore redirects
    2413               0 :         if (!(mPersistFlags & PERSIST_FLAGS_IGNORE_REDIRECTED_DATA))
    2414                 :         {
    2415               0 :             nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(aNewChannel);
    2416               0 :             nsISupportsKey key(keyPtr);
    2417               0 :             mOutputMap.Put(&key, outputData);
    2418                 :         }
    2419                 :     }
    2420                 : 
    2421               4 :     return NS_OK;
    2422                 : }
    2423                 : 
    2424                 : bool
    2425               0 : nsWebBrowserPersist::EnumFixRedirect(nsHashKey *aKey, void *aData, void* closure)
    2426                 : {
    2427               0 :     FixRedirectData *data = (FixRedirectData *) closure;
    2428                 : 
    2429               0 :     nsCOMPtr<nsISupports> keyPtr;
    2430               0 :     ((nsMyISupportsKey *) aKey)->GetISupports(getter_AddRefs(keyPtr));
    2431                 : 
    2432               0 :     nsCOMPtr<nsIChannel> thisChannel = do_QueryInterface(keyPtr);
    2433               0 :     nsCOMPtr<nsIURI> thisURI;
    2434                 : 
    2435               0 :     thisChannel->GetOriginalURI(getter_AddRefs(thisURI));
    2436                 : 
    2437                 :     // Compare this channel's URI to the one passed in.
    2438               0 :     bool matchingURI = false;
    2439               0 :     thisURI->Equals(data->mOriginalURI, &matchingURI);
    2440               0 :     if (matchingURI)
    2441                 :     {
    2442               0 :         data->mMatchingKey = (nsISupportsKey *) aKey;
    2443               0 :         return false; // Stop enumerating
    2444                 :     }
    2445                 : 
    2446               0 :     return true;
    2447                 : }
    2448                 : 
    2449                 : void
    2450              60 : nsWebBrowserPersist::CalcTotalProgress()
    2451                 : {
    2452              60 :     mTotalCurrentProgress = 0;
    2453              60 :     mTotalMaxProgress = 0;
    2454                 : 
    2455              60 :     if (mOutputMap.Count() > 0)
    2456                 :     {
    2457                 :         // Total up the progress of each output stream
    2458              60 :         mOutputMap.Enumerate(EnumCalcProgress, this);
    2459                 :     }
    2460                 : 
    2461              60 :     if (mUploadList.Count() > 0)
    2462                 :     {
    2463                 :         // Total up the progress of each upload
    2464               0 :         mUploadList.Enumerate(EnumCalcUploadProgress, this);
    2465                 :     }
    2466                 : 
    2467                 :     // XXX this code seems pretty bogus and pointless
    2468              60 :     if (mTotalCurrentProgress == LL_ZERO && mTotalMaxProgress == LL_ZERO)
    2469                 :     {
    2470                 :         // No output streams so we must be complete
    2471               0 :         mTotalCurrentProgress = 10000;
    2472               0 :         mTotalMaxProgress = 10000;
    2473                 :     }
    2474              60 : }
    2475                 : 
    2476                 : bool
    2477              60 : nsWebBrowserPersist::EnumCalcProgress(nsHashKey *aKey, void *aData, void* closure)
    2478                 : {
    2479              60 :     nsWebBrowserPersist *pthis = (nsWebBrowserPersist *) closure;
    2480              60 :     OutputData *data = (OutputData *) aData;
    2481                 : 
    2482                 :     // only count toward total progress if destination file is local
    2483             120 :     nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(data->mFile);
    2484              60 :     if (fileURL)
    2485                 :     {
    2486              60 :         pthis->mTotalCurrentProgress += data->mSelfProgress;
    2487              60 :         pthis->mTotalMaxProgress += data->mSelfProgressMax;
    2488                 :     }
    2489              60 :     return true;
    2490                 : }
    2491                 : 
    2492                 : bool
    2493               0 : nsWebBrowserPersist::EnumCalcUploadProgress(nsHashKey *aKey, void *aData, void* closure)
    2494                 : {
    2495               0 :     if (aData && closure)
    2496                 :     {
    2497               0 :         nsWebBrowserPersist *pthis = (nsWebBrowserPersist *) closure;
    2498               0 :         UploadData *data = (UploadData *) aData;
    2499               0 :         pthis->mTotalCurrentProgress += data->mSelfProgress;
    2500               0 :         pthis->mTotalMaxProgress += data->mSelfProgressMax;
    2501                 :     }
    2502               0 :     return true;
    2503                 : }
    2504                 : 
    2505                 : bool
    2506               0 : nsWebBrowserPersist::EnumCountURIsToPersist(nsHashKey *aKey, void *aData, void* closure)
    2507                 : {
    2508               0 :     URIData *data = (URIData *) aData;
    2509               0 :     PRUint32 *count = (PRUint32 *) closure;
    2510               0 :     if (data->mNeedsPersisting && !data->mSaved)
    2511                 :     {
    2512               0 :         (*count)++;
    2513                 :     }
    2514               0 :     return true;
    2515                 : }
    2516                 : 
    2517                 : bool
    2518               0 : nsWebBrowserPersist::EnumPersistURIs(nsHashKey *aKey, void *aData, void* closure)
    2519                 : {
    2520               0 :     URIData *data = (URIData *) aData;
    2521               0 :     if (!data->mNeedsPersisting || data->mSaved)
    2522                 :     {
    2523               0 :         return true;
    2524                 :     }
    2525                 : 
    2526               0 :     nsWebBrowserPersist *pthis = (nsWebBrowserPersist *) closure;
    2527                 :     nsresult rv;
    2528                 : 
    2529                 :     // Create a URI from the key
    2530               0 :     nsCOMPtr<nsIURI> uri;
    2531               0 :     rv = NS_NewURI(getter_AddRefs(uri), 
    2532                 :                    nsDependentCString(((nsCStringKey *) aKey)->GetString(),
    2533               0 :                                       ((nsCStringKey *) aKey)->GetStringLength()),
    2534               0 :                    data->mCharset.get());
    2535               0 :     NS_ENSURE_SUCCESS(rv, false);
    2536                 : 
    2537                 :     // Make a URI to save the data to
    2538               0 :     nsCOMPtr<nsIURI> fileAsURI;
    2539               0 :     rv = data->mDataPath->Clone(getter_AddRefs(fileAsURI));
    2540               0 :     NS_ENSURE_SUCCESS(rv, false);
    2541               0 :     rv = pthis->AppendPathToURI(fileAsURI, data->mFilename);
    2542               0 :     NS_ENSURE_SUCCESS(rv, false);
    2543                 : 
    2544               0 :     rv = pthis->SaveURIInternal(uri, nsnull, nsnull, nsnull, nsnull, fileAsURI, true);
    2545                 :     // if SaveURIInternal fails, then it will have called EndDownload,
    2546                 :     // which means that |aData| is no longer valid memory.  we MUST bail.
    2547               0 :     NS_ENSURE_SUCCESS(rv, false);
    2548                 : 
    2549               0 :     if (rv == NS_OK)
    2550                 :     {
    2551                 :         // Store the actual object because once it's persisted this
    2552                 :         // will be fixed up with the right file extension.
    2553                 : 
    2554               0 :         data->mFile = fileAsURI;
    2555               0 :         data->mSaved = true;
    2556                 :     }
    2557                 :     else
    2558                 :     {
    2559               0 :         data->mNeedsFixup = false;
    2560                 :     }
    2561                 : 
    2562               0 :     if (pthis->mSerializingOutput)
    2563               0 :         return false;
    2564                 : 
    2565               0 :     return true;
    2566                 : }
    2567                 : 
    2568                 : bool
    2569              11 : nsWebBrowserPersist::EnumCleanupOutputMap(nsHashKey *aKey, void *aData, void* closure)
    2570                 : {
    2571              22 :     nsCOMPtr<nsISupports> keyPtr;
    2572              11 :     ((nsMyISupportsKey *) aKey)->GetISupports(getter_AddRefs(keyPtr));
    2573              22 :     nsCOMPtr<nsIChannel> channel = do_QueryInterface(keyPtr);
    2574              11 :     if (channel)
    2575                 :     {
    2576              11 :         channel->Cancel(NS_BINDING_ABORTED);
    2577                 :     }
    2578              11 :     OutputData *data = (OutputData *) aData;
    2579              11 :     delete data;
    2580              11 :     return true;
    2581                 : }
    2582                 : 
    2583                 : 
    2584                 : bool
    2585               0 : nsWebBrowserPersist::EnumCleanupURIMap(nsHashKey *aKey, void *aData, void* closure)
    2586                 : {
    2587               0 :     URIData *data = (URIData *) aData;
    2588               0 :     delete data; // Delete data associated with key
    2589               0 :     return true;
    2590                 : }
    2591                 : 
    2592                 : 
    2593                 : bool
    2594               0 : nsWebBrowserPersist::EnumCleanupUploadList(nsHashKey *aKey, void *aData, void* closure)
    2595                 : {
    2596               0 :     nsCOMPtr<nsISupports> keyPtr;
    2597               0 :     ((nsMyISupportsKey *) aKey)->GetISupports(getter_AddRefs(keyPtr));
    2598               0 :     nsCOMPtr<nsIChannel> channel = do_QueryInterface(keyPtr);
    2599               0 :     if (channel)
    2600                 :     {
    2601               0 :         channel->Cancel(NS_BINDING_ABORTED);
    2602                 :     }
    2603               0 :     UploadData *data = (UploadData *) aData;
    2604               0 :     delete data; // Delete data associated with key
    2605               0 :     return true;
    2606                 : }
    2607                 : 
    2608               0 : nsresult nsWebBrowserPersist::FixupXMLStyleSheetLink(nsIDOMProcessingInstruction *aPI, const nsAString &aHref)
    2609                 : {
    2610               0 :     NS_ENSURE_ARG_POINTER(aPI);
    2611               0 :     nsresult rv = NS_OK;
    2612                 : 
    2613               0 :     nsAutoString data;
    2614               0 :     rv = aPI->GetData(data);
    2615               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    2616                 : 
    2617               0 :     nsAutoString href;
    2618                 :     nsContentUtils::GetPseudoAttributeValue(data,
    2619                 :                                             nsGkAtoms::href,
    2620               0 :                                             href);
    2621                 : 
    2622                 :     // Construct and set a new data value for the xml-stylesheet
    2623               0 :     if (!aHref.IsEmpty() && !href.IsEmpty())
    2624                 :     {
    2625               0 :         nsAutoString alternate;
    2626               0 :         nsAutoString charset;
    2627               0 :         nsAutoString title;
    2628               0 :         nsAutoString type;
    2629               0 :         nsAutoString media;
    2630                 : 
    2631                 :         nsContentUtils::GetPseudoAttributeValue(data,
    2632                 :                                                 nsGkAtoms::alternate,
    2633               0 :                                                 alternate);
    2634                 :         nsContentUtils::GetPseudoAttributeValue(data,
    2635                 :                                                 nsGkAtoms::charset,
    2636               0 :                                                 charset);
    2637                 :         nsContentUtils::GetPseudoAttributeValue(data,
    2638                 :                                                 nsGkAtoms::title,
    2639               0 :                                                 title);
    2640                 :         nsContentUtils::GetPseudoAttributeValue(data,
    2641                 :                                                 nsGkAtoms::type,
    2642               0 :                                                 type);
    2643                 :         nsContentUtils::GetPseudoAttributeValue(data,
    2644                 :                                                 nsGkAtoms::media,
    2645               0 :                                                 media);
    2646                 : 
    2647               0 :         NS_NAMED_LITERAL_STRING(kCloseAttr, "\" ");
    2648               0 :         nsAutoString newData;
    2649               0 :         newData += NS_LITERAL_STRING("href=\"") + aHref + kCloseAttr;
    2650               0 :         if (!title.IsEmpty())
    2651                 :         {
    2652               0 :             newData += NS_LITERAL_STRING("title=\"") + title + kCloseAttr;
    2653                 :         }
    2654               0 :         if (!media.IsEmpty())
    2655                 :         {
    2656               0 :             newData += NS_LITERAL_STRING("media=\"") + media + kCloseAttr;
    2657                 :         }
    2658               0 :         if (!type.IsEmpty())
    2659                 :         {
    2660               0 :             newData += NS_LITERAL_STRING("type=\"") + type + kCloseAttr;
    2661                 :         }
    2662               0 :         if (!charset.IsEmpty())
    2663                 :         {
    2664               0 :             newData += NS_LITERAL_STRING("charset=\"") + charset + kCloseAttr;
    2665                 :         }
    2666               0 :         if (!alternate.IsEmpty())
    2667                 :         {
    2668               0 :             newData += NS_LITERAL_STRING("alternate=\"") + alternate + kCloseAttr;
    2669                 :         }
    2670               0 :         newData.Truncate(newData.Length() - 1);  // Remove the extra space on the end.
    2671               0 :         aPI->SetData(newData);
    2672                 :     }
    2673                 : 
    2674               0 :     return rv;
    2675                 : }
    2676                 : 
    2677               0 : nsresult nsWebBrowserPersist::GetXMLStyleSheetLink(nsIDOMProcessingInstruction *aPI, nsAString &aHref)
    2678                 : {
    2679               0 :     NS_ENSURE_ARG_POINTER(aPI);
    2680                 : 
    2681               0 :     nsresult rv = NS_OK;
    2682               0 :     nsAutoString data;
    2683               0 :     rv = aPI->GetData(data);
    2684               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    2685                 : 
    2686               0 :     nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::href, aHref);
    2687                 : 
    2688               0 :     return NS_OK;
    2689                 : }
    2690                 : 
    2691               0 : nsresult nsWebBrowserPersist::OnWalkDOMNode(nsIDOMNode *aNode)
    2692                 : {
    2693                 :     // Fixup xml-stylesheet processing instructions
    2694               0 :     nsCOMPtr<nsIDOMProcessingInstruction> nodeAsPI = do_QueryInterface(aNode);
    2695               0 :     if (nodeAsPI)
    2696                 :     {
    2697               0 :         nsAutoString target;
    2698               0 :         nodeAsPI->GetTarget(target);
    2699               0 :         if (target.EqualsLiteral("xml-stylesheet"))
    2700                 :         {
    2701               0 :             nsAutoString href;
    2702               0 :             GetXMLStyleSheetLink(nodeAsPI, href);
    2703               0 :             if (!href.IsEmpty())
    2704                 :             {
    2705               0 :                 StoreURI(NS_ConvertUTF16toUTF8(href).get());
    2706                 :             }
    2707                 :         }
    2708               0 :         return NS_OK;
    2709                 :     }
    2710                 : 
    2711                 :     // Test the node to see if it's an image, frame, iframe, css, js
    2712               0 :     nsCOMPtr<nsIDOMHTMLImageElement> nodeAsImage = do_QueryInterface(aNode);
    2713               0 :     if (nodeAsImage)
    2714                 :     {
    2715               0 :         StoreURIAttribute(aNode, "src");
    2716               0 :         return NS_OK;
    2717                 :     }
    2718                 : 
    2719               0 :     nsCOMPtr<nsIDOMSVGImageElement> nodeAsSVGImage = do_QueryInterface(aNode);
    2720               0 :     if (nodeAsSVGImage)
    2721                 :     {
    2722               0 :         StoreURIAttributeNS(aNode, "http://www.w3.org/1999/xlink", "href");
    2723               0 :         return NS_OK;
    2724                 :     }
    2725                 : 
    2726                 : #ifdef MOZ_MEDIA
    2727               0 :     nsCOMPtr<nsIDOMHTMLMediaElement> nodeAsMedia = do_QueryInterface(aNode);
    2728               0 :     if (nodeAsMedia)
    2729                 :     {
    2730               0 :         StoreURIAttribute(aNode, "src");
    2731               0 :         return NS_OK;
    2732                 :     }
    2733               0 :     nsCOMPtr<nsIDOMHTMLSourceElement> nodeAsSource = do_QueryInterface(aNode);
    2734               0 :     if (nodeAsSource)
    2735                 :     {
    2736               0 :         StoreURIAttribute(aNode, "src");
    2737               0 :         return NS_OK;
    2738                 :     }
    2739                 : #endif // MOZ_MEDIA
    2740                 : 
    2741               0 :     nsCOMPtr<nsIDOMHTMLBodyElement> nodeAsBody = do_QueryInterface(aNode);
    2742               0 :     if (nodeAsBody)
    2743                 :     {
    2744               0 :         StoreURIAttribute(aNode, "background");
    2745               0 :         return NS_OK;
    2746                 :     }
    2747                 : 
    2748               0 :     nsCOMPtr<nsIDOMHTMLTableElement> nodeAsTable = do_QueryInterface(aNode);
    2749               0 :     if (nodeAsTable)
    2750                 :     {
    2751               0 :         StoreURIAttribute(aNode, "background");
    2752               0 :         return NS_OK;
    2753                 :     }
    2754                 : 
    2755               0 :     nsCOMPtr<nsIDOMHTMLTableRowElement> nodeAsTableRow = do_QueryInterface(aNode);
    2756               0 :     if (nodeAsTableRow)
    2757                 :     {
    2758               0 :         StoreURIAttribute(aNode, "background");
    2759               0 :         return NS_OK;
    2760                 :     }
    2761                 : 
    2762               0 :     nsCOMPtr<nsIDOMHTMLTableCellElement> nodeAsTableCell = do_QueryInterface(aNode);
    2763               0 :     if (nodeAsTableCell)
    2764                 :     {
    2765               0 :         StoreURIAttribute(aNode, "background");
    2766               0 :         return NS_OK;
    2767                 :     }
    2768                 : 
    2769               0 :     nsCOMPtr<nsIDOMHTMLScriptElement> nodeAsScript = do_QueryInterface(aNode);
    2770               0 :     if (nodeAsScript)
    2771                 :     {
    2772               0 :         StoreURIAttribute(aNode, "src");
    2773               0 :         return NS_OK;
    2774                 :     }
    2775                 : 
    2776               0 :     nsCOMPtr<nsIDOMSVGScriptElement> nodeAsSVGScript = do_QueryInterface(aNode);
    2777               0 :     if (nodeAsSVGScript)
    2778                 :     {
    2779               0 :         StoreURIAttributeNS(aNode, "http://www.w3.org/1999/xlink", "href");
    2780               0 :         return NS_OK;
    2781                 :     }
    2782                 : 
    2783               0 :     nsCOMPtr<nsIDOMHTMLEmbedElement> nodeAsEmbed = do_QueryInterface(aNode);
    2784               0 :     if (nodeAsEmbed)
    2785                 :     {
    2786               0 :         StoreURIAttribute(aNode, "src");
    2787               0 :         return NS_OK;
    2788                 :     }
    2789                 :     
    2790               0 :     nsCOMPtr<nsIDOMHTMLObjectElement> nodeAsObject = do_QueryInterface(aNode);
    2791               0 :     if (nodeAsObject)
    2792                 :     {
    2793               0 :         StoreURIAttribute(aNode, "data");
    2794               0 :         return NS_OK;
    2795                 :     }
    2796                 : 
    2797               0 :     nsCOMPtr<nsIDOMHTMLAppletElement> nodeAsApplet = do_QueryInterface(aNode);
    2798               0 :     if (nodeAsApplet)
    2799                 :     {
    2800                 :         // For an applet, relative URIs are resolved relative to the
    2801                 :         // codebase (which is resolved relative to the base URI).
    2802               0 :         nsCOMPtr<nsIURI> oldBase = mCurrentBaseURI;
    2803               0 :         nsAutoString codebase;
    2804               0 :         nodeAsApplet->GetCodeBase(codebase);
    2805               0 :         if (!codebase.IsEmpty()) {
    2806               0 :             nsCOMPtr<nsIURI> baseURI;
    2807               0 :             NS_NewURI(getter_AddRefs(baseURI), codebase,
    2808               0 :                       mCurrentCharset.get(), mCurrentBaseURI);
    2809               0 :             if (baseURI) {
    2810               0 :                 mCurrentBaseURI = baseURI;
    2811                 :             }
    2812                 :         }
    2813                 : 
    2814               0 :         URIData *archiveURIData = nsnull;
    2815               0 :         StoreURIAttribute(aNode, "archive", true, &archiveURIData);
    2816                 :         // We only store 'code' locally if there is no 'archive',
    2817                 :         // otherwise we assume the archive file(s) contains it (bug 430283).
    2818               0 :         if (!archiveURIData)
    2819               0 :             StoreURIAttribute(aNode, "code");
    2820                 : 
    2821                 :         // restore the base URI we really want to have
    2822               0 :         mCurrentBaseURI = oldBase;
    2823               0 :         return NS_OK;
    2824                 :     }
    2825                 :     
    2826               0 :     nsCOMPtr<nsIDOMHTMLLinkElement> nodeAsLink = do_QueryInterface(aNode);
    2827               0 :     if (nodeAsLink)
    2828                 :     {
    2829                 :         // Test if the link has a rel value indicating it to be a stylesheet
    2830               0 :         nsAutoString linkRel;
    2831               0 :         if (NS_SUCCEEDED(nodeAsLink->GetRel(linkRel)) && !linkRel.IsEmpty())
    2832                 :         {
    2833               0 :             nsReadingIterator<PRUnichar> start;
    2834               0 :             nsReadingIterator<PRUnichar> end;
    2835               0 :             nsReadingIterator<PRUnichar> current;
    2836                 : 
    2837               0 :             linkRel.BeginReading(start);
    2838               0 :             linkRel.EndReading(end);
    2839                 : 
    2840                 :             // Walk through space delimited string looking for "stylesheet"
    2841               0 :             for (current = start; current != end; ++current)
    2842                 :             {
    2843                 :                 // Ignore whitespace
    2844               0 :                 if (nsCRT::IsAsciiSpace(*current))
    2845               0 :                     continue;
    2846                 : 
    2847                 :                 // Grab the next space delimited word
    2848               0 :                 nsReadingIterator<PRUnichar> startWord = current;
    2849               0 :                 do {
    2850               0 :                     ++current;
    2851               0 :                 } while (current != end && !nsCRT::IsAsciiSpace(*current));
    2852                 : 
    2853                 :                 // Store the link for fix up if it says "stylesheet"
    2854               0 :                 if (Substring(startWord, current)
    2855               0 :                         .LowerCaseEqualsLiteral("stylesheet"))
    2856                 :                 {
    2857               0 :                     StoreURIAttribute(aNode, "href");
    2858               0 :                     return NS_OK;
    2859                 :                 }
    2860               0 :                 if (current == end)
    2861               0 :                     break;
    2862                 :             }
    2863                 :         }
    2864               0 :         return NS_OK;
    2865                 :     }
    2866                 : 
    2867               0 :     nsCOMPtr<nsIDOMHTMLFrameElement> nodeAsFrame = do_QueryInterface(aNode);
    2868               0 :     if (nodeAsFrame)
    2869                 :     {
    2870               0 :         URIData *data = nsnull;
    2871               0 :         StoreURIAttribute(aNode, "src", false, &data);
    2872               0 :         if (data)
    2873                 :         {
    2874               0 :             data->mIsSubFrame = true;
    2875                 :             // Save the frame content
    2876               0 :             nsCOMPtr<nsIDOMDocument> content;
    2877               0 :             nodeAsFrame->GetContentDocument(getter_AddRefs(content));
    2878               0 :             if (content)
    2879                 :             {
    2880               0 :                 SaveSubframeContent(content, data);
    2881                 :             }
    2882                 :         }
    2883               0 :         return NS_OK;
    2884                 :     }
    2885                 : 
    2886               0 :     nsCOMPtr<nsIDOMHTMLIFrameElement> nodeAsIFrame = do_QueryInterface(aNode);
    2887               0 :     if (nodeAsIFrame && !(mPersistFlags & PERSIST_FLAGS_IGNORE_IFRAMES))
    2888                 :     {
    2889               0 :         URIData *data = nsnull;
    2890               0 :         StoreURIAttribute(aNode, "src", false, &data);
    2891               0 :         if (data)
    2892                 :         {
    2893               0 :             data->mIsSubFrame = true;
    2894                 :             // Save the frame content
    2895               0 :             nsCOMPtr<nsIDOMDocument> content;
    2896               0 :             nodeAsIFrame->GetContentDocument(getter_AddRefs(content));
    2897               0 :             if (content)
    2898                 :             {
    2899               0 :                 SaveSubframeContent(content, data);
    2900                 :             }
    2901                 :         }
    2902               0 :         return NS_OK;
    2903                 :     }
    2904                 : 
    2905               0 :     nsCOMPtr<nsIDOMHTMLInputElement> nodeAsInput = do_QueryInterface(aNode);
    2906               0 :     if (nodeAsInput)
    2907                 :     {
    2908               0 :         StoreURIAttribute(aNode, "src");
    2909               0 :         return NS_OK;
    2910                 :     }
    2911                 : 
    2912               0 :     return NS_OK;
    2913                 : }
    2914                 : 
    2915                 : nsresult
    2916               0 : nsWebBrowserPersist::GetNodeToFixup(nsIDOMNode *aNodeIn, nsIDOMNode **aNodeOut)
    2917                 : {
    2918               0 :     if (!(mPersistFlags & PERSIST_FLAGS_FIXUP_ORIGINAL_DOM))
    2919                 :     {
    2920               0 :         nsresult rv = aNodeIn->CloneNode(false, 1, aNodeOut);
    2921               0 :         NS_ENSURE_SUCCESS(rv, rv);
    2922                 :     }
    2923                 :     else
    2924                 :     {
    2925               0 :         NS_ADDREF(*aNodeOut = aNodeIn);
    2926                 :     }
    2927               0 :     nsCOMPtr<nsIDOMHTMLElement> element(do_QueryInterface(*aNodeOut));
    2928               0 :     if (element) {
    2929                 :         // Make sure this is not XHTML
    2930               0 :         nsAutoString namespaceURI;
    2931               0 :         element->GetNamespaceURI(namespaceURI);
    2932               0 :         if (namespaceURI.IsEmpty()) {
    2933                 :             // This is a tag-soup node.  It may have a _base_href attribute
    2934                 :             // stuck on it by the parser, but since we're fixing up all URIs
    2935                 :             // relative to the overall document base that will screw us up.
    2936                 :             // Just remove the _base_href.
    2937               0 :             element->RemoveAttribute(NS_LITERAL_STRING("_base_href"));
    2938                 :         }
    2939                 :     }
    2940               0 :     return NS_OK;
    2941                 : }
    2942                 : 
    2943                 : nsresult
    2944               0 : nsWebBrowserPersist::CloneNodeWithFixedUpAttributes(
    2945                 :     nsIDOMNode *aNodeIn, bool *aSerializeCloneKids, nsIDOMNode **aNodeOut)
    2946                 : {
    2947                 :     nsresult rv;
    2948               0 :     *aNodeOut = nsnull;
    2949               0 :     *aSerializeCloneKids = false;
    2950                 : 
    2951                 :     // Fixup xml-stylesheet processing instructions
    2952               0 :     nsCOMPtr<nsIDOMProcessingInstruction> nodeAsPI = do_QueryInterface(aNodeIn);
    2953               0 :     if (nodeAsPI)
    2954                 :     {
    2955               0 :         nsAutoString target;
    2956               0 :         nodeAsPI->GetTarget(target);
    2957               0 :         if (target.EqualsLiteral("xml-stylesheet"))
    2958                 :         {
    2959               0 :             rv = GetNodeToFixup(aNodeIn, aNodeOut);
    2960               0 :             if (NS_SUCCEEDED(rv) && *aNodeOut)
    2961                 :             {
    2962               0 :                 nsCOMPtr<nsIDOMProcessingInstruction> outNode = do_QueryInterface(*aNodeOut);
    2963               0 :                 nsAutoString href;
    2964               0 :                 GetXMLStyleSheetLink(nodeAsPI, href);
    2965               0 :                 if (!href.IsEmpty())
    2966                 :                 {
    2967               0 :                     FixupURI(href);
    2968               0 :                     FixupXMLStyleSheetLink(outNode, href);
    2969                 :                 }
    2970                 :             }
    2971                 :         }
    2972                 :     }
    2973                 : 
    2974                 :     // BASE elements are replaced by a comment so relative links are not hosed.
    2975                 : 
    2976               0 :     if (!(mPersistFlags & PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS))
    2977                 :     {
    2978               0 :         nsCOMPtr<nsIDOMHTMLBaseElement> nodeAsBase = do_QueryInterface(aNodeIn);
    2979               0 :         if (nodeAsBase)
    2980                 :         {
    2981               0 :             nsCOMPtr<nsIDOMDocument> ownerDocument;
    2982               0 :             nodeAsBase->GetOwnerDocument(getter_AddRefs(ownerDocument));
    2983               0 :             if (ownerDocument)
    2984                 :             {
    2985               0 :                 nsAutoString href;
    2986               0 :                 nodeAsBase->GetHref(href); // Doesn't matter if this fails
    2987               0 :                 nsCOMPtr<nsIDOMComment> comment;
    2988               0 :                 nsAutoString commentText; commentText.AssignLiteral(" base ");
    2989               0 :                 if (!href.IsEmpty())
    2990                 :                 {
    2991               0 :                     commentText += NS_LITERAL_STRING("href=\"") + href + NS_LITERAL_STRING("\" ");
    2992                 :                 }
    2993               0 :                 rv = ownerDocument->CreateComment(commentText, getter_AddRefs(comment));
    2994               0 :                 if (comment)
    2995                 :                 {
    2996               0 :                     return CallQueryInterface(comment, aNodeOut);
    2997                 :                 }
    2998                 :             }
    2999                 :         }
    3000                 :     }
    3001                 : 
    3002                 :     // Fix up href and file links in the elements
    3003                 : 
    3004               0 :     nsCOMPtr<nsIDOMHTMLAnchorElement> nodeAsAnchor = do_QueryInterface(aNodeIn);
    3005               0 :     if (nodeAsAnchor)
    3006                 :     {
    3007               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3008               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3009                 :         {
    3010               0 :             FixupAnchor(*aNodeOut);
    3011                 :         }
    3012               0 :         return rv;
    3013                 :     }
    3014                 : 
    3015               0 :     nsCOMPtr<nsIDOMHTMLAreaElement> nodeAsArea = do_QueryInterface(aNodeIn);
    3016               0 :     if (nodeAsArea)
    3017                 :     {
    3018               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3019               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3020                 :         {
    3021               0 :             FixupAnchor(*aNodeOut);
    3022                 :         }
    3023               0 :         return rv;
    3024                 :     }
    3025                 : 
    3026               0 :     nsCOMPtr<nsIDOMHTMLBodyElement> nodeAsBody = do_QueryInterface(aNodeIn);
    3027               0 :     if (nodeAsBody)
    3028                 :     {
    3029               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3030               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3031                 :         {
    3032               0 :             FixupNodeAttribute(*aNodeOut, "background");
    3033                 :         }
    3034               0 :         return rv;
    3035                 :     }
    3036                 : 
    3037               0 :     nsCOMPtr<nsIDOMHTMLTableElement> nodeAsTable = do_QueryInterface(aNodeIn);
    3038               0 :     if (nodeAsTable)
    3039                 :     {
    3040               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3041               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3042                 :         {
    3043               0 :             FixupNodeAttribute(*aNodeOut, "background");
    3044                 :         }
    3045               0 :         return rv;
    3046                 :     }
    3047                 : 
    3048               0 :     nsCOMPtr<nsIDOMHTMLTableRowElement> nodeAsTableRow = do_QueryInterface(aNodeIn);
    3049               0 :     if (nodeAsTableRow)
    3050                 :     {
    3051               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3052               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3053                 :         {
    3054               0 :             FixupNodeAttribute(*aNodeOut, "background");
    3055                 :         }
    3056               0 :         return rv;
    3057                 :     }
    3058                 : 
    3059               0 :     nsCOMPtr<nsIDOMHTMLTableCellElement> nodeAsTableCell = do_QueryInterface(aNodeIn);
    3060               0 :     if (nodeAsTableCell)
    3061                 :     {
    3062               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3063               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3064                 :         {
    3065               0 :             FixupNodeAttribute(*aNodeOut, "background");
    3066                 :         }
    3067               0 :         return rv;
    3068                 :     }
    3069                 : 
    3070               0 :     nsCOMPtr<nsIDOMHTMLImageElement> nodeAsImage = do_QueryInterface(aNodeIn);
    3071               0 :     if (nodeAsImage)
    3072                 :     {
    3073               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3074               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3075                 :         {
    3076                 :             // Disable image loads
    3077                 :             nsCOMPtr<nsIImageLoadingContent> imgCon =
    3078               0 :                 do_QueryInterface(*aNodeOut);
    3079               0 :             if (imgCon)
    3080               0 :                 imgCon->SetLoadingEnabled(false);
    3081                 : 
    3082               0 :             FixupAnchor(*aNodeOut);
    3083               0 :             FixupNodeAttribute(*aNodeOut, "src");
    3084                 :         }
    3085               0 :         return rv;
    3086                 :     }
    3087                 : 
    3088                 : #ifdef MOZ_MEDIA
    3089               0 :     nsCOMPtr<nsIDOMHTMLMediaElement> nodeAsMedia = do_QueryInterface(aNodeIn);
    3090               0 :     if (nodeAsMedia)
    3091                 :     {
    3092               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3093               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3094                 :         {
    3095               0 :             FixupNodeAttribute(*aNodeOut, "src");
    3096                 :         }
    3097                 : 
    3098               0 :         return rv;
    3099                 :     }
    3100                 : 
    3101               0 :     nsCOMPtr<nsIDOMHTMLSourceElement> nodeAsSource = do_QueryInterface(aNodeIn);
    3102               0 :     if (nodeAsSource)
    3103                 :     {
    3104               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3105               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3106                 :         {
    3107               0 :             FixupNodeAttribute(*aNodeOut, "src");
    3108                 :         }
    3109                 : 
    3110               0 :         return rv;
    3111                 :     }
    3112                 : #endif // MOZ_MEDIA
    3113                 : 
    3114               0 :     nsCOMPtr<nsIDOMSVGImageElement> nodeAsSVGImage = do_QueryInterface(aNodeIn);
    3115               0 :     if (nodeAsSVGImage)
    3116                 :     {
    3117               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3118               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3119                 :         {
    3120                 :             // Disable image loads
    3121                 :             nsCOMPtr<nsIImageLoadingContent> imgCon =
    3122               0 :                 do_QueryInterface(*aNodeOut);
    3123               0 :             if (imgCon)
    3124               0 :                 imgCon->SetLoadingEnabled(false);
    3125                 : 
    3126                 :             // FixupAnchor(*aNodeOut);  // XXXjwatt: is this line needed?
    3127               0 :             FixupNodeAttributeNS(*aNodeOut, "http://www.w3.org/1999/xlink", "href");
    3128                 :         }
    3129               0 :         return rv;
    3130                 :     }
    3131                 : 
    3132               0 :     nsCOMPtr<nsIDOMHTMLScriptElement> nodeAsScript = do_QueryInterface(aNodeIn);
    3133               0 :     if (nodeAsScript)
    3134                 :     {
    3135               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3136               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3137                 :         {
    3138               0 :             FixupNodeAttribute(*aNodeOut, "src");
    3139                 :         }
    3140               0 :         return rv;
    3141                 :     }
    3142                 : 
    3143               0 :     nsCOMPtr<nsIDOMSVGScriptElement> nodeAsSVGScript = do_QueryInterface(aNodeIn);
    3144               0 :     if (nodeAsSVGScript)
    3145                 :     {
    3146               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3147               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3148                 :         {
    3149               0 :             FixupNodeAttributeNS(*aNodeOut, "http://www.w3.org/1999/xlink", "href");
    3150                 :         }
    3151               0 :         return rv;
    3152                 :     }
    3153                 : 
    3154               0 :     nsCOMPtr<nsIDOMHTMLEmbedElement> nodeAsEmbed = do_QueryInterface(aNodeIn);
    3155               0 :     if (nodeAsEmbed)
    3156                 :     {
    3157               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3158               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3159                 :         {
    3160               0 :             FixupNodeAttribute(*aNodeOut, "src");
    3161                 :         }
    3162               0 :         return rv;
    3163                 :     }
    3164                 :     
    3165               0 :     nsCOMPtr<nsIDOMHTMLObjectElement> nodeAsObject = do_QueryInterface(aNodeIn);
    3166               0 :     if (nodeAsObject)
    3167                 :     {
    3168               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3169               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3170                 :         {
    3171               0 :             FixupNodeAttribute(*aNodeOut, "data");
    3172                 :         }
    3173               0 :         return rv;
    3174                 :     }
    3175                 : 
    3176               0 :     nsCOMPtr<nsIDOMHTMLAppletElement> nodeAsApplet = do_QueryInterface(aNodeIn);
    3177               0 :     if (nodeAsApplet)
    3178                 :     {
    3179               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3180               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3181                 :         {
    3182                 :             nsCOMPtr<nsIDOMHTMLAppletElement> newApplet =
    3183               0 :                 do_QueryInterface(*aNodeOut);
    3184                 :             // For an applet, relative URIs are resolved relative to the
    3185                 :             // codebase (which is resolved relative to the base URI).
    3186               0 :             nsCOMPtr<nsIURI> oldBase = mCurrentBaseURI;
    3187               0 :             nsAutoString codebase;
    3188               0 :             nodeAsApplet->GetCodeBase(codebase);
    3189               0 :             if (!codebase.IsEmpty()) {
    3190               0 :                 nsCOMPtr<nsIURI> baseURI;
    3191               0 :                 NS_NewURI(getter_AddRefs(baseURI), codebase,
    3192               0 :                           mCurrentCharset.get(), mCurrentBaseURI);
    3193               0 :                 if (baseURI) {
    3194               0 :                     mCurrentBaseURI = baseURI;
    3195                 :                 }
    3196                 :             }
    3197                 :             // Unset the codebase too, since we'll correctly relativize the
    3198                 :             // code and archive paths.
    3199               0 :             newApplet->RemoveAttribute(NS_LITERAL_STRING("codebase"));
    3200               0 :             FixupNodeAttribute(*aNodeOut, "code");
    3201               0 :             FixupNodeAttribute(*aNodeOut, "archive");
    3202                 :             // restore the base URI we really want to have
    3203               0 :             mCurrentBaseURI = oldBase;
    3204                 :         }
    3205               0 :         return rv;
    3206                 :     }
    3207                 :     
    3208               0 :     nsCOMPtr<nsIDOMHTMLLinkElement> nodeAsLink = do_QueryInterface(aNodeIn);
    3209               0 :     if (nodeAsLink)
    3210                 :     {
    3211               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3212               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3213                 :         {
    3214                 :             // First see if the link represents linked content
    3215               0 :             rv = FixupNodeAttribute(*aNodeOut, "href");
    3216               0 :             if (NS_FAILED(rv))
    3217                 :             {
    3218                 :                 // Perhaps this link is actually an anchor to related content
    3219               0 :                 FixupAnchor(*aNodeOut);
    3220                 :             }
    3221                 :             // TODO if "type" attribute == "text/css"
    3222                 :             //        fixup stylesheet
    3223                 :         }
    3224               0 :         return rv;
    3225                 :     }
    3226                 : 
    3227               0 :     nsCOMPtr<nsIDOMHTMLFrameElement> nodeAsFrame = do_QueryInterface(aNodeIn);
    3228               0 :     if (nodeAsFrame)
    3229                 :     {
    3230               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3231               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3232                 :         {
    3233               0 :             FixupNodeAttribute(*aNodeOut, "src");
    3234                 :         }
    3235               0 :         return rv;
    3236                 :     }
    3237                 : 
    3238               0 :     nsCOMPtr<nsIDOMHTMLIFrameElement> nodeAsIFrame = do_QueryInterface(aNodeIn);
    3239               0 :     if (nodeAsIFrame)
    3240                 :     {
    3241               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3242               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3243                 :         {
    3244               0 :             FixupNodeAttribute(*aNodeOut, "src");
    3245                 :         }
    3246               0 :         return rv;
    3247                 :     }
    3248                 : 
    3249               0 :     nsCOMPtr<nsIDOMHTMLInputElement> nodeAsInput = do_QueryInterface(aNodeIn);
    3250               0 :     if (nodeAsInput)
    3251                 :     {
    3252               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3253               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3254                 :         {
    3255                 :             // Disable image loads
    3256                 :             nsCOMPtr<nsIImageLoadingContent> imgCon =
    3257               0 :                 do_QueryInterface(*aNodeOut);
    3258               0 :             if (imgCon)
    3259               0 :                 imgCon->SetLoadingEnabled(false);
    3260                 : 
    3261               0 :             FixupNodeAttribute(*aNodeOut, "src");
    3262                 : 
    3263               0 :             nsAutoString valueStr;
    3264               0 :             NS_NAMED_LITERAL_STRING(valueAttr, "value");
    3265                 :             // Update element node attributes with user-entered form state
    3266               0 :             nsCOMPtr<nsIDOMHTMLInputElement> outElt = do_QueryInterface(*aNodeOut);
    3267               0 :             nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(*aNodeOut);
    3268               0 :             switch (formControl->GetType()) {
    3269                 :                 case NS_FORM_INPUT_EMAIL:
    3270                 :                 case NS_FORM_INPUT_SEARCH:
    3271                 :                 case NS_FORM_INPUT_TEXT:
    3272                 :                 case NS_FORM_INPUT_TEL:
    3273                 :                 case NS_FORM_INPUT_URL:
    3274               0 :                     nodeAsInput->GetValue(valueStr);
    3275                 :                     // Avoid superfluous value="" serialization
    3276               0 :                     if (valueStr.IsEmpty())
    3277               0 :                       outElt->RemoveAttribute(valueAttr);
    3278                 :                     else
    3279               0 :                       outElt->SetAttribute(valueAttr, valueStr);
    3280               0 :                     break;
    3281                 :                 case NS_FORM_INPUT_CHECKBOX:
    3282                 :                 case NS_FORM_INPUT_RADIO:
    3283                 :                     bool checked;
    3284               0 :                     nodeAsInput->GetChecked(&checked);
    3285               0 :                     outElt->SetDefaultChecked(checked);
    3286               0 :                     break;
    3287                 :                 default:
    3288               0 :                     break;
    3289                 :             }
    3290                 :         }
    3291               0 :         return rv;
    3292                 :     }
    3293                 : 
    3294               0 :     nsCOMPtr<nsIDOMHTMLTextAreaElement> nodeAsTextArea = do_QueryInterface(aNodeIn);
    3295               0 :     if (nodeAsTextArea)
    3296                 :     {
    3297               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3298               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3299                 :         {
    3300                 :             // Tell the document encoder to serialize the text child we create below
    3301               0 :             *aSerializeCloneKids = true;
    3302                 : 
    3303               0 :             nsAutoString valueStr;
    3304               0 :             nodeAsTextArea->GetValue(valueStr);
    3305                 :             
    3306               0 :             (*aNodeOut)->SetTextContent(valueStr);
    3307                 :         }
    3308               0 :         return rv;
    3309                 :     }
    3310                 : 
    3311               0 :     nsCOMPtr<nsIDOMHTMLOptionElement> nodeAsOption = do_QueryInterface(aNodeIn);
    3312               0 :     if (nodeAsOption)
    3313                 :     {
    3314               0 :         rv = GetNodeToFixup(aNodeIn, aNodeOut);
    3315               0 :         if (NS_SUCCEEDED(rv) && *aNodeOut)
    3316                 :         {          
    3317               0 :             nsCOMPtr<nsIDOMHTMLOptionElement> outElt = do_QueryInterface(*aNodeOut);
    3318                 :             bool selected;
    3319               0 :             nodeAsOption->GetSelected(&selected);
    3320               0 :             outElt->SetDefaultSelected(selected);
    3321                 :         }
    3322               0 :         return rv;
    3323                 :     }
    3324                 : 
    3325               0 :     return NS_OK;
    3326                 : }
    3327                 : 
    3328                 : nsresult
    3329               0 : nsWebBrowserPersist::StoreURI(
    3330                 :     const char *aURI, bool aNeedsPersisting, URIData **aData)
    3331                 : {
    3332               0 :     NS_ENSURE_ARG_POINTER(aURI);
    3333                 : 
    3334               0 :     nsCOMPtr<nsIURI> uri;
    3335               0 :     nsresult rv = NS_NewURI(getter_AddRefs(uri),
    3336               0 :                             nsDependentCString(aURI),
    3337                 :                             mCurrentCharset.get(),
    3338               0 :                             mCurrentBaseURI);
    3339               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3340                 : 
    3341               0 :     return StoreURI(uri, aNeedsPersisting, aData);
    3342                 : }
    3343                 : 
    3344                 : nsresult
    3345               0 : nsWebBrowserPersist::StoreURI(
    3346                 :     nsIURI *aURI, bool aNeedsPersisting, URIData **aData)
    3347                 : {
    3348               0 :     NS_ENSURE_ARG_POINTER(aURI);
    3349               0 :     if (aData)
    3350                 :     {
    3351               0 :         *aData = nsnull;
    3352                 :     }
    3353                 : 
    3354                 :     // Test if this URI should be persisted. By default
    3355                 :     // we should assume the URI  is persistable.
    3356                 :     bool doNotPersistURI;
    3357                 :     nsresult rv = NS_URIChainHasFlags(aURI,
    3358                 :                                       nsIProtocolHandler::URI_NON_PERSISTABLE,
    3359               0 :                                       &doNotPersistURI);
    3360               0 :     if (NS_FAILED(rv))
    3361                 :     {
    3362               0 :         doNotPersistURI = false;
    3363                 :     }
    3364                 : 
    3365               0 :     if (doNotPersistURI)
    3366                 :     {
    3367               0 :         return NS_OK;
    3368                 :     }
    3369                 : 
    3370               0 :     URIData *data = nsnull;
    3371               0 :     MakeAndStoreLocalFilenameInURIMap(aURI, aNeedsPersisting, &data);
    3372               0 :     if (aData)
    3373                 :     {
    3374               0 :         *aData = data;
    3375                 :     }
    3376                 : 
    3377               0 :     return NS_OK;
    3378                 : }
    3379                 : 
    3380                 : nsresult
    3381               0 : nsWebBrowserPersist::StoreURIAttributeNS(
    3382                 :     nsIDOMNode *aNode, const char *aNamespaceURI, const char *aAttribute,
    3383                 :     bool aNeedsPersisting, URIData **aData)
    3384                 : {
    3385               0 :     NS_ENSURE_ARG_POINTER(aNode);
    3386               0 :     NS_ENSURE_ARG_POINTER(aNamespaceURI);
    3387               0 :     NS_ENSURE_ARG_POINTER(aAttribute);
    3388                 : 
    3389               0 :     nsresult rv = NS_OK;
    3390                 : 
    3391                 :     // Find the named URI attribute on the (element) node and store
    3392                 :     // a reference to the URI that maps onto a local file name
    3393                 : 
    3394               0 :     nsCOMPtr<nsIDOMNamedNodeMap> attrMap;
    3395               0 :     nsCOMPtr<nsIDOMNode> attrNode;
    3396               0 :     rv = aNode->GetAttributes(getter_AddRefs(attrMap));
    3397               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    3398                 : 
    3399               0 :     NS_ConvertASCIItoUTF16 namespaceURI(aNamespaceURI);
    3400               0 :     NS_ConvertASCIItoUTF16 attribute(aAttribute);
    3401               0 :     rv = attrMap->GetNamedItemNS(namespaceURI, attribute, getter_AddRefs(attrNode));
    3402               0 :     if (attrNode)
    3403                 :     {
    3404               0 :         nsAutoString oldValue;
    3405               0 :         attrNode->GetNodeValue(oldValue);
    3406               0 :         if (!oldValue.IsEmpty())
    3407                 :         {
    3408               0 :             NS_ConvertUTF16toUTF8 oldCValue(oldValue);
    3409               0 :             return StoreURI(oldCValue.get(), aNeedsPersisting, aData);
    3410                 :         }
    3411                 :     }
    3412                 : 
    3413               0 :     return NS_OK;
    3414                 : }
    3415                 : 
    3416                 : nsresult
    3417               0 : nsWebBrowserPersist::FixupURI(nsAString &aURI)
    3418                 : {
    3419                 :     // get the current location of the file (absolutized)
    3420               0 :     nsCOMPtr<nsIURI> uri;
    3421               0 :     nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI, 
    3422               0 :                             mCurrentCharset.get(), mCurrentBaseURI);
    3423               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3424               0 :     nsCAutoString spec;
    3425               0 :     rv = uri->GetSpec(spec);
    3426               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3427                 : 
    3428                 :     // Search for the URI in the map and replace it with the local file
    3429               0 :     nsCStringKey key(spec.get());
    3430               0 :     if (!mURIMap.Exists(&key))
    3431                 :     {
    3432               0 :         return NS_ERROR_FAILURE;
    3433                 :     }
    3434               0 :     URIData *data = (URIData *) mURIMap.Get(&key);
    3435               0 :     if (!data->mNeedsFixup)
    3436                 :     {
    3437               0 :         return NS_OK;
    3438                 :     }
    3439               0 :     nsCOMPtr<nsIURI> fileAsURI;
    3440               0 :     if (data->mFile)
    3441                 :     {
    3442               0 :         rv = data->mFile->Clone(getter_AddRefs(fileAsURI)); 
    3443               0 :         NS_ENSURE_SUCCESS(rv, rv);
    3444                 :     }
    3445                 :     else
    3446                 :     {
    3447               0 :         rv = data->mDataPath->Clone(getter_AddRefs(fileAsURI));
    3448               0 :         NS_ENSURE_SUCCESS(rv, rv);
    3449               0 :         rv = AppendPathToURI(fileAsURI, data->mFilename);
    3450               0 :         NS_ENSURE_SUCCESS(rv, rv);
    3451                 :     }
    3452               0 :     nsAutoString newValue;
    3453                 : 
    3454                 :     // remove username/password if present
    3455               0 :     fileAsURI->SetUserPass(EmptyCString());
    3456                 : 
    3457                 :     // reset node attribute 
    3458                 :     // Use relative or absolute links
    3459               0 :     if (data->mDataPathIsRelative)
    3460                 :     {
    3461               0 :         nsCOMPtr<nsIURL> url(do_QueryInterface(fileAsURI));
    3462               0 :         if (!url)
    3463               0 :           return NS_ERROR_FAILURE;
    3464                 :           
    3465               0 :         nsCAutoString filename;
    3466               0 :         url->GetFileName(filename);
    3467                 : 
    3468               0 :         nsCAutoString rawPathURL(data->mRelativePathToData);
    3469               0 :         rawPathURL.Append(filename);
    3470                 : 
    3471               0 :         nsCAutoString buf;
    3472               0 :         AppendUTF8toUTF16(NS_EscapeURL(rawPathURL, esc_FilePath, buf),
    3473               0 :                           newValue);
    3474                 :     }
    3475                 :     else
    3476                 :     {
    3477               0 :         nsCAutoString fileurl;
    3478               0 :         fileAsURI->GetSpec(fileurl);
    3479               0 :         AppendUTF8toUTF16(fileurl, newValue);
    3480                 :     }
    3481               0 :     if (data->mIsSubFrame)
    3482                 :     {
    3483               0 :         newValue.Append(data->mSubFrameExt);
    3484                 :     }
    3485                 : 
    3486               0 :     aURI = newValue;
    3487               0 :     return NS_OK;
    3488                 : }
    3489                 : 
    3490                 : nsresult
    3491               0 : nsWebBrowserPersist::FixupNodeAttributeNS(nsIDOMNode *aNode,
    3492                 :                                         const char *aNamespaceURI,
    3493                 :                                         const char *aAttribute)
    3494                 : {
    3495               0 :     NS_ENSURE_ARG_POINTER(aNode);
    3496               0 :     NS_ENSURE_ARG_POINTER(aNamespaceURI);
    3497               0 :     NS_ENSURE_ARG_POINTER(aAttribute);
    3498                 : 
    3499               0 :     nsresult rv = NS_OK;
    3500                 : 
    3501                 :     // Find the named URI attribute on the (element) node and change it to reference
    3502                 :     // a local file.
    3503                 : 
    3504               0 :     nsCOMPtr<nsIDOMNamedNodeMap> attrMap;
    3505               0 :     nsCOMPtr<nsIDOMNode> attrNode;
    3506               0 :     rv = aNode->GetAttributes(getter_AddRefs(attrMap));
    3507               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    3508                 : 
    3509               0 :     NS_ConvertASCIItoUTF16 attribute(aAttribute);
    3510               0 :     NS_ConvertASCIItoUTF16 namespaceURI(aNamespaceURI);
    3511               0 :     rv = attrMap->GetNamedItemNS(namespaceURI, attribute, getter_AddRefs(attrNode));
    3512               0 :     if (attrNode)
    3513                 :     {
    3514               0 :         nsString uri;
    3515               0 :         attrNode->GetNodeValue(uri);
    3516               0 :         rv = FixupURI(uri);
    3517               0 :         if (NS_SUCCEEDED(rv))
    3518                 :         {
    3519               0 :             attrNode->SetNodeValue(uri);
    3520                 :         }
    3521                 :     }
    3522                 : 
    3523               0 :     return rv;
    3524                 : }
    3525                 : 
    3526                 : nsresult
    3527               0 : nsWebBrowserPersist::FixupAnchor(nsIDOMNode *aNode)
    3528                 : {
    3529               0 :     NS_ENSURE_ARG_POINTER(aNode);
    3530                 : 
    3531               0 :     nsCOMPtr<nsIDOMNamedNodeMap> attrMap;
    3532               0 :     nsCOMPtr<nsIDOMNode> attrNode;
    3533               0 :     nsresult rv = aNode->GetAttributes(getter_AddRefs(attrMap));
    3534               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    3535                 : 
    3536               0 :     if (mPersistFlags & PERSIST_FLAGS_DONT_FIXUP_LINKS)
    3537                 :     {
    3538               0 :         return NS_OK;
    3539                 :     }
    3540                 : 
    3541                 :     // Make all anchor links absolute so they point off onto the Internet
    3542               0 :     nsString attribute(NS_LITERAL_STRING("href"));
    3543               0 :     rv = attrMap->GetNamedItem(attribute, getter_AddRefs(attrNode));
    3544               0 :     if (attrNode)
    3545                 :     {
    3546               0 :         nsString oldValue;
    3547               0 :         attrNode->GetNodeValue(oldValue);
    3548               0 :         NS_ConvertUTF16toUTF8 oldCValue(oldValue);
    3549                 : 
    3550                 :         // Skip empty values and self-referencing bookmarks
    3551               0 :         if (oldCValue.IsEmpty() || oldCValue.CharAt(0) == '#')
    3552                 :         {
    3553               0 :             return NS_OK;
    3554                 :         }
    3555                 : 
    3556                 :         // if saving file to same location, we don't need to do any fixup
    3557               0 :         bool isEqual = false;
    3558               0 :         if (NS_SUCCEEDED(mCurrentBaseURI->Equals(mTargetBaseURI, &isEqual))
    3559                 :             && isEqual)
    3560                 :         {
    3561               0 :             return NS_OK;
    3562                 :         }
    3563                 : 
    3564               0 :         nsCOMPtr<nsIURI> relativeURI;
    3565                 :         relativeURI = (mPersistFlags & PERSIST_FLAGS_FIXUP_LINKS_TO_DESTINATION)
    3566               0 :                       ? mTargetBaseURI : mCurrentBaseURI;
    3567                 :         // Make a new URI to replace the current one
    3568               0 :         nsCOMPtr<nsIURI> newURI;
    3569               0 :         rv = NS_NewURI(getter_AddRefs(newURI), oldCValue, 
    3570               0 :                        mCurrentCharset.get(), relativeURI);
    3571               0 :         if (NS_SUCCEEDED(rv) && newURI)
    3572                 :         {
    3573               0 :             newURI->SetUserPass(EmptyCString());
    3574               0 :             nsCAutoString uriSpec;
    3575               0 :             newURI->GetSpec(uriSpec);
    3576               0 :             attrNode->SetNodeValue(NS_ConvertUTF8toUTF16(uriSpec));
    3577                 :         }
    3578                 :     }
    3579                 : 
    3580               0 :     return NS_OK;
    3581                 : }
    3582                 : 
    3583                 : nsresult
    3584               0 : nsWebBrowserPersist::StoreAndFixupStyleSheet(nsIStyleSheet *aStyleSheet)
    3585                 : {
    3586                 :     // TODO go through the style sheet fixing up all links
    3587               0 :     return NS_OK;
    3588                 : }
    3589                 : 
    3590                 : bool
    3591               0 : nsWebBrowserPersist::DocumentEncoderExists(const PRUnichar *aContentType)
    3592                 : {
    3593                 :     // Check if there is an encoder for the desired content type.
    3594               0 :     nsCAutoString contractID(NS_DOC_ENCODER_CONTRACTID_BASE);
    3595               0 :     AppendUTF16toUTF8(aContentType, contractID);
    3596                 : 
    3597               0 :     nsCOMPtr<nsIComponentRegistrar> registrar;
    3598               0 :     NS_GetComponentRegistrar(getter_AddRefs(registrar));
    3599               0 :     if (registrar)
    3600                 :     {
    3601                 :         bool result;
    3602               0 :         nsresult rv = registrar->IsContractIDRegistered(contractID.get(),
    3603               0 :                                                         &result);
    3604               0 :         if (NS_SUCCEEDED(rv) && result)
    3605                 :         {
    3606               0 :             return true;
    3607                 :         }
    3608                 :     }
    3609               0 :     return false;
    3610                 : }
    3611                 : 
    3612                 : nsresult
    3613               0 : nsWebBrowserPersist::SaveSubframeContent(
    3614                 :     nsIDOMDocument *aFrameContent, URIData *aData)
    3615                 : {
    3616               0 :     NS_ENSURE_ARG_POINTER(aData);
    3617                 : 
    3618                 :     // Extract the content type for the frame's contents.
    3619               0 :     nsCOMPtr<nsIDocument> frameDoc(do_QueryInterface(aFrameContent));
    3620               0 :     NS_ENSURE_STATE(frameDoc);
    3621                 : 
    3622               0 :     nsAutoString contentType;
    3623               0 :     nsresult rv = frameDoc->GetContentType(contentType);
    3624               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3625                 : 
    3626               0 :     nsXPIDLString ext;
    3627               0 :     GetExtensionForContentType(contentType.get(), getter_Copies(ext));
    3628                 : 
    3629                 :     // We must always have an extension so we will try to re-assign
    3630                 :     // the original extension if GetExtensionForContentType fails.
    3631               0 :     if (ext.IsEmpty())
    3632                 :     {
    3633               0 :         nsCOMPtr<nsIURL> url(do_QueryInterface(frameDoc->GetDocumentURI(),
    3634               0 :                                                &rv));
    3635               0 :         nsCAutoString extension;
    3636               0 :         if (NS_SUCCEEDED(rv))
    3637                 :         {
    3638               0 :             url->GetFileExtension(extension);
    3639                 :         }
    3640                 :         else
    3641                 :         {
    3642               0 :             extension.AssignLiteral("htm");
    3643                 :         }
    3644               0 :         aData->mSubFrameExt.Assign(PRUnichar('.'));
    3645               0 :         AppendUTF8toUTF16(extension, aData->mSubFrameExt);
    3646                 :     }
    3647                 :     else
    3648                 :     {
    3649               0 :         aData->mSubFrameExt.Assign(PRUnichar('.'));
    3650               0 :         aData->mSubFrameExt.Append(ext);
    3651                 :     }
    3652                 : 
    3653               0 :     nsString filenameWithExt = aData->mFilename;
    3654               0 :     filenameWithExt.Append(aData->mSubFrameExt);
    3655                 : 
    3656                 :     // Work out the path for the subframe
    3657               0 :     nsCOMPtr<nsIURI> frameURI;
    3658               0 :     rv = mCurrentDataPath->Clone(getter_AddRefs(frameURI));
    3659               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3660               0 :     rv = AppendPathToURI(frameURI, filenameWithExt);
    3661               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3662                 : 
    3663                 :     // Work out the path for the subframe data
    3664               0 :     nsCOMPtr<nsIURI> frameDataURI;
    3665               0 :     rv = mCurrentDataPath->Clone(getter_AddRefs(frameDataURI));
    3666               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3667               0 :     nsAutoString newFrameDataPath(aData->mFilename);
    3668                 : 
    3669                 :     // Append _data
    3670               0 :     newFrameDataPath.AppendLiteral("_data");
    3671               0 :     rv = AppendPathToURI(frameDataURI, newFrameDataPath);
    3672               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3673                 : 
    3674                 :     // Make frame document & data path conformant and unique
    3675               0 :     rv = CalculateUniqueFilename(frameURI);
    3676               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3677               0 :     rv = CalculateUniqueFilename(frameDataURI);
    3678               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3679                 : 
    3680               0 :     mCurrentThingsToPersist++;
    3681                 : 
    3682                 :     // We shouldn't use SaveDocumentInternal for the contents
    3683                 :     // of frames that are not documents, e.g. images.
    3684               0 :     if (DocumentEncoderExists(contentType.get()))
    3685                 :     {
    3686               0 :         rv = SaveDocumentInternal(aFrameContent, frameURI, frameDataURI);
    3687                 :     }
    3688                 :     else
    3689                 :     {
    3690               0 :         rv = StoreURI(frameDoc->GetDocumentURI());
    3691                 :     }
    3692               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3693                 : 
    3694                 :     // Store the updated uri to the frame
    3695               0 :     aData->mFile = frameURI;
    3696               0 :     aData->mSubFrameExt.Truncate(); // we already put this in frameURI
    3697                 : 
    3698               0 :     return NS_OK;
    3699                 : }
    3700                 : 
    3701                 : nsresult
    3702               0 : nsWebBrowserPersist::CreateChannelFromURI(nsIURI *aURI, nsIChannel **aChannel)
    3703                 : {
    3704               0 :     nsresult rv = NS_OK;
    3705               0 :     *aChannel = nsnull;
    3706                 : 
    3707               0 :     nsCOMPtr<nsIIOService> ioserv;
    3708               0 :     ioserv = do_GetIOService(&rv);
    3709               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3710                 : 
    3711               0 :     rv = ioserv->NewChannelFromURI(aURI, aChannel);
    3712               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3713               0 :     NS_ENSURE_ARG_POINTER(*aChannel);
    3714                 : 
    3715               0 :     rv = (*aChannel)->SetNotificationCallbacks(static_cast<nsIInterfaceRequestor *>(this));
    3716               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3717               0 :     return NS_OK;
    3718                 : } 
    3719                 : 
    3720                 : nsresult
    3721               0 : nsWebBrowserPersist::SaveDocumentWithFixup(
    3722                 :     nsIDOMDocument *aDocument, nsIDocumentEncoderNodeFixup *aNodeFixup,
    3723                 :     nsIURI *aFile, bool aReplaceExisting, const nsACString &aFormatType,
    3724                 :     const nsCString &aSaveCharset, PRUint32 aFlags)
    3725                 : {
    3726               0 :     NS_ENSURE_ARG_POINTER(aFile);
    3727                 :     
    3728               0 :     nsresult  rv = NS_OK;
    3729               0 :     nsCOMPtr<nsILocalFile> localFile;
    3730               0 :     GetLocalFileFromURI(aFile, getter_AddRefs(localFile));
    3731               0 :     if (localFile)
    3732                 :     {
    3733                 :         // if we're not replacing an existing file but the file
    3734                 :         // exists, something is wrong
    3735               0 :         bool fileExists = false;
    3736               0 :         rv = localFile->Exists(&fileExists);
    3737               0 :         NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    3738                 : 
    3739               0 :         if (!aReplaceExisting && fileExists)
    3740               0 :             return NS_ERROR_FAILURE;                // where are the file I/O errors?
    3741                 :     }
    3742                 :     
    3743               0 :     nsCOMPtr<nsIOutputStream> outputStream;
    3744               0 :     rv = MakeOutputStream(aFile, getter_AddRefs(outputStream));
    3745               0 :     if (NS_FAILED(rv))
    3746                 :     {
    3747               0 :         SendErrorStatusChange(false, rv, nsnull, aFile);
    3748               0 :         return NS_ERROR_FAILURE;
    3749                 :     }
    3750               0 :     NS_ENSURE_TRUE(outputStream, NS_ERROR_FAILURE);
    3751                 : 
    3752                 :     // Get a document encoder instance
    3753               0 :     nsCAutoString contractID(NS_DOC_ENCODER_CONTRACTID_BASE);
    3754               0 :     contractID.Append(aFormatType);
    3755                 :     
    3756               0 :     nsCOMPtr<nsIDocumentEncoder> encoder = do_CreateInstance(contractID.get(), &rv);
    3757               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    3758                 : 
    3759               0 :     NS_ConvertASCIItoUTF16 newContentType(aFormatType);
    3760               0 :     rv = encoder->Init(aDocument, newContentType, aFlags);
    3761               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    3762                 : 
    3763               0 :     mTargetBaseURI = aFile;
    3764                 : 
    3765                 :     // Set the node fixup callback
    3766               0 :     encoder->SetNodeFixup(aNodeFixup);
    3767                 : 
    3768               0 :     if (mWrapColumn && (aFlags & ENCODE_FLAGS_WRAP))
    3769               0 :         encoder->SetWrapColumn(mWrapColumn);
    3770                 : 
    3771               0 :     nsCAutoString charsetStr(aSaveCharset);
    3772               0 :     if (charsetStr.IsEmpty())
    3773                 :     {
    3774               0 :         nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDocument);
    3775               0 :         NS_ASSERTION(doc, "Need a document");
    3776               0 :         charsetStr = doc->GetDocumentCharacterSet();
    3777                 :     }
    3778                 : 
    3779               0 :     rv = encoder->SetCharset(charsetStr);
    3780               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    3781                 : 
    3782               0 :     rv = encoder->EncodeToStream(outputStream);
    3783               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    3784                 :     
    3785               0 :     if (!localFile)
    3786                 :     {
    3787               0 :         nsCOMPtr<nsIStorageStream> storStream(do_QueryInterface(outputStream));
    3788               0 :         if (storStream)
    3789                 :         {
    3790               0 :             outputStream->Close();
    3791               0 :             rv = StartUpload(storStream, aFile, aFormatType);
    3792               0 :             NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    3793                 :         }
    3794                 :     }
    3795                 : #if defined(XP_OS2)
    3796                 :     else
    3797                 :     {
    3798                 :         // close the stream, then tag the file it created with its source URI
    3799                 :         outputStream->Close();
    3800                 :         nsCOMPtr<nsILocalFileOS2> localFileOS2 = do_QueryInterface(localFile);
    3801                 :         if (localFileOS2)
    3802                 :         {
    3803                 :             nsCAutoString url;
    3804                 :             mCurrentBaseURI->GetSpec(url);
    3805                 :             localFileOS2->SetFileSource(url);
    3806                 :         }
    3807                 :     }
    3808                 : #endif
    3809                 : 
    3810               0 :     return rv;
    3811                 : }
    3812                 : 
    3813                 : 
    3814                 : // we store the current location as the key (absolutized version of domnode's attribute's value)
    3815                 : nsresult
    3816               0 : nsWebBrowserPersist::MakeAndStoreLocalFilenameInURIMap(
    3817                 :     nsIURI *aURI, bool aNeedsPersisting, URIData **aData)
    3818                 : {
    3819               0 :     NS_ENSURE_ARG_POINTER(aURI);
    3820                 : 
    3821               0 :     nsCAutoString spec;
    3822               0 :     nsresult rv = aURI->GetSpec(spec);
    3823               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    3824                 : 
    3825                 :     // Create a sensibly named filename for the URI and store in the URI map
    3826               0 :     nsCStringKey key(spec.get());
    3827                 :     URIData *data;
    3828               0 :     if (mURIMap.Exists(&key))
    3829                 :     {
    3830               0 :         data = (URIData *) mURIMap.Get(&key);
    3831               0 :         if (aNeedsPersisting)
    3832                 :         {
    3833               0 :           data->mNeedsPersisting = true;
    3834                 :         }
    3835               0 :         if (aData)
    3836                 :         {
    3837               0 :             *aData = data;
    3838                 :         }
    3839               0 :         return NS_OK;
    3840                 :     }
    3841                 : 
    3842                 :     // Create a unique file name for the uri
    3843               0 :     nsString filename;
    3844               0 :     rv = MakeFilenameFromURI(aURI, filename);
    3845               0 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
    3846                 : 
    3847                 :     // Store the file name
    3848               0 :     data = new URIData;
    3849               0 :     NS_ENSURE_TRUE(data, NS_ERROR_OUT_OF_MEMORY);
    3850                 : 
    3851               0 :     data->mNeedsPersisting = aNeedsPersisting;
    3852               0 :     data->mNeedsFixup = true;
    3853               0 :     data->mFilename = filename;
    3854               0 :     data->mSaved = false;
    3855               0 :     data->mIsSubFrame = false;
    3856               0 :     data->mDataPath = mCurrentDataPath;
    3857               0 :     data->mDataPathIsRelative = mCurrentDataPathIsRelative;
    3858               0 :     data->mRelativePathToData = mCurrentRelativePathToData;
    3859               0 :     data->mCharset = mCurrentCharset;
    3860                 : 
    3861               0 :     if (aNeedsPersisting)
    3862               0 :         mCurrentThingsToPersist++;
    3863                 : 
    3864               0 :     mURIMap.Put(&key, data);
    3865               0 :     if (aData)
    3866                 :     {
    3867               0 :         *aData = data;
    3868                 :     }
    3869                 : 
    3870               0 :     return NS_OK;
    3871                 : }
    3872                 : 
    3873                 : // Ordered so that typical documents work fastest.
    3874                 : //                                    strlen("blockquote")==10
    3875                 : static const char kSpecialXHTMLTags[][11] = {
    3876                 :     "body",
    3877                 :     "head",
    3878                 :     "img",
    3879                 :     "script",
    3880                 :     "a",
    3881                 :     "area",
    3882                 :     "link",
    3883                 :     "input",
    3884                 :     "frame",
    3885                 :     "iframe",
    3886                 :     "object",
    3887                 :     "applet",
    3888                 :     "form",
    3889                 :     "blockquote",
    3890                 :     "q",
    3891                 :     "del",
    3892                 :     "ins"
    3893                 : };
    3894                 : 
    3895               0 : static bool IsSpecialXHTMLTag(nsIDOMNode *aNode)
    3896                 : {
    3897               0 :     nsAutoString tmp;
    3898               0 :     aNode->GetNamespaceURI(tmp);
    3899               0 :     if (!tmp.EqualsLiteral("http://www.w3.org/1999/xhtml"))
    3900               0 :         return false;
    3901                 : 
    3902               0 :     aNode->GetLocalName(tmp);
    3903               0 :     for (PRUint32 i = 0; i < ArrayLength(kSpecialXHTMLTags); i++) {
    3904               0 :         if (tmp.EqualsASCII(kSpecialXHTMLTags[i]))
    3905                 :         {
    3906                 :             // XXX This element MAY have URI attributes, but
    3907                 :             //     we are not actually checking if they are present.
    3908                 :             //     That would slow us down further, and I am not so sure
    3909                 :             //     how important that would be.
    3910               0 :             return true;
    3911                 :         }
    3912                 :     }
    3913                 : 
    3914               0 :     return false;
    3915                 : }
    3916                 : 
    3917               0 : static bool HasSpecialXHTMLTags(nsIDOMNode *aParent)
    3918                 : {
    3919               0 :     if (IsSpecialXHTMLTag(aParent))
    3920               0 :         return true;
    3921                 : 
    3922               0 :     nsCOMPtr<nsIDOMNodeList> list;
    3923               0 :     aParent->GetChildNodes(getter_AddRefs(list));
    3924               0 :     if (list)
    3925                 :     {
    3926                 :         PRUint32 count;
    3927               0 :         list->GetLength(&count);
    3928                 :         PRUint32 i;
    3929               0 :         for (i = 0; i < count; i++) {
    3930               0 :             nsCOMPtr<nsIDOMNode> node;
    3931               0 :             list->Item(i, getter_AddRefs(node));
    3932               0 :             if (!node)
    3933                 :                 break;
    3934                 :             PRUint16 nodeType;
    3935               0 :             node->GetNodeType(&nodeType);
    3936               0 :             if (nodeType == nsIDOMNode::ELEMENT_NODE) {
    3937               0 :                 return HasSpecialXHTMLTags(node);
    3938                 :             }
    3939                 :         }
    3940                 :     }
    3941                 : 
    3942               0 :     return false;
    3943                 : }
    3944                 : 
    3945               0 : static bool NeedXHTMLBaseTag(nsIDOMDocument *aDocument)
    3946                 : {
    3947               0 :     nsCOMPtr<nsIDOMElement> docElement;
    3948               0 :     aDocument->GetDocumentElement(getter_AddRefs(docElement));
    3949                 : 
    3950               0 :     nsCOMPtr<nsIDOMNode> node(do_QueryInterface(docElement));
    3951               0 :     if (node)
    3952                 :     {
    3953               0 :         return HasSpecialXHTMLTags(node);
    3954                 :     }
    3955                 : 
    3956               0 :     return false;
    3957                 : }
    3958                 : 
    3959                 : // Set document base. This could create an invalid XML document (still well-formed).
    3960                 : nsresult
    3961               0 : nsWebBrowserPersist::SetDocumentBase(
    3962                 :     nsIDOMDocument *aDocument, nsIURI *aBaseURI)
    3963                 : {
    3964               0 :     if (mPersistFlags & PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS)
    3965                 :     {
    3966               0 :         return NS_OK;
    3967                 :     }
    3968                 : 
    3969               0 :     NS_ENSURE_ARG_POINTER(aBaseURI);
    3970                 : 
    3971               0 :     nsCOMPtr<nsIDOMXMLDocument> xmlDoc;
    3972               0 :     nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(aDocument);
    3973               0 :     if (!htmlDoc)
    3974                 :     {
    3975               0 :         xmlDoc = do_QueryInterface(aDocument);
    3976               0 :         if (!xmlDoc)
    3977                 :         {
    3978               0 :             return NS_ERROR_FAILURE;
    3979                 :         }
    3980                 :     }
    3981                 : 
    3982               0 :     NS_NAMED_LITERAL_STRING(kXHTMLNS, "http://www.w3.org/1999/xhtml");
    3983               0 :     NS_NAMED_LITERAL_STRING(kHead, "head");
    3984                 : 
    3985                 :     // Find the head element
    3986               0 :     nsCOMPtr<nsIDOMElement> headElement;
    3987               0 :     nsCOMPtr<nsIDOMNodeList> headList;
    3988               0 :     if (xmlDoc)
    3989                 :     {
    3990                 :         // First see if there is XHTML content that needs base 
    3991                 :         // tags.
    3992               0 :         if (!NeedXHTMLBaseTag(aDocument))
    3993               0 :             return NS_OK;
    3994                 : 
    3995                 :         aDocument->GetElementsByTagNameNS(
    3996                 :             kXHTMLNS,
    3997               0 :             kHead, getter_AddRefs(headList));
    3998                 :     }
    3999                 :     else
    4000                 :     {
    4001                 :         aDocument->GetElementsByTagName(
    4002               0 :             kHead, getter_AddRefs(headList));
    4003                 :     }
    4004               0 :     if (headList)
    4005                 :     {
    4006               0 :         nsCOMPtr<nsIDOMNode> headNode;
    4007               0 :         headList->Item(0, getter_AddRefs(headNode));
    4008               0 :         headElement = do_QueryInterface(headNode);
    4009                 :     }
    4010               0 :     if (!headElement)
    4011                 :     {
    4012                 :         // Create head and insert as first element
    4013               0 :         nsCOMPtr<nsIDOMNode> firstChildNode;
    4014               0 :         nsCOMPtr<nsIDOMNode> newNode;
    4015               0 :         if (xmlDoc)
    4016                 :         {
    4017                 :             aDocument->CreateElementNS(
    4018                 :                 kXHTMLNS,
    4019               0 :                 kHead, getter_AddRefs(headElement));
    4020                 :         }
    4021                 :         else
    4022                 :         {
    4023                 :             aDocument->CreateElement(
    4024               0 :                 kHead, getter_AddRefs(headElement));
    4025                 :         }
    4026               0 :         nsCOMPtr<nsIDOMElement> documentElement;
    4027               0 :         aDocument->GetDocumentElement(getter_AddRefs(documentElement));
    4028               0 :         if (documentElement)
    4029                 :         {
    4030               0 :             documentElement->GetFirstChild(getter_AddRefs(firstChildNode));
    4031               0 :             documentElement->InsertBefore(headElement, firstChildNode, getter_AddRefs(newNode));
    4032                 :         }
    4033                 :     }
    4034               0 :     if (!headElement)
    4035                 :     {
    4036               0 :         return NS_ERROR_FAILURE;
    4037                 :     }
    4038                 : 
    4039                 :     // Find or create the BASE element
    4040               0 :     NS_NAMED_LITERAL_STRING(kBase, "base");
    4041               0 :     nsCOMPtr<nsIDOMElement> baseElement;
    4042               0 :     nsCOMPtr<nsIDOMNodeList> baseList;
    4043               0 :     if (xmlDoc)
    4044                 :     {
    4045               0 :         headElement->GetElementsByTagNameNS(
    4046                 :             kXHTMLNS,
    4047               0 :             kBase, getter_AddRefs(baseList));
    4048                 :     }
    4049                 :     else
    4050                 :     {
    4051               0 :         headElement->GetElementsByTagName(
    4052               0 :             kBase, getter_AddRefs(baseList));
    4053                 :     }
    4054               0 :     if (baseList)
    4055                 :     {
    4056               0 :         nsCOMPtr<nsIDOMNode> baseNode;
    4057               0 :         baseList->Item(0, getter_AddRefs(baseNode));
    4058               0 :         baseElement = do_QueryInterface(baseNode);
    4059                 :     }
    4060                 : 
    4061                 :     // Add the BASE element
    4062               0 :     if (!baseElement)
    4063                 :     {
    4064               0 :       nsCOMPtr<nsIDOMNode> newNode;
    4065               0 :       if (xmlDoc)
    4066                 :       {
    4067                 :           aDocument->CreateElementNS(
    4068                 :               kXHTMLNS,
    4069               0 :               kBase, getter_AddRefs(baseElement));
    4070                 :       }
    4071                 :       else
    4072                 :       {
    4073                 :           aDocument->CreateElement(
    4074               0 :               kBase, getter_AddRefs(baseElement));
    4075                 :       }
    4076               0 :       headElement->AppendChild(baseElement, getter_AddRefs(newNode));
    4077                 :     }
    4078               0 :     if (!baseElement)
    4079                 :     {
    4080               0 :         return NS_ERROR_FAILURE;
    4081                 :     }
    4082               0 :     nsCAutoString uriSpec;
    4083               0 :     aBaseURI->GetSpec(uriSpec);
    4084               0 :     NS_ConvertUTF8toUTF16 href(uriSpec);
    4085               0 :     baseElement->SetAttribute(NS_LITERAL_STRING("href"), href);
    4086                 : 
    4087               0 :     return NS_OK;
    4088                 : }
    4089                 : 
    4090                 : // Decide if we need to apply conversion to the passed channel.
    4091              78 : void nsWebBrowserPersist::SetApplyConversionIfNeeded(nsIChannel *aChannel)
    4092                 : {
    4093              78 :     nsresult rv = NS_OK;
    4094             156 :     nsCOMPtr<nsIEncodedChannel> encChannel = do_QueryInterface(aChannel, &rv);
    4095              78 :     if (NS_FAILED(rv))
    4096                 :         return;
    4097                 : 
    4098                 :     // Set the default conversion preference:
    4099              75 :     encChannel->SetApplyConversion(false);
    4100                 : 
    4101             150 :     nsCOMPtr<nsIURI> thisURI;
    4102              75 :     aChannel->GetURI(getter_AddRefs(thisURI));
    4103             150 :     nsCOMPtr<nsIURL> sourceURL(do_QueryInterface(thisURI));
    4104              75 :     if (!sourceURL)
    4105                 :         return;
    4106             150 :     nsCAutoString extension;
    4107              75 :     sourceURL->GetFileExtension(extension);
    4108                 : 
    4109             150 :     nsCOMPtr<nsIUTF8StringEnumerator> encEnum;
    4110              75 :     encChannel->GetContentEncodings(getter_AddRefs(encEnum));
    4111              75 :     if (!encEnum)
    4112                 :         return;
    4113                 :     nsCOMPtr<nsIExternalHelperAppService> helperAppService =
    4114               0 :         do_GetService(NS_EXTERNALHELPERAPPSERVICE_CONTRACTID, &rv);
    4115               0 :     if (NS_FAILED(rv))
    4116                 :         return;
    4117                 :     bool hasMore;
    4118               0 :     rv = encEnum->HasMore(&hasMore);
    4119               0 :     if (NS_SUCCEEDED(rv) && hasMore)
    4120                 :     {
    4121               0 :         nsCAutoString encType;
    4122               0 :         rv = encEnum->GetNext(encType);
    4123               0 :         if (NS_SUCCEEDED(rv))
    4124                 :         {
    4125               0 :             bool applyConversion = false;
    4126               0 :             rv = helperAppService->ApplyDecodingForExtension(extension, encType,
    4127               0 :                                                              &applyConversion);
    4128               0 :             if (NS_SUCCEEDED(rv))
    4129               0 :                 encChannel->SetApplyConversion(applyConversion);
    4130                 :         }
    4131                 :     }
    4132                 : }
    4133                 : 
    4134                 : ///////////////////////////////////////////////////////////////////////////////
    4135                 : 
    4136                 : 
    4137               0 : nsEncoderNodeFixup::nsEncoderNodeFixup() : mWebBrowserPersist(nsnull)
    4138                 : {
    4139               0 : }
    4140                 : 
    4141                 : 
    4142               0 : nsEncoderNodeFixup::~nsEncoderNodeFixup()
    4143                 : {
    4144               0 : }
    4145                 : 
    4146                 : 
    4147               0 : NS_IMPL_ADDREF(nsEncoderNodeFixup)
    4148               0 : NS_IMPL_RELEASE(nsEncoderNodeFixup)
    4149                 : 
    4150                 : 
    4151               0 : NS_INTERFACE_MAP_BEGIN(nsEncoderNodeFixup)
    4152               0 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocumentEncoderNodeFixup)
    4153               0 :     NS_INTERFACE_MAP_ENTRY(nsIDocumentEncoderNodeFixup)
    4154               0 : NS_INTERFACE_MAP_END
    4155                 : 
    4156                 : 
    4157               0 : NS_IMETHODIMP nsEncoderNodeFixup::FixupNode(
    4158                 :     nsIDOMNode *aNode, bool *aSerializeCloneKids, nsIDOMNode **aOutNode)
    4159                 : {
    4160               0 :     NS_ENSURE_ARG_POINTER(aNode);
    4161               0 :     NS_ENSURE_ARG_POINTER(aOutNode);
    4162               0 :     NS_ENSURE_TRUE(mWebBrowserPersist, NS_ERROR_FAILURE);
    4163                 : 
    4164               0 :     *aOutNode = nsnull;
    4165                 :     
    4166                 :     // Test whether we need to fixup the node
    4167               0 :     PRUint16 type = 0;
    4168               0 :     aNode->GetNodeType(&type);
    4169               0 :     if (type == nsIDOMNode::ELEMENT_NODE ||
    4170                 :         type == nsIDOMNode::PROCESSING_INSTRUCTION_NODE)
    4171                 :     {
    4172               0 :         return mWebBrowserPersist->CloneNodeWithFixedUpAttributes(aNode, aSerializeCloneKids, aOutNode);
    4173                 :     }
    4174                 : 
    4175               0 :     return NS_OK;
    4176                 : }

Generated by: LCOV version 1.7