• 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_algo_deflate.h"
16 #include "pkg_stream.h"
17 #include "pkg_utils.h"
18 #include "securec.h"
19 #include "zlib.h"
20 
21 namespace Hpackage {
22 constexpr uint8_t INFLATE_ERROR_TIMES = 5;
23 constexpr uint32_t IN_BUFFER_SIZE = 1024 * 64;
24 constexpr uint32_t OUT_BUFFER_SIZE = 1024 * 32;
25 
DeflateData(const PkgStreamPtr outStream,z_stream & zstream,int32_t flush,PkgBuffer & outBuffer,size_t & destOffset) const26 int32_t PkgAlgoDeflate::DeflateData(const PkgStreamPtr outStream, z_stream &zstream, int32_t flush,
27     PkgBuffer &outBuffer, size_t &destOffset) const
28 {
29     int32_t ret = Z_OK;
30     do {
31         size_t deflateLen = 0;
32         ret = deflate(&zstream, flush);
33         if (ret < Z_OK) {
34             PKG_LOGE("deflate finish error ret1 %d", ret);
35             return PKG_NOT_EXIST_ALGORITHM;
36         }
37         deflateLen += outBuffer.length - zstream.avail_out;
38         if (deflateLen > 0) {
39             int32_t ret1 = outStream->Write(outBuffer, deflateLen, destOffset);
40             if (ret1 != PKG_SUCCESS) {
41                 PKG_LOGE("error write data deflateLen: %zu", deflateLen);
42                 break;
43             }
44             destOffset += deflateLen;
45             zstream.next_out = outBuffer.buffer;
46             zstream.avail_out = outBuffer.length;
47         }
48         if (flush == Z_NO_FLUSH) {
49             break;
50         }
51     } while (ret == Z_OK && flush == Z_FINISH);
52     return PKG_SUCCESS;
53 }
54 
Pack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)55 int32_t PkgAlgoDeflate::Pack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
56     PkgAlgorithmContext &context)
57 {
58     DigestAlgorithm::DigestAlgorithmPtr algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(context.digestMethod);
59     PKG_CHECK(algorithm != nullptr, return PKG_NOT_EXIST_ALGORITHM, "Can not get digest algor");
60     PKG_CHECK(inStream != nullptr && outStream != nullptr, return PKG_INVALID_PARAM, "Param context null!");
61 
62     PkgBuffer inBuffer = {};
63     PkgBuffer outBuffer = {};
64     z_stream zstream;
65     int32_t ret = InitStream(zstream, true, inBuffer, outBuffer);
66     PKG_CHECK(ret == PKG_SUCCESS, return ret, "fail InitStream ");
67     size_t remainSize = context.unpackedSize;
68     uint32_t crc = 0;
69     size_t srcOffset = context.srcOffset;
70     size_t destOffset = context.destOffset;
71     PkgBuffer crcResult((uint8_t *)&crc, sizeof(crc));
72 
73     while ((remainSize > 0) || (zstream.avail_in > 0)) {
74         size_t readLen = 0;
75         if (zstream.avail_in == 0) {
76             ret = ReadData(inStream, srcOffset, inBuffer, remainSize, readLen);
77             PKG_CHECK(ret == PKG_SUCCESS, break, "Read data fail!");
78             zstream.next_in = reinterpret_cast<unsigned char *>(inBuffer.buffer);
79             zstream.avail_in = readLen;
80             srcOffset += readLen;
81             // Calculate CRC of original file
82             algorithm->Calculate(crcResult, inBuffer, readLen);
83         }
84         ret = DeflateData(outStream, zstream, ((remainSize == 0) ? Z_FINISH : Z_NO_FLUSH), outBuffer, destOffset);
85         PKG_CHECK(ret == PKG_SUCCESS, break, "error write data deflateLen: %zu", destOffset);
86     }
87     ReleaseStream(zstream, true);
88     PKG_CHECK(ret == PKG_SUCCESS, return ret, "error write data");
89     PKG_CHECK(srcOffset == context.unpackedSize, return PKG_INVALID_PKG_FORMAT,
90         "original size error %zu %zu", srcOffset, context.unpackedSize);
91     context.crc = crc;
92     context.packedSize = destOffset - context.destOffset;
93     return ret;
94 }
95 
UnpackCalculate(PkgAlgorithmContext & context,const PkgStreamPtr inStream,const PkgStreamPtr outStream,DigestAlgorithm::DigestAlgorithmPtr algorithm)96 int32_t PkgAlgoDeflate::UnpackCalculate(PkgAlgorithmContext &context, const PkgStreamPtr inStream,
97     const PkgStreamPtr outStream, DigestAlgorithm::DigestAlgorithmPtr algorithm)
98 {
99     z_stream zstream;
100     PkgBuffer inBuffer = {};
101     PkgBuffer outBuffer = {};
102     int32_t ret = InitStream(zstream, false, inBuffer, outBuffer);
103     PKG_CHECK(ret == PKG_SUCCESS, return ret, "fail InitStream ");
104     size_t inflateLen = 0;
105     uint32_t errorTimes = 0;
106     uint32_t crc = 0;
107 
108     PkgBuffer crcResult((uint8_t *)&crc, sizeof(crc));
109     size_t remainCompressedSize = context.packedSize;
110     size_t srcOffset = context.srcOffset;
111     size_t destOffset = context.destOffset;
112     size_t readLen = 0;
113     while ((remainCompressedSize > 0) || (zstream.avail_in > 0)) {
114         if (zstream.avail_in == 0) {
115             ret = ReadData(inStream, srcOffset, inBuffer, remainCompressedSize, readLen);
116             PKG_CHECK(ret == PKG_SUCCESS, break, "Read data fail!");
117             zstream.next_in = reinterpret_cast<uint8_t *>(inBuffer.buffer);
118             zstream.avail_in = readLen;
119             srcOffset += readLen;
120         }
121 
122         ret = inflate(&zstream, Z_SYNC_FLUSH);
123         PKG_CHECK(ret >= Z_OK, break, "fail inflate ret:%d", ret);
124         inflateLen = outBuffer.length - zstream.avail_out;
125         errorTimes++;
126         if (inflateLen > 0) {
127             ret = outStream->Write(outBuffer, inflateLen, destOffset);
128             PKG_CHECK(ret == PKG_SUCCESS, break, "write data is fail!");
129             destOffset += inflateLen;
130             zstream.next_out = outBuffer.buffer;
131             zstream.avail_out = outBuffer.length;
132 
133             errorTimes = 0;
134             algorithm->Calculate(crcResult, outBuffer, inflateLen);
135         }
136         if (ret == Z_STREAM_END) {
137             break;
138         }
139         PKG_CHECK(errorTimes < INFLATE_ERROR_TIMES, break, "unzip inflated data is abnormal!");
140     }
141     ReleaseStream(zstream, false);
142     context.packedSize = context.packedSize - zstream.avail_in - remainCompressedSize;
143     context.unpackedSize = destOffset - context.destOffset;
144     PKG_CHECK(0 == context.crc || crc == context.crc, return ret, "crc fail %u %u!", crc, context.crc);
145     context.crc = crc;
146     return (ret == Z_STREAM_END) ? PKG_SUCCESS : ret;
147 }
148 
Unpack(const PkgStreamPtr inStream,const PkgStreamPtr outStream,PkgAlgorithmContext & context)149 int32_t PkgAlgoDeflate::Unpack(const PkgStreamPtr inStream, const PkgStreamPtr outStream,
150     PkgAlgorithmContext &context)
151 {
152     DigestAlgorithm::DigestAlgorithmPtr algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(context.digestMethod);
153     if (algorithm == nullptr) {
154         PKG_LOGE("Can not get digest algor");
155         return PKG_NOT_EXIST_ALGORITHM;
156     }
157     if (inStream == nullptr || outStream == nullptr) {
158         PKG_LOGE("Param context null!");
159         return PKG_INVALID_PARAM;
160     }
161 
162     return UnpackCalculate(context, inStream, outStream, algorithm);
163 }
164 
InitStream(z_stream & zstream,bool zip,PkgBuffer & inBuffer,PkgBuffer & outBuffer)165 int32_t PkgAlgoDeflate::InitStream(z_stream &zstream, bool zip, PkgBuffer &inBuffer, PkgBuffer &outBuffer)
166 {
167     int32_t ret = PKG_SUCCESS;
168     // init zlib stream
169     if (memset_s(&zstream, sizeof(z_stream), 0, sizeof(z_stream)) != EOK) {
170         PKG_LOGE("memset fail");
171         return PKG_NONE_MEMORY;
172     }
173     if (zip) {
174         PKG_LOGI("InitStream level_:%d method_:%d windowBits_:%d memLevel_:%d strategy_:%d",
175             level_, method_, windowBits_, memLevel_, strategy_);
176         ret = deflateInit2(&zstream, level_, method_, windowBits_, memLevel_, strategy_);
177         if (ret != Z_OK) {
178             PKG_LOGE("fail deflateInit2 ret %d", ret);
179             return PKG_NOT_EXIST_ALGORITHM;
180         }
181         inBuffer.length = IN_BUFFER_SIZE;
182         outBuffer.length = OUT_BUFFER_SIZE;
183     } else {
184         ret = inflateInit2(&zstream, windowBits_);
185         if (ret != Z_OK) {
186             PKG_LOGE("fail deflateInit2");
187             return PKG_NOT_EXIST_ALGORITHM;
188         }
189         inBuffer.length = IN_BUFFER_SIZE;
190         outBuffer.length = OUT_BUFFER_SIZE;
191     }
192 
193     inBuffer.data.resize(inBuffer.length);
194     outBuffer.data.resize(outBuffer.length);
195     inBuffer.buffer = reinterpret_cast<uint8_t *>(inBuffer.data.data());
196     outBuffer.buffer = reinterpret_cast<uint8_t *>(outBuffer.data.data());
197     zstream.next_out = outBuffer.buffer;
198     zstream.avail_out = outBuffer.length;
199     return PKG_SUCCESS;
200 }
201 
ReleaseStream(z_stream & zstream,bool zip) const202 void PkgAlgoDeflate::ReleaseStream(z_stream &zstream, bool zip) const
203 {
204     int32_t ret = Z_OK;
205     if (zip) {
206         ret = deflateEnd(&zstream);
207         if (ret != Z_OK) {
208             PKG_LOGE("fail deflateEnd %d", ret);
209             return;
210         }
211     } else {
212         ret = inflateEnd(&zstream);
213         if (ret != Z_OK) {
214             PKG_LOGE("fail inflateEnd %d", ret);
215             return;
216         }
217     }
218 }
219 } // namespace Hpackage
220