Coverage Report

Created: 2026-03-30 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/libaec/src/sz_compat.c
Line
Count
Source
1
/**
2
 * @file sz_compat.c
3
 *
4
 * @section LICENSE
5
 * Copyright 2026 Mathis Rosenhauer, Moritz Hanke, Joerg Behrens, Luis Kornblueh
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 *
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above
15
 *    copyright notice, this list of conditions and the following
16
 *    disclaimer in the documentation and/or other materials provided
17
 *    with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30
 * OF THE POSSIBILITY OF SUCH DAMAGE.
31
 *
32
 * @section DESCRIPTION
33
 *
34
 * Adaptive Entropy Coding library
35
 *
36
 */
37
38
#include "config.h"
39
#include "szlib.h"
40
#include <stdio.h>
41
#include <stdlib.h>
42
#include <string.h>
43
44
0
#define NOPTS 129
45
0
#define MIN(a, b) (((a) < (b))? (a): (b))
46
47
static int convert_options(int sz_opts)
48
0
{
49
0
    int co[NOPTS];
50
0
    int opts = 0;
51
52
0
    memset(co, 0, sizeof(int) * NOPTS);
53
0
    co[SZ_MSB_OPTION_MASK] = AEC_DATA_MSB;
54
0
    co[SZ_NN_OPTION_MASK] = AEC_DATA_PREPROCESS;
55
56
0
    for (int i = 1; i < NOPTS; i <<= 1)
57
0
        if (sz_opts & i)
58
0
            opts |= co[i];
59
60
0
    return opts;
61
0
}
62
63
static int bits_to_bytes(int bit_length)
64
0
{
65
0
    if (bit_length > 16)
66
0
        return 4;
67
0
    else if (bit_length > 8)
68
0
        return 2;
69
0
    else
70
0
        return 1;
71
0
}
72
73
static void interleave_buffer(void *dest, const void *src,
74
                              size_t n, size_t wordsize)
75
0
{
76
0
    const unsigned char *src8 = (unsigned char *)src;
77
0
    unsigned char *dest8 = (unsigned char *)dest;
78
79
0
    for (size_t i = 0; i < n / wordsize; i++)
80
0
        for (size_t j = 0; j < wordsize; j++)
81
0
            dest8[j * (n / wordsize) + i] = src8[i * wordsize + j];
82
0
}
83
84
static void deinterleave_buffer(void *dest, const void *src,
85
                                size_t n, size_t wordsize)
86
0
{
87
0
    const unsigned char *src8 = (unsigned char *)src;
88
0
    unsigned char *dest8 = (unsigned char *)dest;
89
90
0
    for (size_t i = 0; i < n / wordsize; i++)
91
0
        for (size_t j = 0; j < wordsize; j++)
92
0
            dest8[i * wordsize + j] = src8[j * (n / wordsize) + i];
93
0
}
94
95
static void add_padding(void *dest, const void *src, size_t src_length,
96
                        size_t line_size, size_t padding_size,
97
                        int pixel_size, int pp)
98
0
{
99
0
    const char zero_pixel[] = {0, 0, 0, 0};
100
101
0
    const char *pixel = zero_pixel;
102
0
    size_t j = 0;
103
0
    size_t i = 0;
104
0
    while (i < src_length) {
105
0
        size_t ps;
106
0
        size_t ls = MIN(src_length - i, line_size);
107
0
        memcpy((char *)dest + j, (char *)src + i, ls);
108
0
        j += ls;
109
0
        i += ls;
110
0
        if (pp)
111
0
            pixel = (char *)src + i - pixel_size;
112
0
        ps = line_size + padding_size - ls;
113
0
        for (size_t k = 0; k < ps; k += pixel_size)
114
0
            memcpy((char *)dest + j + k, pixel, pixel_size);
115
0
        j += ps;
116
0
    }
117
0
}
118
119
static void remove_padding(void *buf, size_t buf_length,
120
                           size_t line_size, size_t padding_size,
121
                           int pixel_size)
122
0
{
123
0
    size_t padded_line_size = line_size + padding_size;
124
125
0
    size_t i = line_size;
126
0
    for (size_t j = padded_line_size; j < buf_length; j += padded_line_size) {
127
0
        memmove((char *)buf + i, (char *)buf + j, line_size);
128
0
        i += line_size;
129
0
    }
130
0
}
131
132
int SZ_BufftoBuffCompress(void *dest, size_t *destLen,
133
                          const void *source, size_t sourceLen,
134
                          SZ_com_t *param)
135
0
{
136
0
    struct aec_stream strm;
137
0
    void *buf = 0;
138
0
    void *padbuf = 0;
139
0
    int status;
140
0
    int interleave;
141
0
    int pixel_size;
142
0
    int aec_status;
143
0
    size_t scanlines;
144
0
    size_t padbuf_size;
145
0
    size_t padding_size;
146
147
0
    if (param->pixels_per_scanline == 0
148
0
        || param->pixels_per_scanline > 4096
149
0
        || param->pixels_per_block == 0
150
0
        || param->pixels_per_block & 1
151
0
        || param->bits_per_pixel == 0
152
0
        || (param->bits_per_pixel > 32 && param->bits_per_pixel != 64))
153
0
        return SZ_PARAM_ERROR;
154
155
0
    strm.block_size = param->pixels_per_block;
156
0
    strm.rsi = (param->pixels_per_scanline + param->pixels_per_block - 1)
157
0
        / param->pixels_per_block;
158
0
    strm.flags = AEC_NOT_ENFORCE | convert_options(param->options_mask);
159
0
    strm.avail_out = *destLen;
160
0
    strm.next_out = dest;
161
162
0
    interleave = param->bits_per_pixel == 32 || param->bits_per_pixel == 64;
163
0
    if (interleave) {
164
0
        strm.bits_per_sample = 8;
165
0
        buf = malloc(sourceLen);
166
0
        if (buf == NULL) {
167
0
            status = SZ_MEM_ERROR;
168
0
            goto CLEANUP;
169
0
        }
170
0
        interleave_buffer(buf, source, sourceLen, param->bits_per_pixel / 8);
171
0
    } else {
172
0
        strm.bits_per_sample = param->bits_per_pixel;
173
0
        buf = (void *)source;
174
0
    }
175
176
0
    pixel_size = bits_to_bytes(strm.bits_per_sample);
177
0
    if (sourceLen % pixel_size != 0) {
178
0
        status = SZ_PARAM_ERROR;
179
0
        goto CLEANUP;
180
0
    }
181
182
0
    scanlines = (sourceLen / pixel_size + param->pixels_per_scanline - 1)
183
0
        / param->pixels_per_scanline;
184
0
    padbuf_size = strm.rsi * strm.block_size * pixel_size * scanlines;
185
0
    padbuf = malloc(padbuf_size);
186
0
    if (padbuf == NULL) {
187
0
        status = SZ_MEM_ERROR;
188
0
        goto CLEANUP;
189
0
    }
190
191
0
    padding_size =
192
0
        (strm.rsi * strm.block_size - param->pixels_per_scanline)
193
0
        * pixel_size;
194
195
0
    add_padding(padbuf, buf, sourceLen,
196
0
                param->pixels_per_scanline * pixel_size,
197
0
                padding_size, pixel_size,
198
0
                strm.flags & AEC_DATA_PREPROCESS);
199
0
    strm.next_in = padbuf;
200
0
    strm.avail_in = padbuf_size;
201
202
0
    aec_status = aec_buffer_encode(&strm);
203
0
    if (aec_status == AEC_STREAM_ERROR)
204
0
        status = SZ_OUTBUFF_FULL;
205
0
    else
206
0
        status = aec_status;
207
0
    *destLen = strm.total_out;
208
209
0
CLEANUP:
210
0
    if (padbuf)
211
0
        free(padbuf);
212
0
    if (interleave && buf)
213
0
        free(buf);
214
0
    return status;
215
0
}
216
217
int SZ_BufftoBuffDecompress(void *dest, size_t *destLen,
218
                            const void *source, size_t sourceLen,
219
                            SZ_com_t *param)
220
0
{
221
0
    struct aec_stream strm;
222
0
    void *buf = 0;
223
0
    int status;
224
0
    int pad_scanline;
225
0
    int deinterleave;
226
0
    int extra_buffer;
227
0
    int pixel_size;
228
0
    size_t total_out;
229
0
    size_t scanlines;
230
231
0
    if (param->pixels_per_scanline == 0
232
0
        || param->pixels_per_block == 0
233
0
        || param->pixels_per_block & 1
234
0
        || param->bits_per_pixel == 0
235
0
        || (param->bits_per_pixel > 32 && param->bits_per_pixel != 64))
236
0
        return SZ_PARAM_ERROR;
237
238
0
    strm.block_size = param->pixels_per_block;
239
0
    strm.rsi = (param->pixels_per_scanline + param->pixels_per_block - 1)
240
0
        / param->pixels_per_block;
241
0
    strm.flags = convert_options(param->options_mask);
242
0
    strm.avail_in = sourceLen;
243
0
    strm.next_in = source;
244
245
0
    pad_scanline = param->pixels_per_scanline % param->pixels_per_block;
246
0
    deinterleave = (param->bits_per_pixel == 32
247
0
                        || param->bits_per_pixel == 64);
248
0
    extra_buffer = pad_scanline || deinterleave;
249
250
0
    if (deinterleave)
251
0
        strm.bits_per_sample = 8;
252
0
    else
253
0
        strm.bits_per_sample = param->bits_per_pixel;
254
0
    pixel_size = bits_to_bytes(strm.bits_per_sample);
255
256
257
0
    if (extra_buffer) {
258
0
        size_t buf_size;
259
0
        if (pad_scanline) {
260
0
            scanlines = (*destLen / pixel_size + param->pixels_per_scanline - 1)
261
0
                / param->pixels_per_scanline;
262
0
            buf_size = strm.rsi * strm.block_size * pixel_size * scanlines;
263
0
        } else {
264
0
            buf_size = *destLen;
265
0
        }
266
0
        buf = malloc(buf_size);
267
0
        if (buf == NULL) {
268
0
            status = SZ_MEM_ERROR;
269
0
            goto CLEANUP;
270
0
        }
271
0
        strm.next_out = buf;
272
0
        strm.avail_out = buf_size;
273
0
    } else {
274
0
        strm.next_out = dest;
275
0
        strm.avail_out = *destLen;
276
0
    }
277
278
0
    status = aec_buffer_decode(&strm);
279
0
    if (status != AEC_OK)
280
0
        goto CLEANUP;
281
282
0
    if (pad_scanline) {
283
0
        size_t padding_size =
284
0
            (strm.rsi * strm.block_size - param->pixels_per_scanline)
285
0
            * pixel_size;
286
0
        remove_padding(buf, strm.total_out,
287
0
                       param->pixels_per_scanline * pixel_size,
288
0
                       padding_size, pixel_size);
289
0
        total_out = scanlines * param->pixels_per_scanline * pixel_size;
290
0
    } else {
291
0
        total_out = strm.total_out;
292
0
    }
293
294
0
    if (total_out < *destLen)
295
0
        *destLen = total_out;
296
297
0
    if (deinterleave)
298
0
        deinterleave_buffer(dest, buf, *destLen, param->bits_per_pixel / 8);
299
0
    else if (pad_scanline)
300
0
        memcpy(dest, buf, *destLen);
301
302
0
CLEANUP:
303
0
    if (extra_buffer && buf)
304
0
        free(buf);
305
306
0
    return status;
307
0
}
308
309
int SZ_encoder_enabled(void)
310
9
{
311
9
    return 1;
312
9
}
313
314
/* netcdf searches for SZ_Compress in configure */
315
0
char SZ_Compress() { return SZ_OK; }