mozglue/linker/Zip.h

changeset 0
6474c204b198
     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 */

mercurial