* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_EXTRACTORTOOL_SRC_ZIP_FILE_H
#define ECMASCRIPT_EXTRACTORTOOL_SRC_ZIP_FILE_H
#include <memory>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
#include "file_mapper.h"
#include <contrib/minizip/unzip.h>
namespace panda::ecmascript {
class ZipFileReader;
struct CentralDirEntry;
struct ZipEntry;
using ZipPos = ZPOS64_T;
using ZipEntryMap = std::unordered_map<std::string, ZipEntry>;
using BytePtr = Byte *;
struct __attribute__((packed)) LocalHeader {
uint32_t signature = 0;
uint16_t versionNeeded = 0;
uint16_t flags = 0;
uint16_t compressionMethod = 0;
uint16_t modifiedTime = 0;
uint16_t modifiedDate = 0;
uint32_t crc = 0;
uint32_t compressedSize = 0;
uint32_t uncompressedSize = 0;
uint16_t nameSize = 0;
uint16_t extraSize = 0;
};
struct __attribute__((packed)) CentralDirEntry {
uint32_t signature = 0;
uint16_t versionMade = 0;
uint16_t versionNeeded = 0;
uint16_t flags = 0;
uint16_t compressionMethod = 0;
uint16_t modifiedTime = 0;
uint16_t modifiedDate = 0;
uint32_t crc = 0;
uint32_t compressedSize = 0;
uint32_t uncompressedSize = 0;
uint16_t nameSize = 0;
uint16_t extraSize = 0;
uint16_t commentSize = 0;
uint16_t diskNumStart = 0;
uint16_t internalAttr = 0;
uint32_t externalAttr = 0;
uint32_t localHeaderOffset = 0;
};
struct __attribute__((packed)) EndDir {
uint32_t signature = 0;
uint16_t numDisk = 0;
uint16_t startDiskOfCentralDir = 0;
uint16_t totalEntriesInThisDisk = 0;
uint16_t totalEntries = 0;
uint32_t sizeOfCentralDir = 0;
uint32_t offset = 0;
uint16_t commentLen = 0;
};
struct __attribute__((packed)) DataDesc {
uint32_t signature = 0;
uint32_t crc = 0;
uint32_t compressedSize = 0;
uint32_t uncompressedSize = 0;
};
struct ZipEntry {
ZipEntry() = default;
explicit ZipEntry(const CentralDirEntry ¢ralEntry);
~ZipEntry() = default;
uint16_t compressionMethod = 0;
uint32_t uncompressedSize = 0;
uint32_t compressedSize = 0;
uint32_t localHeaderOffset = 0;
uint32_t crc = 0;
uint16_t flags = 0;
uint16_t modifiedTime = 0;
uint16_t modifiedDate = 0;
uint32_t offset = 0;
std::string fileName;
};
struct DirTreeNode {
std::unordered_map<std::string, std::shared_ptr<DirTreeNode>> children;
};
class ZipFile {
public:
explicit ZipFile(const std::string &pathName);
~ZipFile();
* @brief Open zip file.
* @return Returns true if the zip file is successfully opened; returns false otherwise.
*/
bool Open();
* @brief Close zip file.
*/
void Close();
* @brief Set this zip content start offset and length in the zip file form pathName.
* @param start Indicates the zip content location start position.
* @param length Indicates the zip content length.
*/
void SetContentLocation(const ZipPos start, const size_t length);
* @brief Get all entries in the zip file.
* @param start Indicates the zip content location start position.
* @param length Indicates the zip content length.
* @return Returns the ZipEntryMap object cotain all entries.
*/
const ZipEntryMap &GetAllEntries() const;
* @brief Has entry by name.
* @param entryName Indicates the entry name.
* @return Returns true if the ZipEntry is successfully finded; returns false otherwise.
*/
bool HasEntry(const std::string &entryName) const;
bool IsDirExist(const std::string &dir) const;
void GetAllFileList(const std::string &srcPath, std::vector<std::string> &assetList);
void GetChildNames(const std::string &srcPath, std::set<std::string> &fileSet);
* @brief Get entry by name.
* @param entryName Indicates the entry name.
* @param resultEntry Indicates the obtained ZipEntry object.
* @return Returns true if the ZipEntry is successfully finded; returns false otherwise.
*/
bool GetEntry(const std::string &entryName, ZipEntry &resultEntry) const;
* @brief Get data relative offset for file.
* @param file Indicates the entry name.
* @param offset Indicates the obtained offset.
* @param length Indicates the length.
* @return Returns true if this function is successfully called; returns false otherwise.
*/
bool GetDataOffsetRelative(const std::string &file, ZipPos &offset, uint32_t &length) const;
* @brief Get data relative offset for file.
* @param file Indicates the entry name.
* @param dest Indicates the obtained ostream object.
* @return Returns true if file is successfully extracted; returns false otherwise.
*/
bool ExtractFile(const std::string &file, std::ostream &dest) const;
const std::string &GetFileNameByOffset(uint32_t offset);
std::unique_ptr<FileMapper> CreateFileMapper(const std::string &fileName, FileMapperType type) const;
bool ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr,
size_t &len) const;
friend class ZipFileFriend;
private:
bool GetDataOffsetRelative(const ZipEntry &zipEntry, ZipPos &offset, uint32_t &length) const;
* @brief Check the EndDir object.
* @param endDir Indicates the EndDir object to check.
* @return Returns true if successfully checked; returns false otherwise.
*/
bool CheckEndDir(const EndDir &endDir) const;
* @brief Parse the EndDir.
* @return Returns true if successfully Parsed; returns false otherwise.
*/
bool ParseEndDirectory();
* @brief Parse one entry.
* @return Returns true if successfully parsed; returns false otherwise.
*/
bool ParseOneEntry(uint8_t* &entryPtr);
void AddEntryToTree(const std::string &fileName);
* @brief Parse all Entries.
* @return Returns true if successfully parsed; returns false otherwise.
*/
bool ParseAllEntries();
* @brief Get LocalHeader object size.
* @param nameSize Indicates the nameSize.
* @param extraSize Indicates the extraSize.
* @return Returns size of LocalHeader.
*/
size_t GetLocalHeaderSize(const uint16_t nameSize = 0, const uint16_t extraSize = 0) const;
* @brief Get entry data offset.
* @param zipEntry Indicates the ZipEntry object.
* @param extraSize Indicates the extraSize.
* @return Returns position.
*/
ZipPos GetEntryDataOffset(const ZipEntry &zipEntry, const uint16_t extraSize) const;
* @brief Check data description.
* @param zipEntry Indicates the ZipEntry object.
* @param localHeader Indicates the localHeader object.
* @return Returns true if successfully checked; returns false otherwise.
*/
bool CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const;
* @brief Check coherency LocalHeader object.
* @param zipEntry Indicates the ZipEntry object.
* @param extraSize Indicates the obtained size.
* @return Returns true if successfully checked; returns false otherwise.
*/
bool CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const;
* @brief Unzip ZipEntry object to ostream.
* @param zipEntry Indicates the ZipEntry object.
* @param extraSize Indicates the size.
* @param dest Indicates the obtained ostream object.
* @return Returns true if successfully Unzip; returns false otherwise.
*/
bool UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const;
* @brief Unzip ZipEntry object to ostream.
* @param zipEntry Indicates the ZipEntry object.
* @param extraSize Indicates the size.
* @param dest Indicates the obtained ostream object.
* @return Returns true if successfully Unzip; returns false otherwise.
*/
bool UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const;
* @brief Get Entry start.
* @param zipEntry Indicates the ZipEntry object.
* @param extraSize Indicates the extra size.
* @return Returns true if successfully Seeked; returns false otherwise.
*/
size_t GetEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const;
* @brief Init zlib stream.
* @param zstream Indicates the obtained z_stream object.
* @return Returns true if successfully init; returns false otherwise.
*/
bool InitZStream(z_stream &zstream) const;
* @brief Read zlib stream.
* @param buffer Indicates the buffer to read.
* @param zstream Indicates the obtained z_stream object.
* @param remainCompressedSize Indicates the obtained size.
* @return Returns true if successfully read; returns false otherwise.
*/
bool ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize, size_t &startPos) const;
bool UnzipWithInflatedFromMMap(const ZipEntry &zipEntry, const uint16_t extraSize,
void *mmapDataPtr, std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const;
bool ReadZStreamFromMMap(const BytePtr &buffer, void* &dataPtr,
z_stream &zstream, uint32_t &remainCompressedSize) const;
private:
std::string pathName_;
std::shared_ptr<ZipFileReader> zipFileReader_;
EndDir endDir_;
ZipEntryMap entriesMap_;
std::shared_ptr<DirTreeNode> dirRoot_;
ZipPos centralDirPos_ = 0;
ZipPos fileStartPos_ = 0;
ZipPos fileLength_ = 0;
bool isOpen_ = false;
};
}
#endif