• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #ifndef FOUNDATION_APPEXECFWK_STANDARD_TOOLS_ZIP_READER_H_
16 #define FOUNDATION_APPEXECFWK_STANDARD_TOOLS_ZIP_READER_H_
17 
18 #include <stddef.h>
19 #include <stdint.h>
20 #include <unistd.h>
21 #include <functional>
22 #include <memory>
23 #include <string>
24 #include <time.h>
25 #include <stdio.h>
26 #include "ffrt.h"
27 #include "file_path.h"
28 #include "zip_utils.h"
29 #include "contrib/minizip/unzip.h"
30 
31 namespace OHOS {
32 namespace AppExecFwk {
33 namespace LIBZIP {
34 
35 // A delegate interface used to stream out an entry; see
36 // ZipReader::ExtractCurrentEntry.
37 class WriterDelegate {
38 public:
~WriterDelegate()39     virtual ~WriterDelegate()
40     {}
41 
42     // Invoked once before any data is streamed out to pave the way (e.g., to open
43     // the output file). Return false on failure to cancel extraction.
44     virtual bool PrepareOutput() = 0;
45 
46     // Invoked to write the next chunk of data. Return false on failure to cancel
47     // extraction.
48     virtual bool WriteBytes(const char *data, int numBytes) = 0;
49 
50     // Sets the last-modified time of the data.
51     virtual void SetTimeModified(const struct tm *modifiedTime) = 0;
52 };
53 
54 // This class is used for reading zip files.
55 class ZipReader {
56 public:
57     // A callback that is called when the operation is successful.
58     using SuccessCallback = std::function<void()>;
59     // A callback that is called when the operation fails.
60     using FailureCallback = std::function<void()>;
61 
62     using ProgressCallback = std::function<void(int64_t)>;
63 
64     // This class represents information of an entry (file or directory) in
65     // a zip file.
66     class EntryInfo {
67     public:
68         EntryInfo(const std::string &fileNameInZip, const unz_file_info &rawFileInfo);
~EntryInfo()69         virtual ~EntryInfo()
70         {}
71         // Returns the file path. The path is usually relative like
72         // "foo/bar.txt", but if it's absolute, is_unsafe() returns true.
GetFilePath()73         const FilePath &GetFilePath() const
74         {
75             return filePath_;
76         }
77 
78         // Returns the size of the original file (i.e. after uncompressed).
79         // Returns 0 if the entry is a directory.
80         // Note: this value should not be trusted, because it is stored as metadata
81         // in the zip archive and can be different from the real uncompressed size.
GetOriginalSize()82         int64_t GetOriginalSize() const
83         {
84             return originalSize_;
85         }
86 
87         // Returns the last modified time. If the time stored in the zip file was
88         // not valid, the unix epoch will be returned.
GetLastModified()89         struct tm GetLastModified() const
90         {
91             return lastModified_;
92         }
93 
94         // Returns true if the entry is a directory.
IsDirectory()95         bool IsDirectory() const
96         {
97             return isDirectory_;
98         }
99 
100         // Returns true if the entry is unsafe, like having ".." or invalid
101         // UTF-8 characters in its file name, or the file path is absolute.
IsUnsafe()102         bool IsUnsafe() const
103         {
104             return isUnsafe_;
105         }
106 
107         // Returns true if the entry is encrypted.
IsEncrypted()108         bool IsEncrypted() const
109         {
110             return isEncrypted_;
111         }
112 
113     private:
114         FilePath filePath_;
115         int64_t originalSize_ = 0;
116         struct tm lastModified_ {
117             .tm_sec = 0,
118             .tm_min = 0,
119             .tm_hour = 0,
120             .tm_mday = 0,
121             .tm_mon = 0,
122             .tm_year = 0
123         };
124         bool isDirectory_ = false;
125         bool isUnsafe_ = false;
126         bool isEncrypted_ = false;
127         DISALLOW_COPY_AND_ASSIGN(EntryInfo);
128     };
129 
130     ZipReader();
131     ~ZipReader();
132 
133     // Opens the zip file specified by |zipFilePath|. Returns true on
134     // success.
135     bool Open(FilePath &zipFilePath);
136 
137     // Opens the zip file referred to by the platform file |zipFd|, without
138     // taking ownership of |zipFd|. Returns true on success.
139     bool OpenFromPlatformFile(PlatformFile zipFd);
140 
141     // Opens the zip data stored in |data|. This class uses a weak reference to
142     // the given sring while extracting files, i.e. the caller should keep the
143     // string until it finishes extracting files.
144     bool OpenFromString(const std::string &data);
145 
146     // Closes the currently opened zip file. This function is called in the
147     // destructor of the class, so you usually don't need to call this.
148     void Close();
149 
150     // Returns true if there is at least one entry to read. This function is
151     // used to scan entries with AdvanceToNextEntry().
152     bool HasMore();
153 
154     // Advances the next entry. Returns true on success.
155     bool AdvanceToNextEntry();
156 
157     bool GetCurrentEntryPos(unz_file_pos &filePos);
158 
159     // Opens the current entry in the zip file. On success, returns true and
160     // updates the the current entry state (i.e. CurrentEntryInfo() is
161     // updated). This function should be called before operations over the
162     // current entry like ExtractCurrentEntryToFile().
163     // Note that there is no CloseCurrentEntryInZip(). The the current entry
164     // state is reset automatically as needed.
165     bool OpenCurrentEntryInZip();
166 
167     // Extracts |numBytesToExtract| bytes of the current entry to |delegate|,
168     // starting from the beginning of the entry. Return value specifies whether
169     // the entire file was extracted.
170     bool ExtractCurrentEntry(WriterDelegate *delegate, uint64_t numBytesToExtract) const;
171 
172     bool ExtractEntry(WriterDelegate *delegate, const unzFile &zipFile, uint64_t numBytesToExtract) const;
173 
174     // Returns the current entry info. Returns NULL if the current entry is
175     // not yet opened. OpenCurrentEntryInZip() must be called beforehand.
CurrentEntryInfo()176     EntryInfo *CurrentEntryInfo() const
177     {
178         return currentEntryInfo_.get();
179     }
180 
181     // Returns the number of entries in the zip file.
182     // Open() must be called beforehand.
num_entries()183     int num_entries() const
184     {
185         return numEntries_;
186     }
187 
188 private:
189     // Common code used both in Open and OpenFromFd.
190     bool OpenInternal();
191 
192     // Resets the internal state.
193     void Reset();
194 
195     unzFile zipFile_;
196     int numEntries_;
197     bool reachedEnd_;
198     std::unique_ptr<EntryInfo> currentEntryInfo_;
199 
200     DISALLOW_COPY_AND_ASSIGN(ZipReader);
201 };
202 
203 class ZipParallelReader : public ZipReader {
204 public:
ZipParallelReader()205     ZipParallelReader() : ZipReader() {}
206     ~ZipParallelReader();
207 
208     // Opens th zip file multi times specified by |zipFilePath|. Returns true on
209     // success.
210     bool Open(FilePath &zipFilePath);
211 
212     // Closes the currently opened zip file. This function is called in the
213     // destructor of the class, so you usually don't need to call this.
214     void Close();
215 
216     // Get unzFile handler resource. Returns the handler and give the |resourceId|
217     // by input parameter.
218     unzFile GetZipHandler(int &resourceId);
219     // Release unzFile handler resource accordding to |resourceId|.
220     void ReleaseZipHandler(const int &resourceId);
221 
222     // Get the position in |zipFile| of the entry.
223     unz_file_pos GetEntryPos(unzFile &zipFile);
224     // Go to the entry indicated by |filePos| in |zipFile|.
225     bool GotoEntry(unzFile &zipFile, unz_file_pos filePos);
226 private:
227     const int concurrency_ = sysconf(_SC_NPROCESSORS_ONLN);
228     std::vector<ffrt::mutex> mtxes_ = std::vector<ffrt::mutex> (concurrency_);
229     std::vector<unzFile> zipFiles_;
230 
231     DISALLOW_COPY_AND_ASSIGN(ZipParallelReader);
232 };
233 
234 
235 // A writer delegate that writes a file at a given path.
236 class FilePathWriterDelegate : public WriterDelegate {
237 public:
238     explicit FilePathWriterDelegate(const FilePath &outputFilePath);
239     ~FilePathWriterDelegate() override;
240 
241     // WriterDelegate methods.
242     // Creates the output file and any necessary intermediate directories.
243     bool PrepareOutput() override;
244 
245     // Writes |numBytes| bytes of |data| to the file, returning false if not all
246     // bytes could be written.
247     bool WriteBytes(const char *data, int numBytes) override;
248 
249     // Sets the last-modified time of the data.
250     void SetTimeModified(const struct tm *time) override;
251 
252 private:
253     FilePath outputFilePath_ = FilePath(std::string());
254     FILE *file_ = nullptr;
255 
256     DISALLOW_COPY_AND_ASSIGN(FilePathWriterDelegate);
257 };
258 
259 }  // namespace LIBZIP
260 }  // namespace AppExecFwk
261 }  // namespace OHOS
262 #endif  // FOUNDATION_APPEXECFWK_STANDARD_TOOLS_ZIP_READER_H_
263