1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file known_sizes.c
4 /// \brief Encodes .lzma Stream with sizes known in Block Header
6 /// The input file is encoded in RAM, and the known Compressed Size
7 /// and/or Uncompressed Size values are stored in the Block Header.
8 /// As of writing there's no such Stream encoder in liblzma.
10 // Copyright (C) 2008 Lasse Collin
12 // This library is free software; you can redistribute it and/or
13 // modify it under the terms of the GNU Lesser General Public
14 // License as published by the Free Software Foundation; either
15 // version 2.1 of the License, or (at your option) any later version.
17 // This library is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 // Lesser General Public License for more details.
22 ///////////////////////////////////////////////////////////////////////////////
25 #include <sys/types.h>
27 #include <sys/unistd.h>
31 // Support file sizes up to 1 MiB. We use this for output space too, so files
32 // close to 1 MiB had better compress at least a little or we have a buffer
34 #define BUFFER_SIZE (1U << 20)
40 // Allocate the buffers.
41 uint8_t *in = malloc(BUFFER_SIZE);
42 uint8_t *out = malloc(BUFFER_SIZE);
43 if (in == NULL || out == NULL)
46 // Fill the input buffer.
47 const size_t in_size = fread(in, 1, BUFFER_SIZE, stdin);
50 lzma_options_lzma opt_lzma;
51 if (lzma_lzma_preset(&opt_lzma, 1))
54 lzma_filter filters[] = {
56 .id = LZMA_FILTER_LZMA2,
60 .id = LZMA_VLI_UNKNOWN
65 .check = LZMA_CHECK_CRC32,
66 .compressed_size = BUFFER_SIZE, // Worst case reserve
67 .uncompressed_size = in_size,
71 lzma_stream strm = LZMA_STREAM_INIT;
72 if (lzma_block_encoder(&strm, &block) != LZMA_OK)
75 // Reserve space for Stream Header and Block Header. We need to
76 // calculate the size of the Block Header first.
77 if (lzma_block_header_size(&block) != LZMA_OK)
80 size_t out_size = LZMA_STREAM_HEADER_SIZE + block.header_size;
83 strm.avail_in = in_size;
84 strm.next_out = out + out_size;
85 strm.avail_out = BUFFER_SIZE - out_size;
87 if (lzma_code(&strm, LZMA_FINISH) != LZMA_STREAM_END)
90 out_size += strm.total_out;
92 if (lzma_block_header_encode(&block, out + LZMA_STREAM_HEADER_SIZE)
96 lzma_index *idx = lzma_index_init(NULL, NULL);
100 if (lzma_index_append(idx, NULL, block.header_size + strm.total_out,
101 strm.total_in) != LZMA_OK)
104 if (lzma_index_encoder(&strm, idx) != LZMA_OK)
107 if (lzma_code(&strm, LZMA_RUN) != LZMA_STREAM_END)
110 out_size += strm.total_out;
114 lzma_index_end(idx, NULL);
116 // Encode the Stream Header and Stream Footer. backwards_size is
117 // needed only for the Stream Footer.
118 lzma_stream_flags sf = {
119 .backward_size = strm.total_out,
120 .check = block.check,
123 if (lzma_stream_header_encode(&sf, out) != LZMA_OK)
126 if (lzma_stream_footer_encode(&sf, out + out_size) != LZMA_OK)
129 out_size += LZMA_STREAM_HEADER_SIZE;
131 // Write out the file.
132 fwrite(out, 1, out_size, stdout);