diff --git a/xdelta3/xdelta3-compr.h b/xdelta3/xdelta3-compr.h new file mode 100644 index 00000000..746cd838 --- /dev/null +++ b/xdelta3/xdelta3-compr.h @@ -0,0 +1,42 @@ +int gz_detect_func(uint8_t *data, int len) +{ + uint8_t flags; + if(len < 9) return -1; + flags = data[8]; + switch(flags) { + case 2: return 9; /* maximum compr */ + case 4: return 1; /* minimum compr */ + } + return 6; /* could be 2..8 but 6 is default */ +} + +int bz2_detect_func(uint8_t *data, int len) +{ + if(len < 4) return -1; + return data[3]&0xf; +} + +int xz_detect_func(uint8_t *data, int len) +{ + int offs; + int dict_size; + /* there might be extra headers which need to be skipped */ + for( offs = 14; offs < 26; offs++) { + if(offs+2 >= len) return -1; + if(data[offs+0] != 0x21) continue; /* LZMA filter */ + if(data[offs+1] != 0x01) continue; /* Size of Filter Properties: 1 byte */ + dict_size = data[offs+2]; + switch(dict_size) { + case 12: return 0; + case 16: return 1; + case 18: return 2; + case 20: return 3; /* could also be 4 */ + case 22: return 6; /* could also be 5 but 6 is the default so the guess is correct in 99% of cases */ + case 24: return 7; + case 26: return 8; + case 28: return 9; + default: return -1; /* not guessable */ + } + } + return -1; +} diff --git a/xdelta3/xdelta3-internal.h b/xdelta3/xdelta3-internal.h index 35de56bd..5fa3d82b 100644 --- a/xdelta3/xdelta3-internal.h +++ b/xdelta3/xdelta3-internal.h @@ -87,6 +87,7 @@ struct _main_file const char *realname; /* File name or /dev/stdin, * /dev/stdout, /dev/stderr. */ const main_extcomp *compressor; /* External compression struct. */ + int compression_level; /* 0..9 or -1 if not detected */ int flags; /* RD_FIRST, RD_NONEXTERNAL, ... */ xoff_t nread; /* for input position */ xoff_t nwrite; /* for output position */ diff --git a/xdelta3/xdelta3-main.h b/xdelta3/xdelta3-main.h index 018a6971..f2572fd6 100644 --- a/xdelta3/xdelta3-main.h +++ b/xdelta3/xdelta3-main.h @@ -207,6 +207,8 @@ struct _main_extcomp const char *magic; usize_t magic_size; int flags; +/* function for detecting compression level of input file */ + int (*detect_func)(uint8_t *data, int len); }; /* Merge state: */ @@ -287,16 +289,17 @@ static xd3_stream *recode_stream = NULL; /* merge_stream is used by merge commands for storing the source encoding */ static xd3_stream *merge_stream = NULL; +#include "xdelta3-compr.h" /* This array of compressor types is compiled even if EXTERNAL_COMPRESSION is * false just so the program knows the mapping of IDENT->NAME. */ static main_extcomp extcomp_types[] = { - { "bzip2", "-c", "bzip2", "-dc", "B", "BZh", 3, 0 }, - { "gzip", "-c", "gzip", "-dc", "G", "\037\213", 2, 0 }, - { "compress", "-c", "uncompress", "-c", "Z", "\037\235", 2, 0 }, + { "bzip2", "-c", "bzip2", "-dc", "B", "BZh", 3, 0, bz2_detect_func }, + { "gzip", "-cn", "gzip", "-dc", "G", "\037\213", 2, 0, gz_detect_func }, + { "compress", "-c", "uncompress", "-c", "Z", "\037\235", 2, 0, NULL }, /* Xz is lzma with a magic number http://tukaani.org/xz/format.html */ - { "xz", "-c", "xz", "-dc", "Y", "\xfd\x37\x7a\x58\x5a\x00", 2, 0 }, + { "xz", "-c", "xz", "-dc", "Y", "\xfd\x37\x7a\x58\x5a\x00", 6, 0, xz_detect_func }, }; static int main_input (xd3_cmd cmd, main_file *ifile, @@ -2453,7 +2456,12 @@ main_secondary_decompress_check (main_file *file, if (memcmp (check_buf, decomp->magic, decomp->magic_size) == 0) { + int compression_level = -1; decompressor = decomp; + if(decomp->detect_func) { + compression_level = decomp->detect_func(check_buf, try_read); + } + file->compression_level = compression_level; break; } }