mirror of
https://git.tukaani.org/xz.git
synced 2025-10-14 13:18:18 +00:00
This is a quick and slightly dirty fix to make the code conform to the latest file format specification. Without this patch, it's possible to make corrupt files by specifying start offset that is not a multiple of the filter's alignment. Custom start offset is almost never used, so this was only a minor bug. The xz command line tool doesn't validate the start offset, so one will get a bit unclear error message if trying to use an invalid start offset.
155 lines
3.4 KiB
C
155 lines
3.4 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
/// \file x86.c
|
|
/// \brief Filter for x86 binaries (BCJ filter)
|
|
///
|
|
// Authors: Igor Pavlov
|
|
// Lasse Collin
|
|
//
|
|
// This file has been put into the public domain.
|
|
// You can do whatever you want with this file.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "simple_private.h"
|
|
|
|
|
|
#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
|
|
|
|
|
|
struct lzma_simple_s {
|
|
uint32_t prev_mask;
|
|
uint32_t prev_pos;
|
|
};
|
|
|
|
|
|
static size_t
|
|
x86_code(lzma_simple *simple, uint32_t now_pos, bool is_encoder,
|
|
uint8_t *buffer, size_t size)
|
|
{
|
|
static const bool MASK_TO_ALLOWED_STATUS[8]
|
|
= { true, true, true, false, true, false, false, false };
|
|
|
|
static const uint32_t MASK_TO_BIT_NUMBER[8]
|
|
= { 0, 1, 2, 2, 3, 3, 3, 3 };
|
|
|
|
uint32_t prev_mask = simple->prev_mask;
|
|
uint32_t prev_pos = simple->prev_pos;
|
|
|
|
if (size < 5)
|
|
return 0;
|
|
|
|
if (now_pos - prev_pos > 5)
|
|
prev_pos = now_pos - 5;
|
|
|
|
const size_t limit = size - 5;
|
|
size_t buffer_pos = 0;
|
|
|
|
while (buffer_pos <= limit) {
|
|
uint8_t b = buffer[buffer_pos];
|
|
if (b != 0xE8 && b != 0xE9) {
|
|
++buffer_pos;
|
|
continue;
|
|
}
|
|
|
|
const uint32_t offset = now_pos + (uint32_t)(buffer_pos)
|
|
- prev_pos;
|
|
prev_pos = now_pos + (uint32_t)(buffer_pos);
|
|
|
|
if (offset > 5) {
|
|
prev_mask = 0;
|
|
} else {
|
|
for (uint32_t i = 0; i < offset; ++i) {
|
|
prev_mask &= 0x77;
|
|
prev_mask <<= 1;
|
|
}
|
|
}
|
|
|
|
b = buffer[buffer_pos + 4];
|
|
|
|
if (Test86MSByte(b)
|
|
&& MASK_TO_ALLOWED_STATUS[(prev_mask >> 1) & 0x7]
|
|
&& (prev_mask >> 1) < 0x10) {
|
|
|
|
uint32_t src = ((uint32_t)(b) << 24)
|
|
| ((uint32_t)(buffer[buffer_pos + 3]) << 16)
|
|
| ((uint32_t)(buffer[buffer_pos + 2]) << 8)
|
|
| (buffer[buffer_pos + 1]);
|
|
|
|
uint32_t dest;
|
|
while (true) {
|
|
if (is_encoder)
|
|
dest = src + (now_pos + (uint32_t)(
|
|
buffer_pos) + 5);
|
|
else
|
|
dest = src - (now_pos + (uint32_t)(
|
|
buffer_pos) + 5);
|
|
|
|
if (prev_mask == 0)
|
|
break;
|
|
|
|
const uint32_t i = MASK_TO_BIT_NUMBER[
|
|
prev_mask >> 1];
|
|
|
|
b = (uint8_t)(dest >> (24 - i * 8));
|
|
|
|
if (!Test86MSByte(b))
|
|
break;
|
|
|
|
src = dest ^ ((1 << (32 - i * 8)) - 1);
|
|
}
|
|
|
|
buffer[buffer_pos + 4]
|
|
= (uint8_t)(~(((dest >> 24) & 1) - 1));
|
|
buffer[buffer_pos + 3] = (uint8_t)(dest >> 16);
|
|
buffer[buffer_pos + 2] = (uint8_t)(dest >> 8);
|
|
buffer[buffer_pos + 1] = (uint8_t)(dest);
|
|
buffer_pos += 5;
|
|
prev_mask = 0;
|
|
|
|
} else {
|
|
++buffer_pos;
|
|
prev_mask |= 1;
|
|
if (Test86MSByte(b))
|
|
prev_mask |= 0x10;
|
|
}
|
|
}
|
|
|
|
simple->prev_mask = prev_mask;
|
|
simple->prev_pos = prev_pos;
|
|
|
|
return buffer_pos;
|
|
}
|
|
|
|
|
|
static lzma_ret
|
|
x86_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
|
const lzma_filter_info *filters, bool is_encoder)
|
|
{
|
|
const lzma_ret ret = lzma_simple_coder_init(next, allocator, filters,
|
|
&x86_code, sizeof(lzma_simple), 5, 1, is_encoder);
|
|
|
|
if (ret == LZMA_OK) {
|
|
next->coder->simple->prev_mask = 0;
|
|
next->coder->simple->prev_pos = (uint32_t)(-5);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
extern lzma_ret
|
|
lzma_simple_x86_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
|
const lzma_filter_info *filters)
|
|
{
|
|
return x86_coder_init(next, allocator, filters, true);
|
|
}
|
|
|
|
|
|
extern lzma_ret
|
|
lzma_simple_x86_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
|
const lzma_filter_info *filters)
|
|
{
|
|
return x86_coder_init(next, allocator, filters, false);
|
|
}
|