diff --git a/.gitignore b/.gitignore index e7a3f9b..98d0109 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ pixz +pixzlist *.o test.out test.base diff --git a/Makefile b/Makefile index 9efa070..bc50bfd 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,27 @@ LDFLAGS = -L/Library/Fink/sl64/lib -llzma -Wall CFLAGS = -I/Library/Fink/sl64/include -g -O0 -std=c99 -Wall -PIXZ_OBJS: pixz.o encode.o block.o +CC = gcc $(CFLAGS) -c -o +LD = gcc $(LDFLAGS) -o + + +PIXZ_OBJS = pixz.o encode.o block.o + +all: pixz pixz: $(PIXZ_OBJS) - gcc $(LDFLAGS) -o $@ $^ + $(LD) $@ $^ $(PIXZ_OBJS): %.o: %.c pixz.h - gcc $(CFLAGS) -c -o $@ $< + $(CC) $@ $< + + +pixzlist: pixzlist.o + $(LD) $@ $^ + +pixzlist.o: pixzlist.c + $(CC) $@ $< + run: pixz time ./$< < test.in > test.out @@ -17,4 +31,4 @@ run: pixz clean: rm -f *.o pixz test.out -.PHONY: run clean +.PHONY: all run clean diff --git a/encode.c b/encode.c index c4f8008..c41f06c 100644 --- a/encode.c +++ b/encode.c @@ -53,7 +53,7 @@ fixme_err pixz_encode_options_default(pixz_encode_options *opts) { const size_t k = 1024, m = 1024 * k; // Set defaults - opts->blocksize = 8 * m; + opts->blocksize = 1 * m; opts->chunksize = 64 * k; opts->filters[0].id = LZMA_FILTER_LZMA2; opts->check = LZMA_CHECK_CRC32; diff --git a/pixzlist.c b/pixzlist.c new file mode 100644 index 0000000..d8e6553 --- /dev/null +++ b/pixzlist.c @@ -0,0 +1,132 @@ +#include + +#include +#include +#include + +#define Err(fmt, ...) fprintf(stderr, fmt ".\n", ##__VA_ARGS__) +#define fErr(fmt, ...) Err(fmt, fname, ##__VA_ARGS__) +#define feErr(fmt, ...) fErr(fmt ": %s", strerror(errno), ##__VA_ARGS__) +#define cfErr(code, fmt, ...) Err(fmt, code, fname, ##__VA_ARGS__) + +#define R(ret, ...) ({ __VA_ARGS__; return ret; }) +#define P(pred, ...) ({ if (pred) { __VA_ARGS__; } }) + +#define feRErr(ret, ...) R(ret, feErr(__VA_ARGS__)) +#define fPRErr(pred, ret, ...) P(pred, R(ret, fErr(__VA_ARGS__))) +#define cfPRErr(code, ret, ...) P(code != LZMA_OK, R(ret, cfErr(code, __VA_ARGS__))) + +#define CHUNKSIZE 4096 +#define MEMLIMIT (32 * 1024 * 1204) + +void pixzlist_listfile(char *fname, FILE *f); +lzma_index *pixzlist_index(char *fname, FILE *f); + +int main(int argc, char **argv) { + for (int i = 1; i < argc; ++i) { + char *fname = argv[i]; + FILE *f = fopen(fname, "r"); + if (f == NULL) { + fprintf(stderr, "Can't open file '%s': %s.\n", fname, strerror(errno)); + continue; + } + pixzlist_listfile(fname, f); + fclose(f); + if (i != argc - 1) + printf("\n"); + } + + return 0; +} + +void pixzlist_listfile(char *fname, FILE *f) { + lzma_index *index = pixzlist_index(fname, f); + if (!index) + return; + + printf("%s:\n", fname); + + lzma_index_record rec; + while (!lzma_index_read(index, &rec)) { + printf("%llu / %llu\n", rec.unpadded_size, rec.uncompressed_size); + } + + lzma_index_end(index, NULL); +} + +lzma_index *pixzlist_index(char *fname, FILE *f) { + // Seek to footer + if (fseek(f, -LZMA_STREAM_HEADER_SIZE, SEEK_END) == -1) { + fprintf(stderr, "Can't seek to footer in '%s': %s.\n", + fname, strerror(errno)); + return NULL; + } + + // Read footer + uint8_t header[LZMA_STREAM_HEADER_SIZE]; + if (fread(header, LZMA_STREAM_HEADER_SIZE, 1, f) != 1) { + fprintf(stderr, "Can't read footer from '%s': %s.\n", + fname, strerror(errno)); + return NULL; + } + + // Decode footer + lzma_stream_flags flags; + lzma_ret lerr = lzma_stream_footer_decode(&flags, header); + if (lerr != LZMA_OK) { + if (lerr == LZMA_FORMAT_ERROR) + fprintf(stderr, "'%s' isn't an LZMA file.\n", fname); + else if (lerr == LZMA_DATA_ERROR) + fprintf(stderr, "CRC mismatch in '%s' footer.\n", fname); + else + fprintf(stderr, "Error #%d decoding footer of '%s'.\n", lerr, fname); + return NULL; + } + + // Seek to index + if (fseek(f, -LZMA_STREAM_HEADER_SIZE - flags.backward_size, SEEK_END) == -1) { + fprintf(stderr, "Can't seek to index in '%s': %s.\n", + fname, strerror(errno)); + return NULL; + } + + // Create index decoder + uint8_t chunk[CHUNKSIZE]; + lzma_stream stream = LZMA_STREAM_INIT; + lzma_index *index = NULL; + lerr = lzma_index_decoder(&stream, &index, MEMLIMIT); + if (lerr != LZMA_OK) { + fprintf(stderr, "Error #%d starting decoding index of '%s'.\n", + lerr, fname); + return NULL; + } + + // Decode index + while (lerr != LZMA_STREAM_END) { + size_t rd = fread(chunk, 1, CHUNKSIZE, f); + if (rd == 0) { + fprintf(stderr, "Error reading index from '%s': %s.\n", + fname, strerror(errno)); + goto index_err; + } + stream.next_in = chunk; + stream.avail_in = rd; + + while (stream.avail_in != 0 && lerr != LZMA_STREAM_END) { + lerr = lzma_code(&stream, LZMA_RUN); + if (lerr != LZMA_OK && lerr != LZMA_STREAM_END) { + fprintf(stderr, "Error #%d starting decoding index of '%s'.\n", + lerr, fname); + goto index_err; + } + } + } + lzma_end(&stream); + return index; + +index_err: + lzma_end(&stream); + lzma_index_end(index, NULL); + + return NULL; +}