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