diff --git a/common.c b/common.c index ad291d2..a0e0b30 100644 --- a/common.c +++ b/common.c @@ -229,9 +229,10 @@ static void read_file_index_data(void) { } } -void decode_index(void) { +bool decode_index(void) { if (fseek(gInFile, -LZMA_STREAM_HEADER_SIZE, SEEK_END) == -1) - die("Error seeking to stream footer"); + return false; // not seekable + uint8_t hdrbuf[LZMA_STREAM_HEADER_SIZE]; if (fread(hdrbuf, LZMA_STREAM_HEADER_SIZE, 1, gInFile) != 1) die("Error reading stream footer"); @@ -261,6 +262,7 @@ void decode_index(void) { if (err != LZMA_OK && err != LZMA_STREAM_END) die("Error decoding index"); } + return true; } diff --git a/pixz.h b/pixz.h index d1e9239..ee45a2e 100644 --- a/pixz.h +++ b/pixz.h @@ -68,7 +68,7 @@ extern file_index_t *gFileIndex, *gLastFile; extern lzma_check gCheck; bool is_multi_header(const char *name); -void decode_index(void); +bool decode_index(void); // true on success lzma_vli find_file_index(void **bdatap); lzma_vli read_file_index(void); diff --git a/read.c b/read.c index 134a50d..08d7acd 100644 --- a/read.c +++ b/read.c @@ -33,6 +33,7 @@ typedef struct { static void *block_create(void); static void block_free(void *data); static void read_thread(void); +static void read_thread_noindex(void); static void decode_thread(size_t thnum); @@ -60,17 +61,18 @@ static void check_capacity(io_block_t *ib, size_t incap, size_t outcap); #pragma mark MAIN void pixz_read(bool verify, size_t nspecs, char **specs) { - decode_index(); - if (verify) - gFileIndexOffset = read_file_index(); - wanted_files(nspecs, specs); + if (0 && decode_index()) { // FIXME + if (verify) + gFileIndexOffset = read_file_index(); + wanted_files(nspecs, specs); + } #if DEBUG for (wanted_t *w = gWantedFiles; w; w = w->next) debug("want: %s", w->name); #endif - pipeline_create(block_create, block_free, read_thread, decode_thread); + pipeline_create(block_create, block_free, read_thread_noindex, decode_thread); if (verify && gFileIndexOffset) { gArWanted = gWantedFiles; wanted_t *w = gWantedFiles, *wlast = NULL; @@ -227,7 +229,7 @@ static void wanted_files(size_t count, char **specs) { static void check_capacity(io_block_t *ib, size_t incap, size_t outcap) { if (incap > ib->incap) { ib->incap = incap; - ib->input = malloc(incap); + ib->input = realloc(ib->input, incap); } if (outcap > ib->outcap) { ib->outcap = outcap; @@ -235,6 +237,66 @@ static void check_capacity(io_block_t *ib, size_t incap, size_t outcap) { } } +static void read_thread_noindex(void) { + size_t bytes; + lzma_ret err; + + // Read the header + uint8_t stream_header[LZMA_STREAM_HEADER_SIZE]; + bytes = fread(stream_header, 1, LZMA_STREAM_HEADER_SIZE, gInFile); + if (bytes != LZMA_STREAM_HEADER_SIZE) + die("Error reading stream header"); + lzma_stream_flags stream_flags; + err = lzma_stream_header_decode(&stream_flags, stream_header); + if (err == LZMA_FORMAT_ERROR) + die("Not an XZ file"); + else if (err != LZMA_OK) + die("Error decoding XZ header"); + gCheck = stream_flags.check; + + lzma_filter filters[LZMA_FILTERS_MAX + 1]; + lzma_block block = { .filters = filters, .check = gCheck, .version = 0 }; + while (true) { + // Get pipeline item + pipeline_item_t *pi; + queue_pop(gPipelineStartQ, (void**)&pi); + io_block_t *ib = (io_block_t*)(pi->data); + check_capacity(ib, LZMA_BLOCK_HEADER_SIZE_MAX, 0); + + // Check for index + if (fread(ib->input, 1, 1, gInFile) != 1) + die("Error reading block header size"); + if (ib->input[0] == 0) + break; // Found the index + + // Decode header + block.header_size = lzma_block_header_size_decode(ib->input[0]); + if (block.header_size > LZMA_BLOCK_HEADER_SIZE_MAX) + die("Block header size too large"); + size_t rest = block.header_size - 1; + if (fread(ib->input + 1, 1, rest, gInFile) != rest) + die("Error reading block header"); + if (lzma_block_header_decode(&block, NULL, ib->input) != LZMA_OK) + die("Error decoding block header"); + + lzma_vli comp = block.compressed_size; + ib->insize = lzma_block_total_size(&block); + ib->outsize = block.uncompressed_size; + if (comp == LZMA_VLI_UNKNOWN || ib->outsize == LZMA_VLI_UNKNOWN) + die("No sizes in header!!!"); // FIXME: streaming; file index + check_capacity(ib, ib->insize, ib->outsize); + + rest = ib->insize - block.header_size; + bytes = fread(ib->input + block.header_size, 1, rest, gInFile); + if (bytes != rest) + die("Error reading block contents"); + pipeline_split(pi); + } + + pipeline_stop(); + // FIXME: don't output the pixz file index! heuristic? +} + static void read_thread(void) { off_t offset = ftello(gInFile); wanted_t *w = gWantedFiles;