Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #ifndef Zip_h |
michael@0 | 6 | #define Zip_h |
michael@0 | 7 | |
michael@0 | 8 | #include <cstring> |
michael@0 | 9 | #include <stdint.h> |
michael@0 | 10 | #include <vector> |
michael@0 | 11 | #include <zlib.h> |
michael@0 | 12 | #include "Utils.h" |
michael@0 | 13 | #include "mozilla/RefPtr.h" |
michael@0 | 14 | |
michael@0 | 15 | /** |
michael@0 | 16 | * Forward declaration |
michael@0 | 17 | */ |
michael@0 | 18 | class ZipCollection; |
michael@0 | 19 | |
michael@0 | 20 | /** |
michael@0 | 21 | * Class to handle access to Zip archive streams. The Zip archive is mapped |
michael@0 | 22 | * in memory, and streams are direct references to that mapped memory. |
michael@0 | 23 | * Zip files are assumed to be correctly formed. No boundary checks are |
michael@0 | 24 | * performed, which means hand-crafted malicious Zip archives can make the |
michael@0 | 25 | * code fail in bad ways. However, since the only intended use is to load |
michael@0 | 26 | * libraries from Zip archives, there is no interest in making this code |
michael@0 | 27 | * safe, since the libraries could contain malicious code anyways. |
michael@0 | 28 | */ |
michael@0 | 29 | class Zip: public mozilla::AtomicRefCounted<Zip> |
michael@0 | 30 | { |
michael@0 | 31 | public: |
michael@0 | 32 | MOZ_DECLARE_REFCOUNTED_TYPENAME(Zip) |
michael@0 | 33 | /** |
michael@0 | 34 | * Create a Zip instance for the given file name. Returns nullptr in case |
michael@0 | 35 | * of failure. |
michael@0 | 36 | */ |
michael@0 | 37 | static mozilla::TemporaryRef<Zip> Create(const char *filename); |
michael@0 | 38 | |
michael@0 | 39 | /** |
michael@0 | 40 | * Create a Zip instance using the given buffer. |
michael@0 | 41 | */ |
michael@0 | 42 | static mozilla::TemporaryRef<Zip> Create(void *buffer, size_t size) { |
michael@0 | 43 | return Create(nullptr, buffer, size); |
michael@0 | 44 | } |
michael@0 | 45 | |
michael@0 | 46 | private: |
michael@0 | 47 | static mozilla::TemporaryRef<Zip> Create(const char *filename, |
michael@0 | 48 | void *buffer, size_t size); |
michael@0 | 49 | |
michael@0 | 50 | /** |
michael@0 | 51 | * Private constructor |
michael@0 | 52 | */ |
michael@0 | 53 | Zip(const char *filename, void *buffer, size_t size); |
michael@0 | 54 | |
michael@0 | 55 | public: |
michael@0 | 56 | /** |
michael@0 | 57 | * Destructor |
michael@0 | 58 | */ |
michael@0 | 59 | ~Zip(); |
michael@0 | 60 | |
michael@0 | 61 | /** |
michael@0 | 62 | * Class used to access Zip archive item streams |
michael@0 | 63 | */ |
michael@0 | 64 | class Stream |
michael@0 | 65 | { |
michael@0 | 66 | public: |
michael@0 | 67 | /** |
michael@0 | 68 | * Stream types |
michael@0 | 69 | */ |
michael@0 | 70 | enum Type { |
michael@0 | 71 | STORE = 0, |
michael@0 | 72 | DEFLATE = 8 |
michael@0 | 73 | }; |
michael@0 | 74 | |
michael@0 | 75 | /** |
michael@0 | 76 | * Constructor |
michael@0 | 77 | */ |
michael@0 | 78 | Stream(): compressedBuf(nullptr), compressedSize(0), uncompressedSize(0) |
michael@0 | 79 | , type(STORE) { } |
michael@0 | 80 | |
michael@0 | 81 | /** |
michael@0 | 82 | * Getters |
michael@0 | 83 | */ |
michael@0 | 84 | const void *GetBuffer() { return compressedBuf; } |
michael@0 | 85 | size_t GetSize() { return compressedSize; } |
michael@0 | 86 | size_t GetUncompressedSize() { return uncompressedSize; } |
michael@0 | 87 | Type GetType() { return type; } |
michael@0 | 88 | |
michael@0 | 89 | /** |
michael@0 | 90 | * Returns a z_stream for use with inflate functions using the given |
michael@0 | 91 | * buffer as inflate output. The caller is expected to allocate enough |
michael@0 | 92 | * memory for the Stream uncompressed size. |
michael@0 | 93 | */ |
michael@0 | 94 | z_stream GetZStream(void *buf) |
michael@0 | 95 | { |
michael@0 | 96 | z_stream zStream; |
michael@0 | 97 | memset(&zStream, 0, sizeof(zStream)); |
michael@0 | 98 | zStream.avail_in = compressedSize; |
michael@0 | 99 | zStream.next_in = reinterpret_cast<Bytef *>( |
michael@0 | 100 | const_cast<void *>(compressedBuf)); |
michael@0 | 101 | zStream.avail_out = uncompressedSize; |
michael@0 | 102 | zStream.next_out = static_cast<Bytef *>(buf); |
michael@0 | 103 | return zStream; |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | protected: |
michael@0 | 107 | friend class Zip; |
michael@0 | 108 | const void *compressedBuf; |
michael@0 | 109 | size_t compressedSize; |
michael@0 | 110 | size_t uncompressedSize; |
michael@0 | 111 | Type type; |
michael@0 | 112 | }; |
michael@0 | 113 | |
michael@0 | 114 | /** |
michael@0 | 115 | * Returns a stream from the Zip archive. |
michael@0 | 116 | */ |
michael@0 | 117 | bool GetStream(const char *path, Stream *out) const; |
michael@0 | 118 | |
michael@0 | 119 | /** |
michael@0 | 120 | * Returns the file name of the archive |
michael@0 | 121 | */ |
michael@0 | 122 | const char *GetName() const |
michael@0 | 123 | { |
michael@0 | 124 | return name; |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | private: |
michael@0 | 128 | /* File name of the archive */ |
michael@0 | 129 | char *name; |
michael@0 | 130 | /* Address where the Zip archive is mapped */ |
michael@0 | 131 | void *mapped; |
michael@0 | 132 | /* Size of the archive */ |
michael@0 | 133 | size_t size; |
michael@0 | 134 | |
michael@0 | 135 | /** |
michael@0 | 136 | * Strings (file names, comments, etc.) in the Zip headers are NOT zero |
michael@0 | 137 | * terminated. This class is a helper around them. |
michael@0 | 138 | */ |
michael@0 | 139 | class StringBuf |
michael@0 | 140 | { |
michael@0 | 141 | public: |
michael@0 | 142 | /** |
michael@0 | 143 | * Constructor |
michael@0 | 144 | */ |
michael@0 | 145 | StringBuf(const char *buf, size_t length): buf(buf), length(length) { } |
michael@0 | 146 | |
michael@0 | 147 | /** |
michael@0 | 148 | * Returns whether the string has the same content as the given zero |
michael@0 | 149 | * terminated string. |
michael@0 | 150 | */ |
michael@0 | 151 | bool Equals(const char *str) const |
michael@0 | 152 | { |
michael@0 | 153 | return strncmp(str, buf, length) == 0; |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | private: |
michael@0 | 157 | const char *buf; |
michael@0 | 158 | size_t length; |
michael@0 | 159 | }; |
michael@0 | 160 | |
michael@0 | 161 | /* All the following types need to be packed */ |
michael@0 | 162 | #pragma pack(1) |
michael@0 | 163 | public: |
michael@0 | 164 | /** |
michael@0 | 165 | * A Zip archive is an aggregate of entities which all start with a |
michael@0 | 166 | * signature giving their type. This template is to be used as a base |
michael@0 | 167 | * class for these entities. |
michael@0 | 168 | */ |
michael@0 | 169 | template <typename T> |
michael@0 | 170 | class SignedEntity |
michael@0 | 171 | { |
michael@0 | 172 | public: |
michael@0 | 173 | /** |
michael@0 | 174 | * Equivalent to reinterpret_cast<const T *>(buf), with an additional |
michael@0 | 175 | * check of the signature. |
michael@0 | 176 | */ |
michael@0 | 177 | static const T *validate(const void *buf) |
michael@0 | 178 | { |
michael@0 | 179 | const T *ret = static_cast<const T *>(buf); |
michael@0 | 180 | if (ret->signature == T::magic) |
michael@0 | 181 | return ret; |
michael@0 | 182 | return nullptr; |
michael@0 | 183 | } |
michael@0 | 184 | |
michael@0 | 185 | SignedEntity(uint32_t magic): signature(magic) { } |
michael@0 | 186 | private: |
michael@0 | 187 | le_uint32 signature; |
michael@0 | 188 | }; |
michael@0 | 189 | |
michael@0 | 190 | private: |
michael@0 | 191 | /** |
michael@0 | 192 | * Header used to describe a Local File entry. The header is followed by |
michael@0 | 193 | * the file name and an extra field, then by the data stream. |
michael@0 | 194 | */ |
michael@0 | 195 | struct LocalFile: public SignedEntity<LocalFile> |
michael@0 | 196 | { |
michael@0 | 197 | /* Signature for a Local File header */ |
michael@0 | 198 | static const uint32_t magic = 0x04034b50; |
michael@0 | 199 | |
michael@0 | 200 | /** |
michael@0 | 201 | * Returns the file name |
michael@0 | 202 | */ |
michael@0 | 203 | StringBuf GetName() const |
michael@0 | 204 | { |
michael@0 | 205 | return StringBuf(reinterpret_cast<const char *>(this) + sizeof(*this), |
michael@0 | 206 | filenameSize); |
michael@0 | 207 | } |
michael@0 | 208 | |
michael@0 | 209 | /** |
michael@0 | 210 | * Returns a pointer to the data associated with this header |
michael@0 | 211 | */ |
michael@0 | 212 | const void *GetData() const |
michael@0 | 213 | { |
michael@0 | 214 | return reinterpret_cast<const char *>(this) + sizeof(*this) |
michael@0 | 215 | + filenameSize + extraFieldSize; |
michael@0 | 216 | } |
michael@0 | 217 | |
michael@0 | 218 | le_uint16 minVersion; |
michael@0 | 219 | le_uint16 generalFlag; |
michael@0 | 220 | le_uint16 compression; |
michael@0 | 221 | le_uint16 lastModifiedTime; |
michael@0 | 222 | le_uint16 lastModifiedDate; |
michael@0 | 223 | le_uint32 CRC32; |
michael@0 | 224 | le_uint32 compressedSize; |
michael@0 | 225 | le_uint32 uncompressedSize; |
michael@0 | 226 | le_uint16 filenameSize; |
michael@0 | 227 | le_uint16 extraFieldSize; |
michael@0 | 228 | }; |
michael@0 | 229 | |
michael@0 | 230 | /** |
michael@0 | 231 | * In some cases, when a zip archive is created, compressed size and CRC |
michael@0 | 232 | * are not known when writing the Local File header. In these cases, the |
michael@0 | 233 | * 3rd bit of the general flag in the Local File header is set, and there |
michael@0 | 234 | * is an additional header following the compressed data. |
michael@0 | 235 | */ |
michael@0 | 236 | struct DataDescriptor: public SignedEntity<DataDescriptor> |
michael@0 | 237 | { |
michael@0 | 238 | /* Signature for a Data Descriptor header */ |
michael@0 | 239 | static const uint32_t magic = 0x08074b50; |
michael@0 | 240 | |
michael@0 | 241 | le_uint32 CRC32; |
michael@0 | 242 | le_uint32 compressedSize; |
michael@0 | 243 | le_uint32 uncompressedSize; |
michael@0 | 244 | }; |
michael@0 | 245 | |
michael@0 | 246 | /** |
michael@0 | 247 | * Header used to describe a Central Directory Entry. The header is |
michael@0 | 248 | * followed by the file name, an extra field, and a comment. |
michael@0 | 249 | */ |
michael@0 | 250 | struct DirectoryEntry: public SignedEntity<DirectoryEntry> |
michael@0 | 251 | { |
michael@0 | 252 | /* Signature for a Central Directory Entry header */ |
michael@0 | 253 | static const uint32_t magic = 0x02014b50; |
michael@0 | 254 | |
michael@0 | 255 | /** |
michael@0 | 256 | * Returns the file name |
michael@0 | 257 | */ |
michael@0 | 258 | StringBuf GetName() const |
michael@0 | 259 | { |
michael@0 | 260 | return StringBuf(reinterpret_cast<const char *>(this) + sizeof(*this), |
michael@0 | 261 | filenameSize); |
michael@0 | 262 | } |
michael@0 | 263 | |
michael@0 | 264 | /** |
michael@0 | 265 | * Returns the Central Directory Entry following this one. |
michael@0 | 266 | */ |
michael@0 | 267 | const DirectoryEntry *GetNext() const |
michael@0 | 268 | { |
michael@0 | 269 | return validate(reinterpret_cast<const char *>(this) + sizeof(*this) |
michael@0 | 270 | + filenameSize + extraFieldSize + fileCommentSize); |
michael@0 | 271 | } |
michael@0 | 272 | |
michael@0 | 273 | le_uint16 creatorVersion; |
michael@0 | 274 | le_uint16 minVersion; |
michael@0 | 275 | le_uint16 generalFlag; |
michael@0 | 276 | le_uint16 compression; |
michael@0 | 277 | le_uint16 lastModifiedTime; |
michael@0 | 278 | le_uint16 lastModifiedDate; |
michael@0 | 279 | le_uint32 CRC32; |
michael@0 | 280 | le_uint32 compressedSize; |
michael@0 | 281 | le_uint32 uncompressedSize; |
michael@0 | 282 | le_uint16 filenameSize; |
michael@0 | 283 | le_uint16 extraFieldSize; |
michael@0 | 284 | le_uint16 fileCommentSize; |
michael@0 | 285 | le_uint16 diskNum; |
michael@0 | 286 | le_uint16 internalAttributes; |
michael@0 | 287 | le_uint32 externalAttributes; |
michael@0 | 288 | le_uint32 offset; |
michael@0 | 289 | }; |
michael@0 | 290 | |
michael@0 | 291 | /** |
michael@0 | 292 | * Header used to describe the End of Central Directory Record. |
michael@0 | 293 | */ |
michael@0 | 294 | struct CentralDirectoryEnd: public SignedEntity<CentralDirectoryEnd> |
michael@0 | 295 | { |
michael@0 | 296 | /* Signature for the End of Central Directory Record */ |
michael@0 | 297 | static const uint32_t magic = 0x06054b50; |
michael@0 | 298 | |
michael@0 | 299 | le_uint16 diskNum; |
michael@0 | 300 | le_uint16 startDisk; |
michael@0 | 301 | le_uint16 recordsOnDisk; |
michael@0 | 302 | le_uint16 records; |
michael@0 | 303 | le_uint32 size; |
michael@0 | 304 | le_uint32 offset; |
michael@0 | 305 | le_uint16 commentSize; |
michael@0 | 306 | }; |
michael@0 | 307 | #pragma pack() |
michael@0 | 308 | |
michael@0 | 309 | /** |
michael@0 | 310 | * Returns the first Directory entry |
michael@0 | 311 | */ |
michael@0 | 312 | const DirectoryEntry *GetFirstEntry() const; |
michael@0 | 313 | |
michael@0 | 314 | /* Pointer to the Local File Entry following the last one GetStream() used. |
michael@0 | 315 | * This is used by GetStream to avoid scanning the Directory Entries when the |
michael@0 | 316 | * requested entry is that one. */ |
michael@0 | 317 | mutable const LocalFile *nextFile; |
michael@0 | 318 | |
michael@0 | 319 | /* Likewise for the next Directory entry */ |
michael@0 | 320 | mutable const DirectoryEntry *nextDir; |
michael@0 | 321 | |
michael@0 | 322 | /* Pointer to the Directory entries */ |
michael@0 | 323 | mutable const DirectoryEntry *entries; |
michael@0 | 324 | }; |
michael@0 | 325 | |
michael@0 | 326 | /** |
michael@0 | 327 | * Class for bookkeeping Zip instances |
michael@0 | 328 | */ |
michael@0 | 329 | class ZipCollection |
michael@0 | 330 | { |
michael@0 | 331 | public: |
michael@0 | 332 | static ZipCollection Singleton; |
michael@0 | 333 | |
michael@0 | 334 | /** |
michael@0 | 335 | * Get a Zip instance for the given path. If there is an existing one |
michael@0 | 336 | * already, return that one, otherwise create a new one. |
michael@0 | 337 | */ |
michael@0 | 338 | static mozilla::TemporaryRef<Zip> GetZip(const char *path); |
michael@0 | 339 | |
michael@0 | 340 | protected: |
michael@0 | 341 | friend class Zip; |
michael@0 | 342 | /** |
michael@0 | 343 | * Register the given Zip instance. This method is meant to be called |
michael@0 | 344 | * by Zip::Create. |
michael@0 | 345 | */ |
michael@0 | 346 | static void Register(Zip *zip); |
michael@0 | 347 | |
michael@0 | 348 | /** |
michael@0 | 349 | * Forget about the given Zip instance. This method is meant to be called |
michael@0 | 350 | * by the Zip destructor. |
michael@0 | 351 | */ |
michael@0 | 352 | static void Forget(Zip *zip); |
michael@0 | 353 | |
michael@0 | 354 | private: |
michael@0 | 355 | /* Zip instances bookkept in this collection */ |
michael@0 | 356 | std::vector<Zip *> zips; |
michael@0 | 357 | }; |
michael@0 | 358 | |
michael@0 | 359 | #endif /* Zip_h */ |