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