1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#ifndef OHOS_ABILITY_BASE_ZIP_FILE_H 17#define OHOS_ABILITY_BASE_ZIP_FILE_H 18 19#include <memory> 20#include <set> 21#include <string> 22#include <unordered_map> 23#include <vector> 24 25#include "file_mapper.h" 26#include <contrib/minizip/unzip.h> 27 28namespace panda { 29namespace ecmascript { 30class ZipFileReader; 31struct CentralDirEntry; 32struct ZipEntry; 33using ZipPos = ZPOS64_T; 34using ZipEntryMap = std::unordered_map<std::string, ZipEntry>; 35using BytePtr = Byte *; 36 37// Local file header: descript in APPNOTE-6.3.4 38// local file header signature 4 bytes (0x04034b50) 39// version needed to extract 2 bytes 40// general purpose bit flag 2 bytes 41// compression method 2 bytes 10 42// last mod file time 2 bytes 43// last mod file date 2 bytes 44// crc-32 4 bytes 45// compressed size 4 bytes 22 46// uncompressed size 4 bytes 47// file name length 2 bytes 48// extra field length 2 bytes 30 49struct __attribute__((packed)) LocalHeader { 50 uint32_t signature = 0; 51 uint16_t versionNeeded = 0; 52 uint16_t flags = 0; 53 uint16_t compressionMethod = 0; 54 uint16_t modifiedTime = 0; 55 uint16_t modifiedDate = 0; 56 uint32_t crc = 0; 57 uint32_t compressedSize = 0; 58 uint32_t uncompressedSize = 0; 59 uint16_t nameSize = 0; 60 uint16_t extraSize = 0; 61}; 62 63// central file header 64// Central File header: 65// central file header signature 4 bytes (0x02014b50) 66// version made by 2 bytes 67// version needed to extract 2 bytes 68// general purpose bit flag 2 bytes 10 69// compression method 2 bytes 70// last mod file time 2 bytes 71// last mod file date 2 bytes 72// crc-32 4 bytes 20 73// compressed size 4 bytes 74// uncompressed size 4 bytes 75// file name length 2 bytes 30 76// extra field length 2 bytes 77// file comment length 2 bytes 78// disk number start 2 bytes 79// internal file attributes 2 bytes 80// external file attributes 4 bytes 81// relative offset of local header 4 bytes 46byte 82struct __attribute__((packed)) CentralDirEntry { 83 uint32_t signature = 0; 84 uint16_t versionMade = 0; 85 uint16_t versionNeeded = 0; 86 uint16_t flags = 0; // general purpose bit flag 87 uint16_t compressionMethod = 0; 88 uint16_t modifiedTime = 0; 89 uint16_t modifiedDate = 0; 90 uint32_t crc = 0; 91 uint32_t compressedSize = 0; 92 uint32_t uncompressedSize = 0; 93 uint16_t nameSize = 0; 94 uint16_t extraSize = 0; 95 uint16_t commentSize = 0; 96 uint16_t diskNumStart = 0; 97 uint16_t internalAttr = 0; 98 uint32_t externalAttr = 0; 99 uint32_t localHeaderOffset = 0; 100}; 101 102// end of central directory packed structure 103// end of central dir signature 4 bytes (0x06054b50) 104// number of this disk 2 bytes 105// number of the disk with the 106// start of the central directory 2 bytes 107// total number of entries in the 108// central directory on this disk 2 bytes 109// total number of entries in 110// the central directory 2 bytes 111// size of the central directory 4 bytes 112// offset of start of central 113// directory with respect to 114// the starting disk number 4 bytes 115// .ZIP file comment length 2 bytes 116struct __attribute__((packed)) EndDir { 117 uint32_t signature = 0; 118 uint16_t numDisk = 0; 119 uint16_t startDiskOfCentralDir = 0; 120 uint16_t totalEntriesInThisDisk = 0; 121 uint16_t totalEntries = 0; 122 uint32_t sizeOfCentralDir = 0; 123 uint32_t offset = 0; 124 uint16_t commentLen = 0; 125}; 126 127// Data descriptor: 128// data descriptor signature 4 bytes (0x06054b50) 129// crc-32 4 bytes 130// compressed size 4 bytes 131// uncompressed size 4 bytes 132// This descriptor MUST exist if bit 3 of the general purpose bit flag is set (see below). 133// It is byte aligned and immediately follows the last byte of compressed data. 134struct __attribute__((packed)) DataDesc { 135 uint32_t signature = 0; 136 uint32_t crc = 0; 137 uint32_t compressedSize = 0; 138 uint32_t uncompressedSize = 0; 139}; 140 141struct ZipEntry { 142 ZipEntry() = default; 143 explicit ZipEntry(const CentralDirEntry ¢ralEntry); 144 ~ZipEntry() = default; // for CodeDEX warning 145 146 uint16_t compressionMethod = 0; 147 uint32_t uncompressedSize = 0; 148 uint32_t compressedSize = 0; 149 uint32_t localHeaderOffset = 0; 150 uint32_t crc = 0; 151 uint16_t flags = 0; 152 uint16_t modifiedTime = 0; 153 uint16_t modifiedDate = 0; 154 std::string fileName; 155}; 156 157struct DirTreeNode { 158 std::unordered_map<std::string, std::shared_ptr<DirTreeNode>> children; 159}; 160 161// zip file extract class for bundle format. 162class ZipFile { 163public: 164 explicit ZipFile(const std::string &pathName); 165 ~ZipFile(); 166 /** 167 * @brief Open zip file. 168 * @return Returns true if the zip file is successfully opened; returns false otherwise. 169 */ 170 bool Open(); 171 /** 172 * @brief Close zip file. 173 */ 174 void Close(); 175 /** 176 * @brief Set this zip content start offset and length in the zip file form pathName. 177 * @param start Indicates the zip content location start position. 178 * @param length Indicates the zip content length. 179 */ 180 void SetContentLocation(const ZipPos start, const size_t length); 181 /** 182 * @brief Get all entries in the zip file. 183 * @param start Indicates the zip content location start position. 184 * @param length Indicates the zip content length. 185 * @return Returns the ZipEntryMap object cotain all entries. 186 */ 187 const ZipEntryMap &GetAllEntries() const; 188 /** 189 * @brief Has entry by name. 190 * @param entryName Indicates the entry name. 191 * @return Returns true if the ZipEntry is successfully finded; returns false otherwise. 192 */ 193 bool HasEntry(const std::string &entryName) const; 194 195 bool IsDirExist(const std::string &dir) const; 196 void GetAllFileList(const std::string &srcPath, std::vector<std::string> &assetList); 197 void GetChildNames(const std::string &srcPath, std::set<std::string> &fileSet); 198 199 /** 200 * @brief Get entry by name. 201 * @param entryName Indicates the entry name. 202 * @param resultEntry Indicates the obtained ZipEntry object. 203 * @return Returns true if the ZipEntry is successfully finded; returns false otherwise. 204 */ 205 bool GetEntry(const std::string &entryName, ZipEntry &resultEntry) const; 206 /** 207 * @brief Get data relative offset for file. 208 * @param file Indicates the entry name. 209 * @param offset Indicates the obtained offset. 210 * @param length Indicates the length. 211 * @return Returns true if this function is successfully called; returns false otherwise. 212 */ 213 bool GetDataOffsetRelative(const std::string &file, ZipPos &offset, uint32_t &length) const; 214 /** 215 * @brief Get data relative offset for file. 216 * @param file Indicates the entry name. 217 * @param dest Indicates the obtained ostream object. 218 * @return Returns true if file is successfully extracted; returns false otherwise. 219 */ 220 bool ExtractFile(const std::string &file, std::ostream &dest) const; 221 222 std::unique_ptr<FileMapper> CreateFileMapper(const std::string &fileName, FileMapperType type) const; 223 bool ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr, 224 size_t &len) const; 225 friend class ZipFileFriend; 226private: 227 bool GetDataOffsetRelative(const ZipEntry &zipEntry, ZipPos &offset, uint32_t &length) const; 228 /** 229 * @brief Check the EndDir object. 230 * @param endDir Indicates the EndDir object to check. 231 * @return Returns true if successfully checked; returns false otherwise. 232 */ 233 bool CheckEndDir(const EndDir &endDir) const; 234 /** 235 * @brief Parse the EndDir. 236 * @return Returns true if successfully Parsed; returns false otherwise. 237 */ 238 bool ParseEndDirectory(); 239 /** 240 * @brief Parse one entry. 241 * @return Returns true if successfully parsed; returns false otherwise. 242 */ 243 bool ParseOneEntry(uint8_t* &entryPtr); 244 void AddEntryToTree(const std::string &fileName); 245 /** 246 * @brief Parse all Entries. 247 * @return Returns true if successfully parsed; returns false otherwise. 248 */ 249 bool ParseAllEntries(); 250 /** 251 * @brief Get LocalHeader object size. 252 * @param nameSize Indicates the nameSize. 253 * @param extraSize Indicates the extraSize. 254 * @return Returns size of LocalHeader. 255 */ 256 size_t GetLocalHeaderSize(const uint16_t nameSize = 0, const uint16_t extraSize = 0) const; 257 /** 258 * @brief Get entry data offset. 259 * @param zipEntry Indicates the ZipEntry object. 260 * @param extraSize Indicates the extraSize. 261 * @return Returns position. 262 */ 263 ZipPos GetEntryDataOffset(const ZipEntry &zipEntry, const uint16_t extraSize) const; 264 /** 265 * @brief Check data description. 266 * @param zipEntry Indicates the ZipEntry object. 267 * @param localHeader Indicates the localHeader object. 268 * @return Returns true if successfully checked; returns false otherwise. 269 */ 270 bool CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const; 271 /** 272 * @brief Check coherency LocalHeader object. 273 * @param zipEntry Indicates the ZipEntry object. 274 * @param extraSize Indicates the obtained size. 275 * @return Returns true if successfully checked; returns false otherwise. 276 */ 277 bool CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const; 278 /** 279 * @brief Unzip ZipEntry object to ostream. 280 * @param zipEntry Indicates the ZipEntry object. 281 * @param extraSize Indicates the size. 282 * @param dest Indicates the obtained ostream object. 283 * @return Returns true if successfully Unzip; returns false otherwise. 284 */ 285 bool UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const; 286 /** 287 * @brief Unzip ZipEntry object to ostream. 288 * @param zipEntry Indicates the ZipEntry object. 289 * @param extraSize Indicates the size. 290 * @param dest Indicates the obtained ostream object. 291 * @return Returns true if successfully Unzip; returns false otherwise. 292 */ 293 bool UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const; 294 /** 295 * @brief Get Entry start. 296 * @param zipEntry Indicates the ZipEntry object. 297 * @param extraSize Indicates the extra size. 298 * @return Returns true if successfully Seeked; returns false otherwise. 299 */ 300 size_t GetEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const; 301 /** 302 * @brief Init zlib stream. 303 * @param zstream Indicates the obtained z_stream object. 304 * @return Returns true if successfully init; returns false otherwise. 305 */ 306 bool InitZStream(z_stream &zstream) const; 307 /** 308 * @brief Read zlib stream. 309 * @param buffer Indicates the buffer to read. 310 * @param zstream Indicates the obtained z_stream object. 311 * @param remainCompressedSize Indicates the obtained size. 312 * @return Returns true if successfully read; returns false otherwise. 313 */ 314 bool ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize, size_t &startPos) const; 315 316 bool UnzipWithInflatedFromMMap(const ZipEntry &zipEntry, const uint16_t extraSize, 317 void *mmapDataPtr, std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const; 318 319 bool ReadZStreamFromMMap(const BytePtr &buffer, void* &dataPtr, 320 z_stream &zstream, uint32_t &remainCompressedSize) const; 321 322private: 323 std::string pathName_; 324 std::shared_ptr<ZipFileReader> zipFileReader_; 325 EndDir endDir_; 326 ZipEntryMap entriesMap_; 327 std::shared_ptr<DirTreeNode> dirRoot_; 328 // offset of central directory relative to zip file. 329 ZipPos centralDirPos_ = 0; 330 // this zip content start offset relative to zip file. 331 ZipPos fileStartPos_ = 0; 332 // this zip content length in the zip file. 333 ZipPos fileLength_ = 0; 334 bool isOpen_ = false; 335}; 336} // namespace AbilityBase 337} // namespace OHOS 338#endif // OHOS_ABILITY_BASE_ZIP_FILE_H 339