/* Copyright (C) 2014 Flexible Software Solutions S.L. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #ifdef USE_LZ4 #define SPICE_LOG_DOMAIN "SpiceLz4Encoder" #include #include #include "red_common.h" #include "lz4-encoder.h" typedef struct Lz4Encoder { Lz4EncoderUsrContext *usr; } Lz4Encoder; Lz4EncoderContext* lz4_encoder_create(Lz4EncoderUsrContext *usr) { Lz4Encoder *enc; if (!usr->more_space || !usr->more_lines) { return NULL; } enc = spice_new0(Lz4Encoder, 1); enc->usr = usr; return (Lz4EncoderContext*)enc; } void lz4_encoder_destroy(Lz4EncoderContext* encoder) { free(encoder); } int lz4_encode(Lz4EncoderContext *lz4, int height, int stride, uint8_t *io_ptr, unsigned int num_io_bytes) { Lz4Encoder *enc = (Lz4Encoder *)lz4; uint8_t *lines; int num_lines = 0; int total_lines = 0; int in_size, enc_size, out_size = 0, already_copied; int stride_abs = abs(stride); uint8_t *in_buf, *compressed_lines; uint8_t *out_buf = io_ptr; LZ4_stream_t *stream = LZ4_createStream(); // Encode direction *(out_buf++) = stride < 0 ? 1 : 0; num_io_bytes--; do { num_lines = enc->usr->more_lines(enc->usr, &lines); if (num_lines <= 0) { spice_error("more lines failed"); LZ4_freeStream(stream); return 0; } in_buf = stride < 0 ? lines - (stride_abs * (num_lines - 1)) : lines; lines += stride * num_lines; in_size = stride_abs * num_lines; compressed_lines = (uint8_t *) malloc(LZ4_compressBound(in_size) + 4); enc_size = LZ4_compress_continue(stream, (const char *) in_buf, (char *) compressed_lines + 4, in_size); if (enc_size <= 0) { spice_error("compress failed!"); free(compressed_lines); LZ4_freeStream(stream); return 0; } *((uint32_t *)compressed_lines) = htonl(enc_size); out_size += enc_size += 4; already_copied = 0; while (num_io_bytes < enc_size) { memcpy(out_buf, compressed_lines + already_copied, num_io_bytes); already_copied += num_io_bytes; enc_size -= num_io_bytes; num_io_bytes = enc->usr->more_space(enc->usr, &io_ptr); if (num_io_bytes <= 0) { spice_error("more space failed"); free(compressed_lines); LZ4_freeStream(stream); return 0; } out_buf = io_ptr; } memcpy(out_buf, compressed_lines + already_copied, enc_size); out_buf += enc_size; num_io_bytes -= enc_size; free(compressed_lines); total_lines += num_lines; } while (total_lines < height); LZ4_freeStream(stream); if (total_lines != height) { spice_error("too many lines\n"); out_size = 0; } return out_size; } #endif // USE_LZ4