• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "pkg_zipfile.h"
16 #include <ctime>
17 #include <limits>
18 #include "pkg_algorithm.h"
19 #include "pkg_manager.h"
20 #include "pkg_stream.h"
21 #include "zip_pkg_parse.h"
22 #include "zlib.h"
23 
24 namespace Hpackage {
25 constexpr uint32_t TM_YEAR_BITS = 9;
26 constexpr uint32_t TM_MON_BITS = 5;
27 constexpr uint32_t TM_MIN_BITS = 5;
28 constexpr uint32_t TM_HOUR_BITS = 11;
29 constexpr uint32_t BIG_SIZE_HEADER = 20;
30 constexpr uint32_t START_YEAR = 1900;
31 constexpr uint32_t MAX_FILE_NAME = 256;
32 constexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50;
33 constexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50;
34 constexpr uint32_t END_CENTRAL_SIGNATURE = 0x06054b50;
35 constexpr uint32_t DATA_DESC_SIGNATURE = 0x08074b50;
36 // mask value that signifies that the entry has a DD
37 constexpr uint32_t GPBDD_FLAG_MASK = 0x0008;
38 constexpr uint32_t ZIP_PKG_ALIGNMENT_DEF = 1;
39 constexpr int32_t DEF_MEM_LEVEL = 8;
40 
AddEntry(const PkgManager::FileInfoPtr file,const PkgStreamPtr inStream)41 int32_t ZipPkgFile::AddEntry(const PkgManager::FileInfoPtr file, const PkgStreamPtr inStream)
42 {
43     if (!CheckState({PKG_FILE_STATE_IDLE, PKG_FILE_STATE_WORKING}, PKG_FILE_STATE_WORKING)) {
44         PKG_LOGE("Error state curr %d ", state_);
45         return PKG_INVALID_STATE;
46     }
47     if (file == nullptr || inStream == nullptr) {
48         PKG_LOGE("AddEntry failed, invalid param");
49         return PKG_INVALID_PARAM;
50     }
51     PKG_LOGI("ZipPkgFile::AddEntry %s ", file->identity.c_str());
52 
53     int32_t ret = PKG_SUCCESS;
54     ZipFileEntry* entry = static_cast<ZipFileEntry*>(AddPkgEntry(file->identity));
55     if (entry == nullptr) {
56         PKG_LOGE("Failed to create pkg node for %s", file->identity.c_str());
57         return PKG_NONE_MEMORY;
58     }
59     entry->Init(file, inStream);
60 
61     size_t encodeLen = 0;
62     ret = entry->EncodeHeader(inStream, currentOffset_, encodeLen);
63     if (ret != PKG_SUCCESS) {
64         PKG_LOGE("Failed to encode for %s", file->identity.c_str());
65         return ret;
66     }
67     currentOffset_ += encodeLen;
68     ret = entry->Pack(inStream, currentOffset_, encodeLen);
69     if (ret != PKG_SUCCESS) {
70         PKG_LOGE("Failed to pack for %s", file->identity.c_str());
71         return ret;
72     }
73     currentOffset_ += encodeLen;
74     return PKG_SUCCESS;
75 }
76 
SavePackage(size_t & signOffset)77 int32_t ZipPkgFile::SavePackage(size_t &signOffset)
78 {
79     UNUSED(signOffset);
80     if (!CheckState({PKG_FILE_STATE_WORKING}, PKG_FILE_STATE_CLOSE)) {
81         PKG_LOGE("error state curr %d ", state_);
82         return PKG_INVALID_STATE;
83     }
84     int32_t ret = PKG_SUCCESS;
85     size_t offset = currentOffset_;
86     for (auto &it : pkgEntryMapId_) {
87         ZipFileEntry* entry = static_cast<ZipFileEntry*>(it.second);
88         if (entry == nullptr) {
89             PKG_LOGE("Failed to write CentralDirEntry");
90             return PKG_INVALID_PARAM;
91         }
92         size_t encodeLen = 0;
93         entry->EncodeCentralDirEntry(pkgStream_, offset, encodeLen);
94         offset += encodeLen;
95     }
96 
97     std::vector<uint8_t> buff(sizeof(EndCentralDir));
98     WriteLE32(buff.data() + offsetof(EndCentralDir, signature), END_CENTRAL_SIGNATURE);
99     WriteLE16(buff.data() + offsetof(EndCentralDir, numDisk), 0);
100     WriteLE16(buff.data() + offsetof(EndCentralDir, startDiskOfCentralDir), 0);
101     WriteLE16(buff.data() + offsetof(EndCentralDir, totalEntriesInThisDisk), pkgEntryMapId_.size());
102     WriteLE16(buff.data() + offsetof(EndCentralDir, totalEntries), pkgEntryMapId_.size());
103     WriteLE32(buff.data() + offsetof(EndCentralDir, sizeOfCentralDir), offset - currentOffset_);
104     WriteLE32(buff.data() + offsetof(EndCentralDir, offset), currentOffset_);
105     WriteLE16(buff.data() + offsetof(EndCentralDir, commentLen), 0);
106     PkgBuffer buffer(buff);
107     ret = pkgStream_->Write(buffer, sizeof(EndCentralDir), offset);
108     if (ret != PKG_SUCCESS) {
109         PKG_LOGE("Failed to write CentralDirEntry for %s", pkgStream_->GetFileName().c_str());
110         return ret;
111     }
112     currentOffset_ = offset + sizeof(EndCentralDir);
113     pkgStream_->Flush(currentOffset_);
114     return PKG_SUCCESS;
115 }
116 
LoadPackage(std::vector<std::string> & fileNames,const PkgBuffer & buffer,uint32_t endDirLen,size_t endDirPos,size_t & readLen)117 int32_t ZipPkgFile::LoadPackage(std::vector<std::string> &fileNames, const PkgBuffer &buffer,
118     uint32_t endDirLen, size_t endDirPos, size_t &readLen)
119 {
120     size_t fileLen = pkgStream_->GetFileLength();
121     EndCentralDir endDir;
122     endDir.signature = ReadLE32(buffer.buffer + offsetof(EndCentralDir, signature));
123     endDir.numDisk = ReadLE16(buffer.buffer  + offsetof(EndCentralDir, numDisk));
124     endDir.startDiskOfCentralDir = ReadLE16(buffer.buffer  + offsetof(EndCentralDir, startDiskOfCentralDir));
125     endDir.totalEntriesInThisDisk = ReadLE16(buffer.buffer  + offsetof(EndCentralDir, totalEntriesInThisDisk));
126     endDir.totalEntries = ReadLE16(buffer.buffer  + offsetof(EndCentralDir, totalEntries));
127     endDir.sizeOfCentralDir = ReadLE32(buffer.buffer  + offsetof(EndCentralDir, sizeOfCentralDir));
128     endDir.offset = ReadLE32(buffer.buffer  + offsetof(EndCentralDir, offset));
129     endDir.commentLen = ReadLE16(buffer.buffer  + offsetof(EndCentralDir, commentLen));
130     if ((endDir.numDisk != 0) || (endDir.signature != END_CENTRAL_SIGNATURE) ||
131         (endDir.startDiskOfCentralDir != 0)
132 #ifndef UPDATER_UT
133         || (endDir.offset >= fileLen) || (endDir.totalEntriesInThisDisk != endDir.totalEntries) ||
134         ((endDir.offset + endDir.sizeOfCentralDir + endDirLen) > fileLen)
135 #endif
136         ) {
137         PKG_LOGE("end dir format error %s", pkgStream_->GetFileName().c_str());
138         return PKG_INVALID_PKG_FORMAT;
139     }
140     size_t currentPos = endDir.offset;
141     if (endDir.offset == UINT_MAX) {
142         int32_t ret = pkgStream_->Read(buffer, endDirPos - sizeof(Zip64EndCentralDirLocator),
143             sizeof(Zip64EndCentralDirLocator), readLen);
144         uint32_t signature = ReadLE32(buffer.buffer + offsetof(Zip64EndCentralDirLocator, signature));
145         if (ret != PKG_SUCCESS || signature != 0x07064b50) {
146             return ParseFileEntries(fileNames, endDir, currentPos, fileLen);
147         }
148         currentPos = ReadLE64(buffer.buffer + offsetof(Zip64EndCentralDirLocator, endOfCentralDirectoryRecord));
149         ret = pkgStream_->Read(buffer, currentPos, sizeof(Zip64EndCentralDirRecord), readLen);
150         signature = ReadLE32(buffer.buffer + offsetof(Zip64EndCentralDirRecord, signature));
151         if (ret == PKG_SUCCESS && signature == 0x06064b50) {
152             currentPos = ReadLE64(buffer.buffer + offsetof(Zip64EndCentralDirRecord, offset));
153         }
154     }
155     return ParseFileEntries(fileNames, endDir, currentPos, fileLen);
156 }
157 
LoadPackage(std::vector<std::string> & fileNames,VerifyFunction verifier)158 int32_t ZipPkgFile::LoadPackage(std::vector<std::string>& fileNames, VerifyFunction verifier)
159 {
160     UNUSED(verifier);
161     PKG_LOGI("LoadPackage %s :%zu", pkgStream_->GetFileName().c_str(), pkgStream_->GetFileLength());
162     PKG_CHECK(CheckState({PKG_FILE_STATE_IDLE}, PKG_FILE_STATE_WORKING),
163         return PKG_INVALID_STATE, "Error state curr %d ", state_);
164     // 先从文件尾部获取 EndCentralDir
165     size_t fileLen = pkgStream_->GetFileLength();
166     PKG_CHECK(fileLen > 0, return PKG_INVALID_FILE, "invalid file to load");
167     PKG_CHECK(fileLen <= SIZE_MAX, return PKG_INVALID_FILE,
168         "Invalid file len %zu to load %s", fileLen, pkgStream_->GetFileName().c_str());
169     PKG_CHECK(fileLen >= static_cast<size_t>(sizeof(EndCentralDir)), return PKG_INVALID_FILE,
170         "Too small to be zip %s", pkgStream_->GetFileName().c_str());
171 
172     // 检查最后面是签名信息还是EndCentralDir
173     size_t buffSize = sizeof(EndCentralDir);
174     if (buffSize < sizeof(Zip64EndCentralDirRecord)) {
175         buffSize = sizeof(Zip64EndCentralDirRecord);
176     }
177     size_t signatureLen = 0;
178     uint32_t magic = 0;
179     uint32_t endDirLen = sizeof(EndCentralDir);
180     size_t endDirPos = fileLen - endDirLen;
181     size_t readLen = 0;
182     PkgBuffer buffer(buffSize);
183     int32_t ret = pkgStream_->Read(buffer, endDirPos, sizeof(EndCentralDir), readLen);
184     PKG_CHECK(ret == PKG_SUCCESS, return ret, "read EOCD struct failed %s", pkgStream_->GetFileName().c_str());
185     magic = ReadLE32(buffer.buffer);
186     if (magic != END_CENTRAL_SIGNATURE) { // 按签名处理
187         size_t signatureStart = 0;
188         ZipPkgParse zipParse;
189         ret = zipParse.ParseZipPkg(pkgStream_, signatureStart, signatureLen);
190         PKG_CHECK(ret == PKG_SUCCESS, return ret, "Parse zip package signature failed");
191 
192         endDirPos -= signatureLen;
193         ret = pkgStream_->Read(buffer, endDirPos, sizeof(EndCentralDir), readLen);
194         PKG_CHECK(ret == PKG_SUCCESS, return ret, "read EOCD struct failed %s", pkgStream_->GetFileName().c_str());
195     }
196 
197     return LoadPackage(fileNames, buffer, endDirLen, endDirPos, readLen);
198 }
199 
ParseFileEntries(std::vector<std::string> & fileNames,const EndCentralDir & endDir,size_t currentPos,size_t fileLen)200 int32_t ZipPkgFile::ParseFileEntries(std::vector<std::string> &fileNames,
201     const EndCentralDir &endDir, size_t currentPos, size_t fileLen)
202 {
203     int32_t ret = PKG_SUCCESS;
204     size_t buffLen = MAX_FILE_NAME + sizeof(LocalFileHeader) + sizeof(DataDescriptor)
205         + sizeof(CentralDirEntry) + BIG_SIZE_HEADER;
206     PkgBuffer buffer(buffLen);
207 
208     for (int32_t i = 0; i < endDir.totalEntries; i++) {
209         if (fileLen <= currentPos) {
210             PKG_LOGE("too small to be zip");
211             return PKG_INVALID_FILE;
212         }
213 
214         ZipFileEntry* entry = new ZipFileEntry(this, nodeId_++);
215         if (entry == nullptr) {
216             PKG_LOGE("Failed to create zip node for %s", pkgStream_->GetFileName().c_str());
217             return PKG_NONE_MEMORY;
218         }
219 
220         // 从文件中解析出文件头信息,保存在entry中
221         size_t decodeLen = 0;
222         ret = entry->DecodeHeader(buffer, currentPos, 0, decodeLen);
223         if (ret != PKG_SUCCESS) {
224             PKG_LOGE("DecodeHeader failed");
225             delete entry;
226             return ret;
227         }
228 
229         // 保存entry文件
230         pkgEntryMapId_.insert(std::pair<uint32_t, PkgEntryPtr>(entry->GetNodeId(), (PkgEntryPtr)entry));
231         pkgEntryMapFileName_.insert(std::pair<std::string, PkgEntryPtr>(entry->GetFileName(), (PkgEntryPtr)entry));
232         fileNames.push_back(entry->GetFileName());
233 
234         currentPos += decodeLen;
235     }
236     return ret;
237 }
238 
EncodeHeader(PkgStreamPtr inStream,size_t startOffset,size_t & encodeLen)239 int32_t ZipFileEntry::EncodeHeader(PkgStreamPtr inStream, size_t startOffset, size_t &encodeLen)
240 {
241     // 对zip包,数据和数据头信息在连续位置,使用一个打包
242     encodeLen = 0;
243     fileInfo_.fileInfo.headerOffset = startOffset;
244     return PKG_SUCCESS;
245 }
246 
Pack(PkgStreamPtr inStream,size_t startOffset,size_t & encodeLen)247 int32_t ZipFileEntry::Pack(PkgStreamPtr inStream, size_t startOffset, size_t &encodeLen)
248 {
249     PkgAlgorithm::PkgAlgorithmPtr algorithm = PkgAlgorithmFactory::GetAlgorithm(&fileInfo_.fileInfo);
250     PkgStreamPtr outStream = pkgFile_->GetPkgStream();
251     PKG_CHECK(fileInfo_.fileInfo.headerOffset == startOffset, return PKG_INVALID_PARAM,
252         "Offset error %zu %zu %s", fileInfo_.fileInfo.headerOffset, startOffset, fileInfo_.fileInfo.identity.c_str());
253     PKG_CHECK(algorithm != nullptr && outStream != nullptr && inStream != nullptr, return PKG_INVALID_PARAM,
254         "outStream or inStream null for %s", fileInfo_.fileInfo.identity.c_str());
255 
256     // 为header申请一个buff,先处理到内存,后面在写入文件
257     std::vector<uint8_t> buff(MAX_FILE_NAME + sizeof(LocalFileHeader) + ZIP_PKG_ALIGNMENT_DEF);
258     size_t nameLen = 0;
259     PkgFile::ConvertStringToBuffer(fileInfo_.fileInfo.identity, {
260         buff.data() + sizeof(LocalFileHeader), buff.capacity()
261     }, nameLen);
262 
263     size_t headerLen = nameLen + sizeof(LocalFileHeader);
264     bool hasDataDesc = true;
265     if (fileInfo_.method == Z_DEFLATED) {
266 #ifndef UPDATER_UT
267         hasDataDesc = false;
268 #endif
269     }
270 
271     fileInfo_.fileInfo.dataOffset = startOffset + headerLen;
272     PkgAlgorithmContext context = {
273         {0, startOffset + headerLen},
274         {fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize},
275         0, fileInfo_.fileInfo.digestMethod
276     };
277     int32_t ret = algorithm->Pack(inStream, outStream, context);
278     PKG_CHECK(ret == PKG_SUCCESS, return ret, "Failed to compress for %s", fileInfo_.fileInfo.identity.c_str());
279     // 填充file信息,压缩后的长度和crc
280     fileInfo_.fileInfo.packedSize = context.packedSize;
281     crc32_ = context.crc;
282 
283     // 构建文件头信息,从startOffset开始
284     ret = EncodeLocalFileHeader(buff.data(), sizeof(LocalFileHeader), hasDataDesc, nameLen);
285     PKG_CHECK(ret == PKG_SUCCESS, return ret, "Failed to encodeFileHeader for %s", fileInfo_.fileInfo.identity.c_str());
286     PkgBuffer buffer(buff);
287     ret = outStream->Write(buffer, headerLen, startOffset);
288     PKG_CHECK(ret == PKG_SUCCESS, return ret, "Failed to write header for %s", fileInfo_.fileInfo.identity.c_str());
289 
290     if (hasDataDesc) { //  数据描述部分
291         uint32_t encodeDataDescLen = 0;
292         ret = EncodeDataDescriptor(outStream,
293             startOffset + headerLen + fileInfo_.fileInfo.packedSize, encodeDataDescLen);
294         PKG_CHECK(ret == PKG_SUCCESS, return ret,
295             "Failed to encodeDataDescriptor for %s", fileInfo_.fileInfo.identity.c_str());
296         headerLen += encodeDataDescLen;
297     }
298     encodeLen = headerLen + fileInfo_.fileInfo.packedSize;
299     PKG_LOGI("Pack packedSize:%zu unpackedSize: %zu offset: %zu %zu",
300         fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize,
301         fileInfo_.fileInfo.headerOffset, fileInfo_.fileInfo.dataOffset);
302     return PKG_SUCCESS;
303 }
304 
EncodeCentralDirEntry(const PkgStreamPtr stream,size_t startOffset,size_t & encodeLen)305 int32_t ZipFileEntry::EncodeCentralDirEntry(const PkgStreamPtr stream, size_t startOffset, size_t &encodeLen)
306 {
307     std::vector<uint8_t> buff(sizeof(CentralDirEntry) + MAX_FILE_NAME);
308     size_t realLen = 0;
309     PkgFile::ConvertStringToBuffer(fileInfo_.fileInfo.identity, {
310         buff.data() + sizeof(CentralDirEntry), buff.capacity()
311     }, realLen);
312 
313     CentralDirEntry* centralDir = reinterpret_cast<CentralDirEntry*>(buff.data());
314     centralDir->signature = CENTRAL_SIGNATURE;
315     centralDir->versionMade = 0;
316     centralDir->versionNeeded = 0;
317     if (fileInfo_.method == Z_DEFLATED) {
318         centralDir->flags |= GPBDD_FLAG_MASK;
319     }
320     centralDir->compressionMethod = static_cast<uint16_t>(fileInfo_.method);
321     centralDir->crc = crc32_;
322     uint16_t date;
323     uint16_t time;
324     ExtraTimeAndDate(fileInfo_.fileInfo.modifiedTime, date, time);
325     centralDir->modifiedDate = date;
326     centralDir->modifiedTime = time;
327     centralDir->compressedSize = fileInfo_.fileInfo.packedSize;
328     centralDir->uncompressedSize = fileInfo_.fileInfo.unpackedSize;
329     centralDir->nameSize = realLen;
330     centralDir->extraSize = 0;
331     centralDir->commentSize = 0;
332     centralDir->diskNumStart = 0;
333     centralDir->internalAttr = 0;
334     centralDir->externalAttr = 0;
335     centralDir->localHeaderOffset = fileInfo_.fileInfo.headerOffset;
336     PkgBuffer buffer(buff);
337     int32_t ret = stream->Write(buffer, sizeof(CentralDirEntry) + realLen, startOffset);
338     if (ret != PKG_SUCCESS) {
339         PKG_LOGE("Failed to write CentralDirEntry for %s", fileInfo_.fileInfo.identity.c_str());
340         return ret;
341     }
342     encodeLen = sizeof(CentralDirEntry) + realLen;
343     return PKG_SUCCESS;
344 }
345 
EncodeLocalFileHeader(uint8_t * buffer,size_t bufferLen,bool hasDataDesc,size_t nameLen)346 int32_t ZipFileEntry::EncodeLocalFileHeader(uint8_t *buffer, size_t bufferLen, bool hasDataDesc,
347     size_t nameLen)
348 {
349     if (bufferLen < sizeof(LocalFileHeader)) {
350         PKG_LOGE("invalid buffer for decode");
351         return PKG_INVALID_PARAM;
352     }
353 
354     LocalFileHeader* header = reinterpret_cast<LocalFileHeader*>(buffer);
355     header->signature = LOCAL_HEADER_SIGNATURE;
356     header->versionNeeded = 0;
357     header->flags = 0;
358     header->compressionMethod = static_cast<uint16_t>(fileInfo_.method);
359     uint16_t date;
360     uint16_t time;
361     ExtraTimeAndDate(fileInfo_.fileInfo.modifiedTime, date, time);
362     header->modifiedDate = date;
363     header->modifiedTime = time;
364     header->crc = crc32_;
365     header->compressedSize = fileInfo_.fileInfo.packedSize;
366     header->uncompressedSize = fileInfo_.fileInfo.unpackedSize;
367     header->nameSize = nameLen;
368     header->extraSize = 0;
369     if (hasDataDesc) {
370         header->flags |= GPBDD_FLAG_MASK;
371         header->compressedSize = 0u;
372         header->uncompressedSize = 0u;
373         header->crc = 0u;
374     }
375     return PKG_SUCCESS;
376 }
377 
EncodeDataDescriptor(const PkgStreamPtr stream,size_t startOffset,uint32_t & encodeLen) const378 int32_t ZipFileEntry::EncodeDataDescriptor(const PkgStreamPtr stream, size_t startOffset,
379     uint32_t &encodeLen) const
380 {
381     int32_t ret = PKG_SUCCESS;
382     size_t offset = startOffset;
383     DataDescriptor dataDesc = {};
384     dataDesc.signature = DATA_DESC_SIGNATURE;
385     dataDesc.crc = crc32_;
386     dataDesc.compressedSize = fileInfo_.fileInfo.packedSize;
387     dataDesc.uncompressedSize = fileInfo_.fileInfo.unpackedSize;
388     PkgBuffer buffer((uint8_t *)&dataDesc, sizeof(dataDesc));
389     ret = stream->Write(buffer, sizeof(dataDesc), offset);
390     if (ret != PKG_SUCCESS) {
391         PKG_LOGE("Failed to write DataDescriptor for %s", fileInfo_.fileInfo.identity.c_str());
392         return ret;
393     }
394     offset += sizeof(dataDesc);
395     encodeLen = offset - startOffset;
396     return ret;
397 }
398 
399 /*
400     0x0001     2 bytes    Tag for this "extra" block type
401     Size       2 bytes    Size of this "extra" block
402         Original
403     Size       8 bytes    Original uncompressed file size
404     Compressed
405     Size       8 bytes    Size of compressed data
406     Relative Header
407     Offset     8 bytes    Offset of local header record
408     Disk Start
409     Number     4 bytes    Number of the disk on which
410     this file starts
411 */
DecodeCentralDirEntry(PkgStreamPtr inStream,PkgBuffer & buffer,size_t currentPos,size_t & decodeLen)412 int32_t ZipFileEntry::DecodeCentralDirEntry(PkgStreamPtr inStream, PkgBuffer &buffer, size_t currentPos,
413     size_t &decodeLen)
414 {
415     size_t readLen = buffer.length;
416     PKG_CHECK(readLen >= sizeof(CentralDirEntry), return PKG_INVALID_PKG_FORMAT, "data not not enough %zu", readLen);
417     uint32_t signature = ReadLE32(buffer.buffer + offsetof(CentralDirEntry, signature));
418     PKG_CHECK(signature == CENTRAL_SIGNATURE, return PKG_INVALID_PKG_FORMAT,
419         "Check centralDir signature failed 0x%x", signature);
420     uint16_t nameSize = ReadLE16(buffer.buffer + offsetof(CentralDirEntry, nameSize));
421     uint16_t extraSize = ReadLE16(buffer.buffer + offsetof(CentralDirEntry, extraSize));
422     uint16_t commentSize = ReadLE16(buffer.buffer + offsetof(CentralDirEntry, commentSize));
423     size_t currLen = sizeof(CentralDirEntry) + nameSize + extraSize + commentSize;
424     PKG_CHECK(currentPos < (std::numeric_limits<size_t>::max() - currLen),
425         return PKG_INVALID_PKG_FORMAT, "check centralDir len failed");
426 
427     size_t fileNameLength = nameSize;
428     PKG_CHECK(nameSize < MAX_FILE_NAME, fileNameLength = MAX_FILE_NAME - 1, "file name size too longer %d", nameSize);
429     PKG_CHECK(readLen >= sizeof(CentralDirEntry) + fileNameLength, return PKG_INVALID_PKG_FORMAT,
430         "data not not enough %zu", readLen);
431     fileInfo_.fileInfo.identity.assign(reinterpret_cast<char*>(buffer.buffer + sizeof(CentralDirEntry)),
432                                        fileNameLength);
433     fileInfo_.method = static_cast<int32_t>(ReadLE16(buffer.buffer + offsetof(CentralDirEntry, compressionMethod)));
434     uint16_t modifiedTime = ReadLE16(buffer.buffer + offsetof(CentralDirEntry, modifiedTime));
435     uint16_t modifiedDate = ReadLE16(buffer.buffer + offsetof(CentralDirEntry, modifiedDate));
436     CombineTimeAndDate(fileInfo_.fileInfo.modifiedTime, modifiedTime, modifiedDate);
437     crc32_ = ReadLE32(buffer.buffer + offsetof(CentralDirEntry, crc));
438     fileInfo_.fileInfo.packedSize = ReadLE32(buffer.buffer + offsetof(CentralDirEntry, compressedSize));
439     fileInfo_.fileInfo.unpackedSize = ReadLE32(buffer.buffer + offsetof(CentralDirEntry, uncompressedSize));
440     fileInfo_.fileInfo.headerOffset = ReadLE32(buffer.buffer + offsetof(CentralDirEntry, localHeaderOffset));
441     // 对于zip64,需要解析extra field
442     decodeLen = currLen;
443     if (extraSize <= 0) {
444         return PKG_SUCCESS;
445     }
446     uint8_t* extraData = buffer.buffer + nameSize + sizeof(CentralDirEntry);
447     uint16_t headerId = ReadLE16(extraData);
448     if (headerId != 1) { // zip64 扩展
449         return PKG_SUCCESS;
450     }
451     size_t unpackedSize = ReadLE64(extraData + sizeof(uint32_t));
452     size_t packedSize = ReadLE64(extraData + sizeof(uint32_t) + sizeof(uint64_t));
453     if (fileInfo_.fileInfo.packedSize == UINT_MAX || fileInfo_.fileInfo.unpackedSize == UINT_MAX) {
454         fileInfo_.fileInfo.unpackedSize =
455             (fileInfo_.fileInfo.unpackedSize == UINT_MAX) ? unpackedSize : fileInfo_.fileInfo.unpackedSize;
456         fileInfo_.fileInfo.packedSize =
457             (fileInfo_.fileInfo.packedSize == UINT_MAX) ? packedSize : fileInfo_.fileInfo.packedSize;
458         fileInfo_.fileInfo.headerOffset = (fileInfo_.fileInfo.headerOffset == UINT_MAX) ?
459             ReadLE64(extraData + BIG_SIZE_HEADER) : fileInfo_.fileInfo.headerOffset;
460     } else if (fileInfo_.fileInfo.headerOffset == UINT_MAX) {
461         fileInfo_.fileInfo.headerOffset = unpackedSize;
462     }
463 
464     return PKG_SUCCESS;
465 }
466 
DecodeLocalFileHeaderCheck(PkgStreamPtr inStream,const PkgBuffer & data,size_t currentPos)467 int32_t ZipFileEntry::DecodeLocalFileHeaderCheck(PkgStreamPtr inStream, const PkgBuffer &data,
468     size_t currentPos)
469 {
470     uint16_t flags = ReadLE16(data.buffer + offsetof(LocalFileHeader, flags));
471     uint32_t crc32 = ReadLE32(data.buffer + offsetof(LocalFileHeader, crc));
472     uint32_t packedSize = ReadLE32(data.buffer + offsetof(LocalFileHeader, compressedSize));
473     uint32_t unpackedSize = ReadLE32(data.buffer + offsetof(LocalFileHeader, uncompressedSize));
474     size_t readLen = 0;
475     if ((flags & GPBDD_FLAG_MASK) == GPBDD_FLAG_MASK) {
476         currentPos += fileInfo_.fileInfo.packedSize;
477         int ret = inStream->Read(data, currentPos, data.length, readLen);
478         if (ret != PKG_SUCCESS) {
479             PKG_LOGE("parse entry read centralDir failed");
480             return ret;
481         }
482         if (readLen < sizeof(DataDescriptor)) {
483             PKG_LOGE("data not not enough %zu", readLen);
484             return PKG_INVALID_PKG_FORMAT;
485         }
486 
487         uint32_t signature = ReadLE32(data.buffer + offsetof(DataDescriptor, signature));
488         if (signature != DATA_DESC_SIGNATURE) {
489             PKG_LOGE("check DataDescriptor signature failed");
490             return PKG_INVALID_PKG_FORMAT;
491         }
492         crc32 = ReadLE32(data.buffer + offsetof(DataDescriptor, crc));
493         packedSize = ReadLE32(data.buffer + offsetof(DataDescriptor, compressedSize));
494         unpackedSize = ReadLE32(data.buffer + offsetof(DataDescriptor, uncompressedSize));
495     }
496     if (crc32_ != crc32) {
497         PKG_LOGE("check crc %u %u failed", crc32_, crc32);
498         return PKG_INVALID_PKG_FORMAT;
499     }
500     if (packedSize != UINT32_MAX) {
501         if (fileInfo_.fileInfo.packedSize != static_cast<size_t>(packedSize)) {
502             PKG_LOGE("check packedSize %zu %u failed", fileInfo_.fileInfo.packedSize, packedSize);
503             return PKG_INVALID_PKG_FORMAT;
504         }
505         if (fileInfo_.fileInfo.unpackedSize != static_cast<size_t>(unpackedSize)) {
506             PKG_LOGE("check unpackedSize %zu %u failed", fileInfo_.fileInfo.unpackedSize, unpackedSize);
507             return PKG_INVALID_PKG_FORMAT;
508         }
509     }
510     return PKG_SUCCESS;
511 }
512 
DecodeLocalFileHeader(PkgStreamPtr inStream,const PkgBuffer & data,size_t currentPos,size_t & decodeLen)513 int32_t ZipFileEntry::DecodeLocalFileHeader(PkgStreamPtr inStream, const PkgBuffer &data, size_t currentPos,
514     size_t &decodeLen)
515 {
516     size_t readLen = 0;
517     int32_t ret = inStream->Read(data, currentPos, data.length, readLen);
518     PKG_CHECK(ret == PKG_SUCCESS, return ret, "parse entry read centralDir failed");
519     PKG_CHECK(readLen >= sizeof(LocalFileHeader), return PKG_INVALID_PKG_FORMAT, "data not not enough %zu", readLen);
520     uint32_t signature = ReadLE32(data.buffer + offsetof(LocalFileHeader, signature));
521     PKG_CHECK(signature == LOCAL_HEADER_SIGNATURE,
522         return PKG_INVALID_PKG_FORMAT, "check localHeader signature failed");
523 
524     uint16_t nameSize = ReadLE16(data.buffer + offsetof(LocalFileHeader, nameSize));
525     uint16_t extraSize = ReadLE16(data.buffer + offsetof(LocalFileHeader, extraSize));
526     size_t currLen = sizeof(LocalFileHeader) + nameSize + extraSize;
527     PKG_CHECK(currentPos < (std::numeric_limits<size_t>::max() - currLen),
528         return PKG_INVALID_PKG_FORMAT, "check centralDir len failed");
529     size_t fileNameLength = nameSize;
530     PKG_CHECK(nameSize < MAX_FILE_NAME, fileNameLength = MAX_FILE_NAME - 1, "file name size too longer %d", nameSize);
531     PKG_CHECK(readLen >= sizeof(LocalFileHeader) + fileNameLength,
532         return PKG_INVALID_PKG_FORMAT, "data not not enough %zu", readLen);
533     std::string fileName(reinterpret_cast<char*>(data.buffer + sizeof(LocalFileHeader)), fileNameLength);
534     uint16_t compressionMethod = ReadLE16(data.buffer + offsetof(LocalFileHeader, compressionMethod));
535     fileInfo_.method = static_cast<int32_t>(compressionMethod);
536     fileInfo_.level = Z_BEST_COMPRESSION;
537     fileInfo_.method = Z_DEFLATED;
538     fileInfo_.windowBits = -MAX_WBITS;
539     fileInfo_.memLevel = DEF_MEM_LEVEL;
540     fileInfo_.strategy = Z_DEFAULT_STRATEGY;
541     PKG_CHECK(!fileInfo_.fileInfo.identity.compare(fileName), return PKG_INVALID_PKG_FORMAT,
542         "check file name %s %s failed", fileInfo_.fileInfo.identity.c_str(), fileName.c_str());
543     fileName_.assign(fileInfo_.fileInfo.identity);
544     decodeLen = currLen;
545 
546     // 检查解析的是否正确
547     ret = DecodeLocalFileHeaderCheck(inStream, data, currentPos + currLen);
548     if (ret != PKG_SUCCESS) {
549         return ret;
550     }
551     return PKG_SUCCESS;
552 }
553 
Unpack(PkgStreamPtr outStream)554 int32_t ZipFileEntry::Unpack(PkgStreamPtr outStream)
555 {
556     PkgAlgorithm::PkgAlgorithmPtr algorithm = PkgAlgorithmFactory::GetAlgorithm(&fileInfo_.fileInfo);
557     if (algorithm == nullptr) {
558         PKG_LOGE("ZipFileEntry::Unpack : can not algorithm for %s", fileInfo_.fileInfo.identity.c_str());
559         return PKG_INVALID_PARAM;
560     }
561 
562     PkgStreamPtr inStream = pkgFile_->GetPkgStream();
563     if (outStream == nullptr || inStream == nullptr) {
564         PKG_LOGE("ZipFileEntry::Unpack : outStream or inStream null for %s", fileInfo_.fileInfo.identity.c_str());
565         return PKG_INVALID_PARAM;
566     }
567     PkgAlgorithmContext context = {
568         {this->fileInfo_.fileInfo.dataOffset, 0},
569         {fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize},
570         crc32_, fileInfo_.fileInfo.digestMethod
571     };
572     int32_t ret = algorithm->Unpack(inStream, outStream, context);
573     if (ret != PKG_SUCCESS) {
574         PKG_LOGE("Failed to decompress for %s", fileInfo_.fileInfo.identity.c_str());
575         return ret;
576     }
577     PKG_LOGI("packedSize: %zu unpackedSize: %zu  offset header: %zu data: %zu", fileInfo_.fileInfo.packedSize,
578         fileInfo_.fileInfo.unpackedSize, fileInfo_.fileInfo.headerOffset, fileInfo_.fileInfo.dataOffset);
579     outStream->Flush(fileInfo_.fileInfo.unpackedSize);
580     algorithm->UpdateFileInfo(&fileInfo_.fileInfo);
581     return PKG_SUCCESS;
582 }
583 
CombineTimeAndDate(time_t & time,uint16_t modifiedTime,uint16_t modifiedDate) const584 void ZipFileEntry::CombineTimeAndDate(time_t &time, uint16_t modifiedTime, uint16_t modifiedDate) const
585 {
586     struct tm newTime;
587     newTime.tm_year = ((modifiedDate >> TM_YEAR_BITS) & 0x7f) + START_YEAR; // 年,tm_year为int临时变量减去1900。
588     newTime.tm_mon = (modifiedDate >> TM_MON_BITS) & 0xf; // 月,tm_mon为int临时变量减去1。
589     newTime.tm_mday = modifiedDate & 0x1f;         // 日。
590     newTime.tm_hour = (modifiedTime >> TM_HOUR_BITS) & 0x1f; // 时。
591     newTime.tm_min = (modifiedTime >> TM_MIN_BITS) & 0x2f;   // 分。
592     newTime.tm_sec = (modifiedTime << 1) & 0x1f;   // 秒。
593     newTime.tm_isdst = 0;                          // 非夏令时。
594     time = mktime(&newTime);                      // 将tm结构体转换成time_t格式。
595 }
596 
DecodeHeader(const PkgBuffer & buffer,size_t headOffset,size_t dataOffset,size_t & decodeLen)597 int32_t ZipFileEntry::DecodeHeader(const PkgBuffer &buffer, size_t headOffset, size_t dataOffset,
598     size_t &decodeLen)
599 {
600     PkgStreamPtr inStream = pkgFile_->GetPkgStream();
601     if (inStream == nullptr) {
602         PKG_LOGE("outStream or inStream null for %s", fileInfo_.fileInfo.identity.c_str());
603         return PKG_INVALID_PARAM;
604     }
605 
606     if (headOffset >= (std::numeric_limits<size_t>::max() - buffer.length)) {
607         PKG_LOGE("check centralDir len failed");
608         return PKG_INVALID_PKG_FORMAT;
609     }
610     size_t readLen = 0;
611     int32_t ret = inStream->Read(buffer, headOffset, buffer.length, readLen);
612     if (ret != PKG_SUCCESS) {
613         PKG_LOGE("parse entry read centralDir failed");
614         return ret;
615     }
616     PkgBuffer centralBuff(buffer.buffer, readLen);
617     ret = DecodeCentralDirEntry(inStream, centralBuff, headOffset, decodeLen);
618     if (ret != PKG_SUCCESS) {
619         PKG_LOGE("decode CentralDir failed");
620         return ret;
621     }
622 
623     size_t headerLen = 0;
624     ret = DecodeLocalFileHeader(inStream, buffer, fileInfo_.fileInfo.headerOffset, headerLen);
625     if (ret != PKG_SUCCESS) {
626         PKG_LOGE("decode LocalFileHeader failed");
627         return ret;
628     }
629     fileInfo_.fileInfo.packMethod = PKG_DIGEST_TYPE_CRC;
630     fileInfo_.fileInfo.digestMethod = PKG_COMPRESS_METHOD_ZIP;
631     fileInfo_.fileInfo.dataOffset = fileInfo_.fileInfo.headerOffset + headerLen;
632     PKG_LOGI("packedSize: %zu unpackedSize: %zu  offset header: %zu data: %zu %s",
633         fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize,
634         fileInfo_.fileInfo.headerOffset, fileInfo_.fileInfo.dataOffset, fileInfo_.fileInfo.identity.c_str());
635     return PKG_SUCCESS;
636 }
637 
Init(const PkgManager::FileInfoPtr fileInfo,PkgStreamPtr inStream)638 int32_t ZipFileEntry::Init(const PkgManager::FileInfoPtr fileInfo, PkgStreamPtr inStream)
639 {
640     fileInfo_.level = Z_BEST_COMPRESSION;
641     fileInfo_.method = Z_DEFLATED;
642     fileInfo_.windowBits = -MAX_WBITS;
643     fileInfo_.memLevel = DEF_MEM_LEVEL;
644     fileInfo_.strategy = Z_DEFAULT_STRATEGY;
645     int32_t ret = PkgEntry::Init(&fileInfo_.fileInfo, fileInfo, inStream);
646     if (ret != PKG_SUCCESS) {
647         PKG_LOGE("Failed to check input param");
648         return PKG_INVALID_PARAM;
649     }
650     ZipFileInfo* info = reinterpret_cast<ZipFileInfo*>(fileInfo);
651     if (info != nullptr && info->method != -1) {
652         fileInfo_.level = info->level;
653         fileInfo_.memLevel = info->memLevel;
654         fileInfo_.method = info->method;
655         fileInfo_.strategy = info->strategy;
656         fileInfo_.windowBits = info->windowBits;
657     }
658     return PKG_SUCCESS;
659 }
660 } // namespace Hpackage
661