| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file crc32_tablegen.c | ||
| /// \brief Generate crc32_table_le.h and crc32_table_be.h | ||
| /// | ||
| /// Compiling: gcc -std=c99 -o crc32_tablegen crc32_tablegen.c | ||
| /// Add -DWORDS_BIGENDIAN to generate big endian table. | ||
| /// Add -DLZ_HASH_TABLE to generate lz_encoder_hash_table.h (little endian). | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include <stdio.h> | ||
| #include "tuklib_integer.h" | ||
|
|
||
|
|
||
| static uint32_t crc32_table[8][256]; | ||
|
|
||
|
|
||
| static void | ||
| init_crc32_table(void) | ||
| { | ||
| static const uint32_t poly32 = UINT32_C(0xEDB88320); | ||
|
|
||
| for (size_t s = 0; s < 8; ++s) { | ||
| for (size_t b = 0; b < 256; ++b) { | ||
| uint32_t r = s == 0 ? b : crc32_table[s - 1][b]; | ||
|
|
||
| for (size_t i = 0; i < 8; ++i) { | ||
| if (r & 1) | ||
| r = (r >> 1) ^ poly32; | ||
| else | ||
| r >>= 1; | ||
| } | ||
|
|
||
| crc32_table[s][b] = r; | ||
| } | ||
| } | ||
|
|
||
| #ifdef WORDS_BIGENDIAN | ||
| for (size_t s = 0; s < 8; ++s) | ||
| for (size_t b = 0; b < 256; ++b) | ||
| crc32_table[s][b] = bswap32(crc32_table[s][b]); | ||
| #endif | ||
|
|
||
| return; | ||
| } | ||
|
|
||
|
|
||
| static void | ||
| print_crc32_table(void) | ||
| { | ||
| printf("/* This file has been automatically generated by " | ||
| "crc32_tablegen.c. */\n\n" | ||
| "const uint32_t lzma_crc32_table[8][256] = {\n\t{"); | ||
|
|
||
| for (size_t s = 0; s < 8; ++s) { | ||
| for (size_t b = 0; b < 256; ++b) { | ||
| if ((b % 4) == 0) | ||
| printf("\n\t\t"); | ||
|
|
||
| printf("0x%08" PRIX32, crc32_table[s][b]); | ||
|
|
||
| if (b != 255) | ||
| printf(",%s", (b+1) % 4 == 0 ? "" : " "); | ||
| } | ||
|
|
||
| if (s == 7) | ||
| printf("\n\t}\n};\n"); | ||
| else | ||
| printf("\n\t}, {"); | ||
| } | ||
|
|
||
| return; | ||
| } | ||
|
|
||
|
|
||
| static void | ||
| print_lz_table(void) | ||
| { | ||
| printf("/* This file has been automatically generated by " | ||
| "crc32_tablegen.c. */\n\n" | ||
| "const uint32_t lzma_lz_hash_table[256] = {"); | ||
|
|
||
| for (size_t b = 0; b < 256; ++b) { | ||
| if ((b % 4) == 0) | ||
| printf("\n\t"); | ||
|
|
||
| printf("0x%08" PRIX32, crc32_table[0][b]); | ||
|
|
||
| if (b != 255) | ||
| printf(",%s", (b+1) % 4 == 0 ? "" : " "); | ||
| } | ||
|
|
||
| printf("\n};\n"); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
|
|
||
| int | ||
| main(void) | ||
| { | ||
| init_crc32_table(); | ||
|
|
||
| #ifdef LZ_HASH_TABLE | ||
| print_lz_table(); | ||
| #else | ||
| print_crc32_table(); | ||
| #endif | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file crc64.c | ||
| /// \brief CRC64 calculation | ||
| /// | ||
| /// Calculate the CRC64 using the slice-by-four algorithm. This is the same | ||
| /// idea that is used in crc32_fast.c, but for CRC64 we use only four tables | ||
| /// instead of eight to avoid increasing CPU cache usage. | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "check.h" | ||
| #include "crc_macros.h" | ||
|
|
||
|
|
||
| #ifdef WORDS_BIGENDIAN | ||
| # define A1(x) ((x) >> 56) | ||
| #else | ||
| # define A1 A | ||
| #endif | ||
|
|
||
|
|
||
| // See the comments in crc32_fast.c. They aren't duplicated here. | ||
| extern LZMA_API(uint64_t) | ||
| lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc) | ||
| { | ||
| crc = ~crc; | ||
|
|
||
| #ifdef WORDS_BIGENDIAN | ||
| crc = bswap64(crc); | ||
| #endif | ||
|
|
||
| if (size > 4) { | ||
| while ((uintptr_t)(buf) & 3) { | ||
| crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc); | ||
| --size; | ||
| } | ||
|
|
||
| const uint8_t *const limit = buf + (size & ~(size_t)(3)); | ||
| size &= (size_t)(3); | ||
|
|
||
| while (buf < limit) { | ||
| #ifdef WORDS_BIGENDIAN | ||
| const uint32_t tmp = (crc >> 32) | ||
| ^ *(const uint32_t *)(buf); | ||
| #else | ||
| const uint32_t tmp = crc ^ *(const uint32_t *)(buf); | ||
| #endif | ||
| buf += 4; | ||
|
|
||
| crc = lzma_crc64_table[3][A(tmp)] | ||
| ^ lzma_crc64_table[2][B(tmp)] | ||
| ^ S32(crc) | ||
| ^ lzma_crc64_table[1][C(tmp)] | ||
| ^ lzma_crc64_table[0][D(tmp)]; | ||
| } | ||
| } | ||
|
|
||
| while (size-- != 0) | ||
| crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc); | ||
|
|
||
| #ifdef WORDS_BIGENDIAN | ||
| crc = bswap64(crc); | ||
| #endif | ||
|
|
||
| return ~crc; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file crc64_table.c | ||
| /// \brief Precalculated CRC64 table with correct endianness | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "common.h" | ||
|
|
||
| #ifdef WORDS_BIGENDIAN | ||
| # include "crc64_table_be.h" | ||
| #else | ||
| # include "crc64_table_le.h" | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file crc64_tablegen.c | ||
| /// \brief Generate crc64_table_le.h and crc64_table_be.h | ||
| /// | ||
| /// Compiling: gcc -std=c99 -o crc64_tablegen crc64_tablegen.c | ||
| /// Add -DWORDS_BIGENDIAN to generate big endian table. | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include <stdio.h> | ||
| #include "tuklib_integer.h" | ||
|
|
||
|
|
||
| static uint64_t crc64_table[4][256]; | ||
|
|
||
|
|
||
| extern void | ||
| init_crc64_table(void) | ||
| { | ||
| static const uint64_t poly64 = UINT64_C(0xC96C5795D7870F42); | ||
|
|
||
| for (size_t s = 0; s < 4; ++s) { | ||
| for (size_t b = 0; b < 256; ++b) { | ||
| uint64_t r = s == 0 ? b : crc64_table[s - 1][b]; | ||
|
|
||
| for (size_t i = 0; i < 8; ++i) { | ||
| if (r & 1) | ||
| r = (r >> 1) ^ poly64; | ||
| else | ||
| r >>= 1; | ||
| } | ||
|
|
||
| crc64_table[s][b] = r; | ||
| } | ||
| } | ||
|
|
||
| #ifdef WORDS_BIGENDIAN | ||
| for (size_t s = 0; s < 4; ++s) | ||
| for (size_t b = 0; b < 256; ++b) | ||
| crc64_table[s][b] = bswap64(crc64_table[s][b]); | ||
| #endif | ||
|
|
||
| return; | ||
| } | ||
|
|
||
|
|
||
| static void | ||
| print_crc64_table(void) | ||
| { | ||
| printf("/* This file has been automatically generated by " | ||
| "crc64_tablegen.c. */\n\n" | ||
| "const uint64_t lzma_crc64_table[4][256] = {\n\t{"); | ||
|
|
||
| for (size_t s = 0; s < 4; ++s) { | ||
| for (size_t b = 0; b < 256; ++b) { | ||
| if ((b % 2) == 0) | ||
| printf("\n\t\t"); | ||
|
|
||
| printf("UINT64_C(0x%016" PRIX64 ")", | ||
| crc64_table[s][b]); | ||
|
|
||
| if (b != 255) | ||
| printf(",%s", (b+1) % 2 == 0 ? "" : " "); | ||
| } | ||
|
|
||
| if (s == 3) | ||
| printf("\n\t}\n};\n"); | ||
| else | ||
| printf("\n\t}, {"); | ||
| } | ||
|
|
||
| return; | ||
| } | ||
|
|
||
|
|
||
| int | ||
| main(void) | ||
| { | ||
| init_crc64_table(); | ||
| print_crc64_table(); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file crc_macros.h | ||
| /// \brief Some endian-dependent macros for CRC32 and CRC64 | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #ifdef WORDS_BIGENDIAN | ||
| # define A(x) ((x) >> 24) | ||
| # define B(x) (((x) >> 16) & 0xFF) | ||
| # define C(x) (((x) >> 8) & 0xFF) | ||
| # define D(x) ((x) & 0xFF) | ||
|
|
||
| # define S8(x) ((x) << 8) | ||
| # define S32(x) ((x) << 32) | ||
|
|
||
| #else | ||
| # define A(x) ((x) & 0xFF) | ||
| # define B(x) (((x) >> 8) & 0xFF) | ||
| # define C(x) (((x) >> 16) & 0xFF) | ||
| # define D(x) ((x) >> 24) | ||
|
|
||
| # define S8(x) ((x) >> 8) | ||
| # define S32(x) ((x) >> 32) | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,196 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file sha256.c | ||
| /// \brief SHA-256 | ||
| /// | ||
| /// \todo Crypto++ has x86 ASM optimizations. They use SSE so if they | ||
| /// are imported to liblzma, SSE instructions need to be used | ||
| /// conditionally to keep the code working on older boxes. | ||
| // | ||
| // This code is based on the code found from 7-Zip, which has a modified | ||
| // version of the SHA-256 found from Crypto++ <http://www.cryptopp.com/>. | ||
| // The code was modified a little to fit into liblzma. | ||
| // | ||
| // Authors: Kevin Springle | ||
| // Wei Dai | ||
| // Igor Pavlov | ||
| // Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "check.h" | ||
|
|
||
| // Rotate a uint32_t. GCC can optimize this to a rotate instruction | ||
| // at least on x86. | ||
| static inline uint32_t | ||
| rotr_32(uint32_t num, unsigned amount) | ||
| { | ||
| return (num >> amount) | (num << (32 - amount)); | ||
| } | ||
|
|
||
| #define blk0(i) (W[i] = conv32be(data[i])) | ||
| #define blk2(i) (W[i & 15] += s1(W[(i - 2) & 15]) + W[(i - 7) & 15] \ | ||
| + s0(W[(i - 15) & 15])) | ||
|
|
||
| #define Ch(x, y, z) (z ^ (x & (y ^ z))) | ||
| #define Maj(x, y, z) ((x & (y ^ z)) + (y & z)) | ||
|
|
||
| #define a(i) T[(0 - i) & 7] | ||
| #define b(i) T[(1 - i) & 7] | ||
| #define c(i) T[(2 - i) & 7] | ||
| #define d(i) T[(3 - i) & 7] | ||
| #define e(i) T[(4 - i) & 7] | ||
| #define f(i) T[(5 - i) & 7] | ||
| #define g(i) T[(6 - i) & 7] | ||
| #define h(i) T[(7 - i) & 7] | ||
|
|
||
| #define R(i, j, blk) \ | ||
| h(i) += S1(e(i)) + Ch(e(i), f(i), g(i)) + SHA256_K[i + j] + blk; \ | ||
| d(i) += h(i); \ | ||
| h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) | ||
| #define R0(i) R(i, 0, blk0(i)) | ||
| #define R2(i) R(i, j, blk2(i)) | ||
|
|
||
| #define S0(x) rotr_32(x ^ rotr_32(x ^ rotr_32(x, 9), 11), 2) | ||
| #define S1(x) rotr_32(x ^ rotr_32(x ^ rotr_32(x, 14), 5), 6) | ||
| #define s0(x) (rotr_32(x ^ rotr_32(x, 11), 7) ^ (x >> 3)) | ||
| #define s1(x) (rotr_32(x ^ rotr_32(x, 2), 17) ^ (x >> 10)) | ||
|
|
||
|
|
||
| static const uint32_t SHA256_K[64] = { | ||
| 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, | ||
| 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, | ||
| 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, | ||
| 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, | ||
| 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, | ||
| 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, | ||
| 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, | ||
| 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, | ||
| 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, | ||
| 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, | ||
| 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, | ||
| 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, | ||
| 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, | ||
| 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, | ||
| 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, | ||
| 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, | ||
| }; | ||
|
|
||
|
|
||
| static void | ||
| transform(uint32_t state[8], const uint32_t data[16]) | ||
| { | ||
| uint32_t W[16]; | ||
| uint32_t T[8]; | ||
|
|
||
| // Copy state[] to working vars. | ||
| memcpy(T, state, sizeof(T)); | ||
|
|
||
| // The first 16 operations unrolled | ||
| R0( 0); R0( 1); R0( 2); R0( 3); | ||
| R0( 4); R0( 5); R0( 6); R0( 7); | ||
| R0( 8); R0( 9); R0(10); R0(11); | ||
| R0(12); R0(13); R0(14); R0(15); | ||
|
|
||
| // The remaining 48 operations partially unrolled | ||
| for (unsigned int j = 16; j < 64; j += 16) { | ||
| R2( 0); R2( 1); R2( 2); R2( 3); | ||
| R2( 4); R2( 5); R2( 6); R2( 7); | ||
| R2( 8); R2( 9); R2(10); R2(11); | ||
| R2(12); R2(13); R2(14); R2(15); | ||
| } | ||
|
|
||
| // Add the working vars back into state[]. | ||
| state[0] += a(0); | ||
| state[1] += b(0); | ||
| state[2] += c(0); | ||
| state[3] += d(0); | ||
| state[4] += e(0); | ||
| state[5] += f(0); | ||
| state[6] += g(0); | ||
| state[7] += h(0); | ||
| } | ||
|
|
||
|
|
||
| static void | ||
| process(lzma_check_state *check) | ||
| { | ||
| transform(check->state.sha256.state, check->buffer.u32); | ||
| return; | ||
| } | ||
|
|
||
|
|
||
| extern void | ||
| lzma_sha256_init(lzma_check_state *check) | ||
| { | ||
| static const uint32_t s[8] = { | ||
| 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, | ||
| 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, | ||
| }; | ||
|
|
||
| memcpy(check->state.sha256.state, s, sizeof(s)); | ||
| check->state.sha256.size = 0; | ||
|
|
||
| return; | ||
| } | ||
|
|
||
|
|
||
| extern void | ||
| lzma_sha256_update(const uint8_t *buf, size_t size, lzma_check_state *check) | ||
| { | ||
| // Copy the input data into a properly aligned temporary buffer. | ||
| // This way we can be called with arbitrarily sized buffers | ||
| // (no need to be multiple of 64 bytes), and the code works also | ||
| // on architectures that don't allow unaligned memory access. | ||
| while (size > 0) { | ||
| const size_t copy_start = check->state.sha256.size & 0x3F; | ||
| size_t copy_size = 64 - copy_start; | ||
| if (copy_size > size) | ||
| copy_size = size; | ||
|
|
||
| memcpy(check->buffer.u8 + copy_start, buf, copy_size); | ||
|
|
||
| buf += copy_size; | ||
| size -= copy_size; | ||
| check->state.sha256.size += copy_size; | ||
|
|
||
| if ((check->state.sha256.size & 0x3F) == 0) | ||
| process(check); | ||
| } | ||
|
|
||
| return; | ||
| } | ||
|
|
||
|
|
||
| extern void | ||
| lzma_sha256_finish(lzma_check_state *check) | ||
| { | ||
| // Add padding as described in RFC 3174 (it describes SHA-1 but | ||
| // the same padding style is used for SHA-256 too). | ||
| size_t pos = check->state.sha256.size & 0x3F; | ||
| check->buffer.u8[pos++] = 0x80; | ||
|
|
||
| while (pos != 64 - 8) { | ||
| if (pos == 64) { | ||
| process(check); | ||
| pos = 0; | ||
| } | ||
|
|
||
| check->buffer.u8[pos++] = 0x00; | ||
| } | ||
|
|
||
| // Convert the message size from bytes to bits. | ||
| check->state.sha256.size *= 8; | ||
|
|
||
| check->buffer.u64[(64 - 8) / 8] = conv64be(check->state.sha256.size); | ||
|
|
||
| process(check); | ||
|
|
||
| for (size_t i = 0; i < 8; ++i) | ||
| check->buffer.u32[i] = conv32be(check->state.sha256.state[i]); | ||
|
|
||
| return; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,243 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \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); | ||
|
|
||
| if (++coder->pos == 4) { | ||
| 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->pos = 0; | ||
| coder->sequence = SEQ_UNCOMPRESSED_SIZE; | ||
| } | ||
|
|
||
| ++*in_pos; | ||
| break; | ||
|
|
||
| case SEQ_UNCOMPRESSED_SIZE: | ||
| coder->uncompressed_size | ||
| |= (lzma_vli)(in[*in_pos]) << (coder->pos * 8); | ||
| ++*in_pos; | ||
| if (++coder->pos < 8) | ||
| break; | ||
|
|
||
| // Another hack to ditch false positives: Assume that | ||
| // if the uncompressed size is known, it must be less | ||
| // than 256 GiB. | ||
| if (coder->picky | ||
| && coder->uncompressed_size != LZMA_VLI_UNKNOWN | ||
| && coder->uncompressed_size | ||
| >= (LZMA_VLI_C(1) << 38)) | ||
| return LZMA_FORMAT_ERROR; | ||
|
|
||
| // 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); | ||
|
|
||
| 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 = my_max(1, 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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \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 + 8) | ||
|
|
||
|
|
||
| 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); | ||
|
|
||
| // - Uncompressed size (always unknown and using EOPM) | ||
| memset(coder->header + 1 + 4, 0xFF, 8); | ||
|
|
||
| // 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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,195 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file auto_decoder.c | ||
| /// \brief Autodetect between .xz Stream and .lzma (LZMA_Alone) formats | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "stream_decoder.h" | ||
| #include "alone_decoder.h" | ||
|
|
||
|
|
||
| typedef struct { | ||
| /// Stream decoder or LZMA_Alone decoder | ||
| lzma_next_coder next; | ||
|
|
||
| uint64_t memlimit; | ||
| uint32_t flags; | ||
|
|
||
| enum { | ||
| SEQ_INIT, | ||
| SEQ_CODE, | ||
| SEQ_FINISH, | ||
| } sequence; | ||
| } lzma_auto_coder; | ||
|
|
||
|
|
||
| static lzma_ret | ||
| auto_decode(void *coder_ptr, 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) | ||
| { | ||
| lzma_auto_coder *coder = coder_ptr; | ||
|
|
||
| switch (coder->sequence) { | ||
| case SEQ_INIT: | ||
| if (*in_pos >= in_size) | ||
| return LZMA_OK; | ||
|
|
||
| // Update the sequence now, because we want to continue from | ||
| // SEQ_CODE even if we return some LZMA_*_CHECK. | ||
| coder->sequence = SEQ_CODE; | ||
|
|
||
| // Detect the file format. For now this is simple, since if | ||
| // it doesn't start with 0xFD (the first magic byte of the | ||
| // new format), it has to be LZMA_Alone, or something that | ||
| // we don't support at all. | ||
| if (in[*in_pos] == 0xFD) { | ||
| return_if_error(lzma_stream_decoder_init( | ||
| &coder->next, allocator, | ||
| coder->memlimit, coder->flags)); | ||
| } else { | ||
| return_if_error(lzma_alone_decoder_init(&coder->next, | ||
| allocator, coder->memlimit, true)); | ||
|
|
||
| // If the application wants to know about missing | ||
| // integrity check or about the check in general, we | ||
| // need to handle it here, because LZMA_Alone decoder | ||
| // doesn't accept any flags. | ||
| if (coder->flags & LZMA_TELL_NO_CHECK) | ||
| return LZMA_NO_CHECK; | ||
|
|
||
| if (coder->flags & LZMA_TELL_ANY_CHECK) | ||
| return LZMA_GET_CHECK; | ||
| } | ||
|
|
||
| // Fall through | ||
|
|
||
| case SEQ_CODE: { | ||
| const lzma_ret ret = coder->next.code( | ||
| coder->next.coder, allocator, | ||
| in, in_pos, in_size, | ||
| out, out_pos, out_size, action); | ||
| if (ret != LZMA_STREAM_END | ||
| || (coder->flags & LZMA_CONCATENATED) == 0) | ||
| return ret; | ||
|
|
||
| coder->sequence = SEQ_FINISH; | ||
| } | ||
|
|
||
| // Fall through | ||
|
|
||
| case SEQ_FINISH: | ||
| // When LZMA_DECODE_CONCATENATED was used and we were decoding | ||
| // LZMA_Alone file, we need to check check that there is no | ||
| // trailing garbage and wait for LZMA_FINISH. | ||
| if (*in_pos < in_size) | ||
| return LZMA_DATA_ERROR; | ||
|
|
||
| return action == LZMA_FINISH ? LZMA_STREAM_END : LZMA_OK; | ||
|
|
||
| default: | ||
| assert(0); | ||
| return LZMA_PROG_ERROR; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| static void | ||
| auto_decoder_end(void *coder_ptr, const lzma_allocator *allocator) | ||
| { | ||
| lzma_auto_coder *coder = coder_ptr; | ||
| lzma_next_end(&coder->next, allocator); | ||
| lzma_free(coder, allocator); | ||
| return; | ||
| } | ||
|
|
||
|
|
||
| static lzma_check | ||
| auto_decoder_get_check(const void *coder_ptr) | ||
| { | ||
| const lzma_auto_coder *coder = coder_ptr; | ||
|
|
||
| // It is LZMA_Alone if get_check is NULL. | ||
| return coder->next.get_check == NULL ? LZMA_CHECK_NONE | ||
| : coder->next.get_check(coder->next.coder); | ||
| } | ||
|
|
||
|
|
||
| static lzma_ret | ||
| auto_decoder_memconfig(void *coder_ptr, uint64_t *memusage, | ||
| uint64_t *old_memlimit, uint64_t new_memlimit) | ||
| { | ||
| lzma_auto_coder *coder = coder_ptr; | ||
|
|
||
| lzma_ret ret; | ||
|
|
||
| if (coder->next.memconfig != NULL) { | ||
| ret = coder->next.memconfig(coder->next.coder, | ||
| memusage, old_memlimit, new_memlimit); | ||
| assert(*old_memlimit == coder->memlimit); | ||
| } else { | ||
| // No coder is configured yet. Use the base value as | ||
| // the current memory usage. | ||
| *memusage = LZMA_MEMUSAGE_BASE; | ||
| *old_memlimit = coder->memlimit; | ||
|
|
||
| ret = LZMA_OK; | ||
| if (new_memlimit != 0 && new_memlimit < *memusage) | ||
| ret = LZMA_MEMLIMIT_ERROR; | ||
| } | ||
|
|
||
| if (ret == LZMA_OK && new_memlimit != 0) | ||
| coder->memlimit = new_memlimit; | ||
|
|
||
| return ret; | ||
| } | ||
|
|
||
|
|
||
| static lzma_ret | ||
| auto_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, | ||
| uint64_t memlimit, uint32_t flags) | ||
| { | ||
| lzma_next_coder_init(&auto_decoder_init, next, allocator); | ||
|
|
||
| if (flags & ~LZMA_SUPPORTED_FLAGS) | ||
| return LZMA_OPTIONS_ERROR; | ||
|
|
||
| lzma_auto_coder *coder = next->coder; | ||
| if (coder == NULL) { | ||
| coder = lzma_alloc(sizeof(lzma_auto_coder), allocator); | ||
| if (coder == NULL) | ||
| return LZMA_MEM_ERROR; | ||
|
|
||
| next->coder = coder; | ||
| next->code = &auto_decode; | ||
| next->end = &auto_decoder_end; | ||
| next->get_check = &auto_decoder_get_check; | ||
| next->memconfig = &auto_decoder_memconfig; | ||
| coder->next = LZMA_NEXT_CODER_INIT; | ||
| } | ||
|
|
||
| coder->memlimit = my_max(1, memlimit); | ||
| coder->flags = flags; | ||
| coder->sequence = SEQ_INIT; | ||
|
|
||
| return LZMA_OK; | ||
| } | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_ret) | ||
| lzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags) | ||
| { | ||
| lzma_next_strm_init(auto_decoder_init, strm, memlimit, flags); | ||
|
|
||
| strm->internal->supported_actions[LZMA_RUN] = true; | ||
| strm->internal->supported_actions[LZMA_FINISH] = true; | ||
|
|
||
| return LZMA_OK; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file block_buffer_decoder.c | ||
| /// \brief Single-call .xz Block decoder | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "block_decoder.h" | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_ret) | ||
| lzma_block_buffer_decode(lzma_block *block, const lzma_allocator *allocator, | ||
| const uint8_t *in, size_t *in_pos, size_t in_size, | ||
| uint8_t *out, size_t *out_pos, size_t out_size) | ||
| { | ||
| if (in_pos == NULL || (in == NULL && *in_pos != in_size) | ||
| || *in_pos > in_size || out_pos == NULL | ||
| || (out == NULL && *out_pos != out_size) | ||
| || *out_pos > out_size) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| // Initialize the Block decoder. | ||
| lzma_next_coder block_decoder = LZMA_NEXT_CODER_INIT; | ||
| lzma_ret ret = lzma_block_decoder_init( | ||
| &block_decoder, allocator, block); | ||
|
|
||
| if (ret == LZMA_OK) { | ||
| // Save the positions so that we can restore them in case | ||
| // an error occurs. | ||
| const size_t in_start = *in_pos; | ||
| const size_t out_start = *out_pos; | ||
|
|
||
| // Do the actual decoding. | ||
| ret = block_decoder.code(block_decoder.coder, allocator, | ||
| in, in_pos, in_size, out, out_pos, out_size, | ||
| LZMA_FINISH); | ||
|
|
||
| if (ret == LZMA_STREAM_END) { | ||
| ret = LZMA_OK; | ||
| } else { | ||
| if (ret == LZMA_OK) { | ||
| // Either the input was truncated or the | ||
| // output buffer was too small. | ||
| assert(*in_pos == in_size | ||
| || *out_pos == out_size); | ||
|
|
||
| // If all the input was consumed, then the | ||
| // input is truncated, even if the output | ||
| // buffer is also full. This is because | ||
| // processing the last byte of the Block | ||
| // never produces output. | ||
| // | ||
| // NOTE: This assumption may break when new | ||
| // filters are added, if the end marker of | ||
| // the filter doesn't consume at least one | ||
| // complete byte. | ||
| if (*in_pos == in_size) | ||
| ret = LZMA_DATA_ERROR; | ||
| else | ||
| ret = LZMA_BUF_ERROR; | ||
| } | ||
|
|
||
| // Restore the positions. | ||
| *in_pos = in_start; | ||
| *out_pos = out_start; | ||
| } | ||
| } | ||
|
|
||
| // Free the decoder memory. This needs to be done even if | ||
| // initialization fails, because the internal API doesn't | ||
| // require the initialization function to free its memory on error. | ||
| lzma_next_end(&block_decoder, allocator); | ||
|
|
||
| return ret; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,337 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file block_buffer_encoder.c | ||
| /// \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. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "block_buffer_encoder.h" | ||
| #include "block_encoder.h" | ||
| #include "filter_encoder.h" | ||
| #include "lzma2_encoder.h" | ||
| #include "check.h" | ||
|
|
||
|
|
||
| /// Estimate the maximum size of the Block Header and Check fields for | ||
| /// a Block that uses LZMA2 uncompressed chunks. We could use | ||
| /// lzma_block_header_size() but this is simpler. | ||
| /// | ||
| /// Block Header Size + Block Flags + Compressed Size | ||
| /// + Uncompressed Size + Filter Flags for LZMA2 + CRC32 + Check | ||
| /// and round up to the next multiple of four to take Header Padding | ||
| /// into account. | ||
| #define HEADERS_BOUND ((1 + 1 + 2 * LZMA_VLI_BYTES_MAX + 3 + 4 \ | ||
| + LZMA_CHECK_SIZE_MAX + 3) & ~3) | ||
|
|
||
|
|
||
| static uint64_t | ||
| lzma2_bound(uint64_t uncompressed_size) | ||
| { | ||
| // Prevent integer overflow in overhead calculation. | ||
| if (uncompressed_size > COMPRESSED_SIZE_MAX) | ||
| return 0; | ||
|
|
||
| // Calculate the exact overhead of the LZMA2 headers: Round | ||
| // 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 uint64_t overhead = ((uncompressed_size + LZMA2_CHUNK_MAX - 1) | ||
| / LZMA2_CHUNK_MAX) | ||
| * LZMA2_HEADER_UNCOMPRESSED + 1; | ||
|
|
||
| // Catch the possible integer overflow. | ||
| if (COMPRESSED_SIZE_MAX - overhead < uncompressed_size) | ||
| return 0; | ||
|
|
||
| return uncompressed_size + overhead; | ||
| } | ||
|
|
||
|
|
||
| extern uint64_t | ||
| lzma_block_buffer_bound64(uint64_t 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) & ~UINT64_C(3); | ||
|
|
||
| // No risk of integer overflow because lzma2_bound() already takes | ||
| // into account the size of the headers in the Block. | ||
| 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 ret; | ||
| } | ||
|
|
||
|
|
||
| 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) | ||
| { | ||
| // 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. | ||
| lzma_options_lzma lzma2 = { | ||
| .dict_size = LZMA_DICT_SIZE_MIN, | ||
| }; | ||
|
|
||
| lzma_filter filters[2]; | ||
| filters[0].id = LZMA_FILTER_LZMA2; | ||
| filters[0].options = &lzma2; | ||
| filters[1].id = LZMA_VLI_UNKNOWN; | ||
|
|
||
| // Set the above filter options to *block temporarily so that we can | ||
| // encode the Block Header. | ||
| lzma_filter *filters_orig = block->filters; | ||
| block->filters = filters; | ||
|
|
||
| if (lzma_block_header_size(block) != LZMA_OK) { | ||
| block->filters = filters_orig; | ||
| return LZMA_PROG_ERROR; | ||
| } | ||
|
|
||
| // Check that there's enough output space. The caller has already | ||
| // set block->compressed_size to what lzma2_bound() has returned, | ||
| // so we can reuse that value. We know that compressed_size is a | ||
| // known valid VLI and header_size is a small value so their sum | ||
| // will never overflow. | ||
| assert(block->compressed_size == lzma2_bound(in_size)); | ||
| if (out_size - *out_pos | ||
| < block->header_size + block->compressed_size) { | ||
| block->filters = filters_orig; | ||
| return LZMA_BUF_ERROR; | ||
| } | ||
|
|
||
| if (lzma_block_header_encode(block, out + *out_pos) != LZMA_OK) { | ||
| block->filters = filters_orig; | ||
| return LZMA_PROG_ERROR; | ||
| } | ||
|
|
||
| block->filters = filters_orig; | ||
| *out_pos += block->header_size; | ||
|
|
||
| // Encode the data using LZMA2 uncompressed chunks. | ||
| size_t in_pos = 0; | ||
| uint8_t control = 0x01; // Dictionary reset | ||
|
|
||
| while (in_pos < in_size) { | ||
| // Control byte: Indicate uncompressed chunk, of which | ||
| // the first resets the dictionary. | ||
| out[(*out_pos)++] = control; | ||
| control = 0x02; // No dictionary reset | ||
|
|
||
| // Size of the uncompressed chunk | ||
| const size_t copy_size | ||
| = my_min(in_size - in_pos, LZMA2_CHUNK_MAX); | ||
| out[(*out_pos)++] = (copy_size - 1) >> 8; | ||
| out[(*out_pos)++] = (copy_size - 1) & 0xFF; | ||
|
|
||
| // The actual data | ||
| assert(*out_pos + copy_size <= out_size); | ||
| memcpy(out + *out_pos, in + in_pos, copy_size); | ||
|
|
||
| in_pos += copy_size; | ||
| *out_pos += copy_size; | ||
| } | ||
|
|
||
| // End marker | ||
| out[(*out_pos)++] = 0x00; | ||
| assert(*out_pos <= out_size); | ||
|
|
||
| return LZMA_OK; | ||
| } | ||
|
|
||
|
|
||
| static lzma_ret | ||
| block_encode_normal(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) | ||
| { | ||
| // Find out the size of the Block Header. | ||
| return_if_error(lzma_block_header_size(block)); | ||
|
|
||
| // Reserve space for the Block Header and skip it for now. | ||
| if (out_size - *out_pos <= block->header_size) | ||
| return LZMA_BUF_ERROR; | ||
|
|
||
| const size_t out_start = *out_pos; | ||
| *out_pos += block->header_size; | ||
|
|
||
| // Limit out_size so that we stop encoding if the output would grow | ||
| // bigger than what uncompressed Block would be. | ||
| if (out_size - *out_pos > block->compressed_size) | ||
| out_size = *out_pos + block->compressed_size; | ||
|
|
||
| // TODO: In many common cases this could be optimized to use | ||
| // significantly less memory. | ||
| lzma_next_coder raw_encoder = LZMA_NEXT_CODER_INIT; | ||
| lzma_ret ret = lzma_raw_encoder_init( | ||
| &raw_encoder, allocator, block->filters); | ||
|
|
||
| if (ret == LZMA_OK) { | ||
| size_t in_pos = 0; | ||
| ret = raw_encoder.code(raw_encoder.coder, allocator, | ||
| in, &in_pos, in_size, out, out_pos, out_size, | ||
| LZMA_FINISH); | ||
| } | ||
|
|
||
| // NOTE: This needs to be run even if lzma_raw_encoder_init() failed. | ||
| lzma_next_end(&raw_encoder, allocator); | ||
|
|
||
| if (ret == LZMA_STREAM_END) { | ||
| // Compression was successful. Write the Block Header. | ||
| block->compressed_size | ||
| = *out_pos - (out_start + block->header_size); | ||
| ret = lzma_block_header_encode(block, out + out_start); | ||
| if (ret != LZMA_OK) | ||
| ret = LZMA_PROG_ERROR; | ||
|
|
||
| } else if (ret == LZMA_OK) { | ||
| // Output buffer became full. | ||
| ret = LZMA_BUF_ERROR; | ||
| } | ||
|
|
||
| // Reset *out_pos if something went wrong. | ||
| if (ret != LZMA_OK) | ||
| *out_pos = out_start; | ||
|
|
||
| return ret; | ||
| } | ||
|
|
||
|
|
||
| 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, | ||
| bool try_to_compress) | ||
| { | ||
| // Validate the arguments. | ||
| if (block == NULL || (in == NULL && in_size != 0) || out == NULL | ||
| || out_pos == NULL || *out_pos > out_size) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| // The contents of the structure may depend on the version so | ||
| // check the version before validating the contents of *block. | ||
| if (block->version > 1) | ||
| return LZMA_OPTIONS_ERROR; | ||
|
|
||
| if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX | ||
| || (try_to_compress && block->filters == NULL)) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| if (!lzma_check_is_supported(block->check)) | ||
| return LZMA_UNSUPPORTED_CHECK; | ||
|
|
||
| // Size of a Block has to be a multiple of four, so limit the size | ||
| // here already. This way we don't need to check it again when adding | ||
| // Block Padding. | ||
| out_size -= (out_size - *out_pos) & 3; | ||
|
|
||
| // Get the size of the Check field. | ||
| const size_t check_size = lzma_check_size(block->check); | ||
| assert(check_size != UINT32_MAX); | ||
|
|
||
| // Reserve space for the Check field. | ||
| if (out_size - *out_pos <= check_size) | ||
| return LZMA_BUF_ERROR; | ||
|
|
||
| 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. | ||
| 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. | ||
| if (ret != LZMA_BUF_ERROR) | ||
| return ret; | ||
|
|
||
| // The data was uncompressible (at least with the options | ||
| // given to us) or the output buffer was too small. Use the | ||
| // uncompressed chunks of LZMA2 to wrap the data into a valid | ||
| // Block. If we haven't been given enough output space, even | ||
| // this may fail. | ||
| return_if_error(block_encode_uncompressed(block, in, in_size, | ||
| out, out_pos, out_size)); | ||
| } | ||
|
|
||
| assert(*out_pos <= out_size); | ||
|
|
||
| // Block Padding. No buffer overflow here, because we already adjusted | ||
| // out_size so that (out_size - out_start) is a multiple of four. | ||
| // Thus, if the buffer is full, the loop body can never run. | ||
| for (size_t i = (size_t)(block->compressed_size); i & 3; ++i) { | ||
| assert(*out_pos < out_size); | ||
| out[(*out_pos)++] = 0x00; | ||
| } | ||
|
|
||
| // If there's no Check field, we are done now. | ||
| if (check_size > 0) { | ||
| // Calculate the integrity check. We reserved space for | ||
| // the Check field earlier so we don't need to check for | ||
| // available output space here. | ||
| lzma_check_state check; | ||
| lzma_check_init(&check, block->check); | ||
| lzma_check_update(&check, block->check, in, in_size); | ||
| lzma_check_finish(&check, block->check); | ||
|
|
||
| memcpy(block->raw_check, check.buffer.u8, check_size); | ||
| memcpy(out + *out_pos, check.buffer.u8, check_size); | ||
| *out_pos += check_size; | ||
| } | ||
|
|
||
| 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); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,257 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file block_decoder.c | ||
| /// \brief Decodes .xz Blocks | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "block_decoder.h" | ||
| #include "filter_decoder.h" | ||
| #include "check.h" | ||
|
|
||
|
|
||
| typedef struct { | ||
| enum { | ||
| SEQ_CODE, | ||
| SEQ_PADDING, | ||
| SEQ_CHECK, | ||
| } sequence; | ||
|
|
||
| /// The filters in the chain; initialized with lzma_raw_decoder_init(). | ||
| lzma_next_coder next; | ||
|
|
||
| /// Decoding options; we also write Compressed Size and Uncompressed | ||
| /// Size back to this structure when the decoding has been finished. | ||
| lzma_block *block; | ||
|
|
||
| /// Compressed Size calculated while decoding | ||
| lzma_vli compressed_size; | ||
|
|
||
| /// Uncompressed Size calculated while decoding | ||
| lzma_vli uncompressed_size; | ||
|
|
||
| /// Maximum allowed Compressed Size; this takes into account the | ||
| /// size of the Block Header and Check fields when Compressed Size | ||
| /// is unknown. | ||
| lzma_vli compressed_limit; | ||
|
|
||
| /// Position when reading the Check field | ||
| size_t check_pos; | ||
|
|
||
| /// Check of the uncompressed data | ||
| lzma_check_state check; | ||
|
|
||
| /// True if the integrity check won't be calculated and verified. | ||
| bool ignore_check; | ||
| } lzma_block_coder; | ||
|
|
||
|
|
||
| static inline bool | ||
| update_size(lzma_vli *size, lzma_vli add, lzma_vli limit) | ||
| { | ||
| if (limit > LZMA_VLI_MAX) | ||
| limit = LZMA_VLI_MAX; | ||
|
|
||
| if (limit < *size || limit - *size < add) | ||
| return true; | ||
|
|
||
| *size += add; | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
|
|
||
| static inline bool | ||
| is_size_valid(lzma_vli size, lzma_vli reference) | ||
| { | ||
| return reference == LZMA_VLI_UNKNOWN || reference == size; | ||
| } | ||
|
|
||
|
|
||
| static lzma_ret | ||
| block_decode(void *coder_ptr, 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) | ||
| { | ||
| lzma_block_coder *coder = coder_ptr; | ||
|
|
||
| switch (coder->sequence) { | ||
| case SEQ_CODE: { | ||
| const size_t in_start = *in_pos; | ||
| const size_t out_start = *out_pos; | ||
|
|
||
| const lzma_ret ret = coder->next.code(coder->next.coder, | ||
| allocator, in, in_pos, in_size, | ||
| out, out_pos, out_size, action); | ||
|
|
||
| const size_t in_used = *in_pos - in_start; | ||
| const size_t out_used = *out_pos - out_start; | ||
|
|
||
| // NOTE: We compare to compressed_limit here, which prevents | ||
| // the total size of the Block growing past LZMA_VLI_MAX. | ||
| if (update_size(&coder->compressed_size, in_used, | ||
| coder->compressed_limit) | ||
| || update_size(&coder->uncompressed_size, | ||
| out_used, | ||
| coder->block->uncompressed_size)) | ||
| return LZMA_DATA_ERROR; | ||
|
|
||
| if (!coder->ignore_check) | ||
| lzma_check_update(&coder->check, coder->block->check, | ||
| out + out_start, out_used); | ||
|
|
||
| if (ret != LZMA_STREAM_END) | ||
| return ret; | ||
|
|
||
| // Compressed and Uncompressed Sizes are now at their final | ||
| // values. Verify that they match the values given to us. | ||
| if (!is_size_valid(coder->compressed_size, | ||
| coder->block->compressed_size) | ||
| || !is_size_valid(coder->uncompressed_size, | ||
| coder->block->uncompressed_size)) | ||
| return LZMA_DATA_ERROR; | ||
|
|
||
| // Copy the values into coder->block. The caller | ||
| // may use this information to construct Index. | ||
| coder->block->compressed_size = coder->compressed_size; | ||
| coder->block->uncompressed_size = coder->uncompressed_size; | ||
|
|
||
| coder->sequence = SEQ_PADDING; | ||
| } | ||
|
|
||
| // Fall through | ||
|
|
||
| case SEQ_PADDING: | ||
| // Compressed Data is padded to a multiple of four bytes. | ||
| while (coder->compressed_size & 3) { | ||
| if (*in_pos >= in_size) | ||
| return LZMA_OK; | ||
|
|
||
| // We use compressed_size here just get the Padding | ||
| // right. The actual Compressed Size was stored to | ||
| // coder->block already, and won't be modified by | ||
| // us anymore. | ||
| ++coder->compressed_size; | ||
|
|
||
| if (in[(*in_pos)++] != 0x00) | ||
| return LZMA_DATA_ERROR; | ||
| } | ||
|
|
||
| if (coder->block->check == LZMA_CHECK_NONE) | ||
| return LZMA_STREAM_END; | ||
|
|
||
| if (!coder->ignore_check) | ||
| lzma_check_finish(&coder->check, coder->block->check); | ||
|
|
||
| coder->sequence = SEQ_CHECK; | ||
|
|
||
| // Fall through | ||
|
|
||
| case SEQ_CHECK: { | ||
| const size_t check_size = lzma_check_size(coder->block->check); | ||
| lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check, | ||
| &coder->check_pos, check_size); | ||
| if (coder->check_pos < check_size) | ||
| return LZMA_OK; | ||
|
|
||
| // Validate the Check only if we support it. | ||
| // coder->check.buffer may be uninitialized | ||
| // when the Check ID is not supported. | ||
| if (!coder->ignore_check | ||
| && lzma_check_is_supported(coder->block->check) | ||
| && memcmp(coder->block->raw_check, | ||
| coder->check.buffer.u8, | ||
| check_size) != 0) | ||
| return LZMA_DATA_ERROR; | ||
|
|
||
| return LZMA_STREAM_END; | ||
| } | ||
| } | ||
|
|
||
| return LZMA_PROG_ERROR; | ||
| } | ||
|
|
||
|
|
||
| static void | ||
| block_decoder_end(void *coder_ptr, const lzma_allocator *allocator) | ||
| { | ||
| lzma_block_coder *coder = coder_ptr; | ||
| lzma_next_end(&coder->next, allocator); | ||
| lzma_free(coder, allocator); | ||
| return; | ||
| } | ||
|
|
||
|
|
||
| extern lzma_ret | ||
| lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, | ||
| lzma_block *block) | ||
| { | ||
| lzma_next_coder_init(&lzma_block_decoder_init, next, allocator); | ||
|
|
||
| // Validate the options. lzma_block_unpadded_size() does that for us | ||
| // except for Uncompressed Size and filters. Filters are validated | ||
| // by the raw decoder. | ||
| if (lzma_block_unpadded_size(block) == 0 | ||
| || !lzma_vli_is_valid(block->uncompressed_size)) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| // Allocate *next->coder if needed. | ||
| lzma_block_coder *coder = next->coder; | ||
| if (coder == NULL) { | ||
| coder = lzma_alloc(sizeof(lzma_block_coder), allocator); | ||
| if (coder == NULL) | ||
| return LZMA_MEM_ERROR; | ||
|
|
||
| next->coder = coder; | ||
| next->code = &block_decode; | ||
| next->end = &block_decoder_end; | ||
| coder->next = LZMA_NEXT_CODER_INIT; | ||
| } | ||
|
|
||
| // Basic initializations | ||
| coder->sequence = SEQ_CODE; | ||
| coder->block = block; | ||
| coder->compressed_size = 0; | ||
| coder->uncompressed_size = 0; | ||
|
|
||
| // If Compressed Size is not known, we calculate the maximum allowed | ||
| // value so that encoded size of the Block (including Block Padding) | ||
| // is still a valid VLI and a multiple of four. | ||
| coder->compressed_limit | ||
| = block->compressed_size == LZMA_VLI_UNKNOWN | ||
| ? (LZMA_VLI_MAX & ~LZMA_VLI_C(3)) | ||
| - block->header_size | ||
| - lzma_check_size(block->check) | ||
| : block->compressed_size; | ||
|
|
||
| // Initialize the check. It's caller's problem if the Check ID is not | ||
| // supported, and the Block decoder cannot verify the Check field. | ||
| // Caller can test lzma_check_is_supported(block->check). | ||
| coder->check_pos = 0; | ||
| lzma_check_init(&coder->check, block->check); | ||
|
|
||
| coder->ignore_check = block->version >= 1 | ||
| ? block->ignore_check : false; | ||
|
|
||
| // Initialize the filter chain. | ||
| return lzma_raw_decoder_init(&coder->next, allocator, | ||
| block->filters); | ||
| } | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_ret) | ||
| lzma_block_decoder(lzma_stream *strm, lzma_block *block) | ||
| { | ||
| lzma_next_strm_init(lzma_block_decoder_init, strm, block); | ||
|
|
||
| strm->internal->supported_actions[LZMA_RUN] = true; | ||
| strm->internal->supported_actions[LZMA_FINISH] = true; | ||
|
|
||
| return LZMA_OK; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file block_decoder.h | ||
| /// \brief Decodes .xz Blocks | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #ifndef LZMA_BLOCK_DECODER_H | ||
| #define LZMA_BLOCK_DECODER_H | ||
|
|
||
| #include "common.h" | ||
|
|
||
|
|
||
| extern lzma_ret lzma_block_decoder_init(lzma_next_coder *next, | ||
| const lzma_allocator *allocator, lzma_block *block); | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,223 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file block_encoder.c | ||
| /// \brief Encodes .xz Blocks | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "block_encoder.h" | ||
| #include "filter_encoder.h" | ||
| #include "check.h" | ||
|
|
||
|
|
||
| typedef struct { | ||
| /// The filters in the chain; initialized with lzma_raw_decoder_init(). | ||
| lzma_next_coder next; | ||
|
|
||
| /// Encoding options; we also write Unpadded Size, Compressed Size, | ||
| /// and Uncompressed Size back to this structure when the encoding | ||
| /// has been finished. | ||
| lzma_block *block; | ||
|
|
||
| enum { | ||
| SEQ_CODE, | ||
| SEQ_PADDING, | ||
| SEQ_CHECK, | ||
| } sequence; | ||
|
|
||
| /// Compressed Size calculated while encoding | ||
| lzma_vli compressed_size; | ||
|
|
||
| /// Uncompressed Size calculated while encoding | ||
| lzma_vli uncompressed_size; | ||
|
|
||
| /// Position in the Check field | ||
| size_t pos; | ||
|
|
||
| /// Check of the uncompressed data | ||
| lzma_check_state check; | ||
| } lzma_block_coder; | ||
|
|
||
|
|
||
| static lzma_ret | ||
| block_encode(void *coder_ptr, 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) | ||
| { | ||
| lzma_block_coder *coder = coder_ptr; | ||
|
|
||
| // Check that our amount of input stays in proper limits. | ||
| if (LZMA_VLI_MAX - coder->uncompressed_size < in_size - *in_pos) | ||
| return LZMA_DATA_ERROR; | ||
|
|
||
| switch (coder->sequence) { | ||
| case SEQ_CODE: { | ||
| const size_t in_start = *in_pos; | ||
| const size_t out_start = *out_pos; | ||
|
|
||
| const lzma_ret ret = coder->next.code(coder->next.coder, | ||
| allocator, in, in_pos, in_size, | ||
| out, out_pos, out_size, action); | ||
|
|
||
| const size_t in_used = *in_pos - in_start; | ||
| const size_t out_used = *out_pos - out_start; | ||
|
|
||
| if (COMPRESSED_SIZE_MAX - coder->compressed_size < out_used) | ||
| return LZMA_DATA_ERROR; | ||
|
|
||
| coder->compressed_size += out_used; | ||
|
|
||
| // No need to check for overflow because we have already | ||
| // checked it at the beginning of this function. | ||
| coder->uncompressed_size += in_used; | ||
|
|
||
| lzma_check_update(&coder->check, coder->block->check, | ||
| in + in_start, in_used); | ||
|
|
||
| if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH) | ||
| return ret; | ||
|
|
||
| assert(*in_pos == in_size); | ||
| assert(action == LZMA_FINISH); | ||
|
|
||
| // Copy the values into coder->block. The caller | ||
| // may use this information to construct Index. | ||
| coder->block->compressed_size = coder->compressed_size; | ||
| coder->block->uncompressed_size = coder->uncompressed_size; | ||
|
|
||
| coder->sequence = SEQ_PADDING; | ||
| } | ||
|
|
||
| // Fall through | ||
|
|
||
| case SEQ_PADDING: | ||
| // Pad Compressed Data to a multiple of four bytes. We can | ||
| // use coder->compressed_size for this since we don't need | ||
| // it for anything else anymore. | ||
| while (coder->compressed_size & 3) { | ||
| if (*out_pos >= out_size) | ||
| return LZMA_OK; | ||
|
|
||
| out[*out_pos] = 0x00; | ||
| ++*out_pos; | ||
| ++coder->compressed_size; | ||
| } | ||
|
|
||
| if (coder->block->check == LZMA_CHECK_NONE) | ||
| return LZMA_STREAM_END; | ||
|
|
||
| lzma_check_finish(&coder->check, coder->block->check); | ||
|
|
||
| coder->sequence = SEQ_CHECK; | ||
|
|
||
| // Fall through | ||
|
|
||
| case SEQ_CHECK: { | ||
| const size_t check_size = lzma_check_size(coder->block->check); | ||
| lzma_bufcpy(coder->check.buffer.u8, &coder->pos, check_size, | ||
| out, out_pos, out_size); | ||
| if (coder->pos < check_size) | ||
| return LZMA_OK; | ||
|
|
||
| memcpy(coder->block->raw_check, coder->check.buffer.u8, | ||
| check_size); | ||
| return LZMA_STREAM_END; | ||
| } | ||
| } | ||
|
|
||
| return LZMA_PROG_ERROR; | ||
| } | ||
|
|
||
|
|
||
| static void | ||
| block_encoder_end(void *coder_ptr, const lzma_allocator *allocator) | ||
| { | ||
| lzma_block_coder *coder = coder_ptr; | ||
| lzma_next_end(&coder->next, allocator); | ||
| lzma_free(coder, allocator); | ||
| return; | ||
| } | ||
|
|
||
|
|
||
| static lzma_ret | ||
| block_encoder_update(void *coder_ptr, const lzma_allocator *allocator, | ||
| const lzma_filter *filters lzma_attribute((__unused__)), | ||
| const lzma_filter *reversed_filters) | ||
| { | ||
| lzma_block_coder *coder = coder_ptr; | ||
|
|
||
| if (coder->sequence != SEQ_CODE) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| return lzma_next_filter_update( | ||
| &coder->next, allocator, reversed_filters); | ||
| } | ||
|
|
||
|
|
||
| extern lzma_ret | ||
| lzma_block_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, | ||
| lzma_block *block) | ||
| { | ||
| lzma_next_coder_init(&lzma_block_encoder_init, next, allocator); | ||
|
|
||
| if (block == NULL) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| // The contents of the structure may depend on the version so | ||
| // check the version first. | ||
| if (block->version > 1) | ||
| return LZMA_OPTIONS_ERROR; | ||
|
|
||
| // If the Check ID is not supported, we cannot calculate the check and | ||
| // thus not create a proper Block. | ||
| if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| if (!lzma_check_is_supported(block->check)) | ||
| return LZMA_UNSUPPORTED_CHECK; | ||
|
|
||
| // Allocate and initialize *next->coder if needed. | ||
| lzma_block_coder *coder = next->coder; | ||
| if (coder == NULL) { | ||
| coder = lzma_alloc(sizeof(lzma_block_coder), allocator); | ||
| if (coder == NULL) | ||
| return LZMA_MEM_ERROR; | ||
|
|
||
| next->coder = coder; | ||
| next->code = &block_encode; | ||
| next->end = &block_encoder_end; | ||
| next->update = &block_encoder_update; | ||
| coder->next = LZMA_NEXT_CODER_INIT; | ||
| } | ||
|
|
||
| // Basic initializations | ||
| coder->sequence = SEQ_CODE; | ||
| coder->block = block; | ||
| coder->compressed_size = 0; | ||
| coder->uncompressed_size = 0; | ||
| coder->pos = 0; | ||
|
|
||
| // Initialize the check | ||
| lzma_check_init(&coder->check, block->check); | ||
|
|
||
| // Initialize the requested filters. | ||
| return lzma_raw_encoder_init(&coder->next, allocator, block->filters); | ||
| } | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_ret) | ||
| lzma_block_encoder(lzma_stream *strm, lzma_block *block) | ||
| { | ||
| lzma_next_strm_init(lzma_block_encoder_init, strm, block); | ||
|
|
||
| strm->internal->supported_actions[LZMA_RUN] = true; | ||
| strm->internal->supported_actions[LZMA_FINISH] = true; | ||
|
|
||
| return LZMA_OK; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file block_encoder.h | ||
| /// \brief Encodes .xz Blocks | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #ifndef LZMA_BLOCK_ENCODER_H | ||
| #define LZMA_BLOCK_ENCODER_H | ||
|
|
||
| #include "common.h" | ||
|
|
||
|
|
||
| /// \brief Biggest Compressed Size value that the Block encoder supports | ||
| /// | ||
| /// The maximum size of a single Block is limited by the maximum size of | ||
| /// a Stream, which in theory is 2^63 - 3 bytes (i.e. LZMA_VLI_MAX - 3). | ||
| /// While the size is really big and no one should hit it in practice, we | ||
| /// take it into account in some places anyway to catch some errors e.g. if | ||
| /// application passes insanely big value to some function. | ||
| /// | ||
| /// We could take into account the headers etc. to determine the exact | ||
| /// maximum size of the Compressed Data field, but the complexity would give | ||
| /// us nothing useful. Instead, limit the size of Compressed Data so that | ||
| /// even with biggest possible Block Header and Check fields the total | ||
| /// encoded size of the Block stays as a valid VLI. This doesn't guarantee | ||
| /// that the size of the Stream doesn't grow too big, but that problem is | ||
| /// taken care outside the Block handling code. | ||
| /// | ||
| /// ~LZMA_VLI_C(3) is to guarantee that if we need padding at the end of | ||
| /// the Compressed Data field, it will still stay in the proper limit. | ||
| /// | ||
| /// This constant is in this file because it is needed in both | ||
| /// block_encoder.c and block_buffer_encoder.c. | ||
| #define COMPRESSED_SIZE_MAX ((LZMA_VLI_MAX - LZMA_BLOCK_HEADER_SIZE_MAX \ | ||
| - LZMA_CHECK_SIZE_MAX) & ~LZMA_VLI_C(3)) | ||
|
|
||
|
|
||
| extern lzma_ret lzma_block_encoder_init(lzma_next_coder *next, | ||
| const lzma_allocator *allocator, lzma_block *block); | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file block_header_decoder.c | ||
| /// \brief Decodes Block Header from .xz 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 "check.h" | ||
|
|
||
|
|
||
| static void | ||
| free_properties(lzma_block *block, const lzma_allocator *allocator) | ||
| { | ||
| // Free allocated filter options. The last array member is not | ||
| // touched after the initialization in the beginning of | ||
| // lzma_block_header_decode(), so we don't need to touch that here. | ||
| for (size_t i = 0; i < LZMA_FILTERS_MAX; ++i) { | ||
| lzma_free(block->filters[i].options, allocator); | ||
| block->filters[i].id = LZMA_VLI_UNKNOWN; | ||
| block->filters[i].options = NULL; | ||
| } | ||
|
|
||
| return; | ||
| } | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_ret) | ||
| lzma_block_header_decode(lzma_block *block, | ||
| const lzma_allocator *allocator, const uint8_t *in) | ||
| { | ||
| // NOTE: We consider the header to be corrupt not only when the | ||
| // CRC32 doesn't match, but also when variable-length integers | ||
| // are invalid or over 63 bits, or if the header is too small | ||
| // to contain the claimed information. | ||
|
|
||
| // Initialize the filter options array. This way the caller can | ||
| // safely free() the options even if an error occurs in this function. | ||
| for (size_t i = 0; i <= LZMA_FILTERS_MAX; ++i) { | ||
| block->filters[i].id = LZMA_VLI_UNKNOWN; | ||
| block->filters[i].options = NULL; | ||
| } | ||
|
|
||
| // Versions 0 and 1 are supported. If a newer version was specified, | ||
| // we need to downgrade it. | ||
| if (block->version > 1) | ||
| block->version = 1; | ||
|
|
||
| // This isn't a Block Header option, but since the decompressor will | ||
| // read it if version >= 1, it's better to initialize it here than | ||
| // to expect the caller to do it since in almost all cases this | ||
| // should be false. | ||
| block->ignore_check = false; | ||
|
|
||
| // Validate Block Header Size and Check type. The caller must have | ||
| // already set these, so it is a programming error if this test fails. | ||
| if (lzma_block_header_size_decode(in[0]) != block->header_size | ||
| || (unsigned int)(block->check) > LZMA_CHECK_ID_MAX) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| // Exclude the CRC32 field. | ||
| const size_t in_size = block->header_size - 4; | ||
|
|
||
| // Verify CRC32 | ||
| if (lzma_crc32(in, in_size, 0) != unaligned_read32le(in + in_size)) | ||
| return LZMA_DATA_ERROR; | ||
|
|
||
| // Check for unsupported flags. | ||
| if (in[1] & 0x3C) | ||
| return LZMA_OPTIONS_ERROR; | ||
|
|
||
| // Start after the Block Header Size and Block Flags fields. | ||
| size_t in_pos = 2; | ||
|
|
||
| // Compressed Size | ||
| if (in[1] & 0x40) { | ||
| return_if_error(lzma_vli_decode(&block->compressed_size, | ||
| NULL, in, &in_pos, in_size)); | ||
|
|
||
| // Validate Compressed Size. This checks that it isn't zero | ||
| // and that the total size of the Block is a valid VLI. | ||
| if (lzma_block_unpadded_size(block) == 0) | ||
| return LZMA_DATA_ERROR; | ||
| } else { | ||
| block->compressed_size = LZMA_VLI_UNKNOWN; | ||
| } | ||
|
|
||
| // Uncompressed Size | ||
| if (in[1] & 0x80) | ||
| return_if_error(lzma_vli_decode(&block->uncompressed_size, | ||
| NULL, in, &in_pos, in_size)); | ||
| else | ||
| block->uncompressed_size = LZMA_VLI_UNKNOWN; | ||
|
|
||
| // Filter Flags | ||
| const size_t filter_count = (in[1] & 3) + 1; | ||
| for (size_t i = 0; i < filter_count; ++i) { | ||
| const lzma_ret ret = lzma_filter_flags_decode( | ||
| &block->filters[i], allocator, | ||
| in, &in_pos, in_size); | ||
| if (ret != LZMA_OK) { | ||
| free_properties(block, allocator); | ||
| return ret; | ||
| } | ||
| } | ||
|
|
||
| // Padding | ||
| while (in_pos < in_size) { | ||
| if (in[in_pos++] != 0x00) { | ||
| free_properties(block, allocator); | ||
|
|
||
| // Possibly some new field present so use | ||
| // LZMA_OPTIONS_ERROR instead of LZMA_DATA_ERROR. | ||
| return LZMA_OPTIONS_ERROR; | ||
| } | ||
| } | ||
|
|
||
| return LZMA_OK; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file block_header_encoder.c | ||
| /// \brief Encodes Block Header for .xz 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 "check.h" | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_ret) | ||
| lzma_block_header_size(lzma_block *block) | ||
| { | ||
| if (block->version > 1) | ||
| return LZMA_OPTIONS_ERROR; | ||
|
|
||
| // Block Header Size + Block Flags + CRC32. | ||
| uint32_t size = 1 + 1 + 4; | ||
|
|
||
| // Compressed Size | ||
| if (block->compressed_size != LZMA_VLI_UNKNOWN) { | ||
| const uint32_t add = lzma_vli_size(block->compressed_size); | ||
| if (add == 0 || block->compressed_size == 0) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| size += add; | ||
| } | ||
|
|
||
| // Uncompressed Size | ||
| if (block->uncompressed_size != LZMA_VLI_UNKNOWN) { | ||
| const uint32_t add = lzma_vli_size(block->uncompressed_size); | ||
| if (add == 0) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| size += add; | ||
| } | ||
|
|
||
| // List of Filter Flags | ||
| if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| for (size_t i = 0; block->filters[i].id != LZMA_VLI_UNKNOWN; ++i) { | ||
| // Don't allow too many filters. | ||
| if (i == LZMA_FILTERS_MAX) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| uint32_t add; | ||
| return_if_error(lzma_filter_flags_size(&add, | ||
| block->filters + i)); | ||
|
|
||
| size += add; | ||
| } | ||
|
|
||
| // Pad to a multiple of four bytes. | ||
| block->header_size = (size + 3) & ~UINT32_C(3); | ||
|
|
||
| // NOTE: We don't verify that the encoded size of the Block stays | ||
| // within limits. This is because it is possible that we are called | ||
| // with exaggerated Compressed Size (e.g. LZMA_VLI_MAX) to reserve | ||
| // space for Block Header, and later called again with lower, | ||
| // real values. | ||
|
|
||
| return LZMA_OK; | ||
| } | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_ret) | ||
| lzma_block_header_encode(const lzma_block *block, uint8_t *out) | ||
| { | ||
| // Validate everything but filters. | ||
| if (lzma_block_unpadded_size(block) == 0 | ||
| || !lzma_vli_is_valid(block->uncompressed_size)) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| // Indicate the size of the buffer _excluding_ the CRC32 field. | ||
| const size_t out_size = block->header_size - 4; | ||
|
|
||
| // Store the Block Header Size. | ||
| out[0] = out_size / 4; | ||
|
|
||
| // We write Block Flags in pieces. | ||
| out[1] = 0x00; | ||
| size_t out_pos = 2; | ||
|
|
||
| // Compressed Size | ||
| if (block->compressed_size != LZMA_VLI_UNKNOWN) { | ||
| return_if_error(lzma_vli_encode(block->compressed_size, NULL, | ||
| out, &out_pos, out_size)); | ||
|
|
||
| out[1] |= 0x40; | ||
| } | ||
|
|
||
| // Uncompressed Size | ||
| if (block->uncompressed_size != LZMA_VLI_UNKNOWN) { | ||
| return_if_error(lzma_vli_encode(block->uncompressed_size, NULL, | ||
| out, &out_pos, out_size)); | ||
|
|
||
| out[1] |= 0x80; | ||
| } | ||
|
|
||
| // Filter Flags | ||
| if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| size_t filter_count = 0; | ||
| do { | ||
| // There can be a maximum of four filters. | ||
| if (filter_count == LZMA_FILTERS_MAX) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| return_if_error(lzma_filter_flags_encode( | ||
| block->filters + filter_count, | ||
| out, &out_pos, out_size)); | ||
|
|
||
| } while (block->filters[++filter_count].id != LZMA_VLI_UNKNOWN); | ||
|
|
||
| out[1] |= filter_count - 1; | ||
|
|
||
| // Padding | ||
| memzero(out + out_pos, out_size - out_pos); | ||
|
|
||
| // CRC32 | ||
| unaligned_write32le(out + out_size, lzma_crc32(out, out_size, 0)); | ||
|
|
||
| return LZMA_OK; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file block_header.c | ||
| /// \brief Utility functions to handle lzma_block | ||
| // | ||
| // 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 "index.h" | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_ret) | ||
| lzma_block_compressed_size(lzma_block *block, lzma_vli unpadded_size) | ||
| { | ||
| // Validate everything but Uncompressed Size and filters. | ||
| if (lzma_block_unpadded_size(block) == 0) | ||
| return LZMA_PROG_ERROR; | ||
|
|
||
| const uint32_t container_size = block->header_size | ||
| + lzma_check_size(block->check); | ||
|
|
||
| // Validate that Compressed Size will be greater than zero. | ||
| if (unpadded_size <= container_size) | ||
| return LZMA_DATA_ERROR; | ||
|
|
||
| // Calculate what Compressed Size is supposed to be. | ||
| // If Compressed Size was present in Block Header, | ||
| // compare that the new value matches it. | ||
| const lzma_vli compressed_size = unpadded_size - container_size; | ||
| if (block->compressed_size != LZMA_VLI_UNKNOWN | ||
| && block->compressed_size != compressed_size) | ||
| return LZMA_DATA_ERROR; | ||
|
|
||
| block->compressed_size = compressed_size; | ||
|
|
||
| return LZMA_OK; | ||
| } | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_vli) | ||
| lzma_block_unpadded_size(const lzma_block *block) | ||
| { | ||
| // Validate the values that we are interested in i.e. all but | ||
| // Uncompressed Size and the filters. | ||
| // | ||
| // NOTE: This function is used for validation too, so it is | ||
| // essential that these checks are always done even if | ||
| // Compressed Size is unknown. | ||
| if (block == NULL || block->version > 1 | ||
| || block->header_size < LZMA_BLOCK_HEADER_SIZE_MIN | ||
| || block->header_size > LZMA_BLOCK_HEADER_SIZE_MAX | ||
| || (block->header_size & 3) | ||
| || !lzma_vli_is_valid(block->compressed_size) | ||
| || block->compressed_size == 0 | ||
| || (unsigned int)(block->check) > LZMA_CHECK_ID_MAX) | ||
| return 0; | ||
|
|
||
| // If Compressed Size is unknown, return that we cannot know | ||
| // size of the Block either. | ||
| if (block->compressed_size == LZMA_VLI_UNKNOWN) | ||
| return LZMA_VLI_UNKNOWN; | ||
|
|
||
| // Calculate Unpadded Size and validate it. | ||
| const lzma_vli unpadded_size = block->compressed_size | ||
| + block->header_size | ||
| + lzma_check_size(block->check); | ||
|
|
||
| assert(unpadded_size >= UNPADDED_SIZE_MIN); | ||
| if (unpadded_size > UNPADDED_SIZE_MAX) | ||
| return 0; | ||
|
|
||
| return unpadded_size; | ||
| } | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_vli) | ||
| lzma_block_total_size(const lzma_block *block) | ||
| { | ||
| lzma_vli unpadded_size = lzma_block_unpadded_size(block); | ||
|
|
||
| if (unpadded_size != LZMA_VLI_UNKNOWN) | ||
| unpadded_size = vli_ceil4(unpadded_size); | ||
|
|
||
| return unpadded_size; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,314 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \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 "mythread.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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file easy_buffer_encoder.c | ||
| /// \brief Easy single-call .xz Stream encoder | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "easy_preset.h" | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_ret) | ||
| lzma_easy_buffer_encode(uint32_t preset, lzma_check check, | ||
| const lzma_allocator *allocator, const uint8_t *in, | ||
| size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size) | ||
| { | ||
| lzma_options_easy opt_easy; | ||
| if (lzma_easy_preset(&opt_easy, preset)) | ||
| return LZMA_OPTIONS_ERROR; | ||
|
|
||
| return lzma_stream_buffer_encode(opt_easy.filters, check, | ||
| allocator, in, in_size, out, out_pos, out_size); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file easy_decoder_memusage.c | ||
| /// \brief Decoder memory usage calculation to match easy encoder presets | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "easy_preset.h" | ||
|
|
||
|
|
||
| extern LZMA_API(uint64_t) | ||
| lzma_easy_decoder_memusage(uint32_t preset) | ||
| { | ||
| lzma_options_easy opt_easy; | ||
| if (lzma_easy_preset(&opt_easy, preset)) | ||
| return UINT32_MAX; | ||
|
|
||
| return lzma_raw_decoder_memusage(opt_easy.filters); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file easy_encoder.c | ||
| /// \brief Easy .xz Stream encoder initialization | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "easy_preset.h" | ||
|
|
||
|
|
||
| extern LZMA_API(lzma_ret) | ||
| lzma_easy_encoder(lzma_stream *strm, uint32_t preset, lzma_check check) | ||
| { | ||
| lzma_options_easy opt_easy; | ||
| if (lzma_easy_preset(&opt_easy, preset)) | ||
| return LZMA_OPTIONS_ERROR; | ||
|
|
||
| return lzma_stream_encoder(strm, opt_easy.filters, check); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file easy_encoder_memusage.c | ||
| /// \brief Easy .xz Stream encoder memory usage calculation | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "easy_preset.h" | ||
|
|
||
|
|
||
| extern LZMA_API(uint64_t) | ||
| lzma_easy_encoder_memusage(uint32_t preset) | ||
| { | ||
| lzma_options_easy opt_easy; | ||
| if (lzma_easy_preset(&opt_easy, preset)) | ||
| return UINT32_MAX; | ||
|
|
||
| return lzma_raw_encoder_memusage(opt_easy.filters); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file easy_preset.c | ||
| /// \brief Preset handling for easy encoder and decoder | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "easy_preset.h" | ||
|
|
||
|
|
||
| extern bool | ||
| lzma_easy_preset(lzma_options_easy *opt_easy, uint32_t preset) | ||
| { | ||
| if (lzma_lzma_preset(&opt_easy->opt_lzma, preset)) | ||
| return true; | ||
|
|
||
| opt_easy->filters[0].id = LZMA_FILTER_LZMA2; | ||
| opt_easy->filters[0].options = &opt_easy->opt_lzma; | ||
| opt_easy->filters[1].id = LZMA_VLI_UNKNOWN; | ||
|
|
||
| return false; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| /// \file easy_preset.h | ||
| /// \brief Preset handling for easy encoder and decoder | ||
| // | ||
| // Author: Lasse Collin | ||
| // | ||
| // This file has been put into the public domain. | ||
| // You can do whatever you want with this file. | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include "common.h" | ||
|
|
||
|
|
||
| typedef struct { | ||
| /// We need to keep the filters array available in case | ||
| /// LZMA_FULL_FLUSH is used. | ||
| lzma_filter filters[LZMA_FILTERS_MAX + 1]; | ||
|
|
||
| /// Options for LZMA2 | ||
| lzma_options_lzma opt_lzma; | ||
|
|
||
| // Options for more filters can be added later, so this struct | ||
| // is not ready to be put into the public API. | ||
|
|
||
| } lzma_options_easy; | ||
|
|
||
|
|
||
| /// Set *easy to the settings given by the preset. Returns true on error, | ||
| /// false on success. | ||
| extern bool lzma_easy_preset(lzma_options_easy *easy, uint32_t preset); |