mirror of
https://git.tukaani.org/xz.git
synced 2024-04-04 12:36:23 +02:00
liblzma: Add lzma_block_uncomp_encode().
This also adds a new internal function lzma_block_buffer_bound64() which is similar to lzma_block_buffer_bound() but uses uint64_t instead of size_t.
This commit is contained in:
parent
9e6dabcf22
commit
b465da5988
4 changed files with 106 additions and 31 deletions
|
@ -496,6 +496,24 @@ extern LZMA_API(lzma_ret) lzma_block_buffer_encode(
|
|||
lzma_nothrow lzma_attr_warn_unused_result;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Single-call uncompress .xz Block encoder
|
||||
*
|
||||
* This is like lzma_block_buffer_encode() except this doesn't try to
|
||||
* compress the data and instead encodes the data using LZMA2 uncompressed
|
||||
* chunks. The required output buffer size can be determined with
|
||||
* lzma_block_buffer_bound().
|
||||
*
|
||||
* Since the data won't be compressed, this function ignores block->filters.
|
||||
* This function doesn't take lzma_allocator because this function doesn't
|
||||
* allocate any memory from the heap.
|
||||
*/
|
||||
extern LZMA_API(lzma_ret) lzma_block_uncomp_encode(lzma_block *block,
|
||||
const uint8_t *in, size_t in_size,
|
||||
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||
lzma_nothrow lzma_attr_warn_unused_result;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Single-call .xz Block decoder
|
||||
*
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "block_buffer_encoder.h"
|
||||
#include "block_encoder.h"
|
||||
#include "filter_encoder.h"
|
||||
#include "lzma2_encoder.h"
|
||||
|
@ -28,8 +29,8 @@
|
|||
+ LZMA_CHECK_SIZE_MAX + 3) & ~3)
|
||||
|
||||
|
||||
static lzma_vli
|
||||
lzma2_bound(lzma_vli uncompressed_size)
|
||||
static uint64_t
|
||||
lzma2_bound(uint64_t uncompressed_size)
|
||||
{
|
||||
// Prevent integer overflow in overhead calculation.
|
||||
if (uncompressed_size > COMPRESSED_SIZE_MAX)
|
||||
|
@ -39,7 +40,7 @@ lzma2_bound(lzma_vli uncompressed_size)
|
|||
// uncompressed_size up to the next multiple of LZMA2_CHUNK_MAX,
|
||||
// multiply by the size of per-chunk header, and add one byte for
|
||||
// the end marker.
|
||||
const lzma_vli overhead = ((uncompressed_size + LZMA2_CHUNK_MAX - 1)
|
||||
const uint64_t overhead = ((uncompressed_size + LZMA2_CHUNK_MAX - 1)
|
||||
/ LZMA2_CHUNK_MAX)
|
||||
* LZMA2_HEADER_UNCOMPRESSED + 1;
|
||||
|
||||
|
@ -51,30 +52,36 @@ lzma2_bound(lzma_vli uncompressed_size)
|
|||
}
|
||||
|
||||
|
||||
extern LZMA_API(size_t)
|
||||
lzma_block_buffer_bound(size_t uncompressed_size)
|
||||
extern uint64_t
|
||||
lzma_block_buffer_bound64(uint64_t uncompressed_size)
|
||||
{
|
||||
// For now, if the data doesn't compress, we always use uncompressed
|
||||
// chunks of LZMA2. In future we may use Subblock filter too, but
|
||||
// but for simplicity we probably will still use the same bound
|
||||
// calculation even though Subblock filter would have slightly less
|
||||
// overhead.
|
||||
lzma_vli lzma2_size = lzma2_bound(uncompressed_size);
|
||||
// If the data doesn't compress, we always use uncompressed
|
||||
// LZMA2 chunks.
|
||||
uint64_t lzma2_size = lzma2_bound(uncompressed_size);
|
||||
if (lzma2_size == 0)
|
||||
return 0;
|
||||
|
||||
// Take Block Padding into account.
|
||||
lzma2_size = (lzma2_size + 3) & ~LZMA_VLI_C(3);
|
||||
lzma2_size = (lzma2_size + 3) & ~UINT64_C(3);
|
||||
|
||||
#if SIZE_MAX < LZMA_VLI_MAX
|
||||
// Catch the possible integer overflow on 32-bit systems. There's no
|
||||
// overflow on 64-bit systems, because lzma2_bound() already takes
|
||||
// No risk of integer overflow because lzma2_bound() already takes
|
||||
// into account the size of the headers in the Block.
|
||||
if (SIZE_MAX - HEADERS_BOUND < lzma2_size)
|
||||
return HEADERS_BOUND + lzma2_size;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(size_t)
|
||||
lzma_block_buffer_bound(size_t uncompressed_size)
|
||||
{
|
||||
uint64_t ret = lzma_block_buffer_bound64(uncompressed_size);
|
||||
|
||||
#if SIZE_MAX < UINT64_MAX
|
||||
// Catch the possible integer overflow on 32-bit systems.
|
||||
if (ret > SIZE_MAX)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return HEADERS_BOUND + lzma2_size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,9 +89,6 @@ static lzma_ret
|
|||
block_encode_uncompressed(lzma_block *block, const uint8_t *in, size_t in_size,
|
||||
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||
{
|
||||
// TODO: Figure out if the last filter is LZMA2 or Subblock and use
|
||||
// that filter to encode the uncompressed chunks.
|
||||
|
||||
// Use LZMA2 uncompressed chunks. We wouldn't need a dictionary at
|
||||
// all, but LZMA2 always requires a dictionary, so use the minimum
|
||||
// value to minimize memory usage of the decoder.
|
||||
|
@ -165,11 +169,6 @@ block_encode_normal(lzma_block *block, const lzma_allocator *allocator,
|
|||
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||
{
|
||||
// Find out the size of the Block Header.
|
||||
block->compressed_size = lzma2_bound(in_size);
|
||||
if (block->compressed_size == 0)
|
||||
return LZMA_DATA_ERROR;
|
||||
|
||||
block->uncompressed_size = in_size;
|
||||
return_if_error(lzma_block_header_size(block));
|
||||
|
||||
// Reserve space for the Block Header and skip it for now.
|
||||
|
@ -221,10 +220,11 @@ block_encode_normal(lzma_block *block, const lzma_allocator *allocator,
|
|||
}
|
||||
|
||||
|
||||
extern LZMA_API(lzma_ret)
|
||||
lzma_block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
|
||||
static lzma_ret
|
||||
block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
|
||||
const uint8_t *in, size_t in_size,
|
||||
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||
uint8_t *out, size_t *out_pos, size_t out_size,
|
||||
bool try_to_compress)
|
||||
{
|
||||
// Validate the arguments.
|
||||
if (block == NULL || (in == NULL && in_size != 0) || out == NULL
|
||||
|
@ -237,7 +237,7 @@ lzma_block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
|
|||
return LZMA_OPTIONS_ERROR;
|
||||
|
||||
if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX
|
||||
|| block->filters == NULL)
|
||||
|| (try_to_compress && block->filters == NULL))
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
if (!lzma_check_is_supported(block->check))
|
||||
|
@ -258,9 +258,19 @@ lzma_block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
|
|||
|
||||
out_size -= check_size;
|
||||
|
||||
// Initialize block->uncompressed_size and calculate the worst-case
|
||||
// value for block->compressed_size.
|
||||
block->uncompressed_size = in_size;
|
||||
block->compressed_size = lzma2_bound(in_size);
|
||||
if (block->compressed_size == 0)
|
||||
return LZMA_DATA_ERROR;
|
||||
|
||||
// Do the actual compression.
|
||||
const lzma_ret ret = block_encode_normal(block, allocator,
|
||||
lzma_ret ret = LZMA_BUF_ERROR;
|
||||
if (try_to_compress)
|
||||
ret = block_encode_normal(block, allocator,
|
||||
in, in_size, out, out_pos, out_size);
|
||||
|
||||
if (ret != LZMA_OK) {
|
||||
// If the error was something else than output buffer
|
||||
// becoming full, return the error now.
|
||||
|
@ -303,3 +313,25 @@ lzma_block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
|
|||
|
||||
return LZMA_OK;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(lzma_ret)
|
||||
lzma_block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
|
||||
const uint8_t *in, size_t in_size,
|
||||
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||
{
|
||||
return block_buffer_encode(block, allocator,
|
||||
in, in_size, out, out_pos, out_size, true);
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(lzma_ret)
|
||||
lzma_block_uncomp_encode(lzma_block *block,
|
||||
const uint8_t *in, size_t in_size,
|
||||
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||
{
|
||||
// It won't allocate any memory from heap so no need
|
||||
// for lzma_allocator.
|
||||
return block_buffer_encode(block, NULL,
|
||||
in, in_size, out, out_pos, out_size, false);
|
||||
}
|
||||
|
|
24
src/liblzma/common/block_buffer_encoder.h
Normal file
24
src/liblzma/common/block_buffer_encoder.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file block_buffer_encoder.h
|
||||
/// \brief Single-call .xz Block encoder
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef LZMA_BLOCK_BUFFER_ENCODER_H
|
||||
#define LZMA_BLOCK_BUFFER_ENCODER_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/// uint64_t version of lzma_block_buffer_bound(). It is used by
|
||||
/// stream_encoder_mt.c. Probably the original lzma_block_buffer_bound()
|
||||
/// should have been 64-bit, but fixing it would break the ABI.
|
||||
extern uint64_t lzma_block_buffer_bound64(uint64_t uncompressed_size);
|
||||
|
||||
#endif
|
|
@ -97,6 +97,7 @@ global:
|
|||
|
||||
XZ_5.1.2alpha {
|
||||
global:
|
||||
lzma_block_uncomp_encode;
|
||||
lzma_get_progress;
|
||||
lzma_stream_encoder_mt;
|
||||
lzma_stream_encoder_mt_memusage;
|
||||
|
|
Loading…
Reference in a new issue