#include #include #include #if HAVE_CONFIG_H # include #endif #include "szlib.h" #define NOPTS 129 #define MIN(a, b) (((a) < (b))? (a): (b)) static int convert_options(int sz_opts) { int co[NOPTS]; int opts = 0; memset(co, 0, sizeof(int) * NOPTS); co[SZ_MSB_OPTION_MASK] = AEC_DATA_MSB; co[SZ_NN_OPTION_MASK] = AEC_DATA_PREPROCESS; for (int i = 1; i < NOPTS; i <<= 1) if (sz_opts & i) opts |= co[i]; return opts; } static int bits_to_bytes(int bit_length) { if (bit_length > 16) return 4; else if (bit_length > 8) return 2; else return 1; } static void interleave_buffer(void *dest, const void *src, size_t n, int wordsize) { const unsigned char *src8 = (unsigned char *)src; unsigned char *dest8 = (unsigned char *)dest; for (size_t i = 0; i < n / wordsize; i++) for (size_t j = 0; j < wordsize; j++) dest8[j * (n / wordsize) + i] = src8[i * wordsize + j]; } static void deinterleave_buffer(void *dest, const void *src, size_t n, int wordsize) { const unsigned char *src8 = (unsigned char *)src; unsigned char *dest8 = (unsigned char *)dest; for (size_t i = 0; i < n / wordsize; i++) for (size_t j = 0; j < wordsize; j++) dest8[i * wordsize + j] = src8[j * (n / wordsize) + i]; } static void add_padding(void *dest, const void *src, size_t src_length, size_t line_size, size_t padding_size, int pixel_size, int pp) { const char zero_pixel[] = {0, 0, 0, 0}; const char *pixel = zero_pixel; size_t j = 0; size_t i = 0; while (i < src_length) { size_t ps; size_t ls = MIN(src_length - i, line_size); memcpy((char *)dest + j, (char *)src + i, ls); j += ls; i += ls; if (pp) pixel = (char *)src + i - pixel_size; ps = line_size + padding_size - ls; for (size_t k = 0; k < ps; k += pixel_size) memcpy((char *)dest + j + k, pixel, pixel_size); j += ps; } } static void remove_padding(void *buf, size_t buf_length, size_t line_size, size_t padding_size, int pixel_size) { size_t padded_line_size = line_size + padding_size; size_t i = line_size; for (size_t j = padded_line_size; j < buf_length; j += padded_line_size) { memmove((char *)buf + i, (char *)buf + j, line_size); i += line_size; } } int SZ_BufftoBuffCompress(void *dest, size_t *destLen, const void *source, size_t sourceLen, SZ_com_t *param) { struct aec_stream strm; void *buf = 0; void *padbuf = 0; int status; int interleave; int pixel_size; int aec_status; size_t scanlines; size_t padbuf_size; size_t padding_size; strm.block_size = param->pixels_per_block; strm.rsi = (param->pixels_per_scanline + param->pixels_per_block - 1) / param->pixels_per_block; strm.flags = AEC_NOT_ENFORCE | convert_options(param->options_mask); strm.avail_out = *destLen; strm.next_out = dest; interleave = param->bits_per_pixel == 32 || param->bits_per_pixel == 64; if (interleave) { strm.bits_per_sample = 8; buf = malloc(sourceLen); if (buf == NULL) { status = SZ_MEM_ERROR; goto CLEANUP; } interleave_buffer(buf, source, sourceLen, param->bits_per_pixel / 8); } else { strm.bits_per_sample = param->bits_per_pixel; buf = (void *)source; } pixel_size = bits_to_bytes(strm.bits_per_sample); scanlines = (sourceLen / pixel_size + param->pixels_per_scanline - 1) / param->pixels_per_scanline; padbuf_size = strm.rsi * strm.block_size * pixel_size * scanlines; padbuf = malloc(padbuf_size); if (padbuf == NULL) { status = SZ_MEM_ERROR; goto CLEANUP; } padding_size = (strm.rsi * strm.block_size - param->pixels_per_scanline) * pixel_size; add_padding(padbuf, buf, sourceLen, param->pixels_per_scanline * pixel_size, padding_size, pixel_size, strm.flags & AEC_DATA_PREPROCESS); strm.next_in = padbuf; strm.avail_in = padbuf_size; aec_status = aec_buffer_encode(&strm); if (aec_status == AEC_STREAM_ERROR) status = SZ_OUTBUFF_FULL; else status = aec_status; *destLen = strm.total_out; CLEANUP: if (padbuf) free(padbuf); if (interleave && buf) free(buf); return status; } int SZ_BufftoBuffDecompress(void *dest, size_t *destLen, const void *source, size_t sourceLen, SZ_com_t *param) { struct aec_stream strm; void *buf = 0; int status; int pad_scanline; int deinterleave; int extra_buffer; int pixel_size; size_t total_out; size_t scanlines; strm.block_size = param->pixels_per_block; strm.rsi = (param->pixels_per_scanline + param->pixels_per_block - 1) / param->pixels_per_block; strm.flags = convert_options(param->options_mask); strm.avail_in = sourceLen; strm.next_in = source; pad_scanline = param->pixels_per_scanline % param->pixels_per_block; deinterleave = (param->bits_per_pixel == 32 || param->bits_per_pixel == 64); extra_buffer = pad_scanline || deinterleave; if (deinterleave) strm.bits_per_sample = 8; else strm.bits_per_sample = param->bits_per_pixel; pixel_size = bits_to_bytes(strm.bits_per_sample); if (extra_buffer) { size_t buf_size; if (pad_scanline) { scanlines = (*destLen / pixel_size + param->pixels_per_scanline - 1) / param->pixels_per_scanline; buf_size = strm.rsi * strm.block_size * pixel_size * scanlines; } else { buf_size = *destLen; } buf = malloc(buf_size); if (buf == NULL) { status = SZ_MEM_ERROR; goto CLEANUP; } strm.next_out = buf; strm.avail_out = buf_size; } else { strm.next_out = dest; strm.avail_out = *destLen; } status = aec_buffer_decode(&strm); if (status != AEC_OK) goto CLEANUP; if (pad_scanline) { size_t padding_size = (strm.rsi * strm.block_size - param->pixels_per_scanline) * pixel_size; remove_padding(buf, strm.total_out, param->pixels_per_scanline * pixel_size, padding_size, pixel_size); total_out = scanlines * param->pixels_per_scanline * pixel_size; } else { total_out = strm.total_out; } if (total_out < *destLen) *destLen = total_out; if (deinterleave) deinterleave_buffer(dest, buf, *destLen, param->bits_per_pixel / 8); else if (pad_scanline) memcpy(dest, buf, *destLen); CLEANUP: if (extra_buffer && buf) free(buf); return status; } int SZ_encoder_enabled(void) { return 1; } /* netcdf searches for SZ_Compress in configure */ char SZ_Compress() { return SZ_OK; }