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