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