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
16#include "pkg_lz4file.h"
17#include "pkg_algo_lz4.h"
18
19using namespace std;
20
21namespace Hpackage {
22int32_t Lz4FileEntry::Init(const PkgManager::FileInfoPtr fileInfo, PkgStreamPtr inStream)
23{
24    int32_t ret = PkgEntry::Init(&fileInfo_.fileInfo, fileInfo, inStream);
25    if (ret != PKG_SUCCESS) {
26        PKG_LOGE("Fail to check input param");
27        return PKG_INVALID_PARAM;
28    }
29    Lz4FileInfo *info = (Lz4FileInfo *)fileInfo;
30    if (info != nullptr) {
31        fileInfo_.compressionLevel = info->compressionLevel;
32        fileInfo_.blockIndependence = info->blockIndependence;
33        fileInfo_.blockSizeID = info->blockSizeID;
34        fileInfo_.contentChecksumFlag = info->contentChecksumFlag;
35    }
36    return PKG_SUCCESS;
37}
38
39int32_t Lz4FileEntry::EncodeHeader(PkgStreamPtr inStream, size_t startOffset, size_t &encodeLen)
40{
41    encodeLen = 0;
42    fileInfo_.fileInfo.headerOffset = startOffset;
43    fileInfo_.fileInfo.dataOffset = startOffset;
44    return PKG_SUCCESS;
45}
46
47int32_t Lz4FileEntry::Pack(PkgStreamPtr inStream, size_t startOffset, size_t &encodeLen)
48{
49    PkgAlgorithm::PkgAlgorithmPtr algorithm = PkgAlgorithmFactory::GetAlgorithm(&fileInfo_.fileInfo);
50    PkgStreamPtr outStream = pkgFile_->GetPkgStream();
51    if (fileInfo_.fileInfo.headerOffset != startOffset) {
52        PKG_LOGE("start offset error for %s", fileInfo_.fileInfo.identity.c_str());
53        return PKG_INVALID_PARAM;
54    }
55    if (algorithm == nullptr || outStream == nullptr || inStream == nullptr) {
56        PKG_LOGE("outStream or inStream null for %s", fileInfo_.fileInfo.identity.c_str());
57        return PKG_INVALID_PARAM;
58    }
59    fileInfo_.fileInfo.dataOffset = startOffset;
60    PkgAlgorithmContext context = {
61        {0, startOffset},
62        {fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize},
63        0, fileInfo_.fileInfo.digestMethod
64    };
65    int32_t ret = algorithm->Pack(inStream, outStream, context);
66    if (ret != PKG_SUCCESS) {
67        PKG_LOGE("Fail Compress for %s", fileInfo_.fileInfo.identity.c_str());
68        return ret;
69    }
70    fileInfo_.fileInfo.packedSize = context.packedSize;
71    encodeLen = fileInfo_.fileInfo.packedSize;
72    PKG_LOGI("Pack packedSize:%zu unpackedSize: %zu offset: %zu %zu", fileInfo_.fileInfo.packedSize,
73        fileInfo_.fileInfo.unpackedSize, fileInfo_.fileInfo.headerOffset, fileInfo_.fileInfo.dataOffset);
74    return PKG_SUCCESS;
75}
76
77int32_t Lz4FileEntry::Unpack(PkgStreamPtr outStream)
78{
79    PkgAlgorithm::PkgAlgorithmPtr algorithm = PkgAlgorithmFactory::GetAlgorithm(&fileInfo_.fileInfo);
80    if (algorithm == nullptr) {
81        PKG_LOGE("Lz4FileEntry::Unpack : can not algorithm for %s", fileInfo_.fileInfo.identity.c_str());
82        return PKG_INVALID_PARAM;
83    }
84
85    PkgStreamPtr inStream = pkgFile_->GetPkgStream();
86    if (outStream == nullptr || inStream == nullptr) {
87        PKG_LOGE("Lz4FileEntry::Unpack : outStream or inStream null for %s", fileInfo_.fileInfo.identity.c_str());
88        return PKG_INVALID_PARAM;
89    }
90    PkgAlgorithmContext context = {
91        {fileInfo_.fileInfo.dataOffset, 0},
92        {fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize},
93        0, fileInfo_.fileInfo.digestMethod
94    };
95    int32_t ret = algorithm->Unpack(inStream, outStream, context);
96    if (ret != PKG_SUCCESS) {
97        PKG_LOGE("Failed decompress for %s", fileInfo_.fileInfo.identity.c_str());
98        return ret;
99    }
100    fileInfo_.fileInfo.packedSize = context.packedSize;
101    fileInfo_.fileInfo.unpackedSize = context.unpackedSize;
102    PKG_LOGI("packedSize: %zu unpackedSize: %zu  offset header: %zu data: %zu", fileInfo_.fileInfo.packedSize,
103        fileInfo_.fileInfo.unpackedSize, fileInfo_.fileInfo.headerOffset, fileInfo_.fileInfo.dataOffset);
104    outStream->Flush(fileInfo_.fileInfo.unpackedSize);
105    algorithm->UpdateFileInfo(&fileInfo_.fileInfo);
106    return PKG_SUCCESS;
107}
108
109int32_t Lz4FileEntry::DecodeHeader(PkgBuffer &buffer, size_t headerOffset, size_t dataOffset,
110    size_t &decodeLen)
111{
112    fileInfo_.fileInfo.identity = "lz4_";
113    fileInfo_.fileInfo.identity.append(std::to_string(nodeId_));
114    fileName_ = fileInfo_.fileInfo.identity;
115    fileInfo_.fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
116    uint32_t magicNumber = ReadLE32(buffer.buffer);
117    if (magicNumber == PkgAlgorithmLz4::LZ4S_MAGIC_NUMBER) {
118        fileInfo_.fileInfo.packMethod = PKG_COMPRESS_METHOD_LZ4;
119    } else if (magicNumber == PkgAlgorithmLz4::LZ4B_MAGIC_NUMBER) {
120        fileInfo_.fileInfo.packMethod = PKG_COMPRESS_METHOD_LZ4_BLOCK;
121    }
122    fileInfo_.fileInfo.headerOffset = headerOffset;
123    fileInfo_.fileInfo.dataOffset = dataOffset;
124    fileInfo_.fileInfo.unpackedSize = pkgFile_->GetPkgStream()->GetFileLength();
125    fileInfo_.fileInfo.packedSize = pkgFile_->GetPkgStream()->GetFileLength();
126    return PKG_SUCCESS;
127}
128
129int32_t Lz4PkgFile::AddEntry(const PkgManager::FileInfoPtr file, const PkgStreamPtr inStream)
130{
131    if (file == nullptr || inStream == nullptr) {
132        PKG_LOGE("Fail to check input param");
133        return PKG_INVALID_PARAM;
134    }
135    if (!CheckState({ PKG_FILE_STATE_IDLE, PKG_FILE_STATE_WORKING }, PKG_FILE_STATE_CLOSE)) {
136        PKG_LOGE("error state curr %d ", state_);
137        return PKG_INVALID_STATE;
138    }
139    PKG_LOGI("Add file %s to package", file->identity.c_str());
140
141    Lz4FileEntry *entry = static_cast<Lz4FileEntry *>(AddPkgEntry(file->identity));
142    if (entry == nullptr) {
143        PKG_LOGE("Fail create pkg node for %s", file->identity.c_str());
144        return PKG_NONE_MEMORY;
145    }
146    int32_t ret = entry->Init(file, inStream);
147    if (ret != PKG_SUCCESS) {
148        PKG_LOGE("Fail init entry for %s", file->identity.c_str());
149        return ret;
150    }
151
152    size_t encodeLen = 0;
153    ret = entry->EncodeHeader(inStream, currentOffset_, encodeLen);
154    if (ret != PKG_SUCCESS) {
155        PKG_LOGE("Fail encode header for %s", file->identity.c_str());
156        return ret;
157    }
158    currentOffset_ += encodeLen;
159    ret = entry->Pack(inStream, currentOffset_, encodeLen);
160    if (ret != PKG_SUCCESS) {
161        PKG_LOGE("Fail Pack for %s", file->identity.c_str());
162        return ret;
163    }
164    currentOffset_ += encodeLen;
165    PKG_LOGI("offset:%zu ", currentOffset_);
166    pkgStream_->Flush(currentOffset_);
167    return PKG_SUCCESS;
168}
169
170int32_t Lz4PkgFile::SavePackage(size_t &offset)
171{
172    AddSignData(pkgInfo_.digestMethod, currentOffset_, offset);
173    return PKG_SUCCESS;
174}
175
176int32_t Lz4PkgFile::LoadPackage(std::vector<std::string> &fileNames, VerifyFunction verifier)
177{
178    UNUSED(verifier);
179    if (!CheckState({ PKG_FILE_STATE_IDLE }, PKG_FILE_STATE_WORKING)) {
180        PKG_LOGE("error state curr %d ", state_);
181        return PKG_INVALID_STATE;
182    }
183    PKG_LOGI("LoadPackage %s ", pkgStream_->GetFileName().c_str());
184
185    size_t srcOffset = 0;
186    size_t readLen = 0;
187    PkgBuffer buffer(nullptr, sizeof(PkgAlgorithmLz4::LZ4B_MAGIC_NUMBER));
188    int32_t ret = pkgStream_->Read(buffer, srcOffset, buffer.length, readLen);
189    if (ret != PKG_SUCCESS) {
190        PKG_LOGE("Fail to read buffer");
191        return ret;
192    }
193    if (readLen != sizeof(PkgAlgorithmLz4::LZ4B_MAGIC_NUMBER)) {
194        PKG_LOGE("Fail to read buffer");
195        return PKG_LZ4_FINISH;
196    }
197
198    srcOffset += sizeof(PkgAlgorithmLz4::LZ4B_MAGIC_NUMBER);
199    uint32_t magicNumber = ReadLE32(buffer.buffer);
200    PKG_LOGI("LoadPackage magic 0x%x", magicNumber);
201    ret = PKG_INVALID_FILE;
202    if (magicNumber == PkgAlgorithmLz4::LZ4S_MAGIC_NUMBER ||
203        magicNumber == PkgAlgorithmLz4::LZ4B_MAGIC_NUMBER) {
204        Lz4FileEntry *entry = new Lz4FileEntry(this, nodeId_++);
205        if (entry == nullptr) {
206            PKG_LOGE("Fail create upgrade node for %s", pkgStream_->GetFileName().c_str());
207            return PKG_LZ4_FINISH;
208        }
209        ret = entry->DecodeHeader(buffer, 0, srcOffset, readLen);
210
211        // 保存entry文件
212        pkgEntryMapId_.insert(std::pair<uint32_t, PkgEntryPtr>(entry->GetNodeId(), entry));
213        pkgEntryMapFileName_.insert(std::pair<std::string, PkgEntryPtr>(entry->GetFileName(), entry));
214        fileNames.push_back(entry->GetFileName());
215    }
216    return ret;
217}
218} // namespace Hpackage
219