mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-18 14:31:58 +00:00
touch: add new commands
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file alone_decoder.c
|
||||
/// \brief Decoder for LZMA_Alone files
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "alone_decoder.h"
|
||||
#include "lzma_decoder.h"
|
||||
#include "lz_decoder.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
lzma_next_coder next;
|
||||
|
||||
enum {
|
||||
SEQ_PROPERTIES,
|
||||
SEQ_DICTIONARY_SIZE,
|
||||
SEQ_UNCOMPRESSED_SIZE,
|
||||
SEQ_CODER_INIT,
|
||||
SEQ_CODE,
|
||||
} sequence;
|
||||
|
||||
/// If true, reject files that are unlikely to be .lzma files.
|
||||
/// If false, more non-.lzma files get accepted and will give
|
||||
/// LZMA_DATA_ERROR either immediately or after a few output bytes.
|
||||
bool picky;
|
||||
|
||||
/// Position in the header fields
|
||||
size_t pos;
|
||||
|
||||
/// Uncompressed size decoded from the header
|
||||
lzma_vli uncompressed_size;
|
||||
|
||||
/// Memory usage limit
|
||||
uint64_t memlimit;
|
||||
|
||||
/// Amount of memory actually needed (only an estimate)
|
||||
uint64_t memusage;
|
||||
|
||||
/// Options decoded from the header needed to initialize
|
||||
/// the LZMA decoder
|
||||
lzma_options_lzma options;
|
||||
} lzma_alone_coder;
|
||||
|
||||
|
||||
static lzma_ret
|
||||
alone_decode(void *coder_ptr,
|
||||
const lzma_allocator *allocator lzma_attribute((__unused__)),
|
||||
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)
|
||||
{
|
||||
lzma_alone_coder *coder = coder_ptr;
|
||||
|
||||
while (*out_pos < out_size
|
||||
&& (coder->sequence == SEQ_CODE || *in_pos < in_size))
|
||||
switch (coder->sequence) {
|
||||
case SEQ_PROPERTIES:
|
||||
if (lzma_lzma_lclppb_decode(&coder->options, in[*in_pos]))
|
||||
return LZMA_FORMAT_ERROR;
|
||||
|
||||
coder->sequence = SEQ_DICTIONARY_SIZE;
|
||||
++*in_pos;
|
||||
break;
|
||||
|
||||
case SEQ_DICTIONARY_SIZE:
|
||||
coder->options.dict_size
|
||||
|= (size_t)(in[*in_pos]) << (coder->pos * 8);
|
||||
++*in_pos;
|
||||
if (++coder->pos < 4)
|
||||
break;
|
||||
|
||||
if (coder->picky && coder->options.dict_size
|
||||
!= UINT32_MAX) {
|
||||
// A hack to ditch tons of false positives:
|
||||
// We allow only dictionary sizes that are
|
||||
// 2^n or 2^n + 2^(n-1). LZMA_Alone created
|
||||
// only files with 2^n, but accepts any
|
||||
// dictionary size.
|
||||
uint32_t d = coder->options.dict_size - 1;
|
||||
d |= d >> 2;
|
||||
d |= d >> 3;
|
||||
d |= d >> 4;
|
||||
d |= d >> 8;
|
||||
d |= d >> 16;
|
||||
++d;
|
||||
|
||||
if (d != coder->options.dict_size)
|
||||
return LZMA_FORMAT_ERROR;
|
||||
}
|
||||
|
||||
coder->uncompressed_size = LZMA_VLI_UNKNOWN;
|
||||
|
||||
// Calculate the memory usage so that it is ready
|
||||
// for SEQ_CODER_INIT.
|
||||
coder->memusage = lzma_lzma_decoder_memusage(&coder->options)
|
||||
+ LZMA_MEMUSAGE_BASE;
|
||||
|
||||
coder->pos = 0;
|
||||
coder->sequence = SEQ_CODER_INIT;
|
||||
|
||||
// Fall through
|
||||
|
||||
case SEQ_CODER_INIT: {
|
||||
if (coder->memusage > coder->memlimit)
|
||||
return LZMA_MEMLIMIT_ERROR;
|
||||
|
||||
lzma_filter_info filters[2] = {
|
||||
{
|
||||
.init = &lzma_lzma_decoder_init,
|
||||
.options = &coder->options,
|
||||
}, {
|
||||
.init = NULL,
|
||||
}
|
||||
};
|
||||
|
||||
const lzma_ret ret = lzma_next_filter_init(&coder->next,
|
||||
allocator, filters);
|
||||
if (ret != LZMA_OK)
|
||||
return ret;
|
||||
|
||||
// Use a hack to set the uncompressed size.
|
||||
lzma_lz_decoder_uncompressed(coder->next.coder,
|
||||
coder->uncompressed_size);
|
||||
|
||||
coder->sequence = SEQ_CODE;
|
||||
break;
|
||||
}
|
||||
|
||||
case SEQ_CODE: {
|
||||
return coder->next.code(coder->next.coder,
|
||||
allocator, in, in_pos, in_size,
|
||||
out, out_pos, out_size, action);
|
||||
}
|
||||
|
||||
default:
|
||||
return LZMA_PROG_ERROR;
|
||||
}
|
||||
|
||||
return LZMA_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
alone_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
|
||||
{
|
||||
lzma_alone_coder *coder = coder_ptr;
|
||||
lzma_next_end(&coder->next, allocator);
|
||||
lzma_free(coder, allocator);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static lzma_ret
|
||||
alone_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
|
||||
uint64_t *old_memlimit, uint64_t new_memlimit)
|
||||
{
|
||||
lzma_alone_coder *coder = coder_ptr;
|
||||
|
||||
*memusage = coder->memusage;
|
||||
*old_memlimit = coder->memlimit;
|
||||
|
||||
if (new_memlimit != 0) {
|
||||
if (new_memlimit < coder->memusage)
|
||||
return LZMA_MEMLIMIT_ERROR;
|
||||
|
||||
coder->memlimit = new_memlimit;
|
||||
}
|
||||
|
||||
return LZMA_OK;
|
||||
}
|
||||
|
||||
|
||||
extern lzma_ret
|
||||
lzma_alone_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
uint64_t memlimit, bool picky)
|
||||
{
|
||||
lzma_next_coder_init(&lzma_alone_decoder_init, next, allocator);
|
||||
|
||||
if (memlimit == 0)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
lzma_alone_coder *coder = next->coder;
|
||||
|
||||
if (coder == NULL) {
|
||||
coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
|
||||
if (coder == NULL)
|
||||
return LZMA_MEM_ERROR;
|
||||
|
||||
next->coder = coder;
|
||||
next->code = &alone_decode;
|
||||
next->end = &alone_decoder_end;
|
||||
next->memconfig = &alone_decoder_memconfig;
|
||||
coder->next = LZMA_NEXT_CODER_INIT;
|
||||
}
|
||||
|
||||
coder->sequence = SEQ_PROPERTIES;
|
||||
coder->picky = picky;
|
||||
coder->pos = 0;
|
||||
coder->options.dict_size = 0;
|
||||
coder->options.preset_dict = NULL;
|
||||
coder->options.preset_dict_size = 0;
|
||||
coder->uncompressed_size = 0;
|
||||
coder->memlimit = memlimit;
|
||||
coder->memusage = LZMA_MEMUSAGE_BASE;
|
||||
|
||||
return LZMA_OK;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(lzma_ret)
|
||||
lzma_alone_decoder(lzma_stream *strm, uint64_t memlimit)
|
||||
{
|
||||
lzma_next_strm_init(lzma_alone_decoder_init, strm, memlimit, false);
|
||||
|
||||
strm->internal->supported_actions[LZMA_RUN] = true;
|
||||
strm->internal->supported_actions[LZMA_FINISH] = true;
|
||||
|
||||
return LZMA_OK;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file alone_decoder.h
|
||||
/// \brief Decoder for LZMA_Alone files
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef LZMA_ALONE_DECODER_H
|
||||
#define LZMA_ALONE_DECODER_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
extern lzma_ret lzma_alone_decoder_init(
|
||||
lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
uint64_t memlimit, bool picky);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,160 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file alone_decoder.c
|
||||
/// \brief Decoder for LZMA_Alone files
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "common.h"
|
||||
#include "lzma_encoder.h"
|
||||
|
||||
|
||||
#define ALONE_HEADER_SIZE (1 + 4)
|
||||
|
||||
|
||||
typedef struct {
|
||||
lzma_next_coder next;
|
||||
|
||||
enum {
|
||||
SEQ_HEADER,
|
||||
SEQ_CODE,
|
||||
} sequence;
|
||||
|
||||
size_t header_pos;
|
||||
uint8_t header[ALONE_HEADER_SIZE];
|
||||
} lzma_alone_coder;
|
||||
|
||||
|
||||
static lzma_ret
|
||||
alone_encode(void *coder_ptr,
|
||||
const lzma_allocator *allocator lzma_attribute((__unused__)),
|
||||
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)
|
||||
{
|
||||
lzma_alone_coder *coder = coder_ptr;
|
||||
|
||||
while (*out_pos < out_size)
|
||||
switch (coder->sequence) {
|
||||
case SEQ_HEADER:
|
||||
lzma_bufcpy(coder->header, &coder->header_pos,
|
||||
ALONE_HEADER_SIZE,
|
||||
out, out_pos, out_size);
|
||||
if (coder->header_pos < ALONE_HEADER_SIZE)
|
||||
return LZMA_OK;
|
||||
|
||||
coder->sequence = SEQ_CODE;
|
||||
break;
|
||||
|
||||
case SEQ_CODE:
|
||||
return coder->next.code(coder->next.coder,
|
||||
allocator, in, in_pos, in_size,
|
||||
out, out_pos, out_size, action);
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return LZMA_PROG_ERROR;
|
||||
}
|
||||
|
||||
return LZMA_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
alone_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
|
||||
{
|
||||
lzma_alone_coder *coder = coder_ptr;
|
||||
lzma_next_end(&coder->next, allocator);
|
||||
lzma_free(coder, allocator);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// At least for now, this is not used by any internal function.
|
||||
static lzma_ret
|
||||
alone_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
const lzma_options_lzma *options)
|
||||
{
|
||||
lzma_next_coder_init(&alone_encoder_init, next, allocator);
|
||||
|
||||
lzma_alone_coder *coder = next->coder;
|
||||
|
||||
if (coder == NULL) {
|
||||
coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
|
||||
if (coder == NULL)
|
||||
return LZMA_MEM_ERROR;
|
||||
|
||||
next->coder = coder;
|
||||
next->code = &alone_encode;
|
||||
next->end = &alone_encoder_end;
|
||||
coder->next = LZMA_NEXT_CODER_INIT;
|
||||
}
|
||||
|
||||
// Basic initializations
|
||||
coder->sequence = SEQ_HEADER;
|
||||
coder->header_pos = 0;
|
||||
|
||||
// Encode the header:
|
||||
// - Properties (1 byte)
|
||||
if (lzma_lzma_lclppb_encode(options, coder->header))
|
||||
return LZMA_OPTIONS_ERROR;
|
||||
|
||||
// - Dictionary size (4 bytes)
|
||||
if (options->dict_size < LZMA_DICT_SIZE_MIN)
|
||||
return LZMA_OPTIONS_ERROR;
|
||||
|
||||
// Round up to the next 2^n or 2^n + 2^(n - 1) depending on which
|
||||
// one is the next unless it is UINT32_MAX. While the header would
|
||||
// allow any 32-bit integer, we do this to keep the decoder of liblzma
|
||||
// accepting the resulting files.
|
||||
uint32_t d = options->dict_size - 1;
|
||||
d |= d >> 2;
|
||||
d |= d >> 3;
|
||||
d |= d >> 4;
|
||||
d |= d >> 8;
|
||||
d |= d >> 16;
|
||||
if (d != UINT32_MAX)
|
||||
++d;
|
||||
|
||||
unaligned_write32le(coder->header + 1, d);
|
||||
|
||||
// Initialize the LZMA encoder.
|
||||
const lzma_filter_info filters[2] = {
|
||||
{
|
||||
.init = &lzma_lzma_encoder_init,
|
||||
.options = (void *)(options),
|
||||
}, {
|
||||
.init = NULL,
|
||||
}
|
||||
};
|
||||
|
||||
return lzma_next_filter_init(&coder->next, allocator, filters);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
extern lzma_ret
|
||||
lzma_alone_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
const lzma_options_alone *options)
|
||||
{
|
||||
lzma_next_coder_init(&alone_encoder_init, next, allocator, options);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
extern LZMA_API(lzma_ret)
|
||||
lzma_alone_encoder(lzma_stream *strm, const lzma_options_lzma *options)
|
||||
{
|
||||
lzma_next_strm_init(alone_encoder_init, strm, options);
|
||||
|
||||
strm->internal->supported_actions[LZMA_RUN] = true;
|
||||
strm->internal->supported_actions[LZMA_FINISH] = true;
|
||||
|
||||
return LZMA_OK;
|
||||
}
|
||||
+443
@@ -0,0 +1,443 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file common.h
|
||||
/// \brief Common functions needed in many places in liblzma
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/////////////
|
||||
// Version //
|
||||
/////////////
|
||||
|
||||
extern LZMA_API(uint32_t)
|
||||
lzma_version_number(void)
|
||||
{
|
||||
return LZMA_VERSION;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(const char *)
|
||||
lzma_version_string(void)
|
||||
{
|
||||
return LZMA_VERSION_STRING;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////
|
||||
// Memory allocation //
|
||||
///////////////////////
|
||||
|
||||
extern void * lzma_attribute((__malloc__)) lzma_attr_alloc_size(1)
|
||||
lzma_alloc(size_t size, const lzma_allocator *allocator)
|
||||
{
|
||||
// Some malloc() variants return NULL if called with size == 0.
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
|
||||
void *ptr;
|
||||
|
||||
if (allocator != NULL && allocator->alloc != NULL)
|
||||
ptr = allocator->alloc(allocator->opaque, 1, size);
|
||||
else
|
||||
ptr = malloc(size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
extern void * lzma_attribute((__malloc__)) lzma_attr_alloc_size(1)
|
||||
lzma_alloc_zero(size_t size, const lzma_allocator *allocator)
|
||||
{
|
||||
// Some calloc() variants return NULL if called with size == 0.
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
|
||||
void *ptr;
|
||||
|
||||
if (allocator != NULL && allocator->alloc != NULL) {
|
||||
ptr = allocator->alloc(allocator->opaque, 1, size);
|
||||
if (ptr != NULL)
|
||||
memzero(ptr, size);
|
||||
} else {
|
||||
ptr = calloc(1, size);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
extern void
|
||||
lzma_free(void *ptr, const lzma_allocator *allocator)
|
||||
{
|
||||
if (allocator != NULL && allocator->free != NULL)
|
||||
allocator->free(allocator->opaque, ptr);
|
||||
else
|
||||
free(ptr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//////////
|
||||
// Misc //
|
||||
//////////
|
||||
|
||||
extern size_t
|
||||
lzma_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 = my_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;
|
||||
}
|
||||
|
||||
|
||||
extern lzma_ret
|
||||
lzma_next_filter_init(lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
const lzma_filter_info *filters)
|
||||
{
|
||||
lzma_next_coder_init(filters[0].init, next, allocator);
|
||||
next->id = filters[0].id;
|
||||
return filters[0].init == NULL
|
||||
? LZMA_OK : filters[0].init(next, allocator, filters);
|
||||
}
|
||||
|
||||
|
||||
extern lzma_ret
|
||||
lzma_next_filter_update(lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
const lzma_filter *reversed_filters)
|
||||
{
|
||||
// Check that the application isn't trying to change the Filter ID.
|
||||
// End of filters is indicated with LZMA_VLI_UNKNOWN in both
|
||||
// reversed_filters[0].id and next->id.
|
||||
if (reversed_filters[0].id != next->id)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
if (reversed_filters[0].id == LZMA_VLI_UNKNOWN)
|
||||
return LZMA_OK;
|
||||
|
||||
assert(next->update != NULL);
|
||||
return next->update(next->coder, allocator, NULL, reversed_filters);
|
||||
}
|
||||
|
||||
|
||||
extern void
|
||||
lzma_next_end(lzma_next_coder *next, const lzma_allocator *allocator)
|
||||
{
|
||||
if (next->init != (uintptr_t)(NULL)) {
|
||||
// To avoid tiny end functions that simply call
|
||||
// lzma_free(coder, allocator), we allow leaving next->end
|
||||
// NULL and call lzma_free() here.
|
||||
if (next->end != NULL)
|
||||
next->end(next->coder, allocator);
|
||||
else
|
||||
lzma_free(next->coder, allocator);
|
||||
|
||||
// Reset the variables so the we don't accidentally think
|
||||
// that it is an already initialized coder.
|
||||
*next = LZMA_NEXT_CODER_INIT;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
// External to internal API wrapper //
|
||||
//////////////////////////////////////
|
||||
|
||||
extern lzma_ret
|
||||
lzma_strm_init(lzma_stream *strm)
|
||||
{
|
||||
if (strm == NULL)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
if (strm->internal == NULL) {
|
||||
strm->internal = lzma_alloc(sizeof(lzma_internal),
|
||||
strm->allocator);
|
||||
if (strm->internal == NULL)
|
||||
return LZMA_MEM_ERROR;
|
||||
|
||||
strm->internal->next = LZMA_NEXT_CODER_INIT;
|
||||
}
|
||||
|
||||
memzero(strm->internal->supported_actions,
|
||||
sizeof(strm->internal->supported_actions));
|
||||
strm->internal->sequence = ISEQ_RUN;
|
||||
strm->internal->allow_buf_error = false;
|
||||
|
||||
strm->total_in = 0;
|
||||
strm->total_out = 0;
|
||||
|
||||
return LZMA_OK;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(lzma_ret)
|
||||
lzma_code(lzma_stream *strm, lzma_action action)
|
||||
{
|
||||
// Sanity checks
|
||||
if ((strm->next_in == NULL && strm->avail_in != 0)
|
||||
|| (strm->next_out == NULL && strm->avail_out != 0)
|
||||
|| strm->internal == NULL
|
||||
|| strm->internal->next.code == NULL
|
||||
|| (unsigned int)(action) > LZMA_ACTION_MAX
|
||||
|| !strm->internal->supported_actions[action])
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
// Check if unsupported members have been set to non-zero or non-NULL,
|
||||
// which would indicate that some new feature is wanted.
|
||||
if (strm->reserved_ptr1 != NULL
|
||||
|| strm->reserved_ptr2 != NULL
|
||||
|| strm->reserved_ptr3 != NULL
|
||||
|| strm->reserved_ptr4 != NULL
|
||||
|| strm->reserved_int1 != 0
|
||||
|| strm->reserved_int2 != 0
|
||||
|| strm->reserved_int3 != 0
|
||||
|| strm->reserved_int4 != 0
|
||||
|| strm->reserved_enum1 != LZMA_RESERVED_ENUM
|
||||
|| strm->reserved_enum2 != LZMA_RESERVED_ENUM)
|
||||
return LZMA_OPTIONS_ERROR;
|
||||
|
||||
switch (strm->internal->sequence) {
|
||||
case ISEQ_RUN:
|
||||
switch (action) {
|
||||
case LZMA_RUN:
|
||||
break;
|
||||
|
||||
case LZMA_SYNC_FLUSH:
|
||||
strm->internal->sequence = ISEQ_SYNC_FLUSH;
|
||||
break;
|
||||
|
||||
case LZMA_FULL_FLUSH:
|
||||
strm->internal->sequence = ISEQ_FULL_FLUSH;
|
||||
break;
|
||||
|
||||
case LZMA_FINISH:
|
||||
strm->internal->sequence = ISEQ_FINISH;
|
||||
break;
|
||||
|
||||
case LZMA_FULL_BARRIER:
|
||||
strm->internal->sequence = ISEQ_FULL_BARRIER;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ISEQ_SYNC_FLUSH:
|
||||
// The same action must be used until we return
|
||||
// LZMA_STREAM_END, and the amount of input must not change.
|
||||
if (action != LZMA_SYNC_FLUSH
|
||||
|| strm->internal->avail_in != strm->avail_in)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
break;
|
||||
|
||||
case ISEQ_FULL_FLUSH:
|
||||
if (action != LZMA_FULL_FLUSH
|
||||
|| strm->internal->avail_in != strm->avail_in)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
break;
|
||||
|
||||
case ISEQ_FINISH:
|
||||
if (action != LZMA_FINISH
|
||||
|| strm->internal->avail_in != strm->avail_in)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
break;
|
||||
|
||||
case ISEQ_FULL_BARRIER:
|
||||
if (action != LZMA_FULL_BARRIER
|
||||
|| strm->internal->avail_in != strm->avail_in)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
break;
|
||||
|
||||
case ISEQ_END:
|
||||
return LZMA_STREAM_END;
|
||||
|
||||
case ISEQ_ERROR:
|
||||
default:
|
||||
return LZMA_PROG_ERROR;
|
||||
}
|
||||
|
||||
size_t in_pos = 0;
|
||||
size_t out_pos = 0;
|
||||
lzma_ret ret = strm->internal->next.code(
|
||||
strm->internal->next.coder, strm->allocator,
|
||||
strm->next_in, &in_pos, strm->avail_in,
|
||||
strm->next_out, &out_pos, strm->avail_out, action);
|
||||
|
||||
strm->next_in += in_pos;
|
||||
strm->avail_in -= in_pos;
|
||||
strm->total_in += in_pos;
|
||||
|
||||
strm->next_out += out_pos;
|
||||
strm->avail_out -= out_pos;
|
||||
strm->total_out += out_pos;
|
||||
|
||||
strm->internal->avail_in = strm->avail_in;
|
||||
|
||||
// Cast is needed to silence a warning about LZMA_TIMED_OUT, which
|
||||
// isn't part of lzma_ret enumeration.
|
||||
switch ((unsigned int)(ret)) {
|
||||
case LZMA_OK:
|
||||
// Don't return LZMA_BUF_ERROR when it happens the first time.
|
||||
// This is to avoid returning LZMA_BUF_ERROR when avail_out
|
||||
// was zero but still there was no more data left to written
|
||||
// to next_out.
|
||||
if (out_pos == 0 && in_pos == 0) {
|
||||
if (strm->internal->allow_buf_error)
|
||||
ret = LZMA_BUF_ERROR;
|
||||
else
|
||||
strm->internal->allow_buf_error = true;
|
||||
} else {
|
||||
strm->internal->allow_buf_error = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case LZMA_TIMED_OUT:
|
||||
strm->internal->allow_buf_error = false;
|
||||
ret = LZMA_OK;
|
||||
break;
|
||||
|
||||
case LZMA_STREAM_END:
|
||||
if (strm->internal->sequence == ISEQ_SYNC_FLUSH
|
||||
|| strm->internal->sequence == ISEQ_FULL_FLUSH
|
||||
|| strm->internal->sequence
|
||||
== ISEQ_FULL_BARRIER)
|
||||
strm->internal->sequence = ISEQ_RUN;
|
||||
else
|
||||
strm->internal->sequence = ISEQ_END;
|
||||
|
||||
// Fall through
|
||||
|
||||
case LZMA_NO_CHECK:
|
||||
case LZMA_UNSUPPORTED_CHECK:
|
||||
case LZMA_GET_CHECK:
|
||||
case LZMA_MEMLIMIT_ERROR:
|
||||
// Something else than LZMA_OK, but not a fatal error,
|
||||
// that is, coding may be continued (except if ISEQ_END).
|
||||
strm->internal->allow_buf_error = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
// All the other errors are fatal; coding cannot be continued.
|
||||
assert(ret != LZMA_BUF_ERROR);
|
||||
strm->internal->sequence = ISEQ_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(void)
|
||||
lzma_end(lzma_stream *strm)
|
||||
{
|
||||
if (strm != NULL && strm->internal != NULL) {
|
||||
lzma_next_end(&strm->internal->next, strm->allocator);
|
||||
lzma_free(strm->internal, strm->allocator);
|
||||
strm->internal = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(void)
|
||||
lzma_get_progress(lzma_stream *strm,
|
||||
uint64_t *progress_in, uint64_t *progress_out)
|
||||
{
|
||||
if (strm->internal->next.get_progress != NULL) {
|
||||
strm->internal->next.get_progress(strm->internal->next.coder,
|
||||
progress_in, progress_out);
|
||||
} else {
|
||||
*progress_in = strm->total_in;
|
||||
*progress_out = strm->total_out;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(lzma_check)
|
||||
lzma_get_check(const lzma_stream *strm)
|
||||
{
|
||||
// Return LZMA_CHECK_NONE if we cannot know the check type.
|
||||
// It's a bug in the application if this happens.
|
||||
if (strm->internal->next.get_check == NULL)
|
||||
return LZMA_CHECK_NONE;
|
||||
|
||||
return strm->internal->next.get_check(strm->internal->next.coder);
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(uint64_t)
|
||||
lzma_memusage(const lzma_stream *strm)
|
||||
{
|
||||
uint64_t memusage;
|
||||
uint64_t old_memlimit;
|
||||
|
||||
if (strm == NULL || strm->internal == NULL
|
||||
|| strm->internal->next.memconfig == NULL
|
||||
|| strm->internal->next.memconfig(
|
||||
strm->internal->next.coder,
|
||||
&memusage, &old_memlimit, 0) != LZMA_OK)
|
||||
return 0;
|
||||
|
||||
return memusage;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(uint64_t)
|
||||
lzma_memlimit_get(const lzma_stream *strm)
|
||||
{
|
||||
uint64_t old_memlimit;
|
||||
uint64_t memusage;
|
||||
|
||||
if (strm == NULL || strm->internal == NULL
|
||||
|| strm->internal->next.memconfig == NULL
|
||||
|| strm->internal->next.memconfig(
|
||||
strm->internal->next.coder,
|
||||
&memusage, &old_memlimit, 0) != LZMA_OK)
|
||||
return 0;
|
||||
|
||||
return old_memlimit;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(lzma_ret)
|
||||
lzma_memlimit_set(lzma_stream *strm, uint64_t new_memlimit)
|
||||
{
|
||||
// Dummy variables to simplify memconfig functions
|
||||
uint64_t old_memlimit;
|
||||
uint64_t memusage;
|
||||
|
||||
if (strm == NULL || strm->internal == NULL
|
||||
|| strm->internal->next.memconfig == NULL)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
if (new_memlimit != 0 && new_memlimit < LZMA_MEMUSAGE_BASE)
|
||||
return LZMA_MEMLIMIT_ERROR;
|
||||
|
||||
return strm->internal->next.memconfig(strm->internal->next.coder,
|
||||
&memusage, &old_memlimit, new_memlimit);
|
||||
}
|
||||
+313
@@ -0,0 +1,313 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file common.h
|
||||
/// \brief Definitions common to the whole liblzma library
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef LZMA_COMMON_H
|
||||
#define LZMA_COMMON_H
|
||||
|
||||
#include "sysdefs.h"
|
||||
#include "tuklib_integer.h"
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# ifdef DLL_EXPORT
|
||||
# define LZMA_API_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define LZMA_API_EXPORT
|
||||
# endif
|
||||
// Don't use ifdef or defined() below.
|
||||
#elif HAVE_VISIBILITY
|
||||
# define LZMA_API_EXPORT __attribute__((__visibility__("default")))
|
||||
#else
|
||||
# define LZMA_API_EXPORT
|
||||
#endif
|
||||
|
||||
#define LZMA_API(type) LZMA_API_EXPORT type LZMA_API_CALL
|
||||
|
||||
#include "lzma.h"
|
||||
|
||||
// These allow helping the compiler in some often-executed branches, whose
|
||||
// result is almost always the same.
|
||||
#ifdef __GNUC__
|
||||
# define likely(expr) __builtin_expect(expr, true)
|
||||
# define unlikely(expr) __builtin_expect(expr, false)
|
||||
#else
|
||||
# define likely(expr) (expr)
|
||||
# define unlikely(expr) (expr)
|
||||
#endif
|
||||
|
||||
|
||||
/// Size of temporary buffers needed in some filters
|
||||
#define LZMA_BUFFER_SIZE 4096
|
||||
|
||||
|
||||
/// Maximum number of worker threads within one multithreaded component.
|
||||
/// The limit exists solely to make it simpler to prevent integer overflows
|
||||
/// when allocating structures etc. This should be big enough for now...
|
||||
/// the code won't scale anywhere close to this number anyway.
|
||||
#define LZMA_THREADS_MAX 16384
|
||||
|
||||
|
||||
/// Starting value for memory usage estimates. Instead of calculating size
|
||||
/// of _every_ structure and taking into account malloc() overhead etc., we
|
||||
/// add a base size to all memory usage estimates. It's not very accurate
|
||||
/// but should be easily good enough.
|
||||
#define LZMA_MEMUSAGE_BASE (UINT64_C(1) << 15)
|
||||
|
||||
/// Start of internal Filter ID space. These IDs must never be used
|
||||
/// in Streams.
|
||||
#define LZMA_FILTER_RESERVED_START (LZMA_VLI_C(1) << 62)
|
||||
|
||||
|
||||
/// Supported flags that can be passed to lzma_stream_decoder()
|
||||
/// or lzma_auto_decoder().
|
||||
#define LZMA_SUPPORTED_FLAGS \
|
||||
( LZMA_TELL_NO_CHECK \
|
||||
| LZMA_TELL_UNSUPPORTED_CHECK \
|
||||
| LZMA_TELL_ANY_CHECK \
|
||||
| LZMA_IGNORE_CHECK \
|
||||
| LZMA_CONCATENATED )
|
||||
|
||||
|
||||
/// Largest valid lzma_action value as unsigned integer.
|
||||
#define LZMA_ACTION_MAX ((unsigned int)(LZMA_FULL_BARRIER))
|
||||
|
||||
|
||||
/// Special return value (lzma_ret) to indicate that a timeout was reached
|
||||
/// and lzma_code() must not return LZMA_BUF_ERROR. This is converted to
|
||||
/// LZMA_OK in lzma_code(). This is not in the lzma_ret enumeration because
|
||||
/// there's no need to have it in the public API.
|
||||
#define LZMA_TIMED_OUT 32
|
||||
|
||||
|
||||
typedef struct lzma_next_coder_s lzma_next_coder;
|
||||
|
||||
typedef struct lzma_filter_info_s lzma_filter_info;
|
||||
|
||||
|
||||
/// Type of a function used to initialize a filter encoder or decoder
|
||||
typedef lzma_ret (*lzma_init_function)(
|
||||
lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
const lzma_filter_info *filters);
|
||||
|
||||
/// Type of a function to do some kind of coding work (filters, Stream,
|
||||
/// Block encoders/decoders etc.). Some special coders use don't use both
|
||||
/// input and output buffers, but for simplicity they still use this same
|
||||
/// function prototype.
|
||||
typedef lzma_ret (*lzma_code_function)(
|
||||
void *coder, const 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);
|
||||
|
||||
/// Type of a function to free the memory allocated for the coder
|
||||
typedef void (*lzma_end_function)(
|
||||
void *coder, const lzma_allocator *allocator);
|
||||
|
||||
|
||||
/// Raw coder validates and converts an array of lzma_filter structures to
|
||||
/// an array of lzma_filter_info structures. This array is used with
|
||||
/// lzma_next_filter_init to initialize the filter chain.
|
||||
struct lzma_filter_info_s {
|
||||
/// Filter ID. This is used only by the encoder
|
||||
/// with lzma_filters_update().
|
||||
lzma_vli id;
|
||||
|
||||
/// 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;
|
||||
};
|
||||
|
||||
|
||||
/// Hold data and function pointers of the next filter in the chain.
|
||||
struct lzma_next_coder_s {
|
||||
/// Pointer to coder-specific data
|
||||
void *coder;
|
||||
|
||||
/// Filter ID. This is LZMA_VLI_UNKNOWN when this structure doesn't
|
||||
/// point to a filter coder.
|
||||
lzma_vli id;
|
||||
|
||||
/// "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 lzma_next_coder_init and
|
||||
/// lzma_next_strm_init macros in this file.
|
||||
uintptr_t init;
|
||||
|
||||
/// Pointer to function to do the actual coding
|
||||
lzma_code_function code;
|
||||
|
||||
/// Pointer to function to free lzma_next_coder.coder. This can
|
||||
/// be NULL; in that case, lzma_free is called to free
|
||||
/// lzma_next_coder.coder.
|
||||
lzma_end_function end;
|
||||
|
||||
/// Pointer to a function to get progress information. If this is NULL,
|
||||
/// lzma_stream.total_in and .total_out are used instead.
|
||||
void (*get_progress)(void *coder,
|
||||
uint64_t *progress_in, uint64_t *progress_out);
|
||||
|
||||
/// Pointer to function to return the type of the integrity check.
|
||||
/// Most coders won't support this.
|
||||
lzma_check (*get_check)(const void *coder);
|
||||
|
||||
/// Pointer to function to get and/or change the memory usage limit.
|
||||
/// If new_memlimit == 0, the limit is not changed.
|
||||
lzma_ret (*memconfig)(void *coder, uint64_t *memusage,
|
||||
uint64_t *old_memlimit, uint64_t new_memlimit);
|
||||
|
||||
/// Update the filter-specific options or the whole filter chain
|
||||
/// in the encoder.
|
||||
lzma_ret (*update)(void *coder, const lzma_allocator *allocator,
|
||||
const lzma_filter *filters,
|
||||
const lzma_filter *reversed_filters);
|
||||
};
|
||||
|
||||
|
||||
/// Macro to initialize lzma_next_coder structure
|
||||
#define LZMA_NEXT_CODER_INIT \
|
||||
(lzma_next_coder){ \
|
||||
.coder = NULL, \
|
||||
.init = (uintptr_t)(NULL), \
|
||||
.id = LZMA_VLI_UNKNOWN, \
|
||||
.code = NULL, \
|
||||
.end = NULL, \
|
||||
.get_progress = NULL, \
|
||||
.get_check = NULL, \
|
||||
.memconfig = NULL, \
|
||||
.update = NULL, \
|
||||
}
|
||||
|
||||
|
||||
/// Internal data for lzma_strm_init, lzma_code, and lzma_end. A pointer to
|
||||
/// this is stored in lzma_stream.
|
||||
struct lzma_internal_s {
|
||||
/// The actual coder that should do something useful
|
||||
lzma_next_coder next;
|
||||
|
||||
/// Track the state of the coder. This is used to validate arguments
|
||||
/// so that the actual coders can rely on e.g. that LZMA_SYNC_FLUSH
|
||||
/// is used on every call to lzma_code until next.code has returned
|
||||
/// LZMA_STREAM_END.
|
||||
enum {
|
||||
ISEQ_RUN,
|
||||
ISEQ_SYNC_FLUSH,
|
||||
ISEQ_FULL_FLUSH,
|
||||
ISEQ_FINISH,
|
||||
ISEQ_FULL_BARRIER,
|
||||
ISEQ_END,
|
||||
ISEQ_ERROR,
|
||||
} sequence;
|
||||
|
||||
/// A copy of lzma_stream avail_in. This is used to verify that the
|
||||
/// amount of input doesn't change once e.g. LZMA_FINISH has been
|
||||
/// used.
|
||||
size_t avail_in;
|
||||
|
||||
/// Indicates which lzma_action values are allowed by next.code.
|
||||
bool supported_actions[LZMA_ACTION_MAX + 1];
|
||||
|
||||
/// If true, lzma_code will return LZMA_BUF_ERROR if no progress was
|
||||
/// made (no input consumed and no output produced by next.code).
|
||||
bool allow_buf_error;
|
||||
};
|
||||
|
||||
|
||||
/// Allocates memory
|
||||
extern void *lzma_alloc(size_t size, const lzma_allocator *allocator)
|
||||
lzma_attribute((__malloc__)) lzma_attr_alloc_size(1);
|
||||
|
||||
/// Allocates memory and zeroes it (like calloc()). This can be faster
|
||||
/// than lzma_alloc() + memzero() while being backward compatible with
|
||||
/// custom allocators.
|
||||
extern void * lzma_attribute((__malloc__)) lzma_attr_alloc_size(1)
|
||||
lzma_alloc_zero(size_t size, const lzma_allocator *allocator);
|
||||
|
||||
/// Frees memory
|
||||
extern void lzma_free(void *ptr, const lzma_allocator *allocator);
|
||||
|
||||
|
||||
/// Allocates strm->internal if it is NULL, and initializes *strm and
|
||||
/// strm->internal. This function is only called via lzma_next_strm_init macro.
|
||||
extern lzma_ret lzma_strm_init(lzma_stream *strm);
|
||||
|
||||
/// Initializes the next filter in the chain, if any. This takes care of
|
||||
/// freeing the memory of previously initialized filter if it is different
|
||||
/// than the filter being initialized now. This way the actual filter
|
||||
/// initialization functions don't need to use lzma_next_coder_init macro.
|
||||
extern lzma_ret lzma_next_filter_init(lzma_next_coder *next,
|
||||
const lzma_allocator *allocator,
|
||||
const lzma_filter_info *filters);
|
||||
|
||||
/// Update the next filter in the chain, if any. This checks that
|
||||
/// the application is not trying to change the Filter IDs.
|
||||
extern lzma_ret lzma_next_filter_update(
|
||||
lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
const lzma_filter *reversed_filters);
|
||||
|
||||
/// Frees the memory allocated for next->coder either using next->end or,
|
||||
/// if next->end is NULL, using lzma_free.
|
||||
extern void lzma_next_end(lzma_next_coder *next,
|
||||
const lzma_allocator *allocator);
|
||||
|
||||
|
||||
/// Copy as much data as possible from in[] to out[] and update *in_pos
|
||||
/// and *out_pos accordingly. Returns the number of bytes copied.
|
||||
extern size_t lzma_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);
|
||||
|
||||
|
||||
/// \brief Return if expression doesn't evaluate to LZMA_OK
|
||||
///
|
||||
/// There are several situations where we want to return immediately
|
||||
/// with the value of expr if it isn't LZMA_OK. This macro shortens
|
||||
/// the code a little.
|
||||
#define return_if_error(expr) \
|
||||
do { \
|
||||
const lzma_ret ret_ = (expr); \
|
||||
if (ret_ != LZMA_OK) \
|
||||
return ret_; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/// If next isn't already initialized, free the previous coder. Then mark
|
||||
/// that next is _possibly_ initialized for the coder using this macro.
|
||||
/// "Possibly" means that if e.g. allocation of next->coder fails, the
|
||||
/// structure isn't actually initialized for this coder, but leaving
|
||||
/// next->init to func is still OK.
|
||||
#define lzma_next_coder_init(func, next, allocator) \
|
||||
do { \
|
||||
if ((uintptr_t)(func) != (next)->init) \
|
||||
lzma_next_end(next, allocator); \
|
||||
(next)->init = (uintptr_t)(func); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/// Initializes lzma_strm and calls func() to initialize strm->internal->next.
|
||||
/// (The function being called will use lzma_next_coder_init()). If
|
||||
/// initialization fails, memory that wasn't freed by func() is freed
|
||||
/// along strm->internal.
|
||||
#define lzma_next_strm_init(func, strm, ...) \
|
||||
do { \
|
||||
return_if_error(lzma_strm_init(strm)); \
|
||||
const lzma_ret ret_ = func(&(strm)->internal->next, \
|
||||
(strm)->allocator, __VA_ARGS__); \
|
||||
if (ret_ != LZMA_OK) { \
|
||||
lzma_end(strm); \
|
||||
return ret_; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,238 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file filter_decoder.c
|
||||
/// \brief Filter ID mapping to filter-specific functions
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "filter_encoder.h"
|
||||
#include "lzma_encoder.h"
|
||||
#ifdef HAVE_DECODER_LZMA2
|
||||
#include "lzma2_encoder.h"
|
||||
#endif
|
||||
#if defined(HAVE_DECODER_X86) || \
|
||||
defined(HAVE_DECODER_POWERPC) || \
|
||||
defined(HAVE_DECODER_IA64) || \
|
||||
defined(HAVE_DECODER_ARM) || \
|
||||
defined(HAVE_DECODER_ARMTHUMB) || \
|
||||
defined(HAVE_DECODER_SPARC)
|
||||
#include "simple_encoder.h"
|
||||
#endif
|
||||
#ifdef HAVE_DECODER_DELTA
|
||||
#include "delta_encoder.h"
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
/// Filter ID
|
||||
lzma_vli id;
|
||||
|
||||
/// Initializes the filter encoder and calls lzma_next_filter_init()
|
||||
/// for filters + 1.
|
||||
lzma_init_function init;
|
||||
|
||||
/// Calculates memory usage of the encoder. If the options are
|
||||
/// invalid, UINT64_MAX is returned.
|
||||
uint64_t (*memusage)(const void *options);
|
||||
|
||||
/// Calculates the recommended Uncompressed Size for .xz Blocks to
|
||||
/// which the input data can be split to make multithreaded
|
||||
/// encoding possible. If this is NULL, it is assumed that
|
||||
/// the encoder is fast enough with single thread.
|
||||
uint64_t (*block_size)(const void *options);
|
||||
|
||||
/// Tells the size of the Filter Properties field. If options are
|
||||
/// invalid, UINT32_MAX is returned. If this is NULL, props_size_fixed
|
||||
/// is used.
|
||||
lzma_ret (*props_size_get)(uint32_t *size, const void *options);
|
||||
uint32_t props_size_fixed;
|
||||
|
||||
/// Encodes Filter Properties.
|
||||
///
|
||||
/// \return - LZMA_OK: Properties encoded successfully.
|
||||
/// - LZMA_OPTIONS_ERROR: Unsupported options
|
||||
/// - LZMA_PROG_ERROR: Invalid options or not enough
|
||||
/// output space
|
||||
lzma_ret (*props_encode)(const void *options, uint8_t *out);
|
||||
|
||||
} lzma_filter_encoder;
|
||||
|
||||
|
||||
static const lzma_filter_encoder encoders[] = {
|
||||
#ifdef HAVE_ENCODER_LZMA1
|
||||
{
|
||||
.id = LZMA_FILTER_LZMA1,
|
||||
.init = &lzma_lzma_encoder_init,
|
||||
.memusage = &lzma_lzma_encoder_memusage,
|
||||
.block_size = NULL, // FIXME
|
||||
.props_size_get = NULL,
|
||||
.props_size_fixed = 5,
|
||||
.props_encode = &lzma_lzma_props_encode,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_ENCODER_LZMA2
|
||||
{
|
||||
.id = LZMA_FILTER_LZMA2,
|
||||
.init = &lzma_lzma2_encoder_init,
|
||||
.memusage = &lzma_lzma2_encoder_memusage,
|
||||
.block_size = &lzma_lzma2_block_size, // FIXME
|
||||
.props_size_get = NULL,
|
||||
.props_size_fixed = 1,
|
||||
.props_encode = &lzma_lzma2_props_encode,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_ENCODER_X86
|
||||
{
|
||||
.id = LZMA_FILTER_X86,
|
||||
.init = &lzma_simple_x86_encoder_init,
|
||||
.memusage = NULL,
|
||||
.block_size = NULL,
|
||||
.props_size_get = &lzma_simple_props_size,
|
||||
.props_encode = &lzma_simple_props_encode,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_ENCODER_POWERPC
|
||||
{
|
||||
.id = LZMA_FILTER_POWERPC,
|
||||
.init = &lzma_simple_powerpc_encoder_init,
|
||||
.memusage = NULL,
|
||||
.block_size = NULL,
|
||||
.props_size_get = &lzma_simple_props_size,
|
||||
.props_encode = &lzma_simple_props_encode,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_ENCODER_IA64
|
||||
{
|
||||
.id = LZMA_FILTER_IA64,
|
||||
.init = &lzma_simple_ia64_encoder_init,
|
||||
.memusage = NULL,
|
||||
.block_size = NULL,
|
||||
.props_size_get = &lzma_simple_props_size,
|
||||
.props_encode = &lzma_simple_props_encode,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_ENCODER_ARM
|
||||
{
|
||||
.id = LZMA_FILTER_ARM,
|
||||
.init = &lzma_simple_arm_encoder_init,
|
||||
.memusage = NULL,
|
||||
.block_size = NULL,
|
||||
.props_size_get = &lzma_simple_props_size,
|
||||
.props_encode = &lzma_simple_props_encode,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_ENCODER_ARMTHUMB
|
||||
{
|
||||
.id = LZMA_FILTER_ARMTHUMB,
|
||||
.init = &lzma_simple_armthumb_encoder_init,
|
||||
.memusage = NULL,
|
||||
.block_size = NULL,
|
||||
.props_size_get = &lzma_simple_props_size,
|
||||
.props_encode = &lzma_simple_props_encode,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_ENCODER_SPARC
|
||||
{
|
||||
.id = LZMA_FILTER_SPARC,
|
||||
.init = &lzma_simple_sparc_encoder_init,
|
||||
.memusage = NULL,
|
||||
.block_size = NULL,
|
||||
.props_size_get = &lzma_simple_props_size,
|
||||
.props_encode = &lzma_simple_props_encode,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_ENCODER_DELTA
|
||||
{
|
||||
.id = LZMA_FILTER_DELTA,
|
||||
.init = &lzma_delta_encoder_init,
|
||||
.memusage = &lzma_delta_coder_memusage,
|
||||
.block_size = NULL,
|
||||
.props_size_get = NULL,
|
||||
.props_size_fixed = 1,
|
||||
.props_encode = &lzma_delta_props_encode,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
static const lzma_filter_encoder *
|
||||
encoder_find(lzma_vli id)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_SIZE(encoders); ++i)
|
||||
if (encoders[i].id == id)
|
||||
return encoders + i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(lzma_bool)
|
||||
lzma_filter_encoder_is_supported(lzma_vli id)
|
||||
{
|
||||
return encoder_find(id) != NULL;
|
||||
}
|
||||
|
||||
|
||||
extern uint64_t
|
||||
lzma_mt_block_size(const lzma_filter *filters)
|
||||
{
|
||||
uint64_t max = 0;
|
||||
|
||||
for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
|
||||
const lzma_filter_encoder *const fe
|
||||
= encoder_find(filters[i].id);
|
||||
if (fe->block_size != NULL) {
|
||||
const uint64_t size
|
||||
= fe->block_size(filters[i].options);
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
if (size > max)
|
||||
max = size;
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(lzma_ret)
|
||||
lzma_properties_size(uint32_t *size, const lzma_filter *filter)
|
||||
{
|
||||
const lzma_filter_encoder *const fe = encoder_find(filter->id);
|
||||
if (fe == NULL) {
|
||||
// Unknown filter - if the Filter ID is a proper VLI,
|
||||
// return LZMA_OPTIONS_ERROR instead of LZMA_PROG_ERROR,
|
||||
// because it's possible that we just don't have support
|
||||
// compiled in for the requested filter.
|
||||
return filter->id <= LZMA_VLI_MAX
|
||||
? LZMA_OPTIONS_ERROR : LZMA_PROG_ERROR;
|
||||
}
|
||||
|
||||
if (fe->props_size_get == NULL) {
|
||||
// No props_size_get() function, use props_size_fixed.
|
||||
*size = fe->props_size_fixed;
|
||||
return LZMA_OK;
|
||||
}
|
||||
|
||||
return fe->props_size_get(size, filter->options);
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(lzma_ret)
|
||||
lzma_properties_encode(const lzma_filter *filter, uint8_t *props)
|
||||
{
|
||||
const lzma_filter_encoder *const fe = encoder_find(filter->id);
|
||||
if (fe == NULL)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
if (fe->props_encode == NULL)
|
||||
return LZMA_OK;
|
||||
|
||||
return fe->props_encode(filter->options, props);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file filter_encoder.c
|
||||
/// \brief Filter ID mapping to filter-specific functions
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef LZMA_FILTER_ENCODER_H
|
||||
#define LZMA_FILTER_ENCODER_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
// FIXME: Might become a part of the public API.
|
||||
extern uint64_t lzma_mt_block_size(const lzma_filter *filters);
|
||||
|
||||
|
||||
extern lzma_ret lzma_raw_encoder_init(
|
||||
lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
const lzma_filter *filters);
|
||||
|
||||
#endif
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file index.h
|
||||
/// \brief Handling of Index
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef LZMA_INDEX_H
|
||||
#define LZMA_INDEX_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/// Minimum Unpadded Size
|
||||
#define UNPADDED_SIZE_MIN LZMA_VLI_C(5)
|
||||
|
||||
/// Maximum Unpadded Size
|
||||
#define UNPADDED_SIZE_MAX (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
|
||||
|
||||
|
||||
/// Get the size of the Index Padding field. This is needed by Index encoder
|
||||
/// and decoder, but applications should have no use for this.
|
||||
extern uint32_t lzma_index_padding_size(const lzma_index *i);
|
||||
|
||||
|
||||
/// Set for how many Records to allocate memory the next time
|
||||
/// lzma_index_append() needs to allocate space for a new Record.
|
||||
/// This is used only by the Index decoder.
|
||||
extern void lzma_index_prealloc(lzma_index *i, lzma_vli records);
|
||||
|
||||
|
||||
/// Round the variable-length integer to the next multiple of four.
|
||||
static inline lzma_vli
|
||||
vli_ceil4(lzma_vli vli)
|
||||
{
|
||||
assert(vli <= LZMA_VLI_MAX);
|
||||
return (vli + 3) & ~LZMA_VLI_C(3);
|
||||
}
|
||||
|
||||
|
||||
/// Calculate the size of the Index field excluding Index Padding
|
||||
static inline lzma_vli
|
||||
index_size_unpadded(lzma_vli count, lzma_vli index_list_size)
|
||||
{
|
||||
// Index Indicator + Number of Records + List of Records + CRC32
|
||||
return 1 + lzma_vli_size(count) + index_list_size + 4;
|
||||
}
|
||||
|
||||
|
||||
/// Calculate the size of the Index field including Index Padding
|
||||
static inline lzma_vli
|
||||
index_size(lzma_vli count, lzma_vli index_list_size)
|
||||
{
|
||||
return vli_ceil4(index_size_unpadded(count, index_list_size));
|
||||
}
|
||||
|
||||
|
||||
/// Calculate the total size of the Stream
|
||||
static inline lzma_vli
|
||||
index_stream_size(lzma_vli blocks_size,
|
||||
lzma_vli count, lzma_vli index_list_size)
|
||||
{
|
||||
return LZMA_STREAM_HEADER_SIZE + blocks_size
|
||||
+ index_size(count, index_list_size)
|
||||
+ LZMA_STREAM_HEADER_SIZE;
|
||||
}
|
||||
|
||||
#endif
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file memcmplen.h
|
||||
/// \brief Optimized comparison of two buffers
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef LZMA_MEMCMPLEN_H
|
||||
#define LZMA_MEMCMPLEN_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef HAVE_IMMINTRIN_H
|
||||
# include <immintrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// Find out how many equal bytes the two buffers have.
|
||||
///
|
||||
/// \param buf1 First buffer
|
||||
/// \param buf2 Second buffer
|
||||
/// \param len How many bytes have already been compared and will
|
||||
/// be assumed to match
|
||||
/// \param limit How many bytes to compare at most, including the
|
||||
/// already-compared bytes. This must be significantly
|
||||
/// smaller than UINT32_MAX to avoid integer overflows.
|
||||
/// Up to LZMA_MEMCMPLEN_EXTRA bytes may be read past
|
||||
/// the specified limit from both buf1 and buf2.
|
||||
///
|
||||
/// \return Number of equal bytes in the buffers is returned.
|
||||
/// This is always at least len and at most limit.
|
||||
///
|
||||
/// \note LZMA_MEMCMPLEN_EXTRA defines how many extra bytes may be read.
|
||||
/// It's rounded up to 2^n. This extra amount needs to be
|
||||
/// allocated in the buffers being used. It needs to be
|
||||
/// initialized too to keep Valgrind quiet.
|
||||
static inline uint32_t lzma_attribute((__always_inline__))
|
||||
lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
|
||||
uint32_t len, uint32_t limit)
|
||||
{
|
||||
assert(len <= limit);
|
||||
assert(limit <= UINT32_MAX / 2);
|
||||
|
||||
#if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
|
||||
&& ((TUKLIB_GNUC_REQ(3, 4) && defined(__x86_64__)) \
|
||||
|| (defined(__INTEL_COMPILER) && defined(__x86_64__)) \
|
||||
|| (defined(__INTEL_COMPILER) && defined(_M_X64)) \
|
||||
|| (defined(_MSC_VER) && defined(_M_X64)))
|
||||
// NOTE: This will use 64-bit unaligned access which
|
||||
// TUKLIB_FAST_UNALIGNED_ACCESS wasn't meant to permit, but
|
||||
// it's convenient here at least as long as it's x86-64 only.
|
||||
//
|
||||
// I keep this x86-64 only for now since that's where I know this
|
||||
// to be a good method. This may be fine on other 64-bit CPUs too.
|
||||
// On big endian one should use xor instead of subtraction and switch
|
||||
// to __builtin_clzll().
|
||||
#define LZMA_MEMCMPLEN_EXTRA 8
|
||||
while (len < limit) {
|
||||
const uint64_t x = *(const uint64_t *)(buf1 + len)
|
||||
- *(const uint64_t *)(buf2 + len);
|
||||
if (x != 0) {
|
||||
# if defined(_M_X64) // MSVC or Intel C compiler on Windows
|
||||
unsigned long tmp;
|
||||
_BitScanForward64(&tmp, x);
|
||||
len += (uint32_t)tmp >> 3;
|
||||
# else // GCC, clang, or Intel C compiler
|
||||
len += (uint32_t)__builtin_ctzll(x) >> 3;
|
||||
# endif
|
||||
return my_min(len, limit);
|
||||
}
|
||||
|
||||
len += 8;
|
||||
}
|
||||
|
||||
return limit;
|
||||
|
||||
#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
|
||||
&& defined(HAVE__MM_MOVEMASK_EPI8) \
|
||||
&& ((defined(__GNUC__) && defined(__SSE2_MATH__)) \
|
||||
|| (defined(__INTEL_COMPILER) && defined(__SSE2__)) \
|
||||
|| (defined(_MSC_VER) && defined(_M_IX86_FP) \
|
||||
&& _M_IX86_FP >= 2))
|
||||
// NOTE: Like above, this will use 128-bit unaligned access which
|
||||
// TUKLIB_FAST_UNALIGNED_ACCESS wasn't meant to permit.
|
||||
//
|
||||
// SSE2 version for 32-bit and 64-bit x86. On x86-64 the above
|
||||
// version is sometimes significantly faster and sometimes
|
||||
// slightly slower than this SSE2 version, so this SSE2
|
||||
// version isn't used on x86-64.
|
||||
# define LZMA_MEMCMPLEN_EXTRA 16
|
||||
while (len < limit) {
|
||||
const uint32_t x = 0xFFFF ^ _mm_movemask_epi8(_mm_cmpeq_epi8(
|
||||
_mm_loadu_si128((const __m128i *)(buf1 + len)),
|
||||
_mm_loadu_si128((const __m128i *)(buf2 + len))));
|
||||
|
||||
if (x != 0) {
|
||||
# if defined(__INTEL_COMPILER)
|
||||
len += _bit_scan_forward(x);
|
||||
# elif defined(_MSC_VER)
|
||||
unsigned long tmp;
|
||||
_BitScanForward(&tmp, x);
|
||||
len += tmp;
|
||||
# else
|
||||
len += __builtin_ctz(x);
|
||||
# endif
|
||||
return my_min(len, limit);
|
||||
}
|
||||
|
||||
len += 16;
|
||||
}
|
||||
|
||||
return limit;
|
||||
|
||||
#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && !defined(WORDS_BIGENDIAN)
|
||||
// Generic 32-bit little endian method
|
||||
# define LZMA_MEMCMPLEN_EXTRA 4
|
||||
while (len < limit) {
|
||||
uint32_t x = *(const uint32_t *)(buf1 + len)
|
||||
- *(const uint32_t *)(buf2 + len);
|
||||
if (x != 0) {
|
||||
if ((x & 0xFFFF) == 0) {
|
||||
len += 2;
|
||||
x >>= 16;
|
||||
}
|
||||
|
||||
if ((x & 0xFF) == 0)
|
||||
++len;
|
||||
|
||||
return my_min(len, limit);
|
||||
}
|
||||
|
||||
len += 4;
|
||||
}
|
||||
|
||||
return limit;
|
||||
|
||||
#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && defined(WORDS_BIGENDIAN)
|
||||
// Generic 32-bit big endian method
|
||||
# define LZMA_MEMCMPLEN_EXTRA 4
|
||||
while (len < limit) {
|
||||
uint32_t x = *(const uint32_t *)(buf1 + len)
|
||||
^ *(const uint32_t *)(buf2 + len);
|
||||
if (x != 0) {
|
||||
if ((x & 0xFFFF0000) == 0) {
|
||||
len += 2;
|
||||
x <<= 16;
|
||||
}
|
||||
|
||||
if ((x & 0xFF000000) == 0)
|
||||
++len;
|
||||
|
||||
return my_min(len, limit);
|
||||
}
|
||||
|
||||
len += 4;
|
||||
}
|
||||
|
||||
return limit;
|
||||
|
||||
#else
|
||||
// Simple portable version that doesn't use unaligned access.
|
||||
# define LZMA_MEMCMPLEN_EXTRA 0
|
||||
while (len < limit && buf1[len] == buf2[len])
|
||||
++len;
|
||||
|
||||
return len;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file sysdefs.h
|
||||
/// \brief Common includes, definitions, system-specific things etc.
|
||||
///
|
||||
/// This file is used also by the lzma command line tool, that's why this
|
||||
/// file is separate from common.h.
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef LZMA_SYSDEFS_H
|
||||
#define LZMA_SYSDEFS_H
|
||||
|
||||
//////////////
|
||||
// Includes //
|
||||
//////////////
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
// Get standard-compliant stdio functions under MinGW and MinGW-w64.
|
||||
#ifdef __MINGW32__
|
||||
# define __USE_MINGW_ANSI_STDIO 1
|
||||
#endif
|
||||
|
||||
// size_t and NULL
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
// C99 says that inttypes.h always includes stdint.h, but some systems
|
||||
// don't do that, and require including stdint.h separately.
|
||||
#ifdef HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
// Some pre-C99 systems have SIZE_MAX in limits.h instead of stdint.h. The
|
||||
// limits are also used to figure out some macros missing from pre-C99 systems.
|
||||
#ifdef HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
// Be more compatible with systems that have non-conforming inttypes.h.
|
||||
// We assume that int is 32-bit and that long is either 32-bit or 64-bit.
|
||||
// Full Autoconf test could be more correct, but this should work well enough.
|
||||
// Note that this duplicates some code from lzma.h, but this is better since
|
||||
// we can work without inttypes.h thanks to Autoconf tests.
|
||||
#ifndef UINT32_C
|
||||
# if UINT_MAX != 4294967295U
|
||||
# error UINT32_C is not defined and unsigned int is not 32-bit.
|
||||
# endif
|
||||
# define UINT32_C(n) n ## U
|
||||
#endif
|
||||
#ifndef UINT32_MAX
|
||||
# define UINT32_MAX UINT32_C(4294967295)
|
||||
#endif
|
||||
#ifndef PRIu32
|
||||
# define PRIu32 "u"
|
||||
#endif
|
||||
#ifndef PRIx32
|
||||
# define PRIx32 "x"
|
||||
#endif
|
||||
#ifndef PRIX32
|
||||
# define PRIX32 "X"
|
||||
#endif
|
||||
|
||||
#if ULONG_MAX == 4294967295UL
|
||||
# ifndef UINT64_C
|
||||
# define UINT64_C(n) n ## ULL
|
||||
# endif
|
||||
# ifndef PRIu64
|
||||
# define PRIu64 "llu"
|
||||
# endif
|
||||
# ifndef PRIx64
|
||||
# define PRIx64 "llx"
|
||||
# endif
|
||||
# ifndef PRIX64
|
||||
# define PRIX64 "llX"
|
||||
# endif
|
||||
#else
|
||||
# ifndef UINT64_C
|
||||
# define UINT64_C(n) n ## UL
|
||||
# endif
|
||||
# ifndef PRIu64
|
||||
# define PRIu64 "lu"
|
||||
# endif
|
||||
# ifndef PRIx64
|
||||
# define PRIx64 "lx"
|
||||
# endif
|
||||
# ifndef PRIX64
|
||||
# define PRIX64 "lX"
|
||||
# endif
|
||||
#endif
|
||||
#ifndef UINT64_MAX
|
||||
# define UINT64_MAX UINT64_C(18446744073709551615)
|
||||
#endif
|
||||
|
||||
// Incorrect(?) SIZE_MAX:
|
||||
// - Interix headers typedef size_t to unsigned long,
|
||||
// but a few lines later define SIZE_MAX to INT32_MAX.
|
||||
// - SCO OpenServer (x86) headers typedef size_t to unsigned int
|
||||
// but define SIZE_MAX to INT32_MAX.
|
||||
#if defined(__INTERIX) || defined(_SCO_DS)
|
||||
# undef SIZE_MAX
|
||||
#endif
|
||||
|
||||
// The code currently assumes that size_t is either 32-bit or 64-bit.
|
||||
#ifndef SIZE_MAX
|
||||
# if SIZEOF_SIZE_T == 4
|
||||
# define SIZE_MAX UINT32_MAX
|
||||
# elif SIZEOF_SIZE_T == 8
|
||||
# define SIZE_MAX UINT64_MAX
|
||||
# else
|
||||
# error size_t is not 32-bit or 64-bit
|
||||
# endif
|
||||
#endif
|
||||
#if SIZE_MAX != UINT32_MAX && SIZE_MAX != UINT64_MAX
|
||||
# error size_t is not 32-bit or 64-bit
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
// Pre-C99 systems lack stdbool.h. All the code in LZMA Utils must be written
|
||||
// so that it works with fake bool type, for example:
|
||||
//
|
||||
// bool foo = (flags & 0x100) != 0;
|
||||
// bool bar = !!(flags & 0x100);
|
||||
//
|
||||
// This works with the real C99 bool but breaks with fake bool:
|
||||
//
|
||||
// bool baz = (flags & 0x100);
|
||||
//
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
# include <stdbool.h>
|
||||
#else
|
||||
# if ! HAVE__BOOL
|
||||
typedef unsigned char _Bool;
|
||||
# endif
|
||||
# define bool _Bool
|
||||
# define false 0
|
||||
# define true 1
|
||||
# define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
// string.h should be enough but let's include strings.h and memory.h too if
|
||||
// they exists, since that shouldn't do any harm, but may improve portability.
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMORY_H
|
||||
# include <memory.h>
|
||||
#endif
|
||||
|
||||
// As of MSVC 2013, inline and restrict are supported with
|
||||
// non-standard keywords.
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
# ifndef inline
|
||||
# define inline __inline
|
||||
# endif
|
||||
# ifndef restrict
|
||||
# define restrict __restrict
|
||||
# endif
|
||||
#elif __STDC_VERSION__ < 199901L
|
||||
# define restrict // nothing
|
||||
#endif
|
||||
|
||||
////////////
|
||||
// Macros //
|
||||
////////////
|
||||
|
||||
#undef memzero
|
||||
#define memzero(s, n) memset(s, 0, n)
|
||||
|
||||
// NOTE: Avoid using MIN() and MAX(), because even conditionally defining
|
||||
// those macros can cause some portability trouble, since on some systems
|
||||
// the system headers insist defining their own versions.
|
||||
#define my_min(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define my_max(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
|
||||
#endif
|
||||
|
||||
#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
|
||||
# define lzma_attr_alloc_size(x) __attribute__((__alloc_size__(x)))
|
||||
#else
|
||||
# define lzma_attr_alloc_size(x)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file tuklib_common.h
|
||||
/// \brief Common definitions for tuklib modules
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TUKLIB_COMMON_H
|
||||
#define TUKLIB_COMMON_H
|
||||
|
||||
// The config file may be replaced by a package-specific file.
|
||||
// It should include at least stddef.h, inttypes.h, and limits.h.
|
||||
#include "tuklib_config.h"
|
||||
|
||||
// TUKLIB_SYMBOL_PREFIX is prefixed to all symbols exported by
|
||||
// the tuklib modules. If you use a tuklib module in a library,
|
||||
// you should use TUKLIB_SYMBOL_PREFIX to make sure that there
|
||||
// are no symbol conflicts in case someone links your library
|
||||
// into application that also uses the same tuklib module.
|
||||
#ifndef TUKLIB_SYMBOL_PREFIX
|
||||
# define TUKLIB_SYMBOL_PREFIX
|
||||
#endif
|
||||
|
||||
#define TUKLIB_CAT_X(a, b) a ## b
|
||||
#define TUKLIB_CAT(a, b) TUKLIB_CAT_X(a, b)
|
||||
|
||||
#ifndef TUKLIB_SYMBOL
|
||||
# define TUKLIB_SYMBOL(sym) TUKLIB_CAT(TUKLIB_SYMBOL_PREFIX, sym)
|
||||
#endif
|
||||
|
||||
#ifndef TUKLIB_DECLS_BEGIN
|
||||
# ifdef __cplusplus
|
||||
# define TUKLIB_DECLS_BEGIN extern "C" {
|
||||
# else
|
||||
# define TUKLIB_DECLS_BEGIN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef TUKLIB_DECLS_END
|
||||
# ifdef __cplusplus
|
||||
# define TUKLIB_DECLS_END }
|
||||
# else
|
||||
# define TUKLIB_DECLS_END
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||
# define TUKLIB_GNUC_REQ(major, minor) \
|
||||
((__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)) \
|
||||
|| __GNUC__ > (major))
|
||||
#else
|
||||
# define TUKLIB_GNUC_REQ(major, minor) 0
|
||||
#endif
|
||||
|
||||
#if TUKLIB_GNUC_REQ(2, 5)
|
||||
# define tuklib_attr_noreturn __attribute__((__noreturn__))
|
||||
#else
|
||||
# define tuklib_attr_noreturn
|
||||
#endif
|
||||
|
||||
#if (defined(_WIN32) && !defined(__CYGWIN__)) \
|
||||
|| defined(__OS2__) || defined(__MSDOS__)
|
||||
# define TUKLIB_DOSLIKE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "sysdefs.h"
|
||||
#else
|
||||
# include <stddef.h>
|
||||
# include <inttypes.h>
|
||||
# include <limits.h>
|
||||
#endif
|
||||
@@ -0,0 +1,523 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file tuklib_integer.h
|
||||
/// \brief Various integer and bit operations
|
||||
///
|
||||
/// This file provides macros or functions to do some basic integer and bit
|
||||
/// operations.
|
||||
///
|
||||
/// Endianness related integer operations (XX = 16, 32, or 64; Y = b or l):
|
||||
/// - Byte swapping: bswapXX(num)
|
||||
/// - Byte order conversions to/from native: convXXYe(num)
|
||||
/// - Aligned reads: readXXYe(ptr)
|
||||
/// - Aligned writes: writeXXYe(ptr, num)
|
||||
/// - Unaligned reads (16/32-bit only): unaligned_readXXYe(ptr)
|
||||
/// - Unaligned writes (16/32-bit only): unaligned_writeXXYe(ptr, num)
|
||||
///
|
||||
/// Since they can macros, the arguments should have no side effects since
|
||||
/// they may be evaluated more than once.
|
||||
///
|
||||
/// \todo PowerPC and possibly some other architectures support
|
||||
/// byte swapping load and store instructions. This file
|
||||
/// doesn't take advantage of those instructions.
|
||||
///
|
||||
/// Bit scan operations for non-zero 32-bit integers:
|
||||
/// - Bit scan reverse (find highest non-zero bit): bsr32(num)
|
||||
/// - Count leading zeros: clz32(num)
|
||||
/// - Count trailing zeros: ctz32(num)
|
||||
/// - Bit scan forward (simply an alias for ctz32()): bsf32(num)
|
||||
///
|
||||
/// The above bit scan operations return 0-31. If num is zero,
|
||||
/// the result is undefined.
|
||||
//
|
||||
// Authors: Lasse Collin
|
||||
// Joachim Henke
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TUKLIB_INTEGER_H
|
||||
#define TUKLIB_INTEGER_H
|
||||
|
||||
#include "tuklib_common.h"
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// Operating system specific features //
|
||||
////////////////////////////////////////
|
||||
|
||||
#if defined(HAVE_BYTESWAP_H)
|
||||
// glibc, uClibc, dietlibc
|
||||
# include <byteswap.h>
|
||||
# ifdef HAVE_BSWAP_16
|
||||
# define bswap16(num) bswap_16(num)
|
||||
# endif
|
||||
# ifdef HAVE_BSWAP_32
|
||||
# define bswap32(num) bswap_32(num)
|
||||
# endif
|
||||
# ifdef HAVE_BSWAP_64
|
||||
# define bswap64(num) bswap_64(num)
|
||||
# endif
|
||||
|
||||
#elif defined(HAVE_SYS_ENDIAN_H)
|
||||
// *BSDs and Darwin
|
||||
# include <sys/endian.h>
|
||||
|
||||
#elif defined(HAVE_SYS_BYTEORDER_H)
|
||||
// Solaris
|
||||
# include <sys/byteorder.h>
|
||||
# ifdef BSWAP_16
|
||||
# define bswap16(num) BSWAP_16(num)
|
||||
# endif
|
||||
# ifdef BSWAP_32
|
||||
# define bswap32(num) BSWAP_32(num)
|
||||
# endif
|
||||
# ifdef BSWAP_64
|
||||
# define bswap64(num) BSWAP_64(num)
|
||||
# endif
|
||||
# ifdef BE_16
|
||||
# define conv16be(num) BE_16(num)
|
||||
# endif
|
||||
# ifdef BE_32
|
||||
# define conv32be(num) BE_32(num)
|
||||
# endif
|
||||
# ifdef BE_64
|
||||
# define conv64be(num) BE_64(num)
|
||||
# endif
|
||||
# ifdef LE_16
|
||||
# define conv16le(num) LE_16(num)
|
||||
# endif
|
||||
# ifdef LE_32
|
||||
# define conv32le(num) LE_32(num)
|
||||
# endif
|
||||
# ifdef LE_64
|
||||
# define conv64le(num) LE_64(num)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////
|
||||
// Byte swapping //
|
||||
///////////////////
|
||||
|
||||
#ifndef bswap16
|
||||
# define bswap16(num) \
|
||||
(((uint16_t)(num) << 8) | ((uint16_t)(num) >> 8))
|
||||
#endif
|
||||
|
||||
#ifndef bswap32
|
||||
# define bswap32(num) \
|
||||
( (((uint32_t)(num) << 24) ) \
|
||||
| (((uint32_t)(num) << 8) & UINT32_C(0x00FF0000)) \
|
||||
| (((uint32_t)(num) >> 8) & UINT32_C(0x0000FF00)) \
|
||||
| (((uint32_t)(num) >> 24) ) )
|
||||
#endif
|
||||
|
||||
#ifndef bswap64
|
||||
# define bswap64(num) \
|
||||
( (((uint64_t)(num) << 56) ) \
|
||||
| (((uint64_t)(num) << 40) & UINT64_C(0x00FF000000000000)) \
|
||||
| (((uint64_t)(num) << 24) & UINT64_C(0x0000FF0000000000)) \
|
||||
| (((uint64_t)(num) << 8) & UINT64_C(0x000000FF00000000)) \
|
||||
| (((uint64_t)(num) >> 8) & UINT64_C(0x00000000FF000000)) \
|
||||
| (((uint64_t)(num) >> 24) & UINT64_C(0x0000000000FF0000)) \
|
||||
| (((uint64_t)(num) >> 40) & UINT64_C(0x000000000000FF00)) \
|
||||
| (((uint64_t)(num) >> 56) ) )
|
||||
#endif
|
||||
|
||||
// Define conversion macros using the basic byte swapping macros.
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
# ifndef conv16be
|
||||
# define conv16be(num) ((uint16_t)(num))
|
||||
# endif
|
||||
# ifndef conv32be
|
||||
# define conv32be(num) ((uint32_t)(num))
|
||||
# endif
|
||||
# ifndef conv64be
|
||||
# define conv64be(num) ((uint64_t)(num))
|
||||
# endif
|
||||
# ifndef conv16le
|
||||
# define conv16le(num) bswap16(num)
|
||||
# endif
|
||||
# ifndef conv32le
|
||||
# define conv32le(num) bswap32(num)
|
||||
# endif
|
||||
# ifndef conv64le
|
||||
# define conv64le(num) bswap64(num)
|
||||
# endif
|
||||
#else
|
||||
# ifndef conv16be
|
||||
# define conv16be(num) bswap16(num)
|
||||
# endif
|
||||
# ifndef conv32be
|
||||
# define conv32be(num) bswap32(num)
|
||||
# endif
|
||||
# ifndef conv64be
|
||||
# define conv64be(num) bswap64(num)
|
||||
# endif
|
||||
# ifndef conv16le
|
||||
# define conv16le(num) ((uint16_t)(num))
|
||||
# endif
|
||||
# ifndef conv32le
|
||||
# define conv32le(num) ((uint32_t)(num))
|
||||
# endif
|
||||
# ifndef conv64le
|
||||
# define conv64le(num) ((uint64_t)(num))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// Aligned reads and writes //
|
||||
//////////////////////////////
|
||||
|
||||
static inline uint16_t
|
||||
read16be(const uint8_t *buf)
|
||||
{
|
||||
uint16_t num = *(const uint16_t *)buf;
|
||||
return conv16be(num);
|
||||
}
|
||||
|
||||
|
||||
static inline uint16_t
|
||||
read16le(const uint8_t *buf)
|
||||
{
|
||||
uint16_t num = *(const uint16_t *)buf;
|
||||
return conv16le(num);
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
read32be(const uint8_t *buf)
|
||||
{
|
||||
uint32_t num = *(const uint32_t *)buf;
|
||||
return conv32be(num);
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
read32le(const uint8_t *buf)
|
||||
{
|
||||
uint32_t num = *(const uint32_t *)buf;
|
||||
return conv32le(num);
|
||||
}
|
||||
|
||||
|
||||
static inline uint64_t
|
||||
read64be(const uint8_t *buf)
|
||||
{
|
||||
uint64_t num = *(const uint64_t *)buf;
|
||||
return conv64be(num);
|
||||
}
|
||||
|
||||
|
||||
static inline uint64_t
|
||||
read64le(const uint8_t *buf)
|
||||
{
|
||||
uint64_t num = *(const uint64_t *)buf;
|
||||
return conv64le(num);
|
||||
}
|
||||
|
||||
|
||||
// NOTE: Possible byte swapping must be done in a macro to allow GCC
|
||||
// to optimize byte swapping of constants when using glibc's or *BSD's
|
||||
// byte swapping macros. The actual write is done in an inline function
|
||||
// to make type checking of the buf pointer possible similarly to readXXYe()
|
||||
// functions.
|
||||
|
||||
#define write16be(buf, num) write16ne((buf), conv16be(num))
|
||||
#define write16le(buf, num) write16ne((buf), conv16le(num))
|
||||
#define write32be(buf, num) write32ne((buf), conv32be(num))
|
||||
#define write32le(buf, num) write32ne((buf), conv32le(num))
|
||||
#define write64be(buf, num) write64ne((buf), conv64be(num))
|
||||
#define write64le(buf, num) write64ne((buf), conv64le(num))
|
||||
|
||||
|
||||
static inline void
|
||||
write16ne(uint8_t *buf, uint16_t num)
|
||||
{
|
||||
*(uint16_t *)buf = num;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
write32ne(uint8_t *buf, uint32_t num)
|
||||
{
|
||||
*(uint32_t *)buf = num;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
write64ne(uint8_t *buf, uint64_t num)
|
||||
{
|
||||
*(uint64_t *)buf = num;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
// Unaligned reads and writes //
|
||||
////////////////////////////////
|
||||
|
||||
// NOTE: TUKLIB_FAST_UNALIGNED_ACCESS indicates only support for 16-bit and
|
||||
// 32-bit unaligned integer loads and stores. It's possible that 64-bit
|
||||
// unaligned access doesn't work or is slower than byte-by-byte access.
|
||||
// Since unaligned 64-bit is probably not needed as often as 16-bit or
|
||||
// 32-bit, we simply don't support 64-bit unaligned access for now.
|
||||
#ifdef TUKLIB_FAST_UNALIGNED_ACCESS
|
||||
# define unaligned_read16be read16be
|
||||
# define unaligned_read16le read16le
|
||||
# define unaligned_read32be read32be
|
||||
# define unaligned_read32le read32le
|
||||
# define unaligned_write16be write16be
|
||||
# define unaligned_write16le write16le
|
||||
# define unaligned_write32be write32be
|
||||
# define unaligned_write32le write32le
|
||||
|
||||
#else
|
||||
|
||||
static inline uint16_t
|
||||
unaligned_read16be(const uint8_t *buf)
|
||||
{
|
||||
uint16_t num = ((uint16_t)buf[0] << 8) | (uint16_t)buf[1];
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
static inline uint16_t
|
||||
unaligned_read16le(const uint8_t *buf)
|
||||
{
|
||||
uint16_t num = ((uint16_t)buf[0]) | ((uint16_t)buf[1] << 8);
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
unaligned_read32be(const uint8_t *buf)
|
||||
{
|
||||
uint32_t num = (uint32_t)buf[0] << 24;
|
||||
num |= (uint32_t)buf[1] << 16;
|
||||
num |= (uint32_t)buf[2] << 8;
|
||||
num |= (uint32_t)buf[3];
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
unaligned_read32le(const uint8_t *buf)
|
||||
{
|
||||
uint32_t num = (uint32_t)buf[0];
|
||||
num |= (uint32_t)buf[1] << 8;
|
||||
num |= (uint32_t)buf[2] << 16;
|
||||
num |= (uint32_t)buf[3] << 24;
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
unaligned_write16be(uint8_t *buf, uint16_t num)
|
||||
{
|
||||
buf[0] = (uint8_t)(num >> 8);
|
||||
buf[1] = (uint8_t)num;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
unaligned_write16le(uint8_t *buf, uint16_t num)
|
||||
{
|
||||
buf[0] = (uint8_t)num;
|
||||
buf[1] = (uint8_t)(num >> 8);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
unaligned_write32be(uint8_t *buf, uint32_t num)
|
||||
{
|
||||
buf[0] = (uint8_t)(num >> 24);
|
||||
buf[1] = (uint8_t)(num >> 16);
|
||||
buf[2] = (uint8_t)(num >> 8);
|
||||
buf[3] = (uint8_t)num;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
unaligned_write32le(uint8_t *buf, uint32_t num)
|
||||
{
|
||||
buf[0] = (uint8_t)num;
|
||||
buf[1] = (uint8_t)(num >> 8);
|
||||
buf[2] = (uint8_t)(num >> 16);
|
||||
buf[3] = (uint8_t)(num >> 24);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
bsr32(uint32_t n)
|
||||
{
|
||||
// Check for ICC first, since it tends to define __GNUC__ too.
|
||||
#if defined(__INTEL_COMPILER)
|
||||
return _bit_scan_reverse(n);
|
||||
|
||||
#elif TUKLIB_GNUC_REQ(3, 4) && UINT_MAX == UINT32_MAX
|
||||
// GCC >= 3.4 has __builtin_clz(), which gives good results on
|
||||
// multiple architectures. On x86, __builtin_clz() ^ 31U becomes
|
||||
// either plain BSR (so the XOR gets optimized away) or LZCNT and
|
||||
// XOR (if -march indicates that SSE4a instructions are supported).
|
||||
return __builtin_clz(n) ^ 31U;
|
||||
|
||||
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
uint32_t i;
|
||||
__asm__("bsrl %1, %0" : "=r" (i) : "rm" (n));
|
||||
return i;
|
||||
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
// MSVC isn't supported by tuklib, but since this code exists,
|
||||
// it doesn't hurt to have it here anyway.
|
||||
uint32_t i;
|
||||
_BitScanReverse(&i, n);
|
||||
return i;
|
||||
|
||||
#else
|
||||
uint32_t i = 31;
|
||||
|
||||
if ((n & UINT32_C(0xFFFF0000)) == 0) {
|
||||
n <<= 16;
|
||||
i = 15;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0xFF000000)) == 0) {
|
||||
n <<= 8;
|
||||
i -= 8;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0xF0000000)) == 0) {
|
||||
n <<= 4;
|
||||
i -= 4;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0xC0000000)) == 0) {
|
||||
n <<= 2;
|
||||
i -= 2;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0x80000000)) == 0)
|
||||
--i;
|
||||
|
||||
return i;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
clz32(uint32_t n)
|
||||
{
|
||||
#if defined(__INTEL_COMPILER)
|
||||
return _bit_scan_reverse(n) ^ 31U;
|
||||
|
||||
#elif TUKLIB_GNUC_REQ(3, 4) && UINT_MAX == UINT32_MAX
|
||||
return __builtin_clz(n);
|
||||
|
||||
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
uint32_t i;
|
||||
__asm__("bsrl %1, %0\n\t"
|
||||
"xorl $31, %0"
|
||||
: "=r" (i) : "rm" (n));
|
||||
return i;
|
||||
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
uint32_t i;
|
||||
_BitScanReverse(&i, n);
|
||||
return i ^ 31U;
|
||||
|
||||
#else
|
||||
uint32_t i = 0;
|
||||
|
||||
if ((n & UINT32_C(0xFFFF0000)) == 0) {
|
||||
n <<= 16;
|
||||
i = 16;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0xFF000000)) == 0) {
|
||||
n <<= 8;
|
||||
i += 8;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0xF0000000)) == 0) {
|
||||
n <<= 4;
|
||||
i += 4;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0xC0000000)) == 0) {
|
||||
n <<= 2;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0x80000000)) == 0)
|
||||
++i;
|
||||
|
||||
return i;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
ctz32(uint32_t n)
|
||||
{
|
||||
#if defined(__INTEL_COMPILER)
|
||||
return _bit_scan_forward(n);
|
||||
|
||||
#elif TUKLIB_GNUC_REQ(3, 4) && UINT_MAX >= UINT32_MAX
|
||||
return __builtin_ctz(n);
|
||||
|
||||
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
uint32_t i;
|
||||
__asm__("bsfl %1, %0" : "=r" (i) : "rm" (n));
|
||||
return i;
|
||||
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
uint32_t i;
|
||||
_BitScanForward(&i, n);
|
||||
return i;
|
||||
|
||||
#else
|
||||
uint32_t i = 0;
|
||||
|
||||
if ((n & UINT32_C(0x0000FFFF)) == 0) {
|
||||
n >>= 16;
|
||||
i = 16;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0x000000FF)) == 0) {
|
||||
n >>= 8;
|
||||
i += 8;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0x0000000F)) == 0) {
|
||||
n >>= 4;
|
||||
i += 4;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0x00000003)) == 0) {
|
||||
n >>= 2;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
if ((n & UINT32_C(0x00000001)) == 0)
|
||||
++i;
|
||||
|
||||
return i;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define bsf32 ctz32
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user