mirror of
https://github.com/PCSX2/xz.git
synced 2026-02-05 03:41:17 +01:00
Compare commits
89 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f76f7516d6 | ||
|
|
3cbcaeb07e | ||
|
|
76762ae609 | ||
|
|
2267f5b0d2 | ||
|
|
cee3021d30 | ||
|
|
c5c7ceb08a | ||
|
|
114cab97af | ||
|
|
b8139e11c5 | ||
|
|
47b59d47cf | ||
|
|
bc19799169 | ||
|
|
fb6d4f83cb | ||
|
|
bc577d35c2 | ||
|
|
713bbc1a80 | ||
|
|
a0ee1afbd9 | ||
|
|
a1e2c568de | ||
|
|
cea5cf8d26 | ||
|
|
95d563db3e | ||
|
|
ab72416d62 | ||
|
|
8238898018 | ||
|
|
94e3f986aa | ||
|
|
0b0e1e6803 | ||
|
|
a015cd1f90 | ||
|
|
c2e29f06a7 | ||
|
|
1520f6ec80 | ||
|
|
8269782283 | ||
|
|
e353d0b1cc | ||
|
|
144ef9e19e | ||
|
|
8c9842c265 | ||
|
|
662b27c417 | ||
|
|
c28f0b3d00 | ||
|
|
bba477257d | ||
|
|
310d19816d | ||
|
|
a27920002d | ||
|
|
a0b1dda409 | ||
|
|
84462afaad | ||
|
|
cbc7401793 | ||
|
|
78ae13bced | ||
|
|
0297863fdb | ||
|
|
d4a0462abe | ||
|
|
a01794c52a | ||
|
|
df8f446e3a | ||
|
|
446e4318fa | ||
|
|
1b0ac0c53c | ||
|
|
c83b7a0334 | ||
|
|
ade31a2bfb | ||
|
|
ac398c3baf | ||
|
|
6fd5ecb589 | ||
|
|
473ef0dc69 | ||
|
|
faf302137e | ||
|
|
e52e9151cf | ||
|
|
14115f84a3 | ||
|
|
f4c95ba94b | ||
|
|
c7bc20a6f3 | ||
|
|
5cbca1205d | ||
|
|
af13781886 | ||
|
|
9fa5949330 | ||
|
|
cb3111e3ed | ||
|
|
4cc584985c | ||
|
|
23ed1d4148 | ||
|
|
b0bc3e0385 | ||
|
|
c6bf438ab3 | ||
|
|
e18adc56f2 | ||
|
|
282e768a14 | ||
|
|
372e402713 | ||
|
|
21515d79d7 | ||
|
|
09f395b6b3 | ||
|
|
3bf857edfe | ||
|
|
7f05803979 | ||
|
|
397fcc0946 | ||
|
|
cbc9e39bae | ||
|
|
bcacd8ce7a | ||
|
|
0275a5398c | ||
|
|
a74525cf9b | ||
|
|
fbbb295a91 | ||
|
|
713dbe5c23 | ||
|
|
3a5d755d05 | ||
|
|
b0798c6aa6 | ||
|
|
9b02a4ffda | ||
|
|
c7f4041f6b | ||
|
|
17b29d4f0a | ||
|
|
49c26920d6 | ||
|
|
5b2458cb24 | ||
|
|
6bd0349c58 | ||
|
|
fc0df0f8db | ||
|
|
57393615b3 | ||
|
|
1238381143 | ||
|
|
29a087fb5a | ||
|
|
6e845c6a3e | ||
|
|
3717885f9e |
7
INSTALL
7
INSTALL
@@ -400,12 +400,6 @@ XZ Utils Installation
|
||||
one thread, something bad may happen.
|
||||
|
||||
--enable-sandbox=METHOD
|
||||
This feature is EXPERIMENTAL in the XZ Utils 5.2.x and
|
||||
disabled by default. If you test this, look especially
|
||||
if message translations and locale-specific decimal and
|
||||
thousand separators (e.g. xz --list foo.xz) work the
|
||||
same way as they do without sandboxing.
|
||||
|
||||
There is limited sandboxing support in the xz tool. If
|
||||
built with sandbox support, it's used automatically when
|
||||
(de)compressing exactly one file to standard output and
|
||||
@@ -419,6 +413,7 @@ XZ Utils Installation
|
||||
auto Look for a supported sandboxing method
|
||||
and use it if found. If no method is
|
||||
found, then sandboxing isn't used.
|
||||
This is the default.
|
||||
|
||||
no Disable sandboxing support.
|
||||
|
||||
|
||||
11
NEWS
11
NEWS
@@ -2,6 +2,17 @@
|
||||
XZ Utils Release Notes
|
||||
======================
|
||||
|
||||
5.3.1alpha (2018-04-29)
|
||||
|
||||
* All fixes from 5.2.4.
|
||||
|
||||
* Add lzma_file_info_decoder() into liblzma and use it in xz to
|
||||
implement the --list feature.
|
||||
|
||||
* Capsicum sandbox support is enabled by default where available
|
||||
(FreeBSD >= 10).
|
||||
|
||||
|
||||
5.2.4 (2018-04-29)
|
||||
|
||||
* liblzma:
|
||||
|
||||
1
THANKS
1
THANKS
@@ -103,6 +103,7 @@ has been important. :-) In alphabetical order:
|
||||
- Paul Townsend
|
||||
- Mohammed Adnène Trojette
|
||||
- Alexey Tourbin
|
||||
- Loganaden Velvindron
|
||||
- Patrick J. Volkerding
|
||||
- Martin Väth
|
||||
- Adam Walling
|
||||
|
||||
@@ -498,10 +498,10 @@ AM_CONDITIONAL([COND_SYMVERS], [test "x$enable_symbol_versions" = xyes])
|
||||
|
||||
AC_MSG_CHECKING([if sandboxing should be used])
|
||||
AC_ARG_ENABLE([sandbox], [AS_HELP_STRING([--enable-sandbox=METHOD],
|
||||
[This is an experimental feature.
|
||||
Sandboxing METHOD can be `auto', `no', or `capsicum'.
|
||||
The default is `no'.])],
|
||||
[], [enable_sandbox=no])
|
||||
[Sandboxing METHOD can be `auto', `no', or `capsicum'.
|
||||
The default is `auto' which enables sandboxing if
|
||||
a supported sandboxing method is found.])],
|
||||
[], [enable_sandbox=auto])
|
||||
case $enable_sandbox in
|
||||
auto)
|
||||
AC_MSG_RESULT([maybe (autodetect)])
|
||||
|
||||
206
doc/examples/11_file_info.c
Normal file
206
doc/examples/11_file_info.c
Normal file
@@ -0,0 +1,206 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file 11_file_info.c
|
||||
/// \brief Get uncmopressed size of .xz file(s)
|
||||
///
|
||||
/// Usage: ./11_file_info INFILE1.xz [INFILEn.xz]...
|
||||
///
|
||||
/// Example: ./11_file_info foo.xz
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <lzma.h>
|
||||
|
||||
|
||||
static bool
|
||||
print_file_size(lzma_stream *strm, FILE *infile, const char *filename)
|
||||
{
|
||||
// Get the file size. In standard C it can be done by seeking to
|
||||
// the end of the file and then getting the file position.
|
||||
// In POSIX one can use fstat() and then st_size from struct stat.
|
||||
// Also note that fseek() and ftell() use long and thus don't support
|
||||
// large files on 32-bit systems (POSIX versions fseeko() and
|
||||
// ftello() can support large files).
|
||||
if (fseek(infile, 0, SEEK_END)) {
|
||||
fprintf(stderr, "Error seeking the file `%s': %s\n",
|
||||
filename, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
const long file_size = ftell(infile);
|
||||
|
||||
// The decoder wants to start from the beginning of the .xz file.
|
||||
rewind(infile);
|
||||
|
||||
// Initialize the decoder.
|
||||
lzma_index *i;
|
||||
lzma_ret ret = lzma_file_info_decoder(strm, &i, UINT64_MAX,
|
||||
(uint64_t)file_size);
|
||||
switch (ret) {
|
||||
case LZMA_OK:
|
||||
// Initialization succeeded.
|
||||
break;
|
||||
|
||||
case LZMA_MEM_ERROR:
|
||||
fprintf(stderr, "Out of memory when initializing "
|
||||
"the .xz file info decoder\n");
|
||||
return false;
|
||||
|
||||
case LZMA_PROG_ERROR:
|
||||
default:
|
||||
fprintf(stderr, "Unknown error, possibly a bug\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// This example program reuses the same lzma_stream structure
|
||||
// for multiple files, so we need to reset this when starting
|
||||
// a new file.
|
||||
strm->avail_in = 0;
|
||||
|
||||
// Buffer for input data.
|
||||
uint8_t inbuf[BUFSIZ];
|
||||
|
||||
// Pass data to the decoder and seek when needed.
|
||||
while (true) {
|
||||
if (strm->avail_in == 0) {
|
||||
strm->next_in = inbuf;
|
||||
strm->avail_in = fread(inbuf, 1, sizeof(inbuf),
|
||||
infile);
|
||||
|
||||
if (ferror(infile)) {
|
||||
fprintf(stderr,
|
||||
"Error reading from `%s': %s\n",
|
||||
filename, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't need to care about hitting the end of
|
||||
// the file so no need to check for feof().
|
||||
}
|
||||
|
||||
ret = lzma_code(strm, LZMA_RUN);
|
||||
|
||||
switch (ret) {
|
||||
case LZMA_OK:
|
||||
break;
|
||||
|
||||
case LZMA_SEEK_NEEDED:
|
||||
// The cast is safe because liblzma won't ask us to
|
||||
// seek past the known size of the input file which
|
||||
// did fit into a long.
|
||||
//
|
||||
// NOTE: Remember to change these to off_t if you
|
||||
// switch fseeko() or lseek().
|
||||
if (fseek(infile, (long)(strm->seek_pos), SEEK_SET)) {
|
||||
fprintf(stderr, "Error seeking the "
|
||||
"file `%s': %s\n",
|
||||
filename, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// The old data in the inbuf is useless now. Set
|
||||
// avail_in to zero so that we will read new input
|
||||
// from the new file position on the next iteration
|
||||
// of this loop.
|
||||
strm->avail_in = 0;
|
||||
break;
|
||||
|
||||
case LZMA_STREAM_END:
|
||||
// File information was successfully decoded.
|
||||
// See <lzma/index.h> for functions that can be
|
||||
// used on it. In this example we just print
|
||||
// the uncompressed size (in bytes) of
|
||||
// the .xz file followed by its file name.
|
||||
printf("%10" PRIu64 " %s\n",
|
||||
lzma_index_uncompressed_size(i),
|
||||
filename);
|
||||
|
||||
// Free the memory of the lzma_index structure.
|
||||
lzma_index_end(i, NULL);
|
||||
|
||||
return true;
|
||||
|
||||
case LZMA_FORMAT_ERROR:
|
||||
// .xz magic bytes weren't found.
|
||||
fprintf(stderr, "The file `%s' is not "
|
||||
"in the .xz format\n", filename);
|
||||
return false;
|
||||
|
||||
case LZMA_OPTIONS_ERROR:
|
||||
fprintf(stderr, "The file `%s' has .xz headers that "
|
||||
"are not supported by this liblzma "
|
||||
"version\n", filename);
|
||||
return false;
|
||||
|
||||
case LZMA_DATA_ERROR:
|
||||
fprintf(stderr, "The file `%s' is corrupt\n",
|
||||
filename);
|
||||
return false;
|
||||
|
||||
case LZMA_MEM_ERROR:
|
||||
fprintf(stderr, "Memory allocation failed when "
|
||||
"decoding the file `%s'\n", filename);
|
||||
return false;
|
||||
|
||||
// LZMA_MEMLIMIT_ERROR shouldn't happen because we used
|
||||
// UINT64_MAX as the limit.
|
||||
//
|
||||
// LZMA_BUF_ERROR shouldn't happen because we always provide
|
||||
// new input when the input buffer is empty. The decoder
|
||||
// knows the input file size and thus won't try to read past
|
||||
// the end of the file.
|
||||
case LZMA_MEMLIMIT_ERROR:
|
||||
case LZMA_BUF_ERROR:
|
||||
case LZMA_PROG_ERROR:
|
||||
default:
|
||||
fprintf(stderr, "Unknown error, possibly a bug\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// This line is never reached.
|
||||
}
|
||||
|
||||
|
||||
extern int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
bool success = true;
|
||||
lzma_stream strm = LZMA_STREAM_INIT;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
FILE *infile = fopen(argv[i], "rb");
|
||||
|
||||
if (infile == NULL) {
|
||||
fprintf(stderr, "Cannot open the file `%s': %s\n",
|
||||
argv[i], strerror(errno));
|
||||
success = false;
|
||||
}
|
||||
|
||||
success &= print_file_size(&strm, infile, argv[i]);
|
||||
|
||||
(void)fclose(infile);
|
||||
}
|
||||
|
||||
lzma_end(&strm);
|
||||
|
||||
// Close stdout to catch possible write errors that can occur
|
||||
// when pending data is flushed from the stdio buffers.
|
||||
if (fclose(stdout)) {
|
||||
fprintf(stderr, "Write error: %s\n", strerror(errno));
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
@@ -13,7 +13,8 @@ PROGS = \
|
||||
01_compress_easy \
|
||||
02_decompress \
|
||||
03_compress_custom \
|
||||
04_compress_easy_mt
|
||||
04_compress_easy_mt \
|
||||
11_file_info
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ SRCS_C = \
|
||||
../src/liblzma/common/block_header_encoder.c \
|
||||
../src/liblzma/common/block_util.c \
|
||||
../src/liblzma/common/common.c \
|
||||
../src/liblzma/common/file_info.c \
|
||||
../src/liblzma/common/filter_common.c \
|
||||
../src/liblzma/common/filter_decoder.c \
|
||||
../src/liblzma/common/filter_encoder.c \
|
||||
|
||||
@@ -24,7 +24,7 @@ liblzma_la_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/liblzma/simple \
|
||||
-I$(top_srcdir)/src/common \
|
||||
-DTUKLIB_SYMBOL_PREFIX=lzma_
|
||||
liblzma_la_LDFLAGS = -no-undefined -version-info 7:4:2
|
||||
liblzma_la_LDFLAGS = -no-undefined -version-info 8:99:3
|
||||
|
||||
EXTRA_DIST += liblzma.map validate_map.sh
|
||||
if COND_SYMVERS
|
||||
|
||||
@@ -234,6 +234,23 @@ typedef enum {
|
||||
* can be a sign of a bug in liblzma. See the documentation
|
||||
* how to report bugs.
|
||||
*/
|
||||
|
||||
LZMA_SEEK_NEEDED = 12
|
||||
/**<
|
||||
* \brief Request to change the input file position
|
||||
*
|
||||
* Some coders can do random access in the input file. The
|
||||
* initialization functions of these coders take the file size
|
||||
* as an argument. No other coders can return LZMA_SEEK_NEEDED.
|
||||
*
|
||||
* When this value is returned, the application must seek to
|
||||
* the file position given in lzma_stream.seek_pos. This value
|
||||
* is guaranteed to never exceed the file size that was
|
||||
* specified at the coder initialization.
|
||||
*
|
||||
* After seeking the application should read new input and
|
||||
* pass it normally via lzma_stream.next_in and .avail_in.
|
||||
*/
|
||||
} lzma_ret;
|
||||
|
||||
|
||||
@@ -514,7 +531,19 @@ typedef struct {
|
||||
void *reserved_ptr2;
|
||||
void *reserved_ptr3;
|
||||
void *reserved_ptr4;
|
||||
uint64_t reserved_int1;
|
||||
|
||||
/**
|
||||
* \brief New seek input position for LZMA_SEEK_NEEDED
|
||||
*
|
||||
* When lzma_code() returns LZMA_SEEK_NEEDED, the new input position
|
||||
* needed by liblzma will be available seek_pos. The value is
|
||||
* guaranteed to not exceed the file size that was specified when
|
||||
* this lzma_stream was initialized.
|
||||
*
|
||||
* In all other situations the value of this variable is undefined.
|
||||
*/
|
||||
uint64_t seek_pos;
|
||||
|
||||
uint64_t reserved_int2;
|
||||
size_t reserved_int3;
|
||||
size_t reserved_int4;
|
||||
|
||||
@@ -341,9 +341,10 @@ extern LZMA_API(lzma_ret) lzma_properties_encode(
|
||||
* \param filter filter->id must have been set to the correct
|
||||
* Filter ID. filter->options doesn't need to be
|
||||
* initialized (it's not freed by this function). The
|
||||
* decoded options will be stored to filter->options.
|
||||
* filter->options is set to NULL if there are no
|
||||
* properties or if an error occurs.
|
||||
* decoded options will be stored in filter->options;
|
||||
* it's application's responsibility to free it when
|
||||
* appropriate. filter->options is set to NULL if
|
||||
* there are no properties or if an error occurs.
|
||||
* \param allocator Custom memory allocator used to allocate the
|
||||
* options. Set to NULL to use the default malloc(),
|
||||
* and in case of an error, also free().
|
||||
|
||||
@@ -684,3 +684,69 @@ extern LZMA_API(lzma_ret) lzma_index_buffer_decode(lzma_index **i,
|
||||
uint64_t *memlimit, const lzma_allocator *allocator,
|
||||
const uint8_t *in, size_t *in_pos, size_t in_size)
|
||||
lzma_nothrow;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Initialize a .xz file information decoder
|
||||
*
|
||||
* \param strm Pointer to a properly prepared lzma_stream
|
||||
* \param dest_index Pointer to a pointer where the decoder will put
|
||||
* the decoded lzma_index. The old value
|
||||
* of *dest_index is ignored (not freed).
|
||||
* \param memlimit How much memory the resulting lzma_index is
|
||||
* allowed to require. Use UINT64_MAX to
|
||||
* effectively disable the limiter.
|
||||
* \param file_size Size of the input .xz file
|
||||
*
|
||||
* This decoder decodes the Stream Header, Stream Footer, Index, and
|
||||
* Stream Padding field(s) from the input .xz file and stores the resulting
|
||||
* combined index in *dest_index. This information can be used to get the
|
||||
* uncompressed file size with lzma_index_uncompressed_size(*dest_index) or,
|
||||
* for example, to implement random access reading by locating the Blocks
|
||||
* in the Streams.
|
||||
*
|
||||
* To get the required information from the .xz file, lzma_code() may ask
|
||||
* the application to seek in the input file by returning LZMA_SEEK_NEEDED
|
||||
* and having the target file position specified in lzma_stream.seek_pos.
|
||||
* The number of seeks required depends on the input file and how big buffers
|
||||
* the application provides. When possible, the decoder will seek backward
|
||||
* and forward in the given buffer to avoid useless seek requests. Thus, if
|
||||
* the application provides the whole file at once, no external seeking will
|
||||
* be required (that is, lzma_code() won't return LZMA_SEEK_NEEDED).
|
||||
*
|
||||
* The value in lzma_stream.total_in can be used to estimate how much data
|
||||
* liblzma had to read to get the file information. However, due to seeking
|
||||
* and the way total_in is updated, the value of total_in will be somewhat
|
||||
* inaccurate (a little too big). Thus, total_in is a good estimate but don't
|
||||
* expect to see the same exact value for the same file if you change the
|
||||
* input buffer size or switch to a different liblzma version.
|
||||
*
|
||||
* Valid `action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
|
||||
* You only need to use LZMA_RUN; LZMA_FINISH is only supported because it
|
||||
* might be convenient for some applications. If you use LZMA_FINISH and if
|
||||
* lzma_code() asks the application to seek, remember to reset `action' back
|
||||
* to LZMA_RUN unless you hit the end of the file again.
|
||||
*
|
||||
* Possible return values from lzma_code():
|
||||
* - LZMA_OK: All OK so far, more input needed
|
||||
* - LZMA_SEEK_NEEDED: Provide more input starting from the absolute
|
||||
* file position strm->seek_pos
|
||||
* - LZMA_STREAM_END: Decoding was successful, *dest_index has been set
|
||||
* - LZMA_FORMAT_ERROR: The input file is not in the .xz format (the
|
||||
* expected magic bytes were not found from the beginning of the file)
|
||||
* - LZMA_OPTIONS_ERROR: File looks valid but contains headers that aren't
|
||||
* supported by this version of liblzma
|
||||
* - LZMA_DATA_ERROR: File is corrupt
|
||||
* - LZMA_BUF_ERROR
|
||||
* - LZMA_MEM_ERROR
|
||||
* - LZMA_MEMLIMIT_ERROR
|
||||
* - LZMA_PROG_ERROR
|
||||
*
|
||||
* \return - LZMA_OK
|
||||
* - LZMA_MEM_ERROR
|
||||
* - LZMA_PROG_ERROR
|
||||
*/
|
||||
extern LZMA_API(lzma_ret) lzma_file_info_decoder(
|
||||
lzma_stream *strm, lzma_index **dest_index,
|
||||
uint64_t memlimit, uint64_t file_size)
|
||||
lzma_nothrow;
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
* Version number split into components
|
||||
*/
|
||||
#define LZMA_VERSION_MAJOR 5
|
||||
#define LZMA_VERSION_MINOR 2
|
||||
#define LZMA_VERSION_PATCH 4
|
||||
#define LZMA_VERSION_STABILITY LZMA_VERSION_STABILITY_STABLE
|
||||
#define LZMA_VERSION_MINOR 3
|
||||
#define LZMA_VERSION_PATCH 1
|
||||
#define LZMA_VERSION_STABILITY LZMA_VERSION_STABILITY_ALPHA
|
||||
|
||||
#ifndef LZMA_VERSION_COMMIT
|
||||
# define LZMA_VERSION_COMMIT ""
|
||||
|
||||
@@ -65,11 +65,13 @@ liblzma_la_SOURCES += \
|
||||
common/block_decoder.h \
|
||||
common/block_header_decoder.c \
|
||||
common/easy_decoder_memusage.c \
|
||||
common/file_info.c \
|
||||
common/filter_buffer_decoder.c \
|
||||
common/filter_decoder.c \
|
||||
common/filter_decoder.h \
|
||||
common/filter_flags_decoder.c \
|
||||
common/index_decoder.c \
|
||||
common/index_decoder.h \
|
||||
common/index_hash.c \
|
||||
common/stream_buffer_decoder.c \
|
||||
common/stream_decoder.c \
|
||||
|
||||
@@ -207,7 +207,6 @@ lzma_code(lzma_stream *strm, lzma_action action)
|
||||
|| strm->reserved_ptr2 != NULL
|
||||
|| strm->reserved_ptr3 != NULL
|
||||
|| strm->reserved_ptr4 != NULL
|
||||
|| strm->reserved_int1 != 0
|
||||
|| strm->reserved_int2 != 0
|
||||
|| strm->reserved_int3 != 0
|
||||
|| strm->reserved_int4 != 0
|
||||
@@ -318,6 +317,17 @@ lzma_code(lzma_stream *strm, lzma_action action)
|
||||
ret = LZMA_OK;
|
||||
break;
|
||||
|
||||
case LZMA_SEEK_NEEDED:
|
||||
strm->internal->allow_buf_error = false;
|
||||
|
||||
// If LZMA_FINISH was used, reset it back to the
|
||||
// LZMA_RUN-based state so that new input can be supplied
|
||||
// by the application.
|
||||
if (strm->internal->sequence == ISEQ_FINISH)
|
||||
strm->internal->sequence = ISEQ_RUN;
|
||||
|
||||
break;
|
||||
|
||||
case LZMA_STREAM_END:
|
||||
if (strm->internal->sequence == ISEQ_SYNC_FLUSH
|
||||
|| strm->internal->sequence == ISEQ_FULL_FLUSH
|
||||
|
||||
855
src/liblzma/common/file_info.c
Normal file
855
src/liblzma/common/file_info.c
Normal file
@@ -0,0 +1,855 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file file_info.c
|
||||
/// \brief Decode .xz file information into a lzma_index structure
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "index_decoder.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
enum {
|
||||
SEQ_MAGIC_BYTES,
|
||||
SEQ_PADDING_SEEK,
|
||||
SEQ_PADDING_DECODE,
|
||||
SEQ_FOOTER,
|
||||
SEQ_INDEX_INIT,
|
||||
SEQ_INDEX_DECODE,
|
||||
SEQ_HEADER_DECODE,
|
||||
SEQ_HEADER_COMPARE,
|
||||
} sequence;
|
||||
|
||||
/// Absolute position of in[*in_pos] in the file. All code that
|
||||
/// modifies *in_pos also updates this. seek_to_pos() needs this
|
||||
/// to determine if we need to request the application to seek for
|
||||
/// us or if we can do the seeking internally by adjusting *in_pos.
|
||||
uint64_t file_cur_pos;
|
||||
|
||||
/// This refers to absolute positions of interesting parts of the
|
||||
/// input file. Sometimes it points to the *beginning* of a specific
|
||||
/// field and sometimes to the *end* of a field. The current target
|
||||
/// position at each moment is explained in the comments.
|
||||
uint64_t file_target_pos;
|
||||
|
||||
/// Size of the .xz file (from the application).
|
||||
uint64_t file_size;
|
||||
|
||||
/// Index decoder
|
||||
lzma_next_coder index_decoder;
|
||||
|
||||
/// Number of bytes remaining in the Index field that is currently
|
||||
/// being decoded.
|
||||
lzma_vli index_remaining;
|
||||
|
||||
/// The Index decoder will store the decoded Index in this pointer.
|
||||
lzma_index *this_index;
|
||||
|
||||
/// Amount of Stream Padding in the current Stream.
|
||||
lzma_vli stream_padding;
|
||||
|
||||
/// The final combined index is collected here.
|
||||
lzma_index *combined_index;
|
||||
|
||||
/// Pointer from the application where to store the index information
|
||||
/// after successful decoding.
|
||||
lzma_index **dest_index;
|
||||
|
||||
/// Pointer to lzma_stream.seek_pos to be used when returning
|
||||
/// LZMA_SEEK_NEEDED. This is set by seek_to_pos() when needed.
|
||||
uint64_t *external_seek_pos;
|
||||
|
||||
/// Memory usage limit
|
||||
uint64_t memlimit;
|
||||
|
||||
/// Stream Flags from the very beginning of the file.
|
||||
lzma_stream_flags first_header_flags;
|
||||
|
||||
/// Stream Flags from Stream Header of the current Stream.
|
||||
lzma_stream_flags header_flags;
|
||||
|
||||
/// Stream Flags from Stream Footer of the current Stream.
|
||||
lzma_stream_flags footer_flags;
|
||||
|
||||
size_t temp_pos;
|
||||
size_t temp_size;
|
||||
uint8_t temp[8192];
|
||||
|
||||
} lzma_file_info_coder;
|
||||
|
||||
|
||||
/// Copies data from in[*in_pos] into coder->temp until
|
||||
/// coder->temp_pos == coder->temp_size. This also keeps coder->file_cur_pos
|
||||
/// in sync with *in_pos. Returns true if more input is needed.
|
||||
static bool
|
||||
fill_temp(lzma_file_info_coder *coder, const uint8_t *restrict in,
|
||||
size_t *restrict in_pos, size_t in_size)
|
||||
{
|
||||
coder->file_cur_pos += lzma_bufcpy(in, in_pos, in_size,
|
||||
coder->temp, &coder->temp_pos, coder->temp_size);
|
||||
return coder->temp_pos < coder->temp_size;
|
||||
}
|
||||
|
||||
|
||||
/// Seeks to the absolute file position specified by target_pos.
|
||||
/// This tries to do the seeking by only modifying *in_pos, if possible.
|
||||
/// The main benefit of this is that if one passes the whole file at once
|
||||
/// to lzma_code(), the decoder will never need to return LZMA_SEEK_NEEDED
|
||||
/// as all the seeking can be done by adjusting *in_pos in this function.
|
||||
///
|
||||
/// Returns true if an external seek is needed and the caller must return
|
||||
/// LZMA_SEEK_NEEDED.
|
||||
static bool
|
||||
seek_to_pos(lzma_file_info_coder *coder, uint64_t target_pos,
|
||||
size_t in_start, size_t *in_pos, size_t in_size)
|
||||
{
|
||||
// The input buffer doesn't extend beyond the end of the file.
|
||||
// This has been checked by file_info_decode() already.
|
||||
assert(coder->file_size - coder->file_cur_pos >= in_size - *in_pos);
|
||||
|
||||
const uint64_t pos_min = coder->file_cur_pos - (*in_pos - in_start);
|
||||
const uint64_t pos_max = coder->file_cur_pos + (in_size - *in_pos);
|
||||
|
||||
bool external_seek_needed;
|
||||
|
||||
if (target_pos >= pos_min && target_pos <= pos_max) {
|
||||
// The requested position is available in the current input
|
||||
// buffer or right after it. That is, in a corner case we
|
||||
// end up setting *in_pos == in_size and thus will immediately
|
||||
// need new input bytes from the application.
|
||||
*in_pos += (size_t)(target_pos - coder->file_cur_pos);
|
||||
external_seek_needed = false;
|
||||
} else {
|
||||
// Ask the application to seek the input file.
|
||||
*coder->external_seek_pos = target_pos;
|
||||
external_seek_needed = true;
|
||||
|
||||
// Mark the whole input buffer as used. This way
|
||||
// lzma_stream.total_in will have a better estimate
|
||||
// of the amount of data read. It still won't be perfect
|
||||
// as the value will depend on the input buffer size that
|
||||
// the application uses, but it should be good enough for
|
||||
// those few who want an estimate.
|
||||
*in_pos = in_size;
|
||||
}
|
||||
|
||||
// After seeking (internal or external) the current position
|
||||
// will match the requested target position.
|
||||
coder->file_cur_pos = target_pos;
|
||||
|
||||
return external_seek_needed;
|
||||
}
|
||||
|
||||
|
||||
/// The caller sets coder->file_target_pos so that it points to the *end*
|
||||
/// of the desired file position. This function then determines how far
|
||||
/// backwards from that position we can seek. After seeking fill_temp()
|
||||
/// can be used to read data into coder->temp. When fill_temp() has finished,
|
||||
/// coder->temp[coder->temp_size] will match coder->file_target_pos.
|
||||
///
|
||||
/// This also validates that coder->target_file_pos is sane in sense that
|
||||
/// we aren't trying to seek too far backwards (too close or beyond the
|
||||
/// beginning of the file).
|
||||
static lzma_ret
|
||||
reverse_seek(lzma_file_info_coder *coder,
|
||||
size_t in_start, size_t *in_pos, size_t in_size)
|
||||
{
|
||||
// Check that there is enough data before the target position
|
||||
// to contain at least Stream Header and Stream Footer. If there
|
||||
// isn't, the file cannot be valid.
|
||||
if (coder->file_target_pos < 2 * LZMA_STREAM_HEADER_SIZE)
|
||||
return LZMA_DATA_ERROR;
|
||||
|
||||
coder->temp_pos = 0;
|
||||
|
||||
// The Stream Header at the very beginning of the file gets handled
|
||||
// specially in SEQ_MAGIC_BYTES and thus we will never need to seek
|
||||
// there. By not seeking to the first LZMA_STREAM_HEADER_SIZE bytes
|
||||
// we avoid a useless external seek after SEQ_MAGIC_BYTES if the
|
||||
// application uses an extremely small input buffer and the input
|
||||
// file is very small.
|
||||
if (coder->file_target_pos - LZMA_STREAM_HEADER_SIZE
|
||||
< sizeof(coder->temp))
|
||||
coder->temp_size = (size_t)(coder->file_target_pos
|
||||
- LZMA_STREAM_HEADER_SIZE);
|
||||
else
|
||||
coder->temp_size = sizeof(coder->temp);
|
||||
|
||||
// The above if-statements guarantee this. This is important because
|
||||
// the Stream Header/Footer decoders assume that there's at least
|
||||
// LZMA_STREAM_HEADER_SIZE bytes in coder->temp.
|
||||
assert(coder->temp_size >= LZMA_STREAM_HEADER_SIZE);
|
||||
|
||||
if (seek_to_pos(coder, coder->file_target_pos - coder->temp_size,
|
||||
in_start, in_pos, in_size))
|
||||
return LZMA_SEEK_NEEDED;
|
||||
|
||||
return LZMA_OK;
|
||||
}
|
||||
|
||||
|
||||
/// Gets the number of zero-bytes at the end of the buffer.
|
||||
static size_t
|
||||
get_padding_size(const uint8_t *buf, size_t buf_size)
|
||||
{
|
||||
size_t padding = 0;
|
||||
while (buf_size > 0 && buf[--buf_size] == 0x00)
|
||||
++padding;
|
||||
|
||||
return padding;
|
||||
}
|
||||
|
||||
|
||||
/// With the Stream Header at the very beginning of the file, LZMA_FORMAT_ERROR
|
||||
/// is used to tell the application that Magic Bytes didn't match. In other
|
||||
/// Stream Header/Footer fields (in the middle/end of the file) it could be
|
||||
/// a bit confusing to return LZMA_FORMAT_ERROR as we already know that there
|
||||
/// is a valid Stream Header at the beginning of the file. For those cases
|
||||
/// this function is used to convert LZMA_FORMAT_ERROR to LZMA_DATA_ERROR.
|
||||
static lzma_ret
|
||||
hide_format_error(lzma_ret ret)
|
||||
{
|
||||
if (ret == LZMA_FORMAT_ERROR)
|
||||
ret = LZMA_DATA_ERROR;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/// Calls the Index decoder and updates coder->index_remaining.
|
||||
/// This is a separate function because the input can be either directly
|
||||
/// from the application or from coder->temp.
|
||||
static lzma_ret
|
||||
decode_index(lzma_file_info_coder *coder, const lzma_allocator *allocator,
|
||||
const uint8_t *restrict in, size_t *restrict in_pos,
|
||||
size_t in_size, bool update_file_cur_pos)
|
||||
{
|
||||
const size_t in_start = *in_pos;
|
||||
|
||||
const lzma_ret ret = coder->index_decoder.code(
|
||||
coder->index_decoder.coder,
|
||||
allocator, in, in_pos, in_size,
|
||||
NULL, NULL, 0, LZMA_RUN);
|
||||
|
||||
coder->index_remaining -= *in_pos - in_start;
|
||||
|
||||
if (update_file_cur_pos)
|
||||
coder->file_cur_pos += *in_pos - in_start;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static lzma_ret
|
||||
file_info_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 lzma_attribute((__unused__)),
|
||||
size_t *restrict out_pos lzma_attribute((__unused__)),
|
||||
size_t out_size lzma_attribute((__unused__)),
|
||||
lzma_action action lzma_attribute((__unused__)))
|
||||
{
|
||||
lzma_file_info_coder *coder = coder_ptr;
|
||||
const size_t in_start = *in_pos;
|
||||
|
||||
// If the caller provides input past the end of the file, trim
|
||||
// the extra bytes from the buffer so that we won't read too far.
|
||||
assert(coder->file_size >= coder->file_cur_pos);
|
||||
if (coder->file_size - coder->file_cur_pos < in_size - in_start)
|
||||
in_size = in_start
|
||||
+ (size_t)(coder->file_size - coder->file_cur_pos);
|
||||
|
||||
while (true)
|
||||
switch (coder->sequence) {
|
||||
case SEQ_MAGIC_BYTES:
|
||||
// Decode the Stream Header at the beginning of the file
|
||||
// first to check if the Magic Bytes match. The flags
|
||||
// are stored in coder->first_header_flags so that we
|
||||
// don't need to seek to it again.
|
||||
//
|
||||
// Check that the file is big enough to contain at least
|
||||
// Stream Header.
|
||||
if (coder->file_size < LZMA_STREAM_HEADER_SIZE)
|
||||
return LZMA_FORMAT_ERROR;
|
||||
|
||||
// Read the Stream Header field into coder->temp.
|
||||
if (fill_temp(coder, in, in_pos, in_size))
|
||||
return LZMA_OK;
|
||||
|
||||
// This is the only Stream Header/Footer decoding where we
|
||||
// want to return LZMA_FORMAT_ERROR if the Magic Bytes don't
|
||||
// match. Elsewehere it will be converted to LZMA_DATA_ERROR.
|
||||
return_if_error(lzma_stream_header_decode(
|
||||
&coder->first_header_flags, coder->temp));
|
||||
|
||||
// Now that we know that the Magic Bytes match, check the
|
||||
// file size. It's better to do this here after checking the
|
||||
// Magic Bytes since this way we can give LZMA_FORMAT_ERROR
|
||||
// instead of LZMA_DATA_ERROR when the Magic Bytes don't
|
||||
// match in a file that is too big or isn't a multiple of
|
||||
// four bytes.
|
||||
if (coder->file_size > LZMA_VLI_MAX || (coder->file_size & 3))
|
||||
return LZMA_DATA_ERROR;
|
||||
|
||||
// Start looking for Stream Padding and Stream Footer
|
||||
// at the end of the file.
|
||||
coder->file_target_pos = coder->file_size;
|
||||
|
||||
// Fall through
|
||||
|
||||
case SEQ_PADDING_SEEK:
|
||||
coder->sequence = SEQ_PADDING_DECODE;
|
||||
return_if_error(reverse_seek(
|
||||
coder, in_start, in_pos, in_size));
|
||||
|
||||
// Fall through
|
||||
|
||||
case SEQ_PADDING_DECODE: {
|
||||
// Copy to coder->temp first. This keeps the code simpler if
|
||||
// the application only provides input a few bytes at a time.
|
||||
if (fill_temp(coder, in, in_pos, in_size))
|
||||
return LZMA_OK;
|
||||
|
||||
// Scan the buffer backwards to get the size of the
|
||||
// Stream Padding field (if any).
|
||||
const size_t new_padding = get_padding_size(
|
||||
coder->temp, coder->temp_size);
|
||||
coder->stream_padding += new_padding;
|
||||
|
||||
// Set the target position to the beginning of Stream Padding
|
||||
// that has been observed so far. If all Stream Padding has
|
||||
// been seen, then the target position will be at the end
|
||||
// of the Stream Footer field.
|
||||
coder->file_target_pos -= new_padding;
|
||||
|
||||
if (new_padding == coder->temp_size) {
|
||||
// The whole buffer was padding. Seek backwards in
|
||||
// the file to get more input.
|
||||
coder->sequence = SEQ_PADDING_SEEK;
|
||||
break;
|
||||
}
|
||||
|
||||
// Size of Stream Padding must be a multiple of 4 bytes.
|
||||
if (coder->stream_padding & 3)
|
||||
return LZMA_DATA_ERROR;
|
||||
|
||||
coder->sequence = SEQ_FOOTER;
|
||||
|
||||
// Calculate the amount of non-padding data in coder->temp.
|
||||
coder->temp_size -= new_padding;
|
||||
coder->temp_pos = coder->temp_size;
|
||||
|
||||
// We can avoid an external seek if the whole Stream Footer
|
||||
// is already in coder->temp. In that case SEQ_FOOTER won't
|
||||
// read more input and will find the Stream Footer from
|
||||
// coder->temp[coder->temp_size - LZMA_STREAM_HEADER_SIZE].
|
||||
//
|
||||
// Otherwise we will need to seek. The seeking is done so
|
||||
// that Stream Footer wil be at the end of coder->temp.
|
||||
// This way it's likely that we also get a complete Index
|
||||
// field into coder->temp without needing a separate seek
|
||||
// for that (unless the Index field is big).
|
||||
if (coder->temp_size < LZMA_STREAM_HEADER_SIZE)
|
||||
return_if_error(reverse_seek(
|
||||
coder, in_start, in_pos, in_size));
|
||||
}
|
||||
|
||||
// Fall through
|
||||
|
||||
case SEQ_FOOTER:
|
||||
// Copy the Stream Footer field into coder->temp.
|
||||
// If Stream Footer was already available in coder->temp
|
||||
// in SEQ_PADDING_DECODE, then this does nothing.
|
||||
if (fill_temp(coder, in, in_pos, in_size))
|
||||
return LZMA_OK;
|
||||
|
||||
// Make coder->file_target_pos and coder->temp_size point
|
||||
// to the beginning of Stream Footer and thus to the end
|
||||
// of the Index field. coder->temp_pos will be updated
|
||||
// a bit later.
|
||||
coder->file_target_pos -= LZMA_STREAM_HEADER_SIZE;
|
||||
coder->temp_size -= LZMA_STREAM_HEADER_SIZE;
|
||||
|
||||
// Decode Stream Footer.
|
||||
return_if_error(hide_format_error(lzma_stream_footer_decode(
|
||||
&coder->footer_flags,
|
||||
coder->temp + coder->temp_size)));
|
||||
|
||||
// Check that we won't seek past the beginning of the file.
|
||||
//
|
||||
// LZMA_STREAM_HEADER_SIZE is added because there must be
|
||||
// space for Stream Header too even though we won't seek
|
||||
// there before decoding the Index field.
|
||||
//
|
||||
// There's no risk of integer overflow here because
|
||||
// Backward Size cannot be greater than 2^34.
|
||||
if (coder->file_target_pos < coder->footer_flags.backward_size
|
||||
+ LZMA_STREAM_HEADER_SIZE)
|
||||
return LZMA_DATA_ERROR;
|
||||
|
||||
// Set the target position to the beginning of the Index field.
|
||||
coder->file_target_pos -= coder->footer_flags.backward_size;
|
||||
coder->sequence = SEQ_INDEX_INIT;
|
||||
|
||||
// We can avoid an external seek if the whole Index field is
|
||||
// already available in coder->temp.
|
||||
if (coder->temp_size >= coder->footer_flags.backward_size) {
|
||||
// Set coder->temp_pos to point to the beginning
|
||||
// of the Index.
|
||||
coder->temp_pos = coder->temp_size
|
||||
- coder->footer_flags.backward_size;
|
||||
} else {
|
||||
// These are set to zero to indicate that there's no
|
||||
// useful data (Index or anything else) in coder->temp.
|
||||
coder->temp_pos = 0;
|
||||
coder->temp_size = 0;
|
||||
|
||||
// Seek to the beginning of the Index field.
|
||||
if (seek_to_pos(coder, coder->file_target_pos,
|
||||
in_start, in_pos, in_size))
|
||||
return LZMA_SEEK_NEEDED;
|
||||
}
|
||||
|
||||
// Fall through
|
||||
|
||||
case SEQ_INDEX_INIT: {
|
||||
// Calculate the amount of memory already used by the earlier
|
||||
// Indexes so that we know how big memory limit to pass to
|
||||
// the Index decoder.
|
||||
//
|
||||
// NOTE: When there are multiple Streams, the separate
|
||||
// lzma_index structures can use more RAM (as measured by
|
||||
// lzma_index_memused()) than the final combined lzma_index.
|
||||
// Thus memlimit may need to be slightly higher than the final
|
||||
// calculated memory usage will be. This is perhaps a bit
|
||||
// confusing to the application, but I think it shouldn't
|
||||
// cause problems in practice.
|
||||
uint64_t memused = 0;
|
||||
if (coder->combined_index != NULL) {
|
||||
memused = lzma_index_memused(coder->combined_index);
|
||||
assert(memused <= coder->memlimit);
|
||||
if (memused > coder->memlimit) // Extra sanity check
|
||||
return LZMA_PROG_ERROR;
|
||||
}
|
||||
|
||||
// Initialize the Index decoder.
|
||||
return_if_error(lzma_index_decoder_init(
|
||||
&coder->index_decoder, allocator,
|
||||
&coder->this_index,
|
||||
coder->memlimit - memused));
|
||||
|
||||
coder->index_remaining = coder->footer_flags.backward_size;
|
||||
coder->sequence = SEQ_INDEX_DECODE;
|
||||
}
|
||||
|
||||
// Fall through
|
||||
|
||||
case SEQ_INDEX_DECODE: {
|
||||
// Decode (a part of) the Index. If the whole Index is already
|
||||
// in coder->temp, read it from there. Otherwise read from
|
||||
// in[*in_pos] onwards. Note that index_decode() updates
|
||||
// coder->index_remaining and optionally coder->file_cur_pos.
|
||||
lzma_ret ret;
|
||||
if (coder->temp_size != 0) {
|
||||
assert(coder->temp_size - coder->temp_pos
|
||||
== coder->index_remaining);
|
||||
ret = decode_index(coder, allocator, coder->temp,
|
||||
&coder->temp_pos, coder->temp_size,
|
||||
false);
|
||||
} else {
|
||||
// Don't give the decoder more input than the known
|
||||
// remaining size of the Index field.
|
||||
size_t in_stop = in_size;
|
||||
if (in_size - *in_pos > coder->index_remaining)
|
||||
in_stop = *in_pos
|
||||
+ (size_t)(coder->index_remaining);
|
||||
|
||||
ret = decode_index(coder, allocator,
|
||||
in, in_pos, in_stop, true);
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case LZMA_OK:
|
||||
// If the Index docoder asks for more input when we
|
||||
// have already given it as much input as Backward Size
|
||||
// indicated, the file is invalid.
|
||||
if (coder->index_remaining == 0)
|
||||
return LZMA_DATA_ERROR;
|
||||
|
||||
// We cannot get here if we were reading Index from
|
||||
// coder->temp because when reading from coder->temp
|
||||
// we give the Index decoder exactly
|
||||
// coder->index_remaining bytes of input.
|
||||
assert(coder->temp_size == 0);
|
||||
|
||||
return LZMA_OK;
|
||||
|
||||
case LZMA_STREAM_END:
|
||||
// If the decoding seems to be successful, check also
|
||||
// that the Index decoder consumed as much input as
|
||||
// indicated by the Backward Size field.
|
||||
if (coder->index_remaining != 0)
|
||||
return LZMA_DATA_ERROR;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Calculate how much the Index tells us to seek backwards
|
||||
// (relative to the beginning of the Index): Total size of
|
||||
// all Blocks plus the size of the Stream Header field.
|
||||
// No integer overflow here because lzma_index_total_size()
|
||||
// cannot return a value greater than LZMA_VLI_MAX.
|
||||
const uint64_t seek_amount
|
||||
= lzma_index_total_size(coder->this_index)
|
||||
+ LZMA_STREAM_HEADER_SIZE;
|
||||
|
||||
// Check that Index is sane in sense that seek_amount won't
|
||||
// make us seek past the beginning of the file when locating
|
||||
// the Stream Header.
|
||||
//
|
||||
// coder->file_target_pos still points to the beginning of
|
||||
// the Index field.
|
||||
if (coder->file_target_pos < seek_amount)
|
||||
return LZMA_DATA_ERROR;
|
||||
|
||||
// Set the target to the beginning of Stream Header.
|
||||
coder->file_target_pos -= seek_amount;
|
||||
|
||||
if (coder->file_target_pos == 0) {
|
||||
// We would seek to the beginning of the file, but
|
||||
// since we already decoded that Stream Header in
|
||||
// SEQ_MAGIC_BYTES, we can use the cached value from
|
||||
// coder->first_header_flags to avoid the seek.
|
||||
coder->header_flags = coder->first_header_flags;
|
||||
coder->sequence = SEQ_HEADER_COMPARE;
|
||||
break;
|
||||
}
|
||||
|
||||
coder->sequence = SEQ_HEADER_DECODE;
|
||||
|
||||
// Make coder->file_target_pos point to the end of
|
||||
// the Stream Header field.
|
||||
coder->file_target_pos += LZMA_STREAM_HEADER_SIZE;
|
||||
|
||||
// If coder->temp_size is non-zero, it points to the end
|
||||
// of the Index field. Then the beginning of the Index
|
||||
// field is at coder->temp[coder->temp_size
|
||||
// - coder->footer_flags.backward_size].
|
||||
assert(coder->temp_size == 0 || coder->temp_size
|
||||
>= coder->footer_flags.backward_size);
|
||||
|
||||
// If coder->temp contained the whole Index, see if it has
|
||||
// enough data to contain also the Stream Header. If so,
|
||||
// we avoid an external seek.
|
||||
//
|
||||
// NOTE: This can happen only with small .xz files and only
|
||||
// for the non-first Stream as the Stream Flags of the first
|
||||
// Stream are cached and already handled a few lines above.
|
||||
// So this isn't as useful as the other seek-avoidance cases.
|
||||
if (coder->temp_size != 0 && coder->temp_size
|
||||
- coder->footer_flags.backward_size
|
||||
>= seek_amount) {
|
||||
// Make temp_pos and temp_size point to the *end* of
|
||||
// Stream Header so that SEQ_HEADER_DECODE will find
|
||||
// the start of Stream Header from coder->temp[
|
||||
// coder->temp_size - LZMA_STREAM_HEADER_SIZE].
|
||||
coder->temp_pos = coder->temp_size
|
||||
- coder->footer_flags.backward_size
|
||||
- seek_amount
|
||||
+ LZMA_STREAM_HEADER_SIZE;
|
||||
coder->temp_size = coder->temp_pos;
|
||||
} else {
|
||||
// Seek so that Stream Header will be at the end of
|
||||
// coder->temp. With typical multi-Stream files we
|
||||
// will usually also get the Stream Footer and Index
|
||||
// of the *previous* Stream in coder->temp and thus
|
||||
// won't need a separate seek for them.
|
||||
return_if_error(reverse_seek(coder,
|
||||
in_start, in_pos, in_size));
|
||||
}
|
||||
}
|
||||
|
||||
// Fall through
|
||||
|
||||
case SEQ_HEADER_DECODE:
|
||||
// Copy the Stream Header field into coder->temp.
|
||||
// If Stream Header was already available in coder->temp
|
||||
// in SEQ_INDEX_DECODE, then this does nothing.
|
||||
if (fill_temp(coder, in, in_pos, in_size))
|
||||
return LZMA_OK;
|
||||
|
||||
// Make all these point to the beginning of Stream Header.
|
||||
coder->file_target_pos -= LZMA_STREAM_HEADER_SIZE;
|
||||
coder->temp_size -= LZMA_STREAM_HEADER_SIZE;
|
||||
coder->temp_pos = coder->temp_size;
|
||||
|
||||
// Decode the Stream Header.
|
||||
return_if_error(hide_format_error(lzma_stream_header_decode(
|
||||
&coder->header_flags,
|
||||
coder->temp + coder->temp_size)));
|
||||
|
||||
coder->sequence = SEQ_HEADER_COMPARE;
|
||||
|
||||
// Fall through
|
||||
|
||||
case SEQ_HEADER_COMPARE:
|
||||
// Compare Stream Header against Stream Footer. They must
|
||||
// match.
|
||||
return_if_error(lzma_stream_flags_compare(
|
||||
&coder->header_flags, &coder->footer_flags));
|
||||
|
||||
// Store the decoded Stream Flags into the Index. Use the
|
||||
// Footer Flags because it contains Backward Size, although
|
||||
// it shouldn't matter in practice.
|
||||
if (lzma_index_stream_flags(coder->this_index,
|
||||
&coder->footer_flags) != LZMA_OK)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
// Store also the size of the Stream Padding field. It is
|
||||
// needed to calculate the offsets of the Streams correctly.
|
||||
if (lzma_index_stream_padding(coder->this_index,
|
||||
coder->stream_padding) != LZMA_OK)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
// Reset it so that it's ready for the next Stream.
|
||||
coder->stream_padding = 0;
|
||||
|
||||
// Append the earlier decoded Indexes after this_index.
|
||||
if (coder->combined_index != NULL)
|
||||
return_if_error(lzma_index_cat(coder->this_index,
|
||||
coder->combined_index, allocator));
|
||||
|
||||
coder->combined_index = coder->this_index;
|
||||
coder->this_index = NULL;
|
||||
|
||||
// If the whole file was decoded, tell the caller that we
|
||||
// are finished.
|
||||
if (coder->file_target_pos == 0) {
|
||||
// The combined index must indicate the same file
|
||||
// size as was told to us at initialization.
|
||||
assert(lzma_index_file_size(coder->combined_index)
|
||||
== coder->file_size);
|
||||
|
||||
// Make the combined index available to
|
||||
// the application.
|
||||
*coder->dest_index = coder->combined_index;
|
||||
coder->combined_index = NULL;
|
||||
|
||||
// Mark the input buffer as used since we may have
|
||||
// done internal seeking and thus don't know how
|
||||
// many input bytes were actually used. This way
|
||||
// lzma_stream.total_in gets a slightly better
|
||||
// estimate of the amount of input used.
|
||||
*in_pos = in_size;
|
||||
return LZMA_STREAM_END;
|
||||
}
|
||||
|
||||
// We didn't hit the beginning of the file yet, so continue
|
||||
// reading backwards in the file. If we have unprocessed
|
||||
// data in coder->temp, use it before requesting more data
|
||||
// from the application.
|
||||
//
|
||||
// coder->file_target_pos, coder->temp_size, and
|
||||
// coder->temp_pos all point to the beginning of Stream Header
|
||||
// and thus the end of the previous Stream in the file.
|
||||
coder->sequence = coder->temp_size > 0
|
||||
? SEQ_PADDING_DECODE : SEQ_PADDING_SEEK;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return LZMA_PROG_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static lzma_ret
|
||||
file_info_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
|
||||
uint64_t *old_memlimit, uint64_t new_memlimit)
|
||||
{
|
||||
lzma_file_info_coder *coder = coder_ptr;
|
||||
|
||||
// The memory usage calculation comes from three things:
|
||||
//
|
||||
// (1) The Indexes that have already been decoded and processed into
|
||||
// coder->combined_index.
|
||||
//
|
||||
// (2) The latest Index in coder->this_index that has been decoded but
|
||||
// not yet put into coder->combined_index.
|
||||
//
|
||||
// (3) The latest Index that we have started decoding but haven't
|
||||
// finished and thus isn't available in coder->this_index yet.
|
||||
// Memory usage and limit information needs to be communicated
|
||||
// from/to coder->index_decoder.
|
||||
//
|
||||
// Care has to be taken to not do both (2) and (3) when calculating
|
||||
// the memory usage.
|
||||
uint64_t combined_index_memusage = 0;
|
||||
uint64_t this_index_memusage = 0;
|
||||
|
||||
// (1) If we have already successfully decoded one or more Indexes,
|
||||
// get their memory usage.
|
||||
if (coder->combined_index != NULL)
|
||||
combined_index_memusage = lzma_index_memused(
|
||||
coder->combined_index);
|
||||
|
||||
// Choose between (2), (3), or neither.
|
||||
if (coder->this_index != NULL) {
|
||||
// (2) The latest Index is available. Use its memory usage.
|
||||
this_index_memusage = lzma_index_memused(coder->this_index);
|
||||
|
||||
} else if (coder->sequence == SEQ_INDEX_DECODE) {
|
||||
// (3) The Index decoder is activate and hasn't yet stored
|
||||
// the new index in coder->this_index. Get the memory usage
|
||||
// information from the Index decoder.
|
||||
//
|
||||
// NOTE: If the Index decoder doesn't yet know how much memory
|
||||
// it will eventually need, it will return a tiny value here.
|
||||
uint64_t dummy;
|
||||
if (coder->index_decoder.memconfig(coder->index_decoder.coder,
|
||||
&this_index_memusage, &dummy, 0)
|
||||
!= LZMA_OK) {
|
||||
assert(0);
|
||||
return LZMA_PROG_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we know the total memory usage/requirement. If we had neither
|
||||
// old Indexes nor a new Index, this will be zero which isn't
|
||||
// acceptable as lzma_memusage() has to return non-zero on success
|
||||
// and even with an empty .xz file we will end up with a lzma_index
|
||||
// that takes some memory.
|
||||
*memusage = combined_index_memusage + this_index_memusage;
|
||||
if (*memusage == 0)
|
||||
*memusage = lzma_index_memusage(1, 0);
|
||||
|
||||
*old_memlimit = coder->memlimit;
|
||||
|
||||
// If requested, set a new memory usage limit.
|
||||
if (new_memlimit != 0) {
|
||||
if (new_memlimit < *memusage)
|
||||
return LZMA_MEMLIMIT_ERROR;
|
||||
|
||||
// In the condition (3) we need to tell the Index decoder
|
||||
// its new memory usage limit.
|
||||
if (coder->this_index == NULL
|
||||
&& coder->sequence == SEQ_INDEX_DECODE) {
|
||||
const uint64_t idec_new_memlimit = new_memlimit
|
||||
- combined_index_memusage;
|
||||
|
||||
assert(this_index_memusage > 0);
|
||||
assert(idec_new_memlimit > 0);
|
||||
|
||||
uint64_t dummy1;
|
||||
uint64_t dummy2;
|
||||
|
||||
if (coder->index_decoder.memconfig(
|
||||
coder->index_decoder.coder,
|
||||
&dummy1, &dummy2, idec_new_memlimit)
|
||||
!= LZMA_OK) {
|
||||
assert(0);
|
||||
return LZMA_PROG_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
coder->memlimit = new_memlimit;
|
||||
}
|
||||
|
||||
return LZMA_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
file_info_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
|
||||
{
|
||||
lzma_file_info_coder *coder = coder_ptr;
|
||||
|
||||
lzma_next_end(&coder->index_decoder, allocator);
|
||||
lzma_index_end(coder->this_index, allocator);
|
||||
lzma_index_end(coder->combined_index, allocator);
|
||||
|
||||
lzma_free(coder, allocator);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static lzma_ret
|
||||
lzma_file_info_decoder_init(lzma_next_coder *next,
|
||||
const lzma_allocator *allocator, uint64_t *seek_pos,
|
||||
lzma_index **dest_index,
|
||||
uint64_t memlimit, uint64_t file_size)
|
||||
{
|
||||
lzma_next_coder_init(&lzma_file_info_decoder_init, next, allocator);
|
||||
|
||||
if (dest_index == NULL)
|
||||
return LZMA_PROG_ERROR;
|
||||
|
||||
lzma_file_info_coder *coder = next->coder;
|
||||
if (coder == NULL) {
|
||||
coder = lzma_alloc(sizeof(lzma_file_info_coder), allocator);
|
||||
if (coder == NULL)
|
||||
return LZMA_MEM_ERROR;
|
||||
|
||||
next->coder = coder;
|
||||
next->code = &file_info_decode;
|
||||
next->end = &file_info_decoder_end;
|
||||
next->memconfig = &file_info_decoder_memconfig;
|
||||
|
||||
coder->index_decoder = LZMA_NEXT_CODER_INIT;
|
||||
coder->this_index = NULL;
|
||||
coder->combined_index = NULL;
|
||||
}
|
||||
|
||||
coder->sequence = SEQ_MAGIC_BYTES;
|
||||
coder->file_cur_pos = 0;
|
||||
coder->file_target_pos = 0;
|
||||
coder->file_size = file_size;
|
||||
|
||||
lzma_index_end(coder->this_index, allocator);
|
||||
coder->this_index = NULL;
|
||||
|
||||
lzma_index_end(coder->combined_index, allocator);
|
||||
coder->combined_index = NULL;
|
||||
|
||||
coder->stream_padding = 0;
|
||||
|
||||
coder->dest_index = dest_index;
|
||||
coder->external_seek_pos = seek_pos;
|
||||
|
||||
// If memlimit is 0, make it 1 to ensure that lzma_memlimit_get()
|
||||
// won't return 0 (which would indicate an error).
|
||||
coder->memlimit = my_max(1, memlimit);
|
||||
|
||||
// Preprare thse for reading the first Stream Header into coder->temp.
|
||||
coder->temp_pos = 0;
|
||||
coder->temp_size = LZMA_STREAM_HEADER_SIZE;
|
||||
|
||||
return LZMA_OK;
|
||||
}
|
||||
|
||||
|
||||
extern LZMA_API(lzma_ret)
|
||||
lzma_file_info_decoder(lzma_stream *strm, lzma_index **dest_index,
|
||||
uint64_t memlimit, uint64_t file_size)
|
||||
{
|
||||
lzma_next_strm_init(lzma_file_info_decoder_init, strm, &strm->seek_pos,
|
||||
dest_index, memlimit, file_size);
|
||||
|
||||
// We allow LZMA_FINISH in addition to LZMA_RUN for convenience.
|
||||
// lzma_code() is able to handle the LZMA_FINISH + LZMA_SEEK_NEEDED
|
||||
// combination in a sane way. Applications still need to be careful
|
||||
// if they use LZMA_FINISH so that they remember to reset it back
|
||||
// to LZMA_RUN after seeking if needed.
|
||||
strm->internal->supported_actions[LZMA_RUN] = true;
|
||||
strm->internal->supported_actions[LZMA_FINISH] = true;
|
||||
|
||||
return LZMA_OK;
|
||||
}
|
||||
@@ -825,8 +825,8 @@ lzma_index_cat(lzma_index *restrict dest, lzma_index *restrict src,
|
||||
s->groups.root = &newg->node;
|
||||
}
|
||||
|
||||
if (s->groups.rightmost == &g->node)
|
||||
s->groups.rightmost = &newg->node;
|
||||
assert(s->groups.rightmost == &g->node);
|
||||
s->groups.rightmost = &newg->node;
|
||||
|
||||
lzma_free(g, allocator);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "index.h"
|
||||
#include "index_decoder.h"
|
||||
#include "check.h"
|
||||
|
||||
|
||||
@@ -265,11 +265,11 @@ index_decoder_reset(lzma_index_coder *coder, const lzma_allocator *allocator,
|
||||
}
|
||||
|
||||
|
||||
static lzma_ret
|
||||
index_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
extern lzma_ret
|
||||
lzma_index_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
lzma_index **i, uint64_t memlimit)
|
||||
{
|
||||
lzma_next_coder_init(&index_decoder_init, next, allocator);
|
||||
lzma_next_coder_init(&lzma_index_decoder_init, next, allocator);
|
||||
|
||||
if (i == NULL)
|
||||
return LZMA_PROG_ERROR;
|
||||
@@ -296,7 +296,7 @@ index_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
|
||||
extern LZMA_API(lzma_ret)
|
||||
lzma_index_decoder(lzma_stream *strm, lzma_index **i, uint64_t memlimit)
|
||||
{
|
||||
lzma_next_strm_init(index_decoder_init, strm, i, memlimit);
|
||||
lzma_next_strm_init(lzma_index_decoder_init, strm, i, memlimit);
|
||||
|
||||
strm->internal->supported_actions[LZMA_RUN] = true;
|
||||
strm->internal->supported_actions[LZMA_FINISH] = true;
|
||||
|
||||
24
src/liblzma/common/index_decoder.h
Normal file
24
src/liblzma/common/index_decoder.h
Normal file
@@ -0,0 +1,24 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
/// \file index_decoder.h
|
||||
/// \brief Decodes the Index field
|
||||
//
|
||||
// Author: Lasse Collin
|
||||
//
|
||||
// This file has been put into the public domain.
|
||||
// You can do whatever you want with this file.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef LZMA_INDEX_DECODER_H
|
||||
#define LZMA_INDEX_DECODER_H
|
||||
|
||||
#include "index.h"
|
||||
|
||||
|
||||
extern lzma_ret lzma_index_decoder_init(lzma_next_coder *next,
|
||||
const lzma_allocator *allocator,
|
||||
lzma_index **i, uint64_t memlimit);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -102,7 +102,12 @@ global:
|
||||
lzma_get_progress;
|
||||
lzma_stream_encoder_mt;
|
||||
lzma_stream_encoder_mt_memusage;
|
||||
} XZ_5.0;
|
||||
|
||||
XZ_5.3.1alpha {
|
||||
global:
|
||||
lzma_file_info_decoder;
|
||||
|
||||
local:
|
||||
*;
|
||||
} XZ_5.0;
|
||||
} XZ_5.2;
|
||||
|
||||
@@ -46,7 +46,7 @@ if test "${LESSMETACHARS+set}" != set; then
|
||||
LESSMETACHARS="$space$tab$nl'"';*?"()<>[|&^`#\$%=~'
|
||||
fi
|
||||
|
||||
if test "$(less -V | { read less ver re && echo ${ver}; })" -ge 429; then
|
||||
if test "$(less -V | { read _ ver _ && echo ${ver}; })" -ge 429; then
|
||||
# less 429 or later: LESSOPEN pipe will be used on
|
||||
# standard input if $LESSOPEN begins with |-.
|
||||
LESSOPEN="|-$xz -cdfq -- %s"
|
||||
|
||||
@@ -1169,16 +1169,30 @@ io_read(file_pair *pair, io_buf *buf_union, size_t size)
|
||||
|
||||
|
||||
extern bool
|
||||
io_pread(file_pair *pair, io_buf *buf, size_t size, off_t pos)
|
||||
io_seek_src(file_pair *pair, off_t pos)
|
||||
{
|
||||
// Using lseek() and read() is more portable than pread() and
|
||||
// for us it is as good as real pread().
|
||||
assert(pos >= 0);
|
||||
|
||||
if (lseek(pair->src_fd, pos, SEEK_SET) != pos) {
|
||||
message_error(_("%s: Error seeking the file: %s"),
|
||||
pair->src_name, strerror(errno));
|
||||
return true;
|
||||
}
|
||||
|
||||
pair->src_eof = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
extern bool
|
||||
io_pread(file_pair *pair, io_buf *buf, size_t size, off_t pos)
|
||||
{
|
||||
// Using lseek() and read() is more portable than pread() and
|
||||
// for us it is as good as real pread().
|
||||
if (io_seek_src(pair, pos))
|
||||
return true;
|
||||
|
||||
const size_t amount = io_read(pair, buf, size);
|
||||
if (amount == SIZE_MAX)
|
||||
return true;
|
||||
|
||||
@@ -129,6 +129,19 @@ extern size_t io_read(file_pair *pair, io_buf *buf, size_t size);
|
||||
extern void io_fix_src_pos(file_pair *pair, size_t rewind_size);
|
||||
|
||||
|
||||
/// \brief Seek to the given absolute position in the source file
|
||||
///
|
||||
/// This calls lseek() and also clears pair->src_eof.
|
||||
///
|
||||
/// \param pair Seekable source file
|
||||
/// \param pos Offset relative to the beginning of the file,
|
||||
/// from which the data should be read.
|
||||
///
|
||||
/// \return On success, false is returned. On error, error message
|
||||
/// is printed and true is returned.
|
||||
extern bool io_seek_src(file_pair *pair, off_t pos);
|
||||
|
||||
|
||||
/// \brief Read from source file from given offset to a buffer
|
||||
///
|
||||
/// This is remotely similar to standard pread(). This uses lseek() though,
|
||||
|
||||
266
src/xz/list.c
266
src/xz/list.c
@@ -143,9 +143,6 @@ xz_ver_to_str(uint32_t ver)
|
||||
///
|
||||
/// \return On success, false is returned. On error, true is returned.
|
||||
///
|
||||
// TODO: This function is pretty big. liblzma should have a function that
|
||||
// takes a callback function to parse the Index(es) from a .xz file to make
|
||||
// it easy for applications.
|
||||
static bool
|
||||
parse_indexes(xz_file_info *xfi, file_pair *pair)
|
||||
{
|
||||
@@ -161,238 +158,75 @@ parse_indexes(xz_file_info *xfi, file_pair *pair)
|
||||
}
|
||||
|
||||
io_buf buf;
|
||||
lzma_stream_flags header_flags;
|
||||
lzma_stream_flags footer_flags;
|
||||
lzma_ret ret;
|
||||
|
||||
// lzma_stream for the Index decoder
|
||||
lzma_stream strm = LZMA_STREAM_INIT;
|
||||
lzma_index *idx = NULL;
|
||||
|
||||
// All Indexes decoded so far
|
||||
lzma_index *combined_index = NULL;
|
||||
|
||||
// The Index currently being decoded
|
||||
lzma_index *this_index = NULL;
|
||||
|
||||
// Current position in the file. We parse the file backwards so
|
||||
// initialize it to point to the end of the file.
|
||||
off_t pos = pair->src_st.st_size;
|
||||
|
||||
// Each loop iteration decodes one Index.
|
||||
do {
|
||||
// Check that there is enough data left to contain at least
|
||||
// the Stream Header and Stream Footer. This check cannot
|
||||
// fail in the first pass of this loop.
|
||||
if (pos < 2 * LZMA_STREAM_HEADER_SIZE) {
|
||||
message_error("%s: %s", pair->src_name,
|
||||
message_strm(LZMA_DATA_ERROR));
|
||||
goto error;
|
||||
}
|
||||
|
||||
pos -= LZMA_STREAM_HEADER_SIZE;
|
||||
lzma_vli stream_padding = 0;
|
||||
|
||||
// Locate the Stream Footer. There may be Stream Padding which
|
||||
// we must skip when reading backwards.
|
||||
while (true) {
|
||||
if (pos < LZMA_STREAM_HEADER_SIZE) {
|
||||
message_error("%s: %s", pair->src_name,
|
||||
message_strm(
|
||||
LZMA_DATA_ERROR));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (io_pread(pair, &buf,
|
||||
LZMA_STREAM_HEADER_SIZE, pos))
|
||||
goto error;
|
||||
|
||||
// Stream Padding is always a multiple of four bytes.
|
||||
int i = 2;
|
||||
if (buf.u32[i] != 0)
|
||||
break;
|
||||
|
||||
// To avoid calling io_pread() for every four bytes
|
||||
// of Stream Padding, take advantage that we read
|
||||
// 12 bytes (LZMA_STREAM_HEADER_SIZE) already and
|
||||
// check them too before calling io_pread() again.
|
||||
do {
|
||||
stream_padding += 4;
|
||||
pos -= 4;
|
||||
--i;
|
||||
} while (i >= 0 && buf.u32[i] == 0);
|
||||
}
|
||||
|
||||
// Decode the Stream Footer.
|
||||
ret = lzma_stream_footer_decode(&footer_flags, buf.u8);
|
||||
if (ret != LZMA_OK) {
|
||||
message_error("%s: %s", pair->src_name,
|
||||
message_strm(ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Check that the Stream Footer doesn't specify something
|
||||
// that we don't support. This can only happen if the xz
|
||||
// version is older than liblzma and liblzma supports
|
||||
// something new.
|
||||
//
|
||||
// It is enough to check Stream Footer. Stream Header must
|
||||
// match when it is compared against Stream Footer with
|
||||
// lzma_stream_flags_compare().
|
||||
if (footer_flags.version != 0) {
|
||||
message_error("%s: %s", pair->src_name,
|
||||
message_strm(LZMA_OPTIONS_ERROR));
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Check that the size of the Index field looks sane.
|
||||
lzma_vli index_size = footer_flags.backward_size;
|
||||
if ((lzma_vli)(pos) < index_size + LZMA_STREAM_HEADER_SIZE) {
|
||||
message_error("%s: %s", pair->src_name,
|
||||
message_strm(LZMA_DATA_ERROR));
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Set pos to the beginning of the Index.
|
||||
pos -= index_size;
|
||||
|
||||
// See how much memory we can use for decoding this Index.
|
||||
uint64_t memlimit = hardware_memlimit_get(MODE_LIST);
|
||||
uint64_t memused = 0;
|
||||
if (combined_index != NULL) {
|
||||
memused = lzma_index_memused(combined_index);
|
||||
if (memused > memlimit)
|
||||
message_bug();
|
||||
|
||||
memlimit -= memused;
|
||||
}
|
||||
|
||||
// Decode the Index.
|
||||
ret = lzma_index_decoder(&strm, &this_index, memlimit);
|
||||
if (ret != LZMA_OK) {
|
||||
message_error("%s: %s", pair->src_name,
|
||||
message_strm(ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
do {
|
||||
// Don't give the decoder more input than the
|
||||
// Index size.
|
||||
strm.avail_in = my_min(IO_BUFFER_SIZE, index_size);
|
||||
if (io_pread(pair, &buf, strm.avail_in, pos))
|
||||
goto error;
|
||||
|
||||
pos += strm.avail_in;
|
||||
index_size -= strm.avail_in;
|
||||
lzma_ret ret = lzma_file_info_decoder(&strm, &idx,
|
||||
hardware_memlimit_get(MODE_LIST),
|
||||
(uint64_t)(pair->src_st.st_size));
|
||||
if (ret != LZMA_OK) {
|
||||
message_error("%s: %s", pair->src_name, message_strm(ret));
|
||||
return true;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (strm.avail_in == 0) {
|
||||
strm.next_in = buf.u8;
|
||||
ret = lzma_code(&strm, LZMA_RUN);
|
||||
strm.avail_in = io_read(pair, &buf, IO_BUFFER_SIZE);
|
||||
if (strm.avail_in == SIZE_MAX)
|
||||
goto error;
|
||||
}
|
||||
|
||||
} while (ret == LZMA_OK);
|
||||
ret = lzma_code(&strm, LZMA_RUN);
|
||||
|
||||
// If the decoding seems to be successful, check also that
|
||||
// the Index decoder consumed as much input as indicated
|
||||
// by the Backward Size field.
|
||||
if (ret == LZMA_STREAM_END)
|
||||
if (index_size != 0 || strm.avail_in != 0)
|
||||
ret = LZMA_DATA_ERROR;
|
||||
switch (ret) {
|
||||
case LZMA_OK:
|
||||
break;
|
||||
|
||||
if (ret != LZMA_STREAM_END) {
|
||||
// LZMA_BUFFER_ERROR means that the Index decoder
|
||||
// would have liked more input than what the Index
|
||||
// size should be according to Stream Footer.
|
||||
// The message for LZMA_DATA_ERROR makes more
|
||||
// sense in that case.
|
||||
if (ret == LZMA_BUF_ERROR)
|
||||
ret = LZMA_DATA_ERROR;
|
||||
case LZMA_SEEK_NEEDED:
|
||||
// The cast is safe because liblzma won't ask us to
|
||||
// seek past the known size of the input file which
|
||||
// did fit into off_t.
|
||||
assert(strm.seek_pos
|
||||
<= (uint64_t)(pair->src_st.st_size));
|
||||
if (io_seek_src(pair, (off_t)(strm.seek_pos)))
|
||||
goto error;
|
||||
|
||||
// avail_in must be zero so that we will read new
|
||||
// input.
|
||||
strm.avail_in = 0;
|
||||
break;
|
||||
|
||||
case LZMA_STREAM_END: {
|
||||
lzma_end(&strm);
|
||||
xfi->idx = idx;
|
||||
|
||||
// Calculate xfi->stream_padding.
|
||||
lzma_index_iter iter;
|
||||
lzma_index_iter_init(&iter, xfi->idx);
|
||||
while (!lzma_index_iter_next(&iter,
|
||||
LZMA_INDEX_ITER_STREAM))
|
||||
xfi->stream_padding += iter.stream.padding;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
message_error("%s: %s", pair->src_name,
|
||||
message_strm(ret));
|
||||
|
||||
// If the error was too low memory usage limit,
|
||||
// show also how much memory would have been needed.
|
||||
if (ret == LZMA_MEMLIMIT_ERROR) {
|
||||
uint64_t needed = lzma_memusage(&strm);
|
||||
if (UINT64_MAX - needed < memused)
|
||||
needed = UINT64_MAX;
|
||||
else
|
||||
needed += memused;
|
||||
|
||||
message_mem_needed(V_ERROR, needed);
|
||||
}
|
||||
if (ret == LZMA_MEMLIMIT_ERROR)
|
||||
message_mem_needed(V_ERROR,
|
||||
lzma_memusage(&strm));
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Decode the Stream Header and check that its Stream Flags
|
||||
// match the Stream Footer.
|
||||
pos -= footer_flags.backward_size + LZMA_STREAM_HEADER_SIZE;
|
||||
if ((lzma_vli)(pos) < lzma_index_total_size(this_index)) {
|
||||
message_error("%s: %s", pair->src_name,
|
||||
message_strm(LZMA_DATA_ERROR));
|
||||
goto error;
|
||||
}
|
||||
|
||||
pos -= lzma_index_total_size(this_index);
|
||||
if (io_pread(pair, &buf, LZMA_STREAM_HEADER_SIZE, pos))
|
||||
goto error;
|
||||
|
||||
ret = lzma_stream_header_decode(&header_flags, buf.u8);
|
||||
if (ret != LZMA_OK) {
|
||||
message_error("%s: %s", pair->src_name,
|
||||
message_strm(ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = lzma_stream_flags_compare(&header_flags, &footer_flags);
|
||||
if (ret != LZMA_OK) {
|
||||
message_error("%s: %s", pair->src_name,
|
||||
message_strm(ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Store the decoded Stream Flags into this_index. This is
|
||||
// needed so that we can print which Check is used in each
|
||||
// Stream.
|
||||
ret = lzma_index_stream_flags(this_index, &footer_flags);
|
||||
if (ret != LZMA_OK)
|
||||
message_bug();
|
||||
|
||||
// Store also the size of the Stream Padding field. It is
|
||||
// needed to show the offsets of the Streams correctly.
|
||||
ret = lzma_index_stream_padding(this_index, stream_padding);
|
||||
if (ret != LZMA_OK)
|
||||
message_bug();
|
||||
|
||||
if (combined_index != NULL) {
|
||||
// Append the earlier decoded Indexes
|
||||
// after this_index.
|
||||
ret = lzma_index_cat(
|
||||
this_index, combined_index, NULL);
|
||||
if (ret != LZMA_OK) {
|
||||
message_error("%s: %s", pair->src_name,
|
||||
message_strm(ret));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
combined_index = this_index;
|
||||
this_index = NULL;
|
||||
|
||||
xfi->stream_padding += stream_padding;
|
||||
|
||||
} while (pos > 0);
|
||||
|
||||
lzma_end(&strm);
|
||||
|
||||
// All OK. Make combined_index available to the caller.
|
||||
xfi->idx = combined_index;
|
||||
return false;
|
||||
}
|
||||
|
||||
error:
|
||||
// Something went wrong, free the allocated memory.
|
||||
lzma_end(&strm);
|
||||
lzma_index_end(combined_index, NULL);
|
||||
lzma_index_end(this_index, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -818,6 +818,7 @@ message_strm(lzma_ret code)
|
||||
case LZMA_STREAM_END:
|
||||
case LZMA_GET_CHECK:
|
||||
case LZMA_PROG_ERROR:
|
||||
case LZMA_SEEK_NEEDED:
|
||||
// Without "default", compiler will warn if new constants
|
||||
// are added to lzma_ret, it is not too easy to forget to
|
||||
// add the new constants to this function.
|
||||
|
||||
@@ -229,6 +229,7 @@
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_encoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_encoder_memusage.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_preset.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\file_info.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_buffer_decoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_buffer_encoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_common.c" />
|
||||
@@ -318,6 +319,7 @@
|
||||
<ClInclude Include="..\..\src\liblzma\common\filter_decoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\filter_encoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index_decoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index_encoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\memcmplen.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\outqueue.h" />
|
||||
|
||||
@@ -255,6 +255,7 @@
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_encoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_encoder_memusage.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_preset.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\file_info.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_buffer_decoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_buffer_encoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_common.c" />
|
||||
@@ -344,6 +345,7 @@
|
||||
<ClInclude Include="..\..\src\liblzma\common\filter_decoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\filter_encoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index_decoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index_encoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\memcmplen.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\outqueue.h" />
|
||||
|
||||
@@ -230,6 +230,7 @@
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_encoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_encoder_memusage.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_preset.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\file_info.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_buffer_decoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_buffer_encoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_common.c" />
|
||||
@@ -319,6 +320,7 @@
|
||||
<ClInclude Include="..\..\src\liblzma\common\filter_decoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\filter_encoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index_decoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index_encoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\memcmplen.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\outqueue.h" />
|
||||
|
||||
@@ -256,6 +256,7 @@
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_encoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_encoder_memusage.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\easy_preset.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\file_info.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_buffer_decoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_buffer_encoder.c" />
|
||||
<ClCompile Include="..\..\src\liblzma\common\filter_common.c" />
|
||||
@@ -345,6 +346,7 @@
|
||||
<ClInclude Include="..\..\src\liblzma\common\filter_decoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\filter_encoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index_decoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\index_encoder.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\memcmplen.h" />
|
||||
<ClInclude Include="..\..\src\liblzma\common\outqueue.h" />
|
||||
|
||||
Reference in New Issue
Block a user