1 /* 2 * Copyright (c) 2021 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_AAFWK_STANDARD_TOOLS_ZIP_READER_H_ 16 #define FOUNDATION_AAFWK_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 AAFwk { 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_year = 0, 116 .tm_mon = 0, 117 .tm_mday = 0, 118 .tm_hour = 0, 119 .tm_min = 0, 120 .tm_sec = 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(), like: 150 // 151 // while (reader.HasMore()) { 152 // // Do something with the current file here. 153 // reader.AdvanceToNextEntry(); 154 // } 155 bool HasMore(); 156 157 // Advances the next entry. Returns true on success. 158 bool AdvanceToNextEntry(); 159 160 // Opens the current entry in the zip file. On success, returns true and 161 // updates the the current entry state (i.e. CurrentEntryInfo() is 162 // updated). This function should be called before operations over the 163 // current entry like ExtractCurrentEntryToFile(). 164 // 165 // Note that there is no CloseCurrentEntryInZip(). The the current entry 166 // state is reset automatically as needed. 167 bool OpenCurrentEntryInZip(); 168 169 // Extracts |numBytesToExtract| bytes of the current entry to |delegate|, 170 // starting from the beginning of the entry. Return value specifies whether 171 // the entire file was extracted. 172 bool ExtractCurrentEntry(WriterDelegate *delegate, 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 // A writer delegate that writes a file at a given path. 204 class FilePathWriterDelegate : public WriterDelegate { 205 public: 206 explicit FilePathWriterDelegate(const FilePath &outputFilePath); 207 ~FilePathWriterDelegate() override; 208 209 // WriterDelegate methods: 210 211 // Creates the output file and any necessary intermediate directories. 212 bool PrepareOutput() override; 213 214 // Writes |numBytes| bytes of |data| to the file, returning false if not all 215 // bytes could be written. 216 bool WriteBytes(const char *data, int numBytes) override; 217 218 // Sets the last-modified time of the data. 219 void SetTimeModified(const struct tm *time) override; 220 221 private: 222 FilePath outputFilePath_ = FilePath(std::string()); 223 FILE *file_ = nullptr; 224 225 DISALLOW_COPY_AND_ASSIGN(FilePathWriterDelegate); 226 }; 227 228 } // namespace LIBZIP 229 } // namespace AAFwk 230 } // namespace OHOS 231 #endif // FOUNDATION_AAFWK_STANDARD_TOOLS_ZIP_READER_H_ 232