nsresult nsZipHeader::WriteCDSHeader(nsIOutputStream *aStream) { NS_ASSERTION(mInited, "Not initalised"); PRUint8 buf[ZIP_CDS_HEADER_SIZE]; PRUint32 pos = 0; WRITE32(buf, &pos, ZIP_CDS_HEADER_SIGNATURE); WRITE16(buf, &pos, mVersionMade); WRITE16(buf, &pos, mVersionNeeded); WRITE16(buf, &pos, mFlags); WRITE16(buf, &pos, mMethod); WRITE16(buf, &pos, mTime); WRITE16(buf, &pos, mDate); WRITE32(buf, &pos, mCRC); WRITE32(buf, &pos, mCSize); WRITE32(buf, &pos, mUSize); WRITE16(buf, &pos, mName.Length()); WRITE16(buf, &pos, mFieldLength); WRITE16(buf, &pos, mComment.Length()); WRITE16(buf, &pos, mDisk); WRITE16(buf, &pos, mIAttr); WRITE32(buf, &pos, mEAttr); WRITE32(buf, &pos, mOffset); nsresult rv = ZW_WriteData(aStream, (const char *)buf, pos); NS_ENSURE_SUCCESS(rv, rv); rv = ZW_WriteData(aStream, mName.get(), mName.Length()); NS_ENSURE_SUCCESS(rv, rv); if (mExtraField) { rv = ZW_WriteData(aStream, (const char *)mExtraField.get(), mFieldLength); NS_ENSURE_SUCCESS(rv, rv); } return ZW_WriteData(aStream, mComment.get(), mComment.Length()); }
nsresult nsZipHeader::WriteFileHeader(nsIOutputStream *aStream) { NS_ASSERTION(mInited, "Not initalised"); PRUint8 buf[ZIP_FILE_HEADER_SIZE]; PRUint32 pos = 0; WRITE32(buf, &pos, ZIP_FILE_HEADER_SIGNATURE); WRITE16(buf, &pos, mVersionNeeded); WRITE16(buf, &pos, mFlags); WRITE16(buf, &pos, mMethod); WRITE16(buf, &pos, mTime); WRITE16(buf, &pos, mDate); WRITE32(buf, &pos, mCRC); WRITE32(buf, &pos, mCSize); WRITE32(buf, &pos, mUSize); WRITE16(buf, &pos, mName.Length()); WRITE16(buf, &pos, mLocalFieldLength); nsresult rv = ZW_WriteData(aStream, (const char *)buf, pos); NS_ENSURE_SUCCESS(rv, rv); rv = ZW_WriteData(aStream, mName.get(), mName.Length()); NS_ENSURE_SUCCESS(rv, rv); if (mLocalFieldLength) { rv = ZW_WriteData(aStream, (const char *)mLocalExtraField.get(), mLocalFieldLength); NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; }
/* void close (); */ NS_IMETHODIMP nsZipWriter::Close() { if (!mStream) return NS_ERROR_NOT_INITIALIZED; if (mInQueue) return NS_ERROR_IN_PROGRESS; if (mCDSDirty) { PRUint32 size = 0; for (PRInt32 i = 0; i < mHeaders.Count(); i++) { nsresult rv = mHeaders[i]->WriteCDSHeader(mStream); if (NS_FAILED(rv)) { Cleanup(); return rv; } size += mHeaders[i]->GetCDSHeaderLength(); } char buf[ZIP_EOCDR_HEADER_SIZE]; PRUint32 pos = 0; WRITE32(buf, &pos, ZIP_EOCDR_HEADER_SIGNATURE); WRITE16(buf, &pos, 0); WRITE16(buf, &pos, 0); WRITE16(buf, &pos, mHeaders.Count()); WRITE16(buf, &pos, mHeaders.Count()); WRITE32(buf, &pos, size); WRITE32(buf, &pos, mCDSOffset); WRITE16(buf, &pos, mComment.Length()); nsresult rv = ZW_WriteData(mStream, buf, pos); if (NS_FAILED(rv)) { Cleanup(); return rv; } rv = ZW_WriteData(mStream, mComment.get(), mComment.Length()); if (NS_FAILED(rv)) { Cleanup(); return rv; } nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream); rv = seekable->SetEOF(); if (NS_FAILED(rv)) { Cleanup(); return rv; } } nsresult rv = mStream->Close(); mStream = nsnull; mHeaders.Clear(); mEntryHash.Clear(); mQueue.Clear(); return rv; }
/* * Make all stored(uncompressed) files align to given alignment size. */ NS_IMETHODIMP nsZipWriter::AlignStoredFiles(uint16_t aAlignSize) { nsresult rv; // Check for range and power of 2. if (aAlignSize < 2 || aAlignSize > 32768 || (aAlignSize & (aAlignSize - 1)) != 0) { return NS_ERROR_INVALID_ARG; } for (int i = 0; i < mHeaders.Count(); i++) { nsZipHeader *header = mHeaders[i]; // Check whether this entry is file and compression method is stored. bool isdir; rv = header->GetIsDirectory(&isdir); if (NS_FAILED(rv)) { return rv; } if (isdir || header->mMethod != 0) { continue; } // Pad extra field to align data starting position to specified size. uint32_t old_len = header->mLocalFieldLength; rv = header->PadExtraField(header->mOffset, aAlignSize); if (NS_FAILED(rv)) { continue; } // No padding means data already aligned. uint32_t shift = header->mLocalFieldLength - old_len; if (shift == 0) { continue; } // Flush any remaining data before we start. rv = mStream->Flush(); if (NS_FAILED(rv)) { return rv; } // Open zip file for reading. nsCOMPtr<nsIInputStream> inputStream; rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), mFile); if (NS_FAILED(rv)) { return rv; } nsCOMPtr<nsISeekableStream> in_seekable = do_QueryInterface(inputStream); nsCOMPtr<nsISeekableStream> out_seekable = do_QueryInterface(mStream); uint32_t data_offset = header->mOffset + header->GetFileHeaderLength() - shift; uint32_t count = mCDSOffset - data_offset; uint32_t read; char buf[4096]; // Shift data to aligned postion. while (count > 0) { read = std::min(count, (uint32_t) sizeof(buf)); rv = in_seekable->Seek(nsISeekableStream::NS_SEEK_SET, data_offset + count - read); if (NS_FAILED(rv)) { break; } rv = inputStream->Read(buf, read, &read); if (NS_FAILED(rv)) { break; } rv = out_seekable->Seek(nsISeekableStream::NS_SEEK_SET, data_offset + count - read + shift); if (NS_FAILED(rv)) { break; } rv = ZW_WriteData(mStream, buf, read); if (NS_FAILED(rv)) { break; } count -= read; } inputStream->Close(); if (NS_FAILED(rv)) { Cleanup(); return rv; } // Update current header rv = out_seekable->Seek(nsISeekableStream::NS_SEEK_SET, header->mOffset); if (NS_FAILED(rv)) { Cleanup(); return rv; } rv = header->WriteFileHeader(mStream); if (NS_FAILED(rv)) { Cleanup(); return rv; } // Update offset of all other headers int pos = i + 1; while (pos < mHeaders.Count()) { mHeaders[pos]->mOffset += shift; pos++; } mCDSOffset += shift; rv = SeekCDS(); if (NS_FAILED(rv)) { return rv; } mCDSDirty = true; } return NS_OK; }
NS_IMETHODIMP nsZipWriter::Close() { if (!mStream) return NS_ERROR_NOT_INITIALIZED; if (mInQueue) return NS_ERROR_IN_PROGRESS; if (mCDSDirty) { uint32_t size = 0; for (int32_t i = 0; i < mHeaders.Count(); i++) { nsresult rv = mHeaders[i]->WriteCDSHeader(mStream); if (NS_FAILED(rv)) { Cleanup(); return rv; } size += mHeaders[i]->GetCDSHeaderLength(); } uint8_t buf[ZIP_EOCDR_HEADER_SIZE]; uint32_t pos = 0; WRITE32(buf, &pos, ZIP_EOCDR_HEADER_SIGNATURE); WRITE16(buf, &pos, 0); WRITE16(buf, &pos, 0); WRITE16(buf, &pos, mHeaders.Count()); WRITE16(buf, &pos, mHeaders.Count()); WRITE32(buf, &pos, size); WRITE32(buf, &pos, mCDSOffset); WRITE16(buf, &pos, mComment.Length()); nsresult rv = ZW_WriteData(mStream, (const char *)buf, pos); if (NS_FAILED(rv)) { Cleanup(); return rv; } rv = ZW_WriteData(mStream, mComment.get(), mComment.Length()); if (NS_FAILED(rv)) { Cleanup(); return rv; } nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream); rv = seekable->SetEOF(); if (NS_FAILED(rv)) { Cleanup(); return rv; } // Go back and rewrite the file headers for (int32_t i = 0; i < mHeaders.Count(); i++) { nsZipHeader *header = mHeaders[i]; if (!header->mWriteOnClose) continue; rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, header->mOffset); if (NS_FAILED(rv)) { Cleanup(); return rv; } rv = header->WriteFileHeader(mStream); if (NS_FAILED(rv)) { Cleanup(); return rv; } } } nsresult rv = mStream->Close(); mStream = nullptr; mHeaders.Clear(); mEntryHash.Clear(); mQueue.Clear(); return rv; }
NS_IMETHODIMP nsZipWriter::RemoveEntry(const nsACString & aZipEntry, bool aQueue) { if (!mStream) return NS_ERROR_NOT_INITIALIZED; if (aQueue) { nsZipQueueItem item; item.mOperation = OPERATION_REMOVE; item.mZipEntry = aZipEntry; if (!mQueue.AppendElement(item)) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; } if (mInQueue) return NS_ERROR_IN_PROGRESS; int32_t pos; if (mEntryHash.Get(aZipEntry, &pos)) { // Flush any remaining data before we seek. nsresult rv = mStream->Flush(); NS_ENSURE_SUCCESS(rv, rv); if (pos < mHeaders.Count() - 1) { // This is not the last entry, pull back the data. nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream); rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, mHeaders[pos]->mOffset); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIInputStream> inputStream; rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), mFile); NS_ENSURE_SUCCESS(rv, rv); seekable = do_QueryInterface(inputStream); rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, mHeaders[pos + 1]->mOffset); if (NS_FAILED(rv)) { inputStream->Close(); return rv; } uint32_t count = mCDSOffset - mHeaders[pos + 1]->mOffset; uint32_t read = 0; char buf[4096]; while (count > 0) { read = std::min(count, (uint32_t) sizeof(buf)); rv = inputStream->Read(buf, read, &read); if (NS_FAILED(rv)) { inputStream->Close(); Cleanup(); return rv; } rv = ZW_WriteData(mStream, buf, read); if (NS_FAILED(rv)) { inputStream->Close(); Cleanup(); return rv; } count -= read; } inputStream->Close(); // Rewrite header offsets and update hash uint32_t shift = (mHeaders[pos + 1]->mOffset - mHeaders[pos]->mOffset); mCDSOffset -= shift; int32_t pos2 = pos + 1; while (pos2 < mHeaders.Count()) { mEntryHash.Put(mHeaders[pos2]->mName, pos2-1); mHeaders[pos2]->mOffset -= shift; pos2++; } } else { // Remove the last entry is just a case of moving the CDS mCDSOffset = mHeaders[pos]->mOffset; rv = SeekCDS(); NS_ENSURE_SUCCESS(rv, rv); } mEntryHash.Remove(mHeaders[pos]->mName); mHeaders.RemoveObjectAt(pos); mCDSDirty = true; return NS_OK; } return NS_ERROR_FILE_NOT_FOUND; }