mozglue/linker/Zip.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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 */

mercurial