dom/file/ArchiveZipEvent.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "ArchiveZipEvent.h"
michael@0 8 #include "ArchiveZipFile.h"
michael@0 9
michael@0 10 #include "nsContentUtils.h"
michael@0 11 #include "nsCExternalHandlerService.h"
michael@0 12
michael@0 13 using namespace mozilla::dom;
michael@0 14
michael@0 15 USING_FILE_NAMESPACE
michael@0 16
michael@0 17 #ifndef PATH_MAX
michael@0 18 # define PATH_MAX 65536 // The filename length is stored in 2 bytes
michael@0 19 #endif
michael@0 20
michael@0 21 ArchiveZipItem::ArchiveZipItem(const char* aFilename,
michael@0 22 const ZipCentral& aCentralStruct,
michael@0 23 const nsACString& aEncoding)
michael@0 24 : mFilename(aFilename),
michael@0 25 mCentralStruct(aCentralStruct),
michael@0 26 mEncoding(aEncoding)
michael@0 27 {
michael@0 28 MOZ_COUNT_CTOR(ArchiveZipItem);
michael@0 29 }
michael@0 30
michael@0 31 ArchiveZipItem::~ArchiveZipItem()
michael@0 32 {
michael@0 33 MOZ_COUNT_DTOR(ArchiveZipItem);
michael@0 34 }
michael@0 35
michael@0 36 nsresult
michael@0 37 ArchiveZipItem::ConvertFilename()
michael@0 38 {
michael@0 39 if (mEncoding.IsEmpty()) {
michael@0 40 return NS_ERROR_FAILURE;
michael@0 41 }
michael@0 42
michael@0 43 nsString filenameU;
michael@0 44 nsresult rv = nsContentUtils::ConvertStringFromEncoding(
michael@0 45 mEncoding,
michael@0 46 mFilename, filenameU);
michael@0 47 NS_ENSURE_SUCCESS(rv, rv);
michael@0 48
michael@0 49 if (filenameU.IsEmpty()) {
michael@0 50 return NS_ERROR_FAILURE;
michael@0 51 }
michael@0 52
michael@0 53 mFilenameU = filenameU;
michael@0 54 return NS_OK;
michael@0 55 }
michael@0 56
michael@0 57 nsresult
michael@0 58 ArchiveZipItem::GetFilename(nsString& aFilename)
michael@0 59 {
michael@0 60 if (mFilenameU.IsEmpty()) {
michael@0 61 // Maybe this string is UTF-8:
michael@0 62 if (IsUTF8(mFilename, false)) {
michael@0 63 mFilenameU = NS_ConvertUTF8toUTF16(mFilename);
michael@0 64 }
michael@0 65
michael@0 66 // Let's use the enconding value for the dictionary
michael@0 67 else {
michael@0 68 nsresult rv = ConvertFilename();
michael@0 69 NS_ENSURE_SUCCESS(rv, rv);
michael@0 70 }
michael@0 71 }
michael@0 72
michael@0 73 aFilename = mFilenameU;
michael@0 74 return NS_OK;
michael@0 75 }
michael@0 76
michael@0 77 // From zipItem to DOMFile:
michael@0 78 nsIDOMFile*
michael@0 79 ArchiveZipItem::File(ArchiveReader* aArchiveReader)
michael@0 80 {
michael@0 81 nsString filename;
michael@0 82
michael@0 83 if (NS_FAILED(GetFilename(filename))) {
michael@0 84 return nullptr;
michael@0 85 }
michael@0 86
michael@0 87 return new ArchiveZipFile(filename,
michael@0 88 NS_ConvertUTF8toUTF16(GetType()),
michael@0 89 StrToInt32(mCentralStruct.orglen),
michael@0 90 mCentralStruct,
michael@0 91 aArchiveReader);
michael@0 92 }
michael@0 93
michael@0 94 uint32_t
michael@0 95 ArchiveZipItem::StrToInt32(const uint8_t* aStr)
michael@0 96 {
michael@0 97 return (uint32_t)( (aStr [0] << 0) |
michael@0 98 (aStr [1] << 8) |
michael@0 99 (aStr [2] << 16) |
michael@0 100 (aStr [3] << 24) );
michael@0 101 }
michael@0 102
michael@0 103 uint16_t
michael@0 104 ArchiveZipItem::StrToInt16(const uint8_t* aStr)
michael@0 105 {
michael@0 106 return (uint16_t) ((aStr [0]) | (aStr [1] << 8));
michael@0 107 }
michael@0 108
michael@0 109 // ArchiveReaderZipEvent
michael@0 110
michael@0 111 ArchiveReaderZipEvent::ArchiveReaderZipEvent(ArchiveReader* aArchiveReader,
michael@0 112 const nsACString& aEncoding)
michael@0 113 : ArchiveReaderEvent(aArchiveReader),
michael@0 114 mEncoding(aEncoding)
michael@0 115 {
michael@0 116 }
michael@0 117
michael@0 118 // NOTE: this runs in a different thread!!
michael@0 119 nsresult
michael@0 120 ArchiveReaderZipEvent::Exec()
michael@0 121 {
michael@0 122 uint32_t centralOffset(0);
michael@0 123 nsresult rv;
michael@0 124
michael@0 125 nsCOMPtr<nsIInputStream> inputStream;
michael@0 126 rv = mArchiveReader->GetInputStream(getter_AddRefs(inputStream));
michael@0 127 if (NS_FAILED(rv) || !inputStream) {
michael@0 128 return RunShare(NS_ERROR_UNEXPECTED);
michael@0 129 }
michael@0 130
michael@0 131 // From the input stream to a seekable stream
michael@0 132 nsCOMPtr<nsISeekableStream> seekableStream;
michael@0 133 seekableStream = do_QueryInterface(inputStream);
michael@0 134 if (!seekableStream) {
michael@0 135 return RunShare(NS_ERROR_UNEXPECTED);
michael@0 136 }
michael@0 137
michael@0 138 uint64_t size;
michael@0 139 rv = mArchiveReader->GetSize(&size);
michael@0 140 if (NS_FAILED(rv)) {
michael@0 141 return RunShare(NS_ERROR_UNEXPECTED);
michael@0 142 }
michael@0 143
michael@0 144 // Reading backward.. looking for the ZipEnd signature
michael@0 145 for (uint64_t curr = size - ZIPEND_SIZE; curr > 4; --curr) {
michael@0 146 seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, curr);
michael@0 147
michael@0 148 uint8_t buffer[ZIPEND_SIZE];
michael@0 149 uint32_t ret;
michael@0 150
michael@0 151 rv = inputStream->Read((char*)buffer, sizeof(buffer), &ret);
michael@0 152 if (NS_FAILED(rv) || ret != sizeof(buffer)) {
michael@0 153 return RunShare(NS_ERROR_UNEXPECTED);
michael@0 154 }
michael@0 155
michael@0 156 // Here we are:
michael@0 157 if (ArchiveZipItem::StrToInt32(buffer) == ENDSIG) {
michael@0 158 centralOffset = ArchiveZipItem::StrToInt32(((ZipEnd*)buffer)->offset_central_dir);
michael@0 159 break;
michael@0 160 }
michael@0 161 }
michael@0 162
michael@0 163 // No central Offset
michael@0 164 if (!centralOffset || centralOffset >= size - ZIPEND_SIZE) {
michael@0 165 return RunShare(NS_ERROR_FAILURE);
michael@0 166 }
michael@0 167
michael@0 168 // Seek to the first central directory:
michael@0 169 seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, centralOffset);
michael@0 170
michael@0 171 // For each central directory:
michael@0 172 while (centralOffset <= size - ZIPCENTRAL_SIZE) {
michael@0 173 ZipCentral centralStruct;
michael@0 174 uint32_t ret;
michael@0 175
michael@0 176 rv = inputStream->Read((char*)&centralStruct, ZIPCENTRAL_SIZE, &ret);
michael@0 177 if (NS_FAILED(rv) || ret != ZIPCENTRAL_SIZE) {
michael@0 178 return RunShare(NS_ERROR_UNEXPECTED);
michael@0 179 }
michael@0 180
michael@0 181 uint16_t filenameLen = ArchiveZipItem::StrToInt16(centralStruct.filename_len);
michael@0 182 uint16_t extraLen = ArchiveZipItem::StrToInt16(centralStruct.extrafield_len);
michael@0 183 uint16_t commentLen = ArchiveZipItem::StrToInt16(centralStruct.commentfield_len);
michael@0 184
michael@0 185 // Point to the next item at the top of loop
michael@0 186 centralOffset += ZIPCENTRAL_SIZE + filenameLen + extraLen + commentLen;
michael@0 187 if (filenameLen == 0 || filenameLen >= PATH_MAX || centralOffset >= size) {
michael@0 188 return RunShare(NS_ERROR_FILE_CORRUPTED);
michael@0 189 }
michael@0 190
michael@0 191 // Read the name:
michael@0 192 nsAutoArrayPtr<char> filename(new char[filenameLen + 1]);
michael@0 193 rv = inputStream->Read(filename, filenameLen, &ret);
michael@0 194 if (NS_FAILED(rv) || ret != filenameLen) {
michael@0 195 return RunShare(NS_ERROR_UNEXPECTED);
michael@0 196 }
michael@0 197
michael@0 198 filename[filenameLen] = 0;
michael@0 199
michael@0 200 // We ignore the directories:
michael@0 201 if (filename[filenameLen - 1] != '/') {
michael@0 202 mFileList.AppendElement(new ArchiveZipItem(filename, centralStruct, mEncoding));
michael@0 203 }
michael@0 204
michael@0 205 // Ignore the rest
michael@0 206 seekableStream->Seek(nsISeekableStream::NS_SEEK_CUR, extraLen + commentLen);
michael@0 207 }
michael@0 208
michael@0 209 return RunShare(NS_OK);
michael@0 210 }

mercurial