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