LCOV - code coverage report
Current view: directory - modules/libjar/zipwriter/src - nsZipWriter.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 590 436 73.9 %
Date: 2012-06-02 Functions: 31 30 96.8 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is Zip Writer Component.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is
      17                 :  * Dave Townsend <dtownsend@oxymoronical.com>.
      18                 :  *
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2007
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *      Mook <mook.moz+random.code@gmail.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK *****
      38                 :  */
      39                 : 
      40                 : #include "StreamFunctions.h"
      41                 : #include "nsZipWriter.h"
      42                 : #include "nsZipDataStream.h"
      43                 : #include "nsISeekableStream.h"
      44                 : #include "nsIAsyncStreamCopier.h"
      45                 : #include "nsIStreamListener.h"
      46                 : #include "nsIInputStreamPump.h"
      47                 : #include "nsComponentManagerUtils.h"
      48                 : #include "nsMemory.h"
      49                 : #include "nsNetError.h"
      50                 : #include "nsStreamUtils.h"
      51                 : #include "nsThreadUtils.h"
      52                 : #include "nsNetUtil.h"
      53                 : #include "prio.h"
      54                 : 
      55                 : #define ZIP_EOCDR_HEADER_SIZE 22
      56                 : #define ZIP_EOCDR_HEADER_SIGNATURE 0x06054b50
      57                 : 
      58                 : /**
      59                 :  * nsZipWriter is used to create and add to zip files.
      60                 :  * It is based on the spec available at
      61                 :  * http://www.pkware.com/documents/casestudies/APPNOTE.TXT.
      62                 :  * 
      63                 :  * The basic structure of a zip file created is slightly simpler than that
      64                 :  * illustrated in the spec because certain features of the zip format are
      65                 :  * unsupported:
      66                 :  * 
      67                 :  * [local file header 1]
      68                 :  * [file data 1]
      69                 :  * . 
      70                 :  * .
      71                 :  * .
      72                 :  * [local file header n]
      73                 :  * [file data n]
      74                 :  * [central directory]
      75                 :  * [end of central directory record]
      76                 :  */
      77           24208 : NS_IMPL_ISUPPORTS2(nsZipWriter, nsIZipWriter,
      78                 :                                 nsIRequestObserver)
      79                 : 
      80             945 : nsZipWriter::nsZipWriter()
      81                 : {
      82             945 :     mEntryHash.Init();
      83             945 :     mInQueue = false;
      84             945 : }
      85                 : 
      86            1890 : nsZipWriter::~nsZipWriter()
      87                 : {
      88             945 :     if (mStream && !mInQueue)
      89               0 :         Close();
      90             945 : }
      91                 : 
      92                 : /* attribute AString comment; */
      93               2 : NS_IMETHODIMP nsZipWriter::GetComment(nsACString & aComment)
      94                 : {
      95               2 :     if (!mStream)
      96               1 :         return NS_ERROR_NOT_INITIALIZED;
      97                 : 
      98               1 :     aComment = mComment;
      99               1 :     return NS_OK;
     100                 : }
     101                 : 
     102             609 : NS_IMETHODIMP nsZipWriter::SetComment(const nsACString & aComment)
     103                 : {
     104             609 :     if (!mStream)
     105               1 :         return NS_ERROR_NOT_INITIALIZED;
     106                 : 
     107             608 :     mComment = aComment;
     108             608 :     mCDSDirty = true;
     109             608 :     return NS_OK;
     110                 : }
     111                 : 
     112                 : /* readonly attribute boolean inQueue; */
     113               8 : NS_IMETHODIMP nsZipWriter::GetInQueue(bool *aInQueue)
     114                 : {
     115               8 :     *aInQueue = mInQueue;
     116               8 :     return NS_OK;
     117                 : }
     118                 : 
     119                 : /* readonly attribute nsIFile file; */
     120               1 : NS_IMETHODIMP nsZipWriter::GetFile(nsIFile **aFile)
     121                 : {
     122               1 :     if (!mFile)
     123               1 :         return NS_ERROR_NOT_INITIALIZED;
     124                 : 
     125               0 :     nsCOMPtr<nsIFile> file;
     126               0 :     nsresult rv = mFile->Clone(getter_AddRefs(file));
     127               0 :     NS_ENSURE_SUCCESS(rv, rv);
     128                 : 
     129               0 :     NS_ADDREF(*aFile = file);
     130               0 :     return NS_OK;
     131                 : }
     132                 : 
     133                 : /*
     134                 :  * Reads file entries out of an existing zip file.
     135                 :  */
     136              10 : nsresult nsZipWriter::ReadFile(nsIFile *aFile)
     137                 : {
     138                 :     PRInt64 size;
     139              10 :     nsresult rv = aFile->GetFileSize(&size);
     140              10 :     NS_ENSURE_SUCCESS(rv, rv);
     141                 : 
     142                 :     // If the file is too short, it cannot be a valid archive, thus we fail
     143                 :     // without even attempting to open it
     144              10 :     NS_ENSURE_TRUE(size > ZIP_EOCDR_HEADER_SIZE, NS_ERROR_FILE_CORRUPTED);
     145                 : 
     146              16 :     nsCOMPtr<nsIInputStream> inputStream;
     147               8 :     rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), aFile);
     148               8 :     NS_ENSURE_SUCCESS(rv, rv);
     149                 : 
     150                 :     PRUint8 buf[1024];
     151               8 :     PRInt64 seek = size - 1024;
     152               8 :     PRUint32 length = 1024;
     153                 : 
     154              16 :     nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(inputStream);
     155                 : 
     156               3 :     while (true) {
     157              11 :         if (seek < 0) {
     158               5 :             length += (PRInt32)seek;
     159               5 :             seek = 0;
     160                 :         }
     161                 : 
     162              11 :         rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, seek);
     163              11 :         if (NS_FAILED(rv)) {
     164               0 :             inputStream->Close();
     165               0 :             return rv;
     166                 :         }
     167              11 :         rv = ZW_ReadData(inputStream, (char *)buf, length);
     168              11 :         if (NS_FAILED(rv)) {
     169               0 :             inputStream->Close();
     170               0 :             return rv;
     171                 :         }
     172                 : 
     173                 :         /*
     174                 :          * We have to backtrack from the end of the file until we find the
     175                 :          * CDS signature
     176                 :          */
     177                 :         // We know it's at least this far from the end
     178            3418 :         for (PRUint32 pos = length - ZIP_EOCDR_HEADER_SIZE;
     179                 :              (PRInt32)pos >= 0; pos--) {
     180            3414 :             PRUint32 sig = PEEK32(buf + pos);
     181            3414 :             if (sig == ZIP_EOCDR_HEADER_SIGNATURE) {
     182                 :                 // Skip down to entry count
     183               7 :                 pos += 10;
     184               7 :                 PRUint32 entries = READ16(buf, &pos);
     185                 :                 // Skip past CDS size
     186               7 :                 pos += 4;
     187               7 :                 mCDSOffset = READ32(buf, &pos);
     188               7 :                 PRUint32 commentlen = READ16(buf, &pos);
     189                 : 
     190               7 :                 if (commentlen == 0)
     191               6 :                     mComment.Truncate();
     192               1 :                 else if (pos + commentlen <= length)
     193               1 :                     mComment.Assign((const char *)buf + pos, commentlen);
     194                 :                 else {
     195               0 :                     if ((seek + pos + commentlen) > size) {
     196               0 :                         inputStream->Close();
     197               0 :                         return NS_ERROR_FILE_CORRUPTED;
     198                 :                     }
     199               0 :                     nsAutoArrayPtr<char> field(new char[commentlen]);
     200               0 :                     NS_ENSURE_TRUE(field, NS_ERROR_OUT_OF_MEMORY);
     201               0 :                     rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET,
     202               0 :                                         seek + pos);
     203               0 :                     if (NS_FAILED(rv)) {
     204               0 :                         inputStream->Close();
     205               0 :                         return rv;
     206                 :                     }
     207               0 :                     rv = ZW_ReadData(inputStream, field.get(), length);
     208               0 :                     if (NS_FAILED(rv)) {
     209               0 :                         inputStream->Close();
     210               0 :                         return rv;
     211                 :                     }
     212               0 :                     mComment.Assign(field.get(), commentlen);
     213                 :                 }
     214                 : 
     215               7 :                 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET,
     216               7 :                                     mCDSOffset);
     217               7 :                 if (NS_FAILED(rv)) {
     218               0 :                     inputStream->Close();
     219               0 :                     return rv;
     220                 :                 }
     221                 : 
     222              16 :                 for (PRUint32 entry = 0; entry < entries; entry++) {
     223               9 :                     nsZipHeader* header = new nsZipHeader();
     224               9 :                     if (!header) {
     225               0 :                         inputStream->Close();
     226               0 :                         mEntryHash.Clear();
     227               0 :                         mHeaders.Clear();
     228               0 :                         return NS_ERROR_OUT_OF_MEMORY;
     229                 :                     }
     230               9 :                     rv = header->ReadCDSHeader(inputStream);
     231               9 :                     if (NS_FAILED(rv)) {
     232               0 :                         inputStream->Close();
     233               0 :                         mEntryHash.Clear();
     234               0 :                         mHeaders.Clear();
     235               0 :                         return rv;
     236                 :                     }
     237               9 :                     if (!mEntryHash.Put(header->mName, mHeaders.Count()))
     238               0 :                         return NS_ERROR_OUT_OF_MEMORY;
     239               9 :                     if (!mHeaders.AppendObject(header))
     240               0 :                         return NS_ERROR_OUT_OF_MEMORY;
     241                 :                 }
     242                 : 
     243               7 :                 return inputStream->Close();
     244                 :             }
     245                 :         }
     246                 : 
     247               4 :         if (seek == 0) {
     248                 :             // We've reached the start with no signature found. Corrupt.
     249               1 :             inputStream->Close();
     250               1 :             return NS_ERROR_FILE_CORRUPTED;
     251                 :         }
     252                 : 
     253                 :         // Overlap by the size of the end of cdr
     254               3 :         seek -= (1024 - ZIP_EOCDR_HEADER_SIZE);
     255                 :     }
     256                 :     // Will never reach here in reality
     257                 :     NS_NOTREACHED("Loop should never complete");
     258                 :     return NS_ERROR_UNEXPECTED;
     259                 : }
     260                 : 
     261                 : /* void open (in nsIFile aFile, in PRInt32 aIoFlags); */
     262             948 : NS_IMETHODIMP nsZipWriter::Open(nsIFile *aFile, PRInt32 aIoFlags)
     263                 : {
     264             948 :     if (mStream)
     265               0 :         return NS_ERROR_ALREADY_INITIALIZED;
     266                 : 
     267             948 :     NS_ENSURE_ARG_POINTER(aFile);
     268                 : 
     269                 :     // Need to be able to write to the file
     270             948 :     if (aIoFlags & PR_RDONLY)
     271               0 :         return NS_ERROR_FAILURE;
     272                 :     
     273             948 :     nsresult rv = aFile->Clone(getter_AddRefs(mFile));
     274             948 :     NS_ENSURE_SUCCESS(rv, rv);
     275                 : 
     276                 :     bool exists;
     277             948 :     rv = mFile->Exists(&exists);
     278             948 :     NS_ENSURE_SUCCESS(rv, rv);
     279             948 :     if (!exists && !(aIoFlags & PR_CREATE_FILE))
     280               0 :         return NS_ERROR_FILE_NOT_FOUND;
     281                 : 
     282             948 :     if (exists && !(aIoFlags & (PR_TRUNCATE | PR_WRONLY))) {
     283              10 :         rv = ReadFile(mFile);
     284              10 :         NS_ENSURE_SUCCESS(rv, rv);
     285               7 :         mCDSDirty = false;
     286                 :     }
     287                 :     else {
     288             938 :         mCDSOffset = 0;
     289             938 :         mCDSDirty = true;
     290             938 :         mComment.Truncate();
     291                 :     }
     292                 : 
     293                 :     // Silently drop PR_APPEND
     294             945 :     aIoFlags &= 0xef;
     295                 : 
     296            1890 :     nsCOMPtr<nsIOutputStream> stream;
     297             945 :     rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), mFile, aIoFlags);
     298             945 :     if (NS_FAILED(rv)) {
     299               3 :         mHeaders.Clear();
     300               3 :         mEntryHash.Clear();
     301               3 :         return rv;
     302                 :     }
     303                 : 
     304             942 :     rv = NS_NewBufferedOutputStream(getter_AddRefs(mStream), stream, 64 * 1024);
     305             942 :     if (NS_FAILED(rv)) {
     306               0 :         stream->Close();
     307               0 :         mHeaders.Clear();
     308               0 :         mEntryHash.Clear();
     309               0 :         return rv;
     310                 :     }
     311                 : 
     312             942 :     if (mCDSOffset > 0) {
     313               6 :         rv = SeekCDS();
     314               6 :         NS_ENSURE_SUCCESS(rv, rv);
     315                 :     }
     316                 : 
     317             942 :     return NS_OK;
     318                 : }
     319                 : 
     320                 : /* nsIZipEntry getEntry (in AString aZipEntry); */
     321              11 : NS_IMETHODIMP nsZipWriter::GetEntry(const nsACString & aZipEntry,
     322                 :                                     nsIZipEntry **_retval)
     323                 : {
     324                 :     PRInt32 pos;
     325              11 :     if (mEntryHash.Get(aZipEntry, &pos))
     326              11 :         NS_ADDREF(*_retval = mHeaders[pos]);
     327                 :     else
     328               0 :         *_retval = nsnull;
     329                 : 
     330              11 :     return NS_OK;
     331                 : }
     332                 : 
     333                 : /* boolean hasEntry (in AString aZipEntry); */
     334            5160 : NS_IMETHODIMP nsZipWriter::HasEntry(const nsACString & aZipEntry,
     335                 :                                     bool *_retval)
     336                 : {
     337            5160 :     *_retval = mEntryHash.Get(aZipEntry, nsnull);
     338                 : 
     339            5160 :     return NS_OK;
     340                 : }
     341                 : 
     342                 : /* void addEntryDirectory (in AUTF8String aZipEntry, in PRTime aModTime,
     343                 :  *                         in boolean aQueue); */
     344               4 : NS_IMETHODIMP nsZipWriter::AddEntryDirectory(const nsACString & aZipEntry,
     345                 :                                              PRTime aModTime, bool aQueue)
     346                 : {
     347               4 :     if (!mStream)
     348               1 :         return NS_ERROR_NOT_INITIALIZED;
     349                 : 
     350               3 :     if (aQueue) {
     351               0 :         nsZipQueueItem item;
     352               0 :         item.mOperation = OPERATION_ADD;
     353               0 :         item.mZipEntry = aZipEntry;
     354               0 :         item.mModTime = aModTime;
     355               0 :         item.mPermissions = PERMISSIONS_DIR;
     356               0 :         if (!mQueue.AppendElement(item))
     357               0 :             return NS_ERROR_OUT_OF_MEMORY;
     358               0 :         return NS_OK;
     359                 :     }
     360                 : 
     361               3 :     if (mInQueue)
     362               0 :         return NS_ERROR_IN_PROGRESS;
     363               3 :     return InternalAddEntryDirectory(aZipEntry, aModTime, PERMISSIONS_DIR);
     364                 : }
     365                 : 
     366                 : /* void addEntryFile (in AUTF8String aZipEntry, in PRInt32 aCompression,
     367                 :  *                    in nsIFile aFile, in boolean aQueue); */
     368             269 : NS_IMETHODIMP nsZipWriter::AddEntryFile(const nsACString & aZipEntry,
     369                 :                                         PRInt32 aCompression, nsIFile *aFile,
     370                 :                                         bool aQueue)
     371                 : {
     372             269 :     NS_ENSURE_ARG_POINTER(aFile);
     373             269 :     if (!mStream)
     374               1 :         return NS_ERROR_NOT_INITIALIZED;
     375                 : 
     376                 :     nsresult rv;
     377             268 :     if (aQueue) {
     378               6 :         nsZipQueueItem item;
     379               3 :         item.mOperation = OPERATION_ADD;
     380               3 :         item.mZipEntry = aZipEntry;
     381               3 :         item.mCompression = aCompression;
     382               3 :         rv = aFile->Clone(getter_AddRefs(item.mFile));
     383               3 :         NS_ENSURE_SUCCESS(rv, rv);
     384               3 :         if (!mQueue.AppendElement(item))
     385               0 :             return NS_ERROR_OUT_OF_MEMORY;
     386               3 :         return NS_OK;
     387                 :     }
     388                 : 
     389             265 :     if (mInQueue)
     390               0 :         return NS_ERROR_IN_PROGRESS;
     391                 : 
     392                 :     bool exists;
     393             265 :     rv = aFile->Exists(&exists);
     394             265 :     NS_ENSURE_SUCCESS(rv, rv);
     395             265 :     if (!exists)
     396               0 :         return NS_ERROR_FILE_NOT_FOUND;
     397                 : 
     398                 :     bool isdir;
     399             265 :     rv = aFile->IsDirectory(&isdir);
     400             265 :     NS_ENSURE_SUCCESS(rv, rv);
     401                 : 
     402                 :     PRInt64 modtime;
     403             265 :     rv = aFile->GetLastModifiedTime(&modtime);
     404             265 :     NS_ENSURE_SUCCESS(rv, rv);
     405             265 :     modtime *= PR_USEC_PER_MSEC;
     406                 : 
     407                 :     PRUint32 permissions;
     408             265 :     rv = aFile->GetPermissions(&permissions);
     409             265 :     NS_ENSURE_SUCCESS(rv, rv);
     410                 : 
     411             265 :     if (isdir)
     412               2 :         return InternalAddEntryDirectory(aZipEntry, modtime, permissions);
     413                 : 
     414             263 :     if (mEntryHash.Get(aZipEntry, nsnull))
     415               1 :         return NS_ERROR_FILE_ALREADY_EXISTS;
     416                 : 
     417             524 :     nsCOMPtr<nsIInputStream> inputStream;
     418             262 :     rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream),
     419             262 :                                     aFile);
     420             262 :     NS_ENSURE_SUCCESS(rv, rv);
     421                 : 
     422                 :     rv = AddEntryStream(aZipEntry, modtime, aCompression, inputStream,
     423             262 :                         false, permissions);
     424             262 :     NS_ENSURE_SUCCESS(rv, rv);
     425                 : 
     426             262 :     return inputStream->Close();
     427                 : }
     428                 : 
     429                 : /* void addEntryChannel (in AUTF8String aZipEntry, in PRTime aModTime,
     430                 :  *                       in PRInt32 aCompression, in nsIChannel aChannel,
     431                 :  *                       in boolean aQueue); */
     432               2 : NS_IMETHODIMP nsZipWriter::AddEntryChannel(const nsACString & aZipEntry,
     433                 :                                            PRTime aModTime,
     434                 :                                            PRInt32 aCompression,
     435                 :                                            nsIChannel *aChannel,
     436                 :                                            bool aQueue)
     437                 : {
     438               2 :     NS_ENSURE_ARG_POINTER(aChannel);
     439               2 :     if (!mStream)
     440               0 :         return NS_ERROR_NOT_INITIALIZED;
     441                 : 
     442               2 :     if (aQueue) {
     443               4 :         nsZipQueueItem item;
     444               2 :         item.mOperation = OPERATION_ADD;
     445               2 :         item.mZipEntry = aZipEntry;
     446               2 :         item.mModTime = aModTime;
     447               2 :         item.mCompression = aCompression;
     448               2 :         item.mPermissions = PERMISSIONS_FILE;
     449               2 :         item.mChannel = aChannel;
     450               2 :         if (!mQueue.AppendElement(item))
     451               0 :             return NS_ERROR_OUT_OF_MEMORY;
     452               2 :         return NS_OK;
     453                 :     }
     454                 : 
     455               0 :     if (mInQueue)
     456               0 :         return NS_ERROR_IN_PROGRESS;
     457               0 :     if (mEntryHash.Get(aZipEntry, nsnull))
     458               0 :         return NS_ERROR_FILE_ALREADY_EXISTS;
     459                 : 
     460               0 :     nsCOMPtr<nsIInputStream> inputStream;
     461               0 :     nsresult rv = aChannel->Open(getter_AddRefs(inputStream));
     462               0 :     NS_ENSURE_SUCCESS(rv, rv);
     463                 : 
     464                 :     rv = AddEntryStream(aZipEntry, aModTime, aCompression, inputStream,
     465               0 :                         false, PERMISSIONS_FILE);
     466               0 :     NS_ENSURE_SUCCESS(rv, rv);
     467                 : 
     468               0 :     return inputStream->Close();
     469                 : }
     470                 : 
     471                 : /* void addEntryStream (in AUTF8String aZipEntry, in PRTime aModTime,
     472                 :  *                      in PRInt32 aCompression, in nsIInputStream aStream,
     473                 :  *                      in boolean aQueue); */
     474            5465 : NS_IMETHODIMP nsZipWriter::AddEntryStream(const nsACString & aZipEntry,
     475                 :                                           PRTime aModTime,
     476                 :                                           PRInt32 aCompression,
     477                 :                                           nsIInputStream *aStream,
     478                 :                                           bool aQueue)
     479                 : {
     480                 :     return AddEntryStream(aZipEntry, aModTime, aCompression, aStream, aQueue,
     481            5465 :                           PERMISSIONS_FILE);
     482                 : }
     483                 : 
     484                 : /* void addEntryStream (in AUTF8String aZipEntry, in PRTime aModTime,
     485                 :  *                      in PRInt32 aCompression, in nsIInputStream aStream,
     486                 :  *                      in boolean aQueue, in unsigned long aPermissions); */
     487            5727 : nsresult nsZipWriter::AddEntryStream(const nsACString & aZipEntry,
     488                 :                                      PRTime aModTime,
     489                 :                                      PRInt32 aCompression,
     490                 :                                      nsIInputStream *aStream,
     491                 :                                      bool aQueue,
     492                 :                                      PRUint32 aPermissions)
     493                 : {
     494            5727 :     NS_ENSURE_ARG_POINTER(aStream);
     495            5727 :     if (!mStream)
     496               0 :         return NS_ERROR_NOT_INITIALIZED;
     497                 : 
     498            5727 :     if (aQueue) {
     499               4 :         nsZipQueueItem item;
     500               2 :         item.mOperation = OPERATION_ADD;
     501               2 :         item.mZipEntry = aZipEntry;
     502               2 :         item.mModTime = aModTime;
     503               2 :         item.mCompression = aCompression;
     504               2 :         item.mPermissions = aPermissions;
     505               2 :         item.mStream = aStream;
     506               2 :         if (!mQueue.AppendElement(item))
     507               0 :             return NS_ERROR_OUT_OF_MEMORY;
     508               2 :         return NS_OK;
     509                 :     }
     510                 : 
     511            5725 :     if (mInQueue)
     512               0 :         return NS_ERROR_IN_PROGRESS;
     513            5725 :     if (mEntryHash.Get(aZipEntry, nsnull))
     514               0 :         return NS_ERROR_FILE_ALREADY_EXISTS;
     515                 : 
     516           11450 :     nsRefPtr<nsZipHeader> header = new nsZipHeader();
     517            5725 :     NS_ENSURE_TRUE(header, NS_ERROR_OUT_OF_MEMORY);
     518                 :     header->Init(aZipEntry, aModTime, ZIP_ATTRS(aPermissions, ZIP_ATTRS_FILE),
     519            5725 :                  mCDSOffset);
     520            5725 :     nsresult rv = header->WriteFileHeader(mStream);
     521            5725 :     if (NS_FAILED(rv)) {
     522               0 :         SeekCDS();
     523               0 :         return rv;
     524                 :     }
     525                 : 
     526           11450 :     nsRefPtr<nsZipDataStream> stream = new nsZipDataStream();
     527            5725 :     if (!stream) {
     528               0 :         SeekCDS();
     529               0 :         return NS_ERROR_OUT_OF_MEMORY;
     530                 :     }
     531            5725 :     rv = stream->Init(this, mStream, header, aCompression);
     532            5725 :     if (NS_FAILED(rv)) {
     533               0 :         SeekCDS();
     534               0 :         return rv;
     535                 :     }
     536                 : 
     537            5725 :     rv = stream->ReadStream(aStream);
     538            5725 :     if (NS_FAILED(rv))
     539               0 :         SeekCDS();
     540            5725 :     return rv;
     541                 : }
     542                 : 
     543                 : /* void removeEntry (in AUTF8String aZipEntry, in boolean aQueue); */
     544               9 : NS_IMETHODIMP nsZipWriter::RemoveEntry(const nsACString & aZipEntry,
     545                 :                                        bool aQueue)
     546                 : {
     547               9 :     if (!mStream)
     548               1 :         return NS_ERROR_NOT_INITIALIZED;
     549                 : 
     550               8 :     if (aQueue) {
     551               6 :         nsZipQueueItem item;
     552               3 :         item.mOperation = OPERATION_REMOVE;
     553               3 :         item.mZipEntry = aZipEntry;
     554               3 :         if (!mQueue.AppendElement(item))
     555               0 :             return NS_ERROR_OUT_OF_MEMORY;
     556               3 :         return NS_OK;
     557                 :     }
     558                 : 
     559               5 :     if (mInQueue)
     560               0 :         return NS_ERROR_IN_PROGRESS;
     561                 : 
     562                 :     PRInt32 pos;
     563               5 :     if (mEntryHash.Get(aZipEntry, &pos)) {
     564                 :         // Flush any remaining data before we seek.
     565               4 :         nsresult rv = mStream->Flush();
     566               4 :         NS_ENSURE_SUCCESS(rv, rv);
     567               4 :         if (pos < mHeaders.Count() - 1) {
     568                 :             // This is not the last entry, pull back the data.
     569               4 :             nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream);
     570               2 :             rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET,
     571               2 :                                 mHeaders[pos]->mOffset);
     572               2 :             NS_ENSURE_SUCCESS(rv, rv);
     573                 : 
     574               4 :             nsCOMPtr<nsIInputStream> inputStream;
     575               2 :             rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream),
     576               2 :                                             mFile);
     577               2 :             NS_ENSURE_SUCCESS(rv, rv);
     578               2 :             seekable = do_QueryInterface(inputStream);
     579               2 :             rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET,
     580               2 :                                 mHeaders[pos + 1]->mOffset);
     581               2 :             if (NS_FAILED(rv)) {
     582               0 :                 inputStream->Close();
     583               0 :                 return rv;
     584                 :             }
     585                 : 
     586               2 :             PRUint32 count = mCDSOffset - mHeaders[pos + 1]->mOffset;
     587               2 :             PRUint32 read = 0;
     588                 :             char buf[4096];
     589               6 :             while (count > 0) {
     590               2 :                 if (count < sizeof(buf))
     591               2 :                     read = count;
     592                 :                 else
     593               0 :                     read = sizeof(buf);
     594                 : 
     595               2 :                 rv = inputStream->Read(buf, read, &read);
     596               2 :                 if (NS_FAILED(rv)) {
     597               0 :                     inputStream->Close();
     598               0 :                     Cleanup();
     599               0 :                     return rv;
     600                 :                 }
     601                 : 
     602               2 :                 rv = ZW_WriteData(mStream, buf, read);
     603               2 :                 if (NS_FAILED(rv)) {
     604               0 :                     inputStream->Close();
     605               0 :                     Cleanup();
     606               0 :                     return rv;
     607                 :                 }
     608                 : 
     609               2 :                 count -= read;
     610                 :             }
     611               2 :             inputStream->Close();
     612                 : 
     613                 :             // Rewrite header offsets and update hash
     614               2 :             PRUint32 shift = (mHeaders[pos + 1]->mOffset -
     615               2 :                               mHeaders[pos]->mOffset);
     616               2 :             mCDSOffset -= shift;
     617               2 :             PRInt32 pos2 = pos + 1;
     618               6 :             while (pos2 < mHeaders.Count()) {
     619               2 :                 if (!mEntryHash.Put(mHeaders[pos2]->mName, pos2-1)) {
     620               0 :                     Cleanup();
     621               0 :                     return NS_ERROR_OUT_OF_MEMORY;
     622                 :                 }
     623               2 :                 mHeaders[pos2]->mOffset -= shift;
     624               2 :                 pos2++;
     625                 :             }
     626                 :         }
     627                 :         else {
     628                 :             // Remove the last entry is just a case of moving the CDS
     629               2 :             mCDSOffset = mHeaders[pos]->mOffset;
     630               2 :             rv = SeekCDS();
     631               2 :             NS_ENSURE_SUCCESS(rv, rv);
     632                 :         }
     633                 : 
     634               4 :         mEntryHash.Remove(mHeaders[pos]->mName);
     635               4 :         mHeaders.RemoveObjectAt(pos);
     636               4 :         mCDSDirty = true;
     637                 : 
     638               4 :         return NS_OK;
     639                 :     }
     640                 : 
     641               1 :     return NS_ERROR_FILE_NOT_FOUND;
     642                 : }
     643                 : 
     644                 : /* void processQueue (in nsIRequestObserver aObserver,
     645                 :  *                    in nsISupports aContext); */
     646               5 : NS_IMETHODIMP nsZipWriter::ProcessQueue(nsIRequestObserver *aObserver,
     647                 :                                         nsISupports *aContext)
     648                 : {
     649               5 :     if (!mStream)
     650               1 :         return NS_ERROR_NOT_INITIALIZED;
     651               4 :     if (mInQueue)
     652               0 :         return NS_ERROR_IN_PROGRESS;
     653                 : 
     654               4 :     mProcessObserver = aObserver;
     655               4 :     mProcessContext = aContext;
     656               4 :     mInQueue = true;
     657                 : 
     658               4 :     if (mProcessObserver)
     659               4 :         mProcessObserver->OnStartRequest(nsnull, mProcessContext);
     660                 : 
     661               4 :     BeginProcessingNextItem();
     662                 : 
     663               4 :     return NS_OK;
     664                 : }
     665                 : 
     666                 : /* void close (); */
     667             964 : NS_IMETHODIMP nsZipWriter::Close()
     668                 : {
     669             964 :     if (!mStream)
     670              22 :         return NS_ERROR_NOT_INITIALIZED;
     671             942 :     if (mInQueue)
     672               0 :         return NS_ERROR_IN_PROGRESS;
     673                 : 
     674             942 :     if (mCDSDirty) {
     675             939 :         PRUint32 size = 0;
     676            6675 :         for (PRInt32 i = 0; i < mHeaders.Count(); i++) {
     677            5736 :             nsresult rv = mHeaders[i]->WriteCDSHeader(mStream);
     678            5736 :             if (NS_FAILED(rv)) {
     679               0 :                 Cleanup();
     680               0 :                 return rv;
     681                 :             }
     682            5736 :             size += mHeaders[i]->GetCDSHeaderLength();
     683                 :         }
     684                 : 
     685                 :         PRUint8 buf[ZIP_EOCDR_HEADER_SIZE];
     686             939 :         PRUint32 pos = 0;
     687             939 :         WRITE32(buf, &pos, ZIP_EOCDR_HEADER_SIGNATURE);
     688             939 :         WRITE16(buf, &pos, 0);
     689             939 :         WRITE16(buf, &pos, 0);
     690             939 :         WRITE16(buf, &pos, mHeaders.Count());
     691             939 :         WRITE16(buf, &pos, mHeaders.Count());
     692             939 :         WRITE32(buf, &pos, size);
     693             939 :         WRITE32(buf, &pos, mCDSOffset);
     694             939 :         WRITE16(buf, &pos, mComment.Length());
     695                 : 
     696             939 :         nsresult rv = ZW_WriteData(mStream, (const char *)buf, pos);
     697             939 :         if (NS_FAILED(rv)) {
     698               0 :             Cleanup();
     699               0 :             return rv;
     700                 :         }
     701                 : 
     702             939 :         rv = ZW_WriteData(mStream, mComment.get(), mComment.Length());
     703             939 :         if (NS_FAILED(rv)) {
     704               0 :             Cleanup();
     705               0 :             return rv;
     706                 :         }
     707                 : 
     708            1878 :         nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream);
     709             939 :         rv = seekable->SetEOF();
     710             939 :         if (NS_FAILED(rv)) {
     711               0 :             Cleanup();
     712               0 :             return rv;
     713                 :         }
     714                 : 
     715                 :         // Go back and rewrite the file headers
     716            6675 :         for (PRInt32 i = 0; i < mHeaders.Count(); i++) {
     717            5736 :             nsZipHeader *header = mHeaders[i];
     718            5736 :             if (!header->mWriteOnClose)
     719               7 :               continue;
     720                 : 
     721            5729 :             rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, header->mOffset);
     722            5729 :             if (NS_FAILED(rv)) {
     723               0 :                Cleanup();
     724               0 :                return rv;
     725                 :             }
     726            5729 :             rv = header->WriteFileHeader(mStream);
     727            5729 :             if (NS_FAILED(rv)) {
     728               0 :                Cleanup();
     729               0 :                return rv;
     730                 :             }
     731                 :         }
     732                 :     }
     733                 : 
     734             942 :     nsresult rv = mStream->Close();
     735             942 :     mStream = nsnull;
     736             942 :     mHeaders.Clear();
     737             942 :     mEntryHash.Clear();
     738             942 :     mQueue.Clear();
     739                 : 
     740             942 :     return rv;
     741                 : }
     742                 : 
     743                 : // Our nsIRequestObserver monitors removal operations performed on the queue
     744                 : /* void onStartRequest (in nsIRequest aRequest, in nsISupports aContext); */
     745               1 : NS_IMETHODIMP nsZipWriter::OnStartRequest(nsIRequest *aRequest,
     746                 :                                           nsISupports *aContext)
     747                 : {
     748               1 :     return NS_OK;
     749                 : }
     750                 : 
     751                 : /* void onStopRequest (in nsIRequest aRequest, in nsISupports aContext,
     752                 :  *                                             in nsresult aStatusCode); */
     753               1 : NS_IMETHODIMP nsZipWriter::OnStopRequest(nsIRequest *aRequest,
     754                 :                                          nsISupports *aContext,
     755                 :                                          nsresult aStatusCode)
     756                 : {
     757               1 :     if (NS_FAILED(aStatusCode)) {
     758               0 :         FinishQueue(aStatusCode);
     759               0 :         Cleanup();
     760                 :     }
     761                 : 
     762               1 :     nsresult rv = mStream->Flush();
     763               1 :     if (NS_FAILED(rv)) {
     764               0 :         FinishQueue(rv);
     765               0 :         Cleanup();
     766               0 :         return rv;
     767                 :     }
     768               1 :     rv = SeekCDS();
     769               1 :     if (NS_FAILED(rv)) {
     770               0 :         FinishQueue(rv);
     771               0 :         return rv;
     772                 :     }
     773                 : 
     774               1 :     BeginProcessingNextItem();
     775                 : 
     776               1 :     return NS_OK;
     777                 : }
     778                 : 
     779               5 : nsresult nsZipWriter::InternalAddEntryDirectory(const nsACString & aZipEntry,
     780                 :                                                 PRTime aModTime,
     781                 :                                                 PRUint32 aPermissions)
     782                 : {
     783              10 :     nsRefPtr<nsZipHeader> header = new nsZipHeader();
     784               5 :     NS_ENSURE_TRUE(header, NS_ERROR_OUT_OF_MEMORY);
     785                 : 
     786               5 :     PRUint32 zipAttributes = ZIP_ATTRS(aPermissions, ZIP_ATTRS_DIRECTORY);
     787                 : 
     788               5 :     if (aZipEntry.Last() != '/') {
     789               2 :         nsCString dirPath;
     790               1 :         dirPath.Assign(aZipEntry + NS_LITERAL_CSTRING("/"));
     791               1 :         header->Init(dirPath, aModTime, zipAttributes, mCDSOffset);
     792                 :     }
     793                 :     else
     794               4 :         header->Init(aZipEntry, aModTime, zipAttributes, mCDSOffset);
     795                 : 
     796               5 :     if (mEntryHash.Get(header->mName, nsnull))
     797               0 :         return NS_ERROR_FILE_ALREADY_EXISTS;
     798                 : 
     799               5 :     nsresult rv = header->WriteFileHeader(mStream);
     800               5 :     if (NS_FAILED(rv)) {
     801               0 :         Cleanup();
     802               0 :         return rv;
     803                 :     }
     804                 : 
     805               5 :     mCDSDirty = true;
     806               5 :     mCDSOffset += header->GetFileHeaderLength();
     807               5 :     if (!mEntryHash.Put(header->mName, mHeaders.Count())) {
     808               0 :         Cleanup();
     809               0 :         return NS_ERROR_OUT_OF_MEMORY;
     810                 :     }
     811               5 :     if (!mHeaders.AppendObject(header)) {
     812               0 :         Cleanup();
     813               0 :         return NS_ERROR_OUT_OF_MEMORY;
     814                 :     }
     815                 : 
     816               5 :     return NS_OK;
     817                 : }
     818                 : 
     819                 : /*
     820                 :  * Recovering from an error while adding a new entry is simply a case of
     821                 :  * seeking back to the CDS. If we fail trying to do that though then cleanup
     822                 :  * and bail out.
     823                 :  */
     824              11 : nsresult nsZipWriter::SeekCDS()
     825                 : {
     826                 :     nsresult rv;
     827              22 :     nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream, &rv);
     828              11 :     if (NS_FAILED(rv)) {
     829               0 :         Cleanup();
     830               0 :         return rv;
     831                 :     }
     832              11 :     rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, mCDSOffset);
     833              11 :     if (NS_FAILED(rv))
     834               0 :         Cleanup();
     835              11 :     return rv;
     836                 : }
     837                 : 
     838                 : /*
     839                 :  * In a bad error condition this essentially closes down the component as best
     840                 :  * it can.
     841                 :  */
     842               0 : void nsZipWriter::Cleanup()
     843                 : {
     844               0 :     mHeaders.Clear();
     845               0 :     mEntryHash.Clear();
     846               0 :     if (mStream)
     847               0 :         mStream->Close();
     848               0 :     mStream = nsnull;
     849               0 :     mFile = nsnull;
     850               0 : }
     851                 : 
     852                 : /*
     853                 :  * Called when writing a file to the zip is complete.
     854                 :  */
     855            5731 : nsresult nsZipWriter::EntryCompleteCallback(nsZipHeader* aHeader,
     856                 :                                             nsresult aStatus)
     857                 : {
     858            5731 :     if (NS_SUCCEEDED(aStatus)) {
     859            5731 :         if (!mEntryHash.Put(aHeader->mName, mHeaders.Count())) {
     860               0 :             SeekCDS();
     861               0 :             return NS_ERROR_OUT_OF_MEMORY;
     862                 :         }
     863            5731 :         if (!mHeaders.AppendObject(aHeader)) {
     864               0 :             mEntryHash.Remove(aHeader->mName);
     865               0 :             SeekCDS();
     866               0 :             return NS_ERROR_OUT_OF_MEMORY;
     867                 :         }
     868            5731 :         mCDSDirty = true;
     869            5731 :         mCDSOffset += aHeader->mCSize + aHeader->GetFileHeaderLength();
     870                 : 
     871            5731 :         if (mInQueue)
     872               6 :             BeginProcessingNextItem();
     873                 : 
     874            5731 :         return NS_OK;
     875                 :     }
     876                 : 
     877               0 :     nsresult rv = SeekCDS();
     878               0 :     if (mInQueue)
     879               0 :         FinishQueue(aStatus);
     880               0 :     return rv;
     881                 : }
     882                 : 
     883               7 : inline nsresult nsZipWriter::BeginProcessingAddition(nsZipQueueItem* aItem,
     884                 :                                                      bool* complete)
     885                 : {
     886               7 :     if (aItem->mFile) {
     887                 :         bool exists;
     888               3 :         nsresult rv = aItem->mFile->Exists(&exists);
     889               3 :         NS_ENSURE_SUCCESS(rv, rv);
     890                 : 
     891               3 :         if (!exists) return NS_ERROR_FILE_NOT_FOUND;
     892                 : 
     893                 :         bool isdir;
     894               2 :         rv = aItem->mFile->IsDirectory(&isdir);
     895               2 :         NS_ENSURE_SUCCESS(rv, rv);
     896                 : 
     897               2 :         rv = aItem->mFile->GetLastModifiedTime(&aItem->mModTime);
     898               2 :         NS_ENSURE_SUCCESS(rv, rv);
     899               2 :         aItem->mModTime *= PR_USEC_PER_MSEC;
     900                 : 
     901               2 :         rv = aItem->mFile->GetPermissions(&aItem->mPermissions);
     902               2 :         NS_ENSURE_SUCCESS(rv, rv);
     903                 : 
     904               2 :         if (!isdir) {
     905                 :             // Set up for fall through to stream reader
     906               2 :             rv = NS_NewLocalFileInputStream(getter_AddRefs(aItem->mStream),
     907               2 :                                             aItem->mFile);
     908               2 :             NS_ENSURE_SUCCESS(rv, rv);
     909                 :         }
     910                 :         // If a dir then this will fall through to the plain dir addition
     911                 :     }
     912                 : 
     913               6 :     PRUint32 zipAttributes = ZIP_ATTRS(aItem->mPermissions, ZIP_ATTRS_FILE);
     914                 : 
     915               6 :     if (aItem->mStream || aItem->mChannel) {
     916              12 :         nsRefPtr<nsZipHeader> header = new nsZipHeader();
     917               6 :         NS_ENSURE_TRUE(header, NS_ERROR_OUT_OF_MEMORY);
     918                 : 
     919                 :         header->Init(aItem->mZipEntry, aItem->mModTime, zipAttributes,
     920               6 :                      mCDSOffset);
     921               6 :         nsresult rv = header->WriteFileHeader(mStream);
     922               6 :         NS_ENSURE_SUCCESS(rv, rv);
     923                 : 
     924              12 :         nsRefPtr<nsZipDataStream> stream = new nsZipDataStream();
     925               6 :         NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY);
     926               6 :         rv = stream->Init(this, mStream, header, aItem->mCompression);
     927               6 :         NS_ENSURE_SUCCESS(rv, rv);
     928                 : 
     929               6 :         if (aItem->mStream) {
     930               8 :             nsCOMPtr<nsIInputStreamPump> pump;
     931               4 :             rv = NS_NewInputStreamPump(getter_AddRefs(pump), aItem->mStream,
     932               4 :                                        -1, -1, 0, 0, true);
     933               4 :             NS_ENSURE_SUCCESS(rv, rv);
     934                 : 
     935               4 :             rv = pump->AsyncRead(stream, nsnull);
     936               4 :             NS_ENSURE_SUCCESS(rv, rv);
     937                 :         }
     938                 :         else {
     939               2 :             rv = aItem->mChannel->AsyncOpen(stream, nsnull);
     940               2 :             NS_ENSURE_SUCCESS(rv, rv);
     941                 :         }
     942                 : 
     943               6 :         return NS_OK;
     944                 :     }
     945                 : 
     946                 :     // Must be plain directory addition
     947               0 :     *complete = true;
     948                 :     return InternalAddEntryDirectory(aItem->mZipEntry, aItem->mModTime,
     949               0 :                                      aItem->mPermissions);
     950                 : }
     951                 : 
     952               1 : inline nsresult nsZipWriter::BeginProcessingRemoval(PRInt32 aPos)
     953                 : {
     954                 :     // Open the zip file for reading
     955               2 :     nsCOMPtr<nsIInputStream> inputStream;
     956               1 :     nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream),
     957               1 :                                              mFile);
     958               1 :     NS_ENSURE_SUCCESS(rv, rv);
     959               2 :     nsCOMPtr<nsIInputStreamPump> pump;
     960               1 :     rv = NS_NewInputStreamPump(getter_AddRefs(pump), inputStream, -1, -1, 0,
     961               1 :                                0, true);
     962               1 :     if (NS_FAILED(rv)) {
     963               0 :         inputStream->Close();
     964               0 :         return rv;
     965                 :     }
     966               2 :     nsCOMPtr<nsIStreamListener> listener;
     967               1 :     rv = NS_NewSimpleStreamListener(getter_AddRefs(listener), mStream, this);
     968               1 :     if (NS_FAILED(rv)) {
     969               0 :         inputStream->Close();
     970               0 :         return rv;
     971                 :     }
     972                 : 
     973               2 :     nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream);
     974               1 :     rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET,
     975               1 :                         mHeaders[aPos]->mOffset);
     976               1 :     if (NS_FAILED(rv)) {
     977               0 :         inputStream->Close();
     978               0 :         return rv;
     979                 :     }
     980                 : 
     981               1 :     PRUint32 shift = (mHeaders[aPos + 1]->mOffset -
     982               1 :                       mHeaders[aPos]->mOffset);
     983               1 :     mCDSOffset -= shift;
     984               1 :     PRInt32 pos2 = aPos + 1;
     985               3 :     while (pos2 < mHeaders.Count()) {
     986               1 :         mEntryHash.Put(mHeaders[pos2]->mName, pos2 - 1);
     987               1 :         mHeaders[pos2]->mOffset -= shift;
     988               1 :         pos2++;
     989                 :     }
     990                 : 
     991               1 :     mEntryHash.Remove(mHeaders[aPos]->mName);
     992               1 :     mHeaders.RemoveObjectAt(aPos);
     993               1 :     mCDSDirty = true;
     994                 : 
     995               1 :     rv = pump->AsyncRead(listener, nsnull);
     996               1 :     if (NS_FAILED(rv)) {
     997               0 :         inputStream->Close();
     998               0 :         Cleanup();
     999               0 :         return rv;
    1000                 :     }
    1001               1 :     return NS_OK;
    1002                 : }
    1003                 : 
    1004                 : /*
    1005                 :  * Starts processing on the next item in the queue.
    1006                 :  */
    1007              11 : void nsZipWriter::BeginProcessingNextItem()
    1008                 : {
    1009              23 :     while (!mQueue.IsEmpty()) {
    1010                 : 
    1011              20 :         nsZipQueueItem next = mQueue[0];
    1012              10 :         mQueue.RemoveElementAt(0);
    1013                 : 
    1014              10 :         if (next.mOperation == OPERATION_REMOVE) {
    1015               3 :             PRInt32 pos = -1;
    1016               3 :             if (mEntryHash.Get(next.mZipEntry, &pos)) {
    1017               2 :                 if (pos < mHeaders.Count() - 1) {
    1018               1 :                     nsresult rv = BeginProcessingRemoval(pos);
    1019               1 :                     if (NS_FAILED(rv)) FinishQueue(rv);
    1020                 :                     return;
    1021                 :                 }
    1022                 : 
    1023               1 :                 mCDSOffset = mHeaders[pos]->mOffset;
    1024               1 :                 nsresult rv = SeekCDS();
    1025               1 :                 if (NS_FAILED(rv)) {
    1026               0 :                     FinishQueue(rv);
    1027                 :                     return;
    1028                 :                 }
    1029               1 :                 mEntryHash.Remove(mHeaders[pos]->mName);
    1030               1 :                 mHeaders.RemoveObjectAt(pos);
    1031                 :             }
    1032                 :             else {
    1033               1 :                 FinishQueue(NS_ERROR_FILE_NOT_FOUND);
    1034                 :                 return;
    1035                 :             }
    1036                 :         }
    1037               7 :         else if (next.mOperation == OPERATION_ADD) {
    1038               7 :             if (mEntryHash.Get(next.mZipEntry, nsnull)) {
    1039               0 :                 FinishQueue(NS_ERROR_FILE_ALREADY_EXISTS);
    1040                 :                 return;
    1041                 :             }
    1042                 : 
    1043               7 :             bool complete = false;
    1044               7 :             nsresult rv = BeginProcessingAddition(&next, &complete);
    1045               7 :             if (NS_FAILED(rv)) {
    1046               1 :                 SeekCDS();
    1047               1 :                 FinishQueue(rv);
    1048                 :                 return;
    1049                 :             }
    1050               6 :             if (!complete)
    1051                 :                 return;
    1052                 :         }
    1053                 :     }
    1054                 : 
    1055               2 :     FinishQueue(NS_OK);
    1056                 : }
    1057                 : 
    1058                 : /*
    1059                 :  * Ends processing with the given status.
    1060                 :  */
    1061               4 : void nsZipWriter::FinishQueue(nsresult aStatus)
    1062                 : {
    1063               8 :     nsCOMPtr<nsIRequestObserver> observer = mProcessObserver;
    1064               8 :     nsCOMPtr<nsISupports> context = mProcessContext;
    1065                 :     // Clean up everything first in case the observer decides to queue more
    1066                 :     // things
    1067               4 :     mProcessObserver = nsnull;
    1068               4 :     mProcessContext = nsnull;
    1069               4 :     mInQueue = false;
    1070                 : 
    1071               4 :     if (observer)
    1072               4 :         observer->OnStopRequest(nsnull, context, aStatus);
    1073               4 : }

Generated by: LCOV version 1.7