1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: expandtab:ts=8:sw=4:softtabstop=4:
3 ///////////////////////////////////////////////////////////////////////////////
4 //
5 /// \file block_header_encoder.c
6 /// \brief Encodes Block Header for .xz files
7 //
8 // Author: Lasse Collin
9 //
10 // This file has been put into the public domain.
11 // You can do whatever you want with this file.
12 //
13 ///////////////////////////////////////////////////////////////////////////////
14
15 #include "common.h"
16 #include "check.h"
17
18
19 extern LZMA_API(lzma_ret)
lzma_block_header_size(lzma_block * block)20 lzma_block_header_size(lzma_block *block)
21 {
22 if (block->version != 0)
23 return LZMA_OPTIONS_ERROR;
24
25 // Block Header Size + Block Flags + CRC32.
26 uint32_t size = 1 + 1 + 4;
27
28 // Compressed Size
29 if (block->compressed_size != LZMA_VLI_UNKNOWN) {
30 const uint32_t add = lzma_vli_size(block->compressed_size);
31 if (add == 0 || block->compressed_size == 0)
32 return LZMA_PROG_ERROR;
33
34 size += add;
35 }
36
37 // Uncompressed Size
38 if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
39 const uint32_t add = lzma_vli_size(block->uncompressed_size);
40 if (add == 0)
41 return LZMA_PROG_ERROR;
42
43 size += add;
44 }
45
46 // List of Filter Flags
47 if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
48 return LZMA_PROG_ERROR;
49
50 for (size_t i = 0; block->filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
51 // Don't allow too many filters.
52 if (i == LZMA_FILTERS_MAX)
53 return LZMA_PROG_ERROR;
54
55 uint32_t add;
56 return_if_error(lzma_filter_flags_size(&add,
57 block->filters + i));
58
59 size += add;
60 }
61
62 // Pad to a multiple of four bytes.
63 block->header_size = (size + 3) & ~UINT32_C(3);
64
65 // NOTE: We don't verify that the encoded size of the Block stays
66 // within limits. This is because it is possible that we are called
67 // with exaggerated Compressed Size (e.g. LZMA_VLI_MAX) to reserve
68 // space for Block Header, and later called again with lower,
69 // real values.
70
71 return LZMA_OK;
72 }
73
74
75 extern LZMA_API(lzma_ret)
lzma_block_header_encode(const lzma_block * block,uint8_t * out)76 lzma_block_header_encode(const lzma_block *block, uint8_t *out)
77 {
78 // Valdidate everything but filters.
79 if (lzma_block_unpadded_size(block) == 0
80 || !lzma_vli_is_valid(block->uncompressed_size))
81 return LZMA_PROG_ERROR;
82
83 // Indicate the size of the buffer _excluding_ the CRC32 field.
84 const size_t out_size = block->header_size - 4;
85
86 // Store the Block Header Size.
87 out[0] = out_size / 4;
88
89 // We write Block Flags in pieces.
90 out[1] = 0x00;
91 size_t out_pos = 2;
92
93 // Compressed Size
94 if (block->compressed_size != LZMA_VLI_UNKNOWN) {
95 return_if_error(lzma_vli_encode(block->compressed_size, NULL,
96 out, &out_pos, out_size));
97
98 out[1] |= 0x40;
99 }
100
101 // Uncompressed Size
102 if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
103 return_if_error(lzma_vli_encode(block->uncompressed_size, NULL,
104 out, &out_pos, out_size));
105
106 out[1] |= 0x80;
107 }
108
109 // Filter Flags
110 if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
111 return LZMA_PROG_ERROR;
112
113 size_t filter_count = 0;
114 do {
115 // There can be at maximum of four filters.
116 if (filter_count == LZMA_FILTERS_MAX)
117 return LZMA_PROG_ERROR;
118
119 return_if_error(lzma_filter_flags_encode(
120 block->filters + filter_count,
121 out, &out_pos, out_size));
122
123 } while (block->filters[++filter_count].id != LZMA_VLI_UNKNOWN);
124
125 out[1] |= filter_count - 1;
126
127 // Padding
128 memzero(out + out_pos, out_size - out_pos);
129
130 // CRC32
131 integer_write_32(out + out_size, lzma_crc32(out, out_size, 0));
132
133 return LZMA_OK;
134 }
135