1 /* 2 * The Doomsday Engine Project -- libcore 3 * 4 * Copyright © 2004-2017 Jaakko Keränen <jaakko.keranen@iki.fi> 5 * 6 * @par License 7 * LGPL: http://www.gnu.org/licenses/lgpl.html 8 * 9 * <small>This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU Lesser General Public License as published by 11 * the Free Software Foundation; either version 3 of the License, or (at your 12 * option) any later version. This program is distributed in the hope that it 13 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 15 * General Public License for more details. You should have received a copy of 16 * the GNU Lesser General Public License along with this program; if not, see: 17 * http://www.gnu.org/licenses</small> 18 */ 19 20 #ifndef LIBDENG2_ZIPARCHIVE_H 21 #define LIBDENG2_ZIPARCHIVE_H 22 23 #include "../Archive" 24 #include "../NativePath" 25 #include "../filesys/IInterpreter" 26 27 namespace de { 28 29 /** 30 * Archive whose serialization uses the ZIP file format. 31 * @ingroup data 32 * 33 * All the features of the ZIP format are not supported: 34 * - Deflate is the only supported compression method. 35 * - Multipart ZIP files are not supported. 36 * 37 * @see http://en.wikipedia.org/wiki/Zip_(file_format) 38 */ 39 class DENG2_PUBLIC ZipArchive : public Archive 40 { 41 public: 42 /// The central directory of the ZIP archive cannot be located. Maybe it's not 43 /// a ZIP archive after all? @ingroup errors 44 DENG2_SUB_ERROR(FormatError, MissingCentralDirectoryError); 45 46 /// The source archive belongs to a multipart archive. @ingroup errors 47 DENG2_SUB_ERROR(FormatError, MultiPartError); 48 49 /// An entry in the archive uses a compression algorithm not supported by the 50 /// implementation. @ingroup errors 51 DENG2_SUB_ERROR(FormatError, UnknownCompressionError); 52 53 /// An entry is encrypted. Decrypting is not supported. @ingroup errors 54 DENG2_SUB_ERROR(FormatError, EncryptionError); 55 56 /// There is an error during decompression. @ingroup errors 57 DENG2_SUB_ERROR(ContentError, InflateError); 58 59 /// There is an error during compression. @ingroup errors 60 DENG2_SUB_ERROR(ContentError, DeflateError); 61 62 public: 63 /** 64 * Constructs an empty ZIP archive. 65 */ 66 ZipArchive(); 67 68 /** 69 * Constructs a new ZIP archive instance. The content index contained 70 * in @a data is read during construction. 71 * 72 * @param data Data of the source archive. No copy of the 73 * data is made, so the caller must make sure the 74 * byte array remains in existence for the lifetime 75 * of the Archive instance. 76 * @param dirCacheId ID of cached ZIP directory data. 77 */ 78 ZipArchive(IByteArray const &data, Block const &dirCacheId = Block()); 79 80 void operator >> (Writer &to) const; 81 82 public: 83 /** 84 * Determines whether a File looks like it could be accessed using ZipArchive. 85 * 86 * @param file File to check. 87 * 88 * @return @c true, if the file looks like an archive. 89 */ 90 static bool recognize(File const &file); 91 92 /** 93 * Determines whether a native file looks like it could be in ZIP format. 94 * 95 * @param path Native path of the file to check. 96 * 97 * @return @c true, if the file looks like an archive. 98 */ 99 static bool recognize(NativePath const &path); 100 101 struct DENG2_PUBLIC Interpreter : public filesys::IInterpreter { 102 File *interpretFile(File *sourceData) const override; 103 }; 104 105 protected: 106 void readFromSource(Entry const &entry, Path const &path, IBlock &uncompressedData) const; 107 108 struct ZipEntry : public Entry 109 { 110 duint16 compression; ///< Type of compression employed by the entry. 111 duint32 crc32; ///< CRC32 checksum. 112 dsize localHeaderOffset; ///< Offset of the local file header. 113 ZipEntryZipEntry114 ZipEntry(PathTree::NodeArgs const &args) : Entry(args), 115 compression(0), crc32(0), localHeaderOffset(0) {} 116 117 /// Recalculates CRC32 of the entry. 118 void update(); 119 }; 120 121 typedef PathTreeT<ZipEntry> Index; 122 123 Index const &index() const; 124 125 private: 126 DENG2_PRIVATE(d) 127 }; 128 129 } // namespace de 130 131 #endif // LIBDENG2_ZIPARCHIVE_H 132