1 /*
2  * Copyright (c) 2020 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_BUNDLE_ZIP_FILE_H
17 #define OHOS_BUNDLE_ZIP_FILE_H
18 
19 #include <map>
20 #include <string>
21 #include <vector>
22 
23 #include "stdint.h"
24 #include "unzip.h"
25 
26 namespace OHOS {
27 using ZipPos = ZPOS64_T;
28 using CentralDirEntry = struct CentralDirEntry;
29 using LocalHeader = struct LocalHeader;
30 using EndDir = struct EndDir;
31 using DataDesc = struct DataDesc;
32 using ZipEntry = struct ZipEntry;
33 using ZipEntryMap = std::map<std::string, ZipEntry>;
34 using BytePtr = Byte *;
35 
36 // Local file header: descript in APPNOTE-6.3.4
37 //    local file header signature     4 bytes  (0x04034b50)
38 //    version needed to extract       2 bytes
39 //    general purpose bit flag        2 bytes
40 //    compression method              2 bytes  10
41 //    last mod file time              2 bytes
42 //    last mod file date              2 bytes
43 //    crc-32                          4 bytes
44 //    compressed size                 4 bytes  22
45 //    uncompressed size               4 bytes
46 //    file name length                2 bytes
47 //    extra field length              2 bytes  30
48 struct __attribute__((packed)) LocalHeader {
49     uint32_t signature = 0;
50     uint16_t versionNeeded = 0;
51     uint16_t flags = 0;
52     uint16_t compressionMethod = 0;
53     uint16_t modifiedTime = 0;
54     uint16_t modifiedDate = 0;
55     uint32_t crc = 0;
56     uint32_t compressedSize = 0;
57     uint32_t uncompressedSize = 0;
58     uint16_t nameSize = 0;
59     uint16_t extraSize = 0;
60 };
61 
62 // central file header
63 //    Central File header:
64 //    central file header signature   4 bytes  (0x02014b50)
65 //    version made by                 2 bytes
66 //    version needed to extract       2 bytes
67 //    general purpose bit flag        2 bytes  10
68 //    compression method              2 bytes
69 //    last mod file time              2 bytes
70 //    last mod file date              2 bytes
71 //    crc-32                          4 bytes  20
72 //    compressed size                 4 bytes
73 //    uncompressed size               4 bytes
74 //    file name length                2 bytes  30
75 //    extra field length              2 bytes
76 //    file comment length             2 bytes
77 //    disk number start               2 bytes
78 //    internal file attributes        2 bytes
79 //    external file attributes        4 bytes
80 //    relative offset of local header 4 bytes 46byte
81 struct __attribute__((packed)) CentralDirEntry {
82     uint32_t signature = 0;
83     uint16_t versionMade = 0;
84     uint16_t versionNeeded = 0;
85     uint16_t flags = 0; // general purpose bit flag
86     uint16_t compressionMethod = 0;
87     uint16_t modifiedTime = 0;
88     uint16_t modifiedDate = 0;
89     uint32_t crc = 0;
90     uint32_t compressedSize = 0;
91     uint32_t uncompressedSize = 0;
92     uint16_t nameSize = 0;
93     uint16_t extraSize = 0;
94     uint16_t commentSize = 0;
95     uint16_t diskNumStart = 0;
96     uint16_t internalAttr = 0;
97     uint32_t externalAttr = 0;
98     uint32_t localHeaderOffset = 0;
99 };
100 
101 struct __attribute__((packed)) EndDir {
102     uint32_t signature = 0;
103     uint16_t numDisk = 0;
104     uint16_t startDiskOfCentralDir = 0;
105     uint16_t totalEntriesInThisDisk = 0;
106     uint16_t totalEntries = 0;
107     uint32_t sizeOfCentralDir = 0;
108     uint32_t offset = 0;
109     uint16_t commentLen = 0;
110 };
111 
112 // Data descriptor:
113 //    data descriptor signature       4 bytes  (0x06054b50)
114 //    crc-32                          4 bytes
115 //    compressed size                 4 bytes
116 //    uncompressed size               4 bytes
117 // This descriptor MUST exist if bit 3 of the general purpose bit flag is set (see below).
118 // It is byte aligned and immediately follows the last byte of compressed data.
119 struct __attribute__((packed)) DataDesc {
120     uint32_t signature = 0;
121     uint32_t crc = 0;
122     uint32_t compressedSize = 0;
123     uint32_t uncompressedSize = 0;
124 };
125 
126 struct ZipEntry {
127     ZipEntry() = default;
128     explicit ZipEntry(const CentralDirEntry &centralEntry);
129     ~ZipEntry() = default;
130 
131     uint16_t compressionMethod = 0;
132     uint32_t uncompressedSize = 0;
133     uint32_t compressedSize = 0;
134     uint32_t localHeaderOffset = 0;
135     uint32_t crc = 0;
136     uint16_t flags = 0;
137     std::string fileName;
138 };
139 
140 // zip file extract class for bundle format.
141 class ZipFile {
142 public:
143     explicit ZipFile(const std::string &pathName);
144     ~ZipFile();
145 
146     bool Open();
147     void Close();
148     // set this zip content start offset and length in the zip file form pathName.
149     void SetContentLocation(ZipPos start, size_t length);
150 
151     const ZipEntryMap &GetAllEntries() const;
152     bool GetEntry(const std::string &entryName, ZipEntry &resultEntry) const;
153     bool ExtractFile(const std::string &file, std::ostream &dest) const;
154     const std::vector<std::string> &GetFileNames() const;
155 
156 private:
157     bool CheckEndDir(const EndDir &endDir) const;
158     bool ParseEndDirectory();
159     bool ParseAllEntries();
160     size_t GetLocalHeaderSize(const uint16_t nameSize = 0, const uint16_t extraSize = 0) const;
161     bool CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const;
162     bool CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const;
163     bool UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const;
164     bool UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const;
165     bool SeekToEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const;
166     bool InitZStream(z_stream &zstream) const;
167     bool ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize) const;
168 
169 private:
170     std::string pathName_;
171     FILE* file_ = nullptr;
172     EndDir endDir_;
173     ZipEntryMap entriesMap_;
174     // offset of central directory relative to zip file.
175     ZipPos centralDirPos_ = 0;
176     // this zip content length in the zip file.
177     ZipPos fileLength_ = 0;
178     // entryName vector
179     std::vector<std::string> fileNames_;
180     bool isOpen_ = false;
181 };
182 } // namespace OHOS
183 #endif // OHOS_BUNDLE_ZIP_FILE_H