1 /*
2  * Copyright (c) 2021-2022 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 FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_ZIP_FILE_H
17 #define FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_ZIP_FILE_H
18 
19 #include <cstdint>
20 #include <map>
21 #include <string>
22 
23 #include "unzip.h"
24 
25 namespace OHOS {
26 namespace AppExecFwk {
27 struct CentralDirEntry;
28 struct ZipEntry;
29 using ZipPos = ZPOS64_T;
30 using ZipEntryMap = std::map<std::string, ZipEntry>;
31 using BytePtr = Byte *;
32 
33 // Local file header: descript in APPNOTE-6.3.4
34 //    local file header signature     4 bytes  (0x04034b50)
35 //    version needed to extract       2 bytes
36 //    general purpose bit flag        2 bytes
37 //    compression method              2 bytes  10
38 //    last mod file time              2 bytes
39 //    last mod file date              2 bytes
40 //    crc-32                          4 bytes
41 //    compressed size                 4 bytes  22
42 //    uncompressed size               4 bytes
43 //    file name length                2 bytes
44 //    extra field length              2 bytes  30
45 struct __attribute__((packed)) LocalHeader {
46     uint32_t signature = 0;
47     uint16_t versionNeeded = 0;
48     uint16_t flags = 0;
49     uint16_t compressionMethod = 0;
50     uint16_t modifiedTime = 0;
51     uint16_t modifiedDate = 0;
52     uint32_t crc = 0;
53     uint32_t compressedSize = 0;
54     uint32_t uncompressedSize = 0;
55     uint16_t nameSize = 0;
56     uint16_t extraSize = 0;
57 };
58 
59 // central file header
60 //    Central File header:
61 //    central file header signature   4 bytes  (0x02014b50)
62 //    version made by                 2 bytes
63 //    version needed to extract       2 bytes
64 //    general purpose bit flag        2 bytes  10
65 //    compression method              2 bytes
66 //    last mod file time              2 bytes
67 //    last mod file date              2 bytes
68 //    crc-32                          4 bytes  20
69 //    compressed size                 4 bytes
70 //    uncompressed size               4 bytes
71 //    file name length                2 bytes  30
72 //    extra field length              2 bytes
73 //    file comment length             2 bytes
74 //    disk number start               2 bytes
75 //    internal file attributes        2 bytes
76 //    external file attributes        4 bytes
77 //    relative offset of local header 4 bytes 46byte
78 struct __attribute__((packed)) CentralDirEntry {
79     uint32_t signature = 0;
80     uint16_t versionMade = 0;
81     uint16_t versionNeeded = 0;
82     uint16_t flags = 0;  // general purpose bit flag
83     uint16_t compressionMethod = 0;
84     uint16_t modifiedTime = 0;
85     uint16_t modifiedDate = 0;
86     uint32_t crc = 0;
87     uint32_t compressedSize = 0;
88     uint32_t uncompressedSize = 0;
89     uint16_t nameSize = 0;
90     uint16_t extraSize = 0;
91     uint16_t commentSize = 0;
92     uint16_t diskNumStart = 0;
93     uint16_t internalAttr = 0;
94     uint32_t externalAttr = 0;
95     uint32_t localHeaderOffset = 0;
96 };
97 
98 // end of central directory packed structure
99 //    end of central dir signature    4 bytes  (0x06054b50)
100 //    number of this disk             2 bytes
101 //    number of the disk with the
102 //    start of the central directory  2 bytes
103 //    total number of entries in the
104 //    central directory on this disk  2 bytes
105 //    total number of entries in
106 //    the central directory           2 bytes
107 //    size of the central directory   4 bytes
108 //    offset of start of central
109 //    directory with respect to
110 //    the starting disk number        4 bytes
111 //    .ZIP file comment length        2 bytes
112 struct __attribute__((packed)) EndDir {
113     uint32_t signature = 0;
114     uint16_t numDisk = 0;
115     uint16_t startDiskOfCentralDir = 0;
116     uint16_t totalEntriesInThisDisk = 0;
117     uint16_t totalEntries = 0;
118     uint32_t sizeOfCentralDir = 0;
119     uint32_t offset = 0;
120     uint16_t commentLen = 0;
121 };
122 
123 // Data descriptor:
124 //    data descriptor signature       4 bytes  (0x06054b50)
125 //    crc-32                          4 bytes
126 //    compressed size                 4 bytes
127 //    uncompressed size               4 bytes
128 // This descriptor MUST exist if bit 3 of the general purpose bit flag is set (see below).
129 // It is byte aligned and immediately follows the last byte of compressed data.
130 struct __attribute__((packed)) DataDesc {
131     uint32_t signature = 0;
132     uint32_t crc = 0;
133     uint32_t compressedSize = 0;
134     uint32_t uncompressedSize = 0;
135 };
136 
137 struct ZipEntry {
138     ZipEntry() = default;
139     explicit ZipEntry(const CentralDirEntry &centralEntry);
140     ~ZipEntry() = default;  // for CodeDEX warning
141 
142     uint16_t compressionMethod = 0;
143     uint32_t uncompressedSize = 0;
144     uint32_t compressedSize = 0;
145     uint32_t localHeaderOffset = 0;
146     uint32_t crc = 0;
147     uint16_t flags = 0;
148     std::string fileName;
149 };
150 
151 // zip file extract class for bundle format.
152 class ZipFile {
153 public:
154     explicit ZipFile(const std::string &pathName);
155     ~ZipFile();
156     /**
157      * @brief Open zip file.
158      * @return Returns true if the zip file is successfully opened; returns false otherwise.
159      */
160     bool Open();
161     /**
162      * @brief Close zip file.
163      */
164     void Close();
165     /**
166      * @brief Set this zip content start offset and length in the zip file form pathName.
167      * @param start Indicates the zip content location start position.
168      * @param length Indicates the zip content length.
169      */
170     void SetContentLocation(ZipPos start, size_t length);
171     /**
172      * @brief Get all entries in the zip file.
173      * @param start Indicates the zip content location start position.
174      * @param length Indicates the zip content length.
175      * @return Returns the ZipEntryMap object cotain all entries.
176      */
177     const ZipEntryMap &GetAllEntries() const;
178     /**
179      * @brief Has entry by name.
180      * @param entryName Indicates the entry name.
181      * @return Returns true if the ZipEntry is successfully finded; returns false otherwise.
182      */
183     bool HasEntry(const std::string &entryName) const;
184 
185     bool IsDirExist(const std::string &dir) const;
186 
187     /**
188      * @brief Get entry by name.
189      * @param entryName Indicates the entry name.
190      * @param resultEntry Indicates the obtained ZipEntry object.
191      * @return Returns true if the ZipEntry is successfully finded; returns false otherwise.
192      */
193     bool GetEntry(const std::string &entryName, ZipEntry &resultEntry) const;
194     /**
195      * @brief Get data relative offset for file.
196      * @param file Indicates the entry name.
197      * @param offset Indicates the obtained offset.
198      * @param length Indicates the length.
199      * @return Returns true if this function is successfully called; returns false otherwise.
200      */
201     bool GetDataOffsetRelative(const std::string &file, ZipPos &offset, uint32_t &length) const;
202     /**
203      * @brief Get data relative offset for file.
204      * @param file Indicates the entry name.
205      * @param dest Indicates the obtained ostream object.
206      * @return Returns true if file is successfully extracted; returns false otherwise.
207      */
208     bool ExtractFile(const std::string &file, std::ostream &dest) const;
209 
210 private:
211     /**
212      * @brief Check the EndDir object.
213      * @param endDir Indicates the EndDir object to check.
214      * @return Returns true if  successfully checked; returns false otherwise.
215      */
216     bool CheckEndDir(const EndDir &endDir) const;
217     /**
218      * @brief Parse the EndDir.
219      * @return Returns true if  successfully Parsed; returns false otherwise.
220      */
221     bool ParseEndDirectory();
222     /**
223      * @brief Parse all Entries.
224      * @return Returns true if successfully parsed; returns false otherwise.
225      */
226     bool ParseAllEntries();
227     /**
228      * @brief Get LocalHeader object size.
229      * @param nameSize Indicates the nameSize.
230      * @param extraSize Indicates the extraSize.
231      * @return Returns size of LocalHeader.
232      */
233     size_t GetLocalHeaderSize(const uint16_t nameSize = 0, const uint16_t extraSize = 0) const;
234     /**
235      * @brief Get entry data offset.
236      * @param zipEntry Indicates the ZipEntry object.
237      * @param extraSize Indicates the extraSize.
238      * @return Returns position.
239      */
240     ZipPos GetEntryDataOffset(const ZipEntry &zipEntry, const uint16_t extraSize) const;
241     /**
242      * @brief Check data description.
243      * @param zipEntry Indicates the ZipEntry object.
244      * @param localHeader Indicates the localHeader object.
245      * @return Returns true if successfully checked; returns false otherwise.
246      */
247     bool CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const;
248     /**
249      * @brief Check coherency LocalHeader object.
250      * @param zipEntry Indicates the ZipEntry object.
251      * @param extraSize Indicates the obtained size.
252      * @return Returns true if successfully checked; returns false otherwise.
253      */
254     bool CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const;
255     /**
256      * @brief Unzip ZipEntry object to ostream.
257      * @param zipEntry Indicates the ZipEntry object.
258      * @param extraSize Indicates the size.
259      * @param dest Indicates the obtained ostream object.
260      * @return Returns true if successfully Unzip; returns false otherwise.
261      */
262     bool UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const;
263     /**
264      * @brief Unzip ZipEntry object to ostream.
265      * @param zipEntry Indicates the ZipEntry object.
266      * @param extraSize Indicates the size.
267      * @param dest Indicates the obtained ostream object.
268      * @return Returns true if successfully Unzip; returns false otherwise.
269      */
270     bool UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const;
271     /**
272      * @brief Seek to Entry start.
273      * @param zipEntry Indicates the ZipEntry object.
274      * @param extraSize Indicates the extra size.
275      * @return Returns true if successfully Seeked; returns false otherwise.
276      */
277     bool SeekToEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const;
278     /**
279      * @brief Init zlib stream.
280      * @param zstream Indicates the obtained z_stream object.
281      * @return Returns true if successfully init; returns false otherwise.
282      */
283     bool InitZStream(z_stream &zstream) const;
284     /**
285      * @brief Read zlib stream.
286      * @param buffer Indicates the buffer to read.
287      * @param zstream Indicates the obtained z_stream object.
288      * @param remainCompressedSize Indicates the obtained size.
289      * @return Returns true if successfully read; returns false otherwise.
290      */
291     bool ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize) const;
292 
293 private:
294     std::string pathName_;
295     FILE *file_ = nullptr;
296     EndDir endDir_;
297     ZipEntryMap entriesMap_;
298     // offset of central directory relative to zip file.
299     ZipPos centralDirPos_ = 0;
300     // this zip content start offset relative to zip file.
301     ZipPos fileStartPos_ = 0;
302     // this zip content length in the zip file.
303     ZipPos fileLength_ = 0;
304     bool isOpen_ = false;
305 };
306 }  // namespace AppExecFwk
307 }  // namespace OHOS
308 #endif  // FOUNDATION_APPEXECFWK_SERVICES_BUNDLEMGR_INCLUDE_ZIP_FILE_H
309