1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mozglue/linker/Zip.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,359 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifndef Zip_h 1.9 +#define Zip_h 1.10 + 1.11 +#include <cstring> 1.12 +#include <stdint.h> 1.13 +#include <vector> 1.14 +#include <zlib.h> 1.15 +#include "Utils.h" 1.16 +#include "mozilla/RefPtr.h" 1.17 + 1.18 +/** 1.19 + * Forward declaration 1.20 + */ 1.21 +class ZipCollection; 1.22 + 1.23 +/** 1.24 + * Class to handle access to Zip archive streams. The Zip archive is mapped 1.25 + * in memory, and streams are direct references to that mapped memory. 1.26 + * Zip files are assumed to be correctly formed. No boundary checks are 1.27 + * performed, which means hand-crafted malicious Zip archives can make the 1.28 + * code fail in bad ways. However, since the only intended use is to load 1.29 + * libraries from Zip archives, there is no interest in making this code 1.30 + * safe, since the libraries could contain malicious code anyways. 1.31 + */ 1.32 +class Zip: public mozilla::AtomicRefCounted<Zip> 1.33 +{ 1.34 +public: 1.35 + MOZ_DECLARE_REFCOUNTED_TYPENAME(Zip) 1.36 + /** 1.37 + * Create a Zip instance for the given file name. Returns nullptr in case 1.38 + * of failure. 1.39 + */ 1.40 + static mozilla::TemporaryRef<Zip> Create(const char *filename); 1.41 + 1.42 + /** 1.43 + * Create a Zip instance using the given buffer. 1.44 + */ 1.45 + static mozilla::TemporaryRef<Zip> Create(void *buffer, size_t size) { 1.46 + return Create(nullptr, buffer, size); 1.47 + } 1.48 + 1.49 +private: 1.50 + static mozilla::TemporaryRef<Zip> Create(const char *filename, 1.51 + void *buffer, size_t size); 1.52 + 1.53 + /** 1.54 + * Private constructor 1.55 + */ 1.56 + Zip(const char *filename, void *buffer, size_t size); 1.57 + 1.58 +public: 1.59 + /** 1.60 + * Destructor 1.61 + */ 1.62 + ~Zip(); 1.63 + 1.64 + /** 1.65 + * Class used to access Zip archive item streams 1.66 + */ 1.67 + class Stream 1.68 + { 1.69 + public: 1.70 + /** 1.71 + * Stream types 1.72 + */ 1.73 + enum Type { 1.74 + STORE = 0, 1.75 + DEFLATE = 8 1.76 + }; 1.77 + 1.78 + /** 1.79 + * Constructor 1.80 + */ 1.81 + Stream(): compressedBuf(nullptr), compressedSize(0), uncompressedSize(0) 1.82 + , type(STORE) { } 1.83 + 1.84 + /** 1.85 + * Getters 1.86 + */ 1.87 + const void *GetBuffer() { return compressedBuf; } 1.88 + size_t GetSize() { return compressedSize; } 1.89 + size_t GetUncompressedSize() { return uncompressedSize; } 1.90 + Type GetType() { return type; } 1.91 + 1.92 + /** 1.93 + * Returns a z_stream for use with inflate functions using the given 1.94 + * buffer as inflate output. The caller is expected to allocate enough 1.95 + * memory for the Stream uncompressed size. 1.96 + */ 1.97 + z_stream GetZStream(void *buf) 1.98 + { 1.99 + z_stream zStream; 1.100 + memset(&zStream, 0, sizeof(zStream)); 1.101 + zStream.avail_in = compressedSize; 1.102 + zStream.next_in = reinterpret_cast<Bytef *>( 1.103 + const_cast<void *>(compressedBuf)); 1.104 + zStream.avail_out = uncompressedSize; 1.105 + zStream.next_out = static_cast<Bytef *>(buf); 1.106 + return zStream; 1.107 + } 1.108 + 1.109 + protected: 1.110 + friend class Zip; 1.111 + const void *compressedBuf; 1.112 + size_t compressedSize; 1.113 + size_t uncompressedSize; 1.114 + Type type; 1.115 + }; 1.116 + 1.117 + /** 1.118 + * Returns a stream from the Zip archive. 1.119 + */ 1.120 + bool GetStream(const char *path, Stream *out) const; 1.121 + 1.122 + /** 1.123 + * Returns the file name of the archive 1.124 + */ 1.125 + const char *GetName() const 1.126 + { 1.127 + return name; 1.128 + } 1.129 + 1.130 +private: 1.131 + /* File name of the archive */ 1.132 + char *name; 1.133 + /* Address where the Zip archive is mapped */ 1.134 + void *mapped; 1.135 + /* Size of the archive */ 1.136 + size_t size; 1.137 + 1.138 + /** 1.139 + * Strings (file names, comments, etc.) in the Zip headers are NOT zero 1.140 + * terminated. This class is a helper around them. 1.141 + */ 1.142 + class StringBuf 1.143 + { 1.144 + public: 1.145 + /** 1.146 + * Constructor 1.147 + */ 1.148 + StringBuf(const char *buf, size_t length): buf(buf), length(length) { } 1.149 + 1.150 + /** 1.151 + * Returns whether the string has the same content as the given zero 1.152 + * terminated string. 1.153 + */ 1.154 + bool Equals(const char *str) const 1.155 + { 1.156 + return strncmp(str, buf, length) == 0; 1.157 + } 1.158 + 1.159 + private: 1.160 + const char *buf; 1.161 + size_t length; 1.162 + }; 1.163 + 1.164 +/* All the following types need to be packed */ 1.165 +#pragma pack(1) 1.166 +public: 1.167 + /** 1.168 + * A Zip archive is an aggregate of entities which all start with a 1.169 + * signature giving their type. This template is to be used as a base 1.170 + * class for these entities. 1.171 + */ 1.172 + template <typename T> 1.173 + class SignedEntity 1.174 + { 1.175 + public: 1.176 + /** 1.177 + * Equivalent to reinterpret_cast<const T *>(buf), with an additional 1.178 + * check of the signature. 1.179 + */ 1.180 + static const T *validate(const void *buf) 1.181 + { 1.182 + const T *ret = static_cast<const T *>(buf); 1.183 + if (ret->signature == T::magic) 1.184 + return ret; 1.185 + return nullptr; 1.186 + } 1.187 + 1.188 + SignedEntity(uint32_t magic): signature(magic) { } 1.189 + private: 1.190 + le_uint32 signature; 1.191 + }; 1.192 + 1.193 +private: 1.194 + /** 1.195 + * Header used to describe a Local File entry. The header is followed by 1.196 + * the file name and an extra field, then by the data stream. 1.197 + */ 1.198 + struct LocalFile: public SignedEntity<LocalFile> 1.199 + { 1.200 + /* Signature for a Local File header */ 1.201 + static const uint32_t magic = 0x04034b50; 1.202 + 1.203 + /** 1.204 + * Returns the file name 1.205 + */ 1.206 + StringBuf GetName() const 1.207 + { 1.208 + return StringBuf(reinterpret_cast<const char *>(this) + sizeof(*this), 1.209 + filenameSize); 1.210 + } 1.211 + 1.212 + /** 1.213 + * Returns a pointer to the data associated with this header 1.214 + */ 1.215 + const void *GetData() const 1.216 + { 1.217 + return reinterpret_cast<const char *>(this) + sizeof(*this) 1.218 + + filenameSize + extraFieldSize; 1.219 + } 1.220 + 1.221 + le_uint16 minVersion; 1.222 + le_uint16 generalFlag; 1.223 + le_uint16 compression; 1.224 + le_uint16 lastModifiedTime; 1.225 + le_uint16 lastModifiedDate; 1.226 + le_uint32 CRC32; 1.227 + le_uint32 compressedSize; 1.228 + le_uint32 uncompressedSize; 1.229 + le_uint16 filenameSize; 1.230 + le_uint16 extraFieldSize; 1.231 + }; 1.232 + 1.233 + /** 1.234 + * In some cases, when a zip archive is created, compressed size and CRC 1.235 + * are not known when writing the Local File header. In these cases, the 1.236 + * 3rd bit of the general flag in the Local File header is set, and there 1.237 + * is an additional header following the compressed data. 1.238 + */ 1.239 + struct DataDescriptor: public SignedEntity<DataDescriptor> 1.240 + { 1.241 + /* Signature for a Data Descriptor header */ 1.242 + static const uint32_t magic = 0x08074b50; 1.243 + 1.244 + le_uint32 CRC32; 1.245 + le_uint32 compressedSize; 1.246 + le_uint32 uncompressedSize; 1.247 + }; 1.248 + 1.249 + /** 1.250 + * Header used to describe a Central Directory Entry. The header is 1.251 + * followed by the file name, an extra field, and a comment. 1.252 + */ 1.253 + struct DirectoryEntry: public SignedEntity<DirectoryEntry> 1.254 + { 1.255 + /* Signature for a Central Directory Entry header */ 1.256 + static const uint32_t magic = 0x02014b50; 1.257 + 1.258 + /** 1.259 + * Returns the file name 1.260 + */ 1.261 + StringBuf GetName() const 1.262 + { 1.263 + return StringBuf(reinterpret_cast<const char *>(this) + sizeof(*this), 1.264 + filenameSize); 1.265 + } 1.266 + 1.267 + /** 1.268 + * Returns the Central Directory Entry following this one. 1.269 + */ 1.270 + const DirectoryEntry *GetNext() const 1.271 + { 1.272 + return validate(reinterpret_cast<const char *>(this) + sizeof(*this) 1.273 + + filenameSize + extraFieldSize + fileCommentSize); 1.274 + } 1.275 + 1.276 + le_uint16 creatorVersion; 1.277 + le_uint16 minVersion; 1.278 + le_uint16 generalFlag; 1.279 + le_uint16 compression; 1.280 + le_uint16 lastModifiedTime; 1.281 + le_uint16 lastModifiedDate; 1.282 + le_uint32 CRC32; 1.283 + le_uint32 compressedSize; 1.284 + le_uint32 uncompressedSize; 1.285 + le_uint16 filenameSize; 1.286 + le_uint16 extraFieldSize; 1.287 + le_uint16 fileCommentSize; 1.288 + le_uint16 diskNum; 1.289 + le_uint16 internalAttributes; 1.290 + le_uint32 externalAttributes; 1.291 + le_uint32 offset; 1.292 + }; 1.293 + 1.294 + /** 1.295 + * Header used to describe the End of Central Directory Record. 1.296 + */ 1.297 + struct CentralDirectoryEnd: public SignedEntity<CentralDirectoryEnd> 1.298 + { 1.299 + /* Signature for the End of Central Directory Record */ 1.300 + static const uint32_t magic = 0x06054b50; 1.301 + 1.302 + le_uint16 diskNum; 1.303 + le_uint16 startDisk; 1.304 + le_uint16 recordsOnDisk; 1.305 + le_uint16 records; 1.306 + le_uint32 size; 1.307 + le_uint32 offset; 1.308 + le_uint16 commentSize; 1.309 + }; 1.310 +#pragma pack() 1.311 + 1.312 + /** 1.313 + * Returns the first Directory entry 1.314 + */ 1.315 + const DirectoryEntry *GetFirstEntry() const; 1.316 + 1.317 + /* Pointer to the Local File Entry following the last one GetStream() used. 1.318 + * This is used by GetStream to avoid scanning the Directory Entries when the 1.319 + * requested entry is that one. */ 1.320 + mutable const LocalFile *nextFile; 1.321 + 1.322 + /* Likewise for the next Directory entry */ 1.323 + mutable const DirectoryEntry *nextDir; 1.324 + 1.325 + /* Pointer to the Directory entries */ 1.326 + mutable const DirectoryEntry *entries; 1.327 +}; 1.328 + 1.329 +/** 1.330 + * Class for bookkeeping Zip instances 1.331 + */ 1.332 +class ZipCollection 1.333 +{ 1.334 +public: 1.335 + static ZipCollection Singleton; 1.336 + 1.337 + /** 1.338 + * Get a Zip instance for the given path. If there is an existing one 1.339 + * already, return that one, otherwise create a new one. 1.340 + */ 1.341 + static mozilla::TemporaryRef<Zip> GetZip(const char *path); 1.342 + 1.343 +protected: 1.344 + friend class Zip; 1.345 + /** 1.346 + * Register the given Zip instance. This method is meant to be called 1.347 + * by Zip::Create. 1.348 + */ 1.349 + static void Register(Zip *zip); 1.350 + 1.351 + /** 1.352 + * Forget about the given Zip instance. This method is meant to be called 1.353 + * by the Zip destructor. 1.354 + */ 1.355 + static void Forget(Zip *zip); 1.356 + 1.357 +private: 1.358 + /* Zip instances bookkept in this collection */ 1.359 + std::vector<Zip *> zips; 1.360 +}; 1.361 + 1.362 +#endif /* Zip_h */