///////////////////////////////////////////////////////////////////////////////
//
/// \file common.h
/// \brief Definitions common to the whole liblzma library
//
// Copyright (C) 2007 Lasse Collin
//
// 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.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_COMMON_H
#define LZMA_COMMON_H
#include "sysdefs.h"
// Don't use ifdef...
#if HAVE_VISIBILITY
# define LZMA_API __attribute__((__visibility__("default")))
#else
# define LZMA_API
#endif
/// Size of temporary buffers needed in some filters
#define LZMA_BUFFER_SIZE 4096
/// Internal helper filter used by Subblock decoder. It is mapped to an
/// otherwise invalid Filter ID, which is impossible to get from any input
/// file (even if malicious file).
#define LZMA_FILTER_SUBBLOCK_HELPER (UINT64_MAX - 2)
///////////
// Types //
///////////
typedef struct lzma_coder_s lzma_coder;
typedef struct lzma_next_coder_s lzma_next_coder;
typedef struct lzma_filter_info_s lzma_filter_info;
typedef lzma_ret (*lzma_init_function)(
lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter_info *filters);
typedef lzma_ret (*lzma_code_function)(
lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size,
lzma_action action);
typedef void (*lzma_end_function)(
lzma_coder *coder, lzma_allocator *allocator);
/// Hold data and function pointers of the next filter in the chain.
struct lzma_next_coder_s {
/// Pointer to coder-specific data
lzma_coder *coder;
/// "Pointer" to init function. This is never called here.
/// We need only to detect if we are initializing a coder
/// that was allocated earlier. See code.c and next_coder.c.
uintptr_t init;
/// Pointer to function to do the actual coding
lzma_code_function code;
/// Pointer to function to free lzma_next_coder.coder
lzma_end_function end;
};
#define LZMA_NEXT_CODER_INIT \
(lzma_next_coder){ \
.coder = NULL, \
.init = 0, \
.code = NULL, \
.end = NULL, \
}
struct lzma_internal_s {
lzma_next_coder next;
enum {
ISEQ_RUN,
ISEQ_SYNC_FLUSH,
ISEQ_FULL_FLUSH,
ISEQ_FINISH,
ISEQ_END,
ISEQ_ERROR,
} sequence;
bool supported_actions[4];
bool allow_buf_error;
size_t avail_in;
};
struct lzma_filter_info_s {
/// Pointer to function used to initialize the filter.
/// This is NULL to indicate end of array.
lzma_init_function init;
/// Pointer to filter's options structure
void *options;
/// Uncompressed size of the filter, or LZMA_VLI_VALUE_UNKNOWN
/// if unknown.
lzma_vli uncompressed_size;
};
/*
typedef struct {
lzma_init_function init;
uint32_t (*input_alignment)(lzma_vli id, const void *options);
uint32_t (*output_alignment)(lzma_vli id, const void *options);
bool changes_uncompressed_size;
bool supports_eopm;
} lzma_filter_hook;
*/
///////////////
// Functions //
///////////////
/// Allocates memory
extern void *lzma_alloc(size_t size, lzma_allocator *allocator)
lzma_attribute((malloc));
/// Frees memory
extern void lzma_free(void *ptr, lzma_allocator *allocator);
/// Initializes lzma_stream FIXME desc
extern lzma_ret lzma_strm_init(lzma_stream *strm);
///
extern lzma_ret lzma_next_filter_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
///
extern void lzma_next_coder_end(lzma_next_coder *next,
lzma_allocator *allocator);
extern lzma_ret lzma_filter_flags_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, lzma_options_filter *options);
extern lzma_ret lzma_block_header_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, lzma_options_block *options);
extern lzma_ret lzma_stream_encoder_single_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_options_stream *options);
extern lzma_ret lzma_stream_decoder_init(
lzma_next_coder *next, lzma_allocator *allocator,
lzma_extra **header, lzma_extra **footer);
/// \brief Wrapper for memcpy()
///
/// This function copies as much data as possible from in[] to out[] and
/// updates *in_pos and *out_pos accordingly.
///
static inline size_t
bufcpy(const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size,
uint8_t *restrict out, size_t *restrict out_pos,
size_t out_size)
{
const size_t in_avail = in_size - *in_pos;
const size_t out_avail = out_size - *out_pos;
const size_t copy_size = MIN(in_avail, out_avail);
memcpy(out + *out_pos, in + *in_pos, copy_size);
*in_pos += copy_size;
*out_pos += copy_size;
return copy_size;
}
/// \brief Initializing the next coder
///
/// lzma_next_coder can point to different types of coders. The existing
/// coder may be different than what we are initializing now. In that case
/// we must git rid of the old coder first. Otherwise we reuse the existing
/// coder structure.
///
#define lzma_next_coder_init2(next, allocator, cmpfunc, func, ...) \
do { \
if ((uintptr_t)(&cmpfunc) != (next)->init) \
lzma_next_coder_end(next, allocator); \
const lzma_ret ret = func(next, __VA_ARGS__); \
if (ret == LZMA_OK) { \
(next)->init = (uintptr_t)(&cmpfunc); \
assert((next)->code != NULL); \
assert((next)->end != NULL); \
} else { \
lzma_next_coder_end(next, allocator); \
} \
return ret; \
} while (0)
/// \brief Initializing lzma_next_coder
///
/// Call the initialization function, which must take at least one
/// argument in addition to lzma_next_coder and lzma_allocator.
#define lzma_next_coder_init(func, next, allocator, ...) \
lzma_next_coder_init2(next, allocator, \
func, func, allocator, __VA_ARGS__)
/// \brief Initializing lzma_stream
///
/// lzma_strm initialization with more detailed options.
#define lzma_next_strm_init2(strm, cmpfunc, func, ...) \
do { \
lzma_ret ret = lzma_strm_init(strm); \
if (ret != LZMA_OK) \
return ret; \
if ((uintptr_t)(&cmpfunc) != (strm)->internal->next.init) \
lzma_next_coder_end(\
&(strm)->internal->next, (strm)->allocator); \
ret = func(&(strm)->internal->next, __VA_ARGS__); \
if (ret != LZMA_OK) { \
lzma_end(strm); \
return ret; \
} \
(strm)->internal->next.init = (uintptr_t)(&cmpfunc); \
assert((strm)->internal->next.code != NULL); \
assert((strm)->internal->next.end != NULL); \
} while (0)
/// \brief Initializing lzma_stream
///
/// Call the initialization function, which must take at least one
/// argument in addition to lzma_next_coder and lzma_allocator.
#define lzma_next_strm_init(strm, func, ...) \
lzma_next_strm_init2(strm, func, func, (strm)->allocator, __VA_ARGS__)
/// \brief Return if expression doesn't evaluate to LZMA_OK
///
/// There are several situations where we want to return immediatelly
/// with the value of expr if it isn't LZMA_OK. This macro shortens
/// the code a bit.
///
#define return_if_error(expr) \
do { \
const lzma_ret ret_ = expr; \
if (ret_ != LZMA_OK) \
return ret_; \
} while (0)
#endif