/*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except idata compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to idata writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file prefix.h * */ #ifndef XM_LZ4_PREFIX_H #define XM_LZ4_PREFIX_H /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../prefix.h" #include "lz4frame.h" #include "lz4.h" #include "lz4hc.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // we need to define LZ4_byte if < 1.9.3 #if defined(LZ4_VERSION_NUMBER) && LZ4_VERSION_NUMBER < (1 * 100 * 100 + 9 * 100 + 3) #if defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) #include typedef int8_t LZ4_i8; typedef uint8_t LZ4_byte; typedef uint16_t LZ4_u16; typedef uint32_t LZ4_u32; #else typedef signed char LZ4_i8; typedef unsigned char LZ4_byte; typedef unsigned short LZ4_u16; typedef unsigned int LZ4_u32; #endif #endif /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the lz4 compress stream type typedef struct __xm_lz4_cstream_t { LZ4F_cctx *cctx; LZ4_byte *buffer; tb_size_t buffer_size; tb_size_t buffer_maxn; tb_size_t write_maxn; tb_size_t header_size; LZ4_byte header[LZ4F_HEADER_SIZE_MAX]; } xm_lz4_cstream_t; // the lz4 decompress stream type typedef struct __xm_lz4_dstream_t { LZ4F_dctx *dctx; LZ4_byte *buffer; tb_size_t buffer_size; tb_size_t buffer_maxn; tb_size_t header_size; LZ4_byte header[LZ4F_HEADER_SIZE_MAX]; } xm_lz4_dstream_t; /* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ static __tb_inline__ tb_void_t xm_lz4_cstream_exit(xm_lz4_cstream_t *stream) { if (stream) { if (stream->cctx) { LZ4F_freeCompressionContext(stream->cctx); stream->cctx = tb_null; } if (stream->buffer) { tb_free(stream->buffer); stream->buffer = tb_null; } tb_free(stream); } } static __tb_inline__ xm_lz4_cstream_t *xm_lz4_cstream_init() { tb_size_t ret; tb_bool_t ok = tb_false; xm_lz4_cstream_t *stream = tb_null; LZ4F_preferences_t const *prefsPtr = tb_null; do { stream = tb_malloc0_type(xm_lz4_cstream_t); tb_assert_and_check_break(stream); stream->write_maxn = 64 * 1024; stream->buffer_maxn = LZ4F_compressBound(stream->write_maxn, prefsPtr); stream->buffer = (LZ4_byte *)tb_malloc(stream->buffer_maxn); tb_assert_and_check_break(stream->buffer); ret = LZ4F_createCompressionContext(&stream->cctx, LZ4F_getVersion()); if (LZ4F_isError(ret)) break; ret = LZ4F_compressBegin(stream->cctx, stream->header, LZ4F_HEADER_SIZE_MAX, prefsPtr); if (LZ4F_isError(ret)) break; stream->header_size = ret; ok = tb_true; } while (0); if (!ok && stream) { xm_lz4_cstream_exit(stream); stream = tb_null; } return stream; } static __tb_inline__ tb_long_t xm_lz4_cstream_write(xm_lz4_cstream_t *stream, tb_byte_t const *idata, tb_size_t isize, tb_bool_t end) { tb_assert_and_check_return_val(stream && stream->cctx && idata && isize, -1); tb_assert_and_check_return_val(isize <= stream->write_maxn, -1); tb_assert_and_check_return_val(stream->buffer_size + isize < stream->buffer_maxn, -1); tb_size_t real = LZ4F_compressUpdate(stream->cctx, stream->buffer + stream->buffer_size, stream->buffer_maxn - stream->buffer_size, idata, isize, tb_null); if (LZ4F_isError(real)) return -1; stream->buffer_size += real; if (end) { tb_size_t ret = LZ4F_compressEnd(stream->cctx, stream->buffer + stream->buffer_size, stream->buffer_maxn - stream->buffer_size, tb_null); if (LZ4F_isError(ret)) return -1; real += ret; stream->buffer_size += ret; } return isize; } static __tb_inline__ tb_long_t xm_lz4_cstream_read(xm_lz4_cstream_t *stream, tb_byte_t *odata, tb_size_t osize) { tb_assert_and_check_return_val(stream && stream->cctx && odata && osize, -1); tb_assert_and_check_return_val(osize >= stream->header_size, -1); tb_size_t read = 0; if (stream->header_size) { tb_memcpy(odata, stream->header, stream->header_size); read += stream->header_size; osize -= stream->header_size; stream->header_size = 0; } tb_size_t need = tb_min(stream->buffer_size, osize); tb_memcpy(odata + read, stream->buffer, need); if (need < stream->buffer_size) tb_memmov(stream->buffer, stream->buffer + need, stream->buffer_size - need); stream->buffer_size -= need; read += need; return read; } static __tb_inline__ tb_void_t xm_lz4_dstream_exit(xm_lz4_dstream_t *stream) { if (stream) { if (stream->dctx) { LZ4F_freeDecompressionContext(stream->dctx); stream->dctx = tb_null; } if (stream->buffer) { tb_free(stream->buffer); stream->buffer = tb_null; } tb_free(stream); } } static __tb_inline__ xm_lz4_dstream_t *xm_lz4_dstream_init() { LZ4F_errorCode_t ret; tb_bool_t ok = tb_false; xm_lz4_dstream_t *stream = tb_null; do { stream = tb_malloc0_type(xm_lz4_dstream_t); tb_assert_and_check_break(stream); ret = LZ4F_createDecompressionContext(&stream->dctx, LZ4F_getVersion()); if (LZ4F_isError(ret)) break; ok = tb_true; } while (0); if (!ok && stream) { xm_lz4_dstream_exit(stream); stream = tb_null; } return stream; } static __tb_inline__ tb_long_t xm_lz4_dstream_write(xm_lz4_dstream_t *stream, tb_byte_t const *idata, tb_size_t isize, tb_bool_t end) { tb_assert_and_check_return_val(stream && stream->dctx && idata && isize, -1); // read header first const tb_size_t header_size = sizeof(stream->header); if (stream->header_size < header_size) { tb_size_t size = tb_min(header_size - stream->header_size, isize); tb_memcpy(stream->header + stream->header_size, idata, size); stream->header_size += size; idata += size; isize -= size; // get frame info if header is ok if (stream->header_size == header_size) { LZ4F_frameInfo_t info; size_t consumed_size = header_size; LZ4F_errorCode_t ret = LZ4F_getFrameInfo(stream->dctx, &info, stream->header, &consumed_size); if (LZ4F_isError(ret)) return -1; switch (info.blockSizeID) { case LZ4F_default: case LZ4F_max64KB: stream->buffer_maxn = 64 * 1024; break; case LZ4F_max256KB: stream->buffer_maxn = 256 * 1024; break; case LZ4F_max1MB: stream->buffer_maxn = 1 * 1024 * 1024; break; case LZ4F_max4MB: stream->buffer_maxn = 4 * 1024 * 1024; break; default: return -1; } stream->buffer = (LZ4_byte *)tb_malloc(stream->buffer_maxn); tb_assert_and_check_return_val(stream->buffer, -1); stream->buffer_size = header_size - consumed_size; tb_memcpy(stream->buffer, stream->header + consumed_size, stream->buffer_size); } } tb_check_return_val(stream->header_size == header_size && isize, 0); tb_assert_and_check_return_val(stream->buffer && stream->buffer_size + isize <= stream->buffer_maxn, -1); // append the input data tb_memcpy(stream->buffer + stream->buffer_size, idata, isize); stream->buffer_size += isize; return isize; } static __tb_inline__ tb_long_t xm_lz4_dstream_read(xm_lz4_dstream_t *stream, tb_byte_t *odata, tb_size_t osize) { tb_assert_and_check_return_val(stream && stream->dctx && stream->buffer && odata && osize, -1); tb_check_return_val(stream->buffer_size, 0); // do decompress size_t srcsize = stream->buffer_size; size_t dstsize = osize; tb_size_t ret = LZ4F_decompress(stream->dctx, odata, &dstsize, stream->buffer, &srcsize, tb_null); if (LZ4F_isError(ret)) return -1; // move the left input data if (srcsize < stream->buffer_size) tb_memmov(stream->buffer, stream->buffer + srcsize, stream->buffer_size - srcsize); stream->buffer_size -= srcsize; return dstsize; } #endif