]> git.ipfire.org Git - thirdparty/xz.git/commitdiff
Docs: Add doc/examples/11_file_info.c.
authorLasse Collin <lasse.collin@tukaani.org>
Mon, 24 Apr 2017 17:20:11 +0000 (20:20 +0300)
committerLasse Collin <lasse.collin@tukaani.org>
Mon, 24 Apr 2017 17:20:11 +0000 (20:20 +0300)
doc/examples/11_file_info.c [new file with mode: 0644]
doc/examples/Makefile

diff --git a/doc/examples/11_file_info.c b/doc/examples/11_file_info.c
new file mode 100644 (file)
index 0000000..c38c041
--- /dev/null
@@ -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;
+}
index 0f3d1851ebdc83bf06c7cce8d16c7aeb2a806098..e8839d881e7b38ea47315a6a874890c5dbed90d7 100644 (file)
@@ -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)