LCOV - code coverage report
Current view: top level - modules/libjar/zipwriter - nsZipWriter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 663 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 32 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13