/** * @brief Free a file * * This function will free the @ref SquashFile, but unlike @ref * squash_file_close it will not actually close the underlying *FILE* * pointer. Instead, it will return the value in the @a fp argument, * allowing you to further manipulate it. * * @param file file to free * @param[out] fp location to store the underlying *FILE* pointer * @return @ref SQUASH_OK on success or a negative error code on * failure */ SquashStatus squash_file_free (SquashFile* file, FILE** fp) { SquashStatus res = SQUASH_OK; if (SQUASH_UNLIKELY(file == NULL)) { if (fp != NULL) *fp = NULL; return SQUASH_OK; } squash_file_lock (file); if (file->stream != NULL && file->stream->stream_type == SQUASH_STREAM_COMPRESS) res = squash_file_write_internal (file, 0, NULL, SQUASH_OPERATION_FINISH); #if defined(SQUASH_MMAP_IO) squash_mapped_file_destroy (&(file->map), false); #endif if (fp != NULL) *fp = file->fp; SQUASH_FUNLOCKFILE(file->fp); squash_object_unref (file->stream); squash_object_unref (file->options); squash_file_unlock (file); mtx_destroy (&(file->mtx)); free (file); return res; }
/** * @brief Decompress a buffer with an existing @ref SquashOptions * * @param codec The codec to use * @param[out] decompressed Location to store the decompressed data * @param[in,out] decompressed_length Location storing the size of the * @a decompressed buffer on input, replaced with the actual size of * the decompressed data * @param compressed The compressed data * @param compressed_length Length of the compressed data (in bytes) * @param options Compression options * @return A status code */ SquashStatus squash_codec_decompress_with_options (SquashCodec* codec, size_t* decompressed_length, uint8_t decompressed[SQUASH_ARRAY_PARAM(*decompressed_length)], size_t compressed_length, const uint8_t compressed[SQUASH_ARRAY_PARAM(compressed_length)], SquashOptions* options) { SquashCodecImpl* impl = NULL; assert (codec != NULL); impl = squash_codec_get_impl (codec); if (impl == NULL) return squash_error (SQUASH_UNABLE_TO_LOAD); if (decompressed == compressed) return squash_error (SQUASH_INVALID_BUFFER); if (impl->decompress_buffer != NULL) { SquashStatus res; res = impl->decompress_buffer (codec, decompressed_length, decompressed, compressed_length, compressed, squash_object_ref (options)); squash_object_unref (options); return res; } else { SquashStatus status; SquashStream* stream; stream = squash_codec_create_stream_with_options (codec, SQUASH_STREAM_DECOMPRESS, options); stream->next_in = compressed; stream->avail_in = compressed_length; stream->next_out = decompressed; stream->avail_out = *decompressed_length; do { status = squash_stream_process (stream); } while (status == SQUASH_PROCESSING); if (status == SQUASH_END_OF_STREAM) { status = SQUASH_OK; *decompressed_length = stream->total_out; } else if (status == SQUASH_OK) { do { status = squash_stream_finish (stream); } while (status == SQUASH_PROCESSING); if (status == SQUASH_OK) { *decompressed_length = stream->total_out; } } assert (stream->stream_type == SQUASH_STREAM_DECOMPRESS); squash_object_unref (stream); return status; } }
static SquashBZ2Stream* squash_bz2_stream_new (SquashCodec* codec, SquashStreamType stream_type, SquashBZ2Options* options) { int bz2_e = 0; SquashBZ2Stream* stream; assert (codec != NULL); assert (stream_type == SQUASH_STREAM_COMPRESS || stream_type == SQUASH_STREAM_DECOMPRESS); stream = (SquashBZ2Stream*) malloc (sizeof (SquashBZ2Stream)); squash_bz2_stream_init (stream, codec, stream_type, options, squash_bz2_stream_free); if (stream_type == SQUASH_STREAM_COMPRESS) { bz2_e = BZ2_bzCompressInit (&(stream->stream), squash_bz2_options_get_block_size_100k (options), 0, squash_bz2_options_get_work_factor (options)); } else if (stream_type == SQUASH_STREAM_DECOMPRESS) { bz2_e = BZ2_bzDecompressInit (&(stream->stream), 0, squash_bz2_options_get_small (options) ? 1 : 0); } else { assert (false); } if (bz2_e != BZ_OK) { /* We validate the params so OOM is really the only time this should happen, and that really shouldn't be happening here. */ stream = squash_object_unref (stream); } return stream; }
static void benchmark_codec (SquashCodec* codec, void* data) { struct BenchmarkContext* context = (struct BenchmarkContext*) data; SquashOptions* opts; int level = 0; char level_s[4]; bool have_results = false; umask (0100); fprintf (stdout, " %s:%s\n", squash_plugin_get_name (squash_codec_get_plugin (codec)), squash_codec_get_name (codec)); opts = squash_options_new (codec, NULL); if (opts != NULL) { squash_object_ref_sink (opts); for ( level = 0 ; level <= 999 ; level++ ) { snprintf (level_s, 4, "%d", level); if (squash_options_parse_option (opts, "level", level_s) == SQUASH_OK) { if (benchmark_codec_with_options (context, codec, opts)) { have_results = true; } } } squash_object_unref (opts); } if (!have_results) { benchmark_codec_with_options (context, codec, NULL); } }
static SquashMSCompStream* squash_ms_stream_new (SquashCodec* codec, SquashStreamType stream_type, SquashOptions* options) { SquashMSCompStream* stream; assert (codec != NULL); assert (stream_type == SQUASH_STREAM_COMPRESS || stream_type == SQUASH_STREAM_DECOMPRESS); stream = squash_malloc (sizeof (SquashMSCompStream)); if (SQUASH_UNLIKELY(stream == NULL)) return (squash_error (SQUASH_MEMORY), NULL); squash_ms_stream_init (stream, codec, stream_type, options, squash_ms_stream_destroy); MSCompStatus status; MSCompFormat format = squash_ms_format_from_codec (codec); if (stream->base_object.stream_type == SQUASH_STREAM_COMPRESS) { status = ms_deflate_init (format, &(stream->mscomp)); } else { status = ms_inflate_init (format, &(stream->mscomp)); } if (SQUASH_UNLIKELY(status != MSCOMP_OK)) { squash_object_unref (stream); return (squash_error (squash_ms_status_to_squash_status (status)), NULL); } return stream; }
/** * @brief Destroy a stream. * @protected * * @warning This function must only be used to implement a subclass of * @ref SquashObject. Each subclass should implement a *_destroy * function which should perform any operations needed to destroy * their own data and chain up to the *_destroy function of the base * class, eventually invoking ::squash_object_destroy. Invoking this * function in any other context is likely to cause a memory leak or * crash. If you are not creating a subclass, you should be calling * @ref squash_object_unref instead. * * @param stream The stream. * * @see squash_object_destroy */ void squash_stream_destroy (void* stream) { SquashStream* s; assert (stream != NULL); s = (SquashStream*) stream; if (SQUASH_UNLIKELY(s->priv != NULL)) { SquashStreamPrivate* priv = (SquashStreamPrivate*) s->priv; if (!priv->finished) { squash_stream_send_to_thread (s, SQUASH_OPERATION_TERMINATE); } cnd_destroy (&(priv->request_cnd)); cnd_destroy (&(priv->result_cnd)); mtx_destroy (&(priv->io_mtx)); squash_free (s->priv); } if (s->destroy_user_data != NULL && s->user_data != NULL) { s->destroy_user_data (s->user_data); } if (s->options != NULL) { s->options = squash_object_unref (s->options); } squash_object_destroy (stream); }
static SquashBZ2Stream* squash_bz2_stream_new (SquashCodec* codec, SquashStreamType stream_type, SquashOptions* options) { int bz2_e = 0; SquashBZ2Stream* stream; assert (codec != NULL); assert (stream_type == SQUASH_STREAM_COMPRESS || stream_type == SQUASH_STREAM_DECOMPRESS); stream = squash_malloc (sizeof (SquashBZ2Stream)); squash_bz2_stream_init (stream, codec, stream_type, options, squash_bz2_stream_destroy); if (stream_type == SQUASH_STREAM_COMPRESS) { bz2_e = BZ2_bzCompressInit (&(stream->stream), squash_codec_get_option_int_index (codec, options, SQUASH_BZ2_OPT_LEVEL), 0, squash_codec_get_option_int_index (codec, options, SQUASH_BZ2_OPT_WORK_FACTOR)); } else if (stream_type == SQUASH_STREAM_DECOMPRESS) { bz2_e = BZ2_bzDecompressInit (&(stream->stream), 0, squash_codec_get_option_int_index (codec, options, SQUASH_BZ2_OPT_SMALL)); } else { squash_assert_unreachable(); } if (bz2_e != BZ_OK) { /* We validate the params so OOM is really the only time this should happen, and that really shouldn't be happening here. */ stream = squash_object_unref (stream); } return stream; }
//---------- void Stream::clear() { if (this->squashStream) { squash_stream_destroy(this->squashStream); squash_object_unref(this->squashStream); this->squashStream = nullptr; } }
static SquashLZ4FStream* squash_lz4f_stream_new (SquashCodec* codec, SquashStreamType stream_type, SquashOptions* options) { SquashLZ4FStream* stream; LZ4F_errorCode_t ec; assert (codec != NULL); stream = (SquashLZ4FStream*) squash_malloc (sizeof (SquashLZ4FStream)); if (SQUASH_UNLIKELY(stream == NULL)) return (squash_error (SQUASH_MEMORY), NULL); squash_lz4f_stream_init (stream, codec, stream_type, options, squash_lz4f_stream_destroy); if (stream_type == SQUASH_STREAM_COMPRESS) { ec = LZ4F_createCompressionContext(&(stream->data.comp.ctx), LZ4F_VERSION); stream->data.comp.state = SQUASH_LZ4F_STATE_INIT; stream->data.comp.output_buffer = NULL; stream->data.comp.output_buffer_pos = 0; stream->data.comp.output_buffer_size = 0; stream->data.comp.input_buffer_size = 0; stream->data.comp.prefs = (LZ4F_preferences_t) { { (LZ4F_blockSizeID_t) squash_codec_get_option_int_index (codec, options, SQUASH_LZ4F_OPT_BLOCK_SIZE), blockLinked, squash_codec_get_option_bool_index (codec, options, SQUASH_LZ4F_OPT_CHECKSUM) ? contentChecksumEnabled : noContentChecksum, }, squash_codec_get_option_int_index (codec, options, SQUASH_LZ4F_OPT_LEVEL) }; } else { ec = LZ4F_createDecompressionContext(&(stream->data.decomp.ctx), LZ4F_VERSION); } if (SQUASH_UNLIKELY(LZ4F_isError (ec))) { squash_object_unref (stream); return (squash_error (SQUASH_FAILED), NULL); } return stream; }
//---------- Stream & Stream::operator<<(const Finish &) { if (this->squashStream == nullptr) { OFXSQUASH_WARNING << "Stream already finished. You need to make a new one."; return* this; } SquashStatus status; do { this->squashStream->next_out = this->buffer.data(); this->squashStream->avail_out = this->buffer.size(); status = squash_stream_finish(this->squashStream); if (status != SQUASH_OK && status != SQUASH_PROCESSING) { OFXSQUASH_ERROR << "Processing failed: " << squash_status_to_string(status); return * this; } const size_t outputSize = this->buffer.size() - this->squashStream->avail_out; if (outputSize > 0) { if (this->writeFunction) { WriteFunctionArguments args{ this->buffer.data(), outputSize, false }; this->writeFunction(args); } else { OFXSQUASH_WARNING << "Cannot write stream output. No WriteFunction has been set"; } } } while (status == SQUASH_PROCESSING); if (this->writeFunction) { WriteFunctionArguments args{ nullptr, 0, true }; this->writeFunction(args); } squash_stream_destroy(this->squashStream); squash_object_unref(this->squashStream); this->squashStream = nullptr; return * this; }
/** * @brief Compress a buffer with an existing @ref SquashOptions * * @param codec The codec to use * @param[out] compressed Location to store the compressed data * @param[in,out] compressed_length Location storing the size of the * @a compressed buffer on input, replaced with the actual size of * the compressed data * @param uncompressed The uncompressed data * @param uncompressed_length Length of the uncompressed data (in bytes) * @param options Compression options * @return A status code */ SquashStatus squash_codec_compress_with_options (SquashCodec* codec, size_t* compressed_length, uint8_t compressed[SQUASH_ARRAY_PARAM(*compressed_length)], size_t uncompressed_length, const uint8_t uncompressed[SQUASH_ARRAY_PARAM(uncompressed_length)], SquashOptions* options) { SquashCodecImpl* impl = NULL; assert (codec != NULL); assert (compressed != NULL); assert (uncompressed != NULL); impl = squash_codec_get_impl (codec); if (impl == NULL) return squash_error (SQUASH_UNABLE_TO_LOAD); if (compressed == uncompressed) return squash_error (SQUASH_INVALID_BUFFER); if (impl->compress_buffer || impl->compress_buffer_unsafe) { size_t max_compressed_length = squash_codec_get_max_compressed_size (codec, uncompressed_length); if (*compressed_length >= max_compressed_length) { if (impl->compress_buffer_unsafe != NULL) { return impl->compress_buffer_unsafe (codec, compressed_length, compressed, uncompressed_length, uncompressed, options); } else { return impl->compress_buffer (codec, compressed_length, compressed, uncompressed_length, uncompressed, options); } } else if (impl->compress_buffer != NULL) { return impl->compress_buffer (codec, compressed_length, compressed, uncompressed_length, uncompressed, options); } else { SquashStatus status; uint8_t* tmp_buf = malloc (max_compressed_length); if (tmp_buf == NULL) return squash_error (SQUASH_MEMORY); status = impl->compress_buffer_unsafe (codec, &max_compressed_length, tmp_buf, uncompressed_length, uncompressed, options); if (status == SQUASH_OK) { if (*compressed_length < max_compressed_length) { *compressed_length = max_compressed_length; free (tmp_buf); return squash_error (SQUASH_BUFFER_FULL); } else { *compressed_length = max_compressed_length; memcpy (compressed, tmp_buf, max_compressed_length); free (tmp_buf); return SQUASH_OK; } } else { free (tmp_buf); return status; } } } else { SquashStatus status; SquashStream* stream; stream = squash_codec_create_stream_with_options (codec, SQUASH_STREAM_COMPRESS, options); if (stream == NULL) return squash_error (SQUASH_FAILED); stream->next_in = uncompressed; stream->avail_in = uncompressed_length; stream->next_out = compressed; stream->avail_out = *compressed_length; do { status = squash_stream_process (stream); } while (status == SQUASH_PROCESSING); if (status != SQUASH_OK) { squash_object_unref (stream); return status; } do { status = squash_stream_finish (stream); } while (status == SQUASH_PROCESSING); if (status != SQUASH_OK) { squash_object_unref (stream); return status; } *compressed_length = stream->total_out; squash_object_unref (stream); return status; } }