1 /*
2  * Copyright (c) 2023 - 2024 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 "lnn_compress.h"
17 
18 #include <securec.h>
19 #include <zlib.h>
20 
21 #include "softbus_adapter_file.h"
22 #include "softbus_errcode.h"
23 #include "softbus_feature_config.h"
24 #include "softbus_adapter_mem.h"
25 #include "lnn_log.h"
26 
27 #define CHUNK 4096
28 #define GZIP_ENCODING 16
29 #define MAX_WBITS 15
30 #define Z_MEM_LEVEL 8
31 
32 /* compress data by GZIP  */
DataCompress(uint8_t * in,uint32_t inLen,uint8_t ** out,uint32_t * outLen)33 int32_t DataCompress(uint8_t *in, uint32_t inLen, uint8_t **out, uint32_t *outLen)
34 {
35     if ((in == NULL) || (inLen == 0) || (out == NULL) || (outLen == NULL)) {
36         LNN_LOGE(LNN_STATE, "param invalid");
37         return SOFTBUS_INVALID_PARAM;
38     }
39     z_stream strm;
40     int32_t ret = SOFTBUS_OK;
41     uint32_t tmpLen = compressBound(inLen);
42     *out = SoftBusCalloc(tmpLen);
43     if (*out == NULL) {
44         LNN_LOGE(LNN_STATE, "malloc fail.");
45         return SOFTBUS_MALLOC_ERR;
46     }
47 
48     strm.zalloc = Z_NULL;
49     strm.zfree = Z_NULL;
50     strm.opaque = Z_NULL;
51     ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS | GZIP_ENCODING, Z_MEM_LEVEL,
52         Z_DEFAULT_STRATEGY);
53     if (ret != Z_OK) {
54         SoftBusFree(*out);
55         *out = NULL;
56         LNN_LOGE(LNN_STATE, "deflateInit2 fail, ret=%{public}d", ret);
57         return SOFTBUS_ERR;
58     }
59 
60     strm.avail_in = inLen;
61     strm.next_in = in;
62     strm.avail_out = tmpLen;
63     strm.next_out = *out;
64     ret = deflate(&strm, Z_FINISH);
65     if (ret != Z_STREAM_END) {
66         deflateEnd(&strm);
67         SoftBusFree(*out);
68         *out = NULL;
69         LNN_LOGE(LNN_STATE, "deflate fail, ret=%{public}d", ret);
70         return SOFTBUS_ERR;
71     }
72     *outLen = strm.total_out;
73     deflateEnd(&strm);
74     return SOFTBUS_OK;
75 }
76 
PerformInflate(z_stream * strm,uint8_t * in,uint32_t inLen,uint8_t ** out,uint32_t * outLen)77 static int32_t PerformInflate(z_stream *strm, uint8_t *in, uint32_t inLen, uint8_t **out, uint32_t *outLen)
78 {
79     int32_t ret = SOFTBUS_OK;
80     uint32_t chunk = CHUNK;
81     uint32_t bufferSize = chunk;
82     unsigned char *buffer = SoftBusCalloc(bufferSize);
83     if (buffer == NULL) {
84         LNN_LOGE(LNN_STATE, "malloc fail.");
85         return SOFTBUS_MALLOC_ERR;
86     }
87     strm->avail_in = inLen;
88     strm->next_in = in;
89     *outLen = 0;
90     do {
91         strm->avail_out = chunk;
92         if (*outLen + chunk > bufferSize)  {
93             uint32_t newBufferSize = bufferSize * 2;
94             unsigned char *newBuffer = SoftBusCalloc(newBufferSize);
95             if (newBuffer == NULL) {
96                 LNN_LOGE(LNN_STATE, "malloc fail.");
97                 SoftBusFree(buffer);
98                 return SOFTBUS_MALLOC_ERR;
99             }
100             if (memcpy_s(newBuffer, newBufferSize, buffer, *outLen) != EOK) {
101                 LNN_LOGE(LNN_STATE, "memcpy fail.");
102                 SoftBusFree(buffer);
103                 SoftBusFree(newBuffer);
104                 return SOFTBUS_MEM_ERR;
105             }
106             SoftBusFree(buffer);
107             buffer = newBuffer;
108             bufferSize = newBufferSize;
109         }
110         strm->next_out = buffer + *outLen;
111         ret = inflate(strm, Z_NO_FLUSH);
112         if (ret != Z_OK && ret != Z_STREAM_END) {
113             SoftBusFree(buffer);
114             LNN_LOGE(LNN_STATE, "inflate fail, ret=%{public}d", ret);
115             return SOFTBUS_ERR;
116         }
117         *outLen += chunk - strm->avail_out;
118     } while (strm->avail_out == 0);
119     if (ret != Z_STREAM_END) {
120         SoftBusFree(buffer);
121         LNN_LOGE(LNN_STATE, "performInflate fail, ret=%{public}d", ret);
122         return SOFTBUS_ERR;
123     }
124     *out = buffer;
125     return SOFTBUS_OK;
126 }
127 
128 /* decompress data by GZIP */
DataDecompress(uint8_t * in,uint32_t inLen,uint8_t ** out,uint32_t * outLen)129 int32_t DataDecompress(uint8_t *in, uint32_t inLen, uint8_t **out, uint32_t *outLen)
130 {
131     if ((in == NULL) || (inLen == 0) || (out == NULL) || (outLen == NULL)) {
132         LNN_LOGE(LNN_STATE, "param invalid");
133         return SOFTBUS_INVALID_PARAM;
134     }
135     z_stream strm;
136     strm.zalloc = Z_NULL;
137     strm.zfree = Z_NULL;
138     strm.opaque = Z_NULL;
139     strm.avail_in = 0;
140     strm.next_in = Z_NULL;
141     int32_t ret = inflateInit2(&strm, MAX_WBITS | GZIP_ENCODING);
142     if (ret != Z_OK) {
143         LNN_LOGE(LNN_STATE, "inflateInit2 fail, ret=%{public}d", ret);
144         return SOFTBUS_ERR;
145     }
146     ret = PerformInflate(&strm, in, inLen, out, outLen);
147     if (ret != SOFTBUS_OK) {
148         LNN_LOGE(LNN_STATE, "performInflate fail, ret=%{public}d", ret);
149     }
150     inflateEnd(&strm);
151     return ret;
152 }