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 "zip_adapter.h"
17#include <iostream>
18#include <vector>
19#include "zlib.h"
20
21using namespace Hpackage;
22
23namespace UpdatePatch {
24ZipAdapter::ZipAdapter(UpdatePatchWriterPtr outStream, size_t offset, const PkgManager::FileInfoPtr fileInfo)
25    : DeflateAdapter(), outStream_(outStream), offset_(offset)
26{
27    const Hpackage::ZipFileInfo *info = (const Hpackage::ZipFileInfo *)fileInfo;
28    method_ = info->method;
29    level_ = info->level;
30    windowBits_ = info->windowBits;
31    memLevel_ = info->memLevel;
32    strategy_ = info->strategy;
33}
34
35int32_t ZipAdapter::Open()
36{
37    if (init_) {
38        PATCH_LOGE("Has been open");
39        return 0;
40    }
41    if (memset_s(&zstream_, sizeof(zstream_), 0, sizeof(z_stream)) != EOK) {
42        PATCH_LOGE("Failed to memset stream");
43        return -1;
44    }
45    PATCH_DEBUG("Open level_:%d method_:%d windowBits_:%d memLevel_:%d strategy_:%d",
46        level_, method_, windowBits_, memLevel_, strategy_);
47    int32_t ret = deflateInit2(&zstream_, level_, method_, windowBits_, memLevel_, strategy_);
48    if (ret != Z_OK) {
49        PATCH_LOGE("Failed to deflateInit2 ret %d", ret);
50        return -1;
51    }
52    buffer_.resize(BUFFER_SIZE);
53    init_ = true;
54    return ret;
55}
56
57int32_t ZipAdapter::Close()
58{
59    if (!init_) {
60        PATCH_LOGE("Has been close");
61        return 0;
62    }
63    int32_t ret = deflateEnd(&zstream_);
64    if (ret != Z_OK) {
65        PATCH_LOGE("Failed to deflateEnd %d", ret);
66        return -1;
67    }
68    init_ = false;
69    return ret;
70}
71
72int32_t ZipAdapter::WriteData(const BlockBuffer &srcData)
73{
74    zstream_.next_in = srcData.buffer;
75    zstream_.avail_in = static_cast<uint32_t>(srcData.length);
76    zstream_.avail_out =  static_cast<uint32_t>(buffer_.size());
77    zstream_.next_out = reinterpret_cast<unsigned char*>(buffer_.data());
78    size_t deflateLen = 0;
79    int32_t ret = Z_OK;
80    do {
81        ret = deflate(&zstream_, Z_NO_FLUSH);
82        deflateLen = buffer_.size() -  zstream_.avail_out;
83        if (deflateLen > 0) {
84            ret = outStream_->Write(offset_, {buffer_.data(), deflateLen}, deflateLen);
85            if (ret != 0) {
86                PATCH_LOGE("Failed to deflate data");
87                return -1;
88            }
89            offset_ += deflateLen;
90
91            zstream_.next_out = reinterpret_cast<unsigned char*>(buffer_.data());
92            zstream_.avail_out = buffer_.size();
93        }
94        if (zstream_.avail_in == 0) {
95            break;
96        }
97    } while (ret == Z_OK);
98    if (ret != Z_OK) {
99        PATCH_LOGE("WriteData : Failed to write data ret %d", ret);
100        return ret;
101    }
102    if (zstream_.avail_in != 0) {
103        PATCH_LOGE("WriteData : Failed to write data");
104        return ret;
105    }
106    return ret;
107}
108
109int32_t ZipAdapter::FlushData(size_t &offset)
110{
111    zstream_.next_in = nullptr;
112    zstream_.avail_in = 0;
113    zstream_.avail_out =  buffer_.size();
114    zstream_.next_out = reinterpret_cast<unsigned char*>(buffer_.data());
115    size_t deflateLen = 0;
116    int32_t ret = Z_OK;
117    do {
118        ret = deflate(&zstream_, Z_FINISH);
119        deflateLen = buffer_.size() -  zstream_.avail_out;
120        if (deflateLen > 0) {
121            ret = outStream_->Write(offset_, {buffer_.data(), deflateLen}, deflateLen);
122            if (ret != 0) {
123                PATCH_LOGE("Failed to deflate data");
124                return 1;
125            }
126            offset_ += deflateLen;
127
128            zstream_.next_out = reinterpret_cast<unsigned char*>(buffer_.data());
129            zstream_.avail_out = buffer_.size();
130        }
131        if (ret == Z_STREAM_END) {
132            ret = Z_OK;
133            break;
134        }
135    } while (ret == Z_OK);
136    if (ret != Z_OK) {
137        PATCH_LOGE("FlushData : Failed to write data ret %d", ret);
138        return ret;
139    }
140    if (zstream_.avail_in != 0) {
141        PATCH_LOGE("FlushData : Failed to write data");
142        return ret;
143    }
144    offset = offset_;
145    return ret;
146}
147} // namespace UpdatePatch
148