]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/block_header_encoder.c
1dd9eab27be6a047e5469072e34ff4bc82661d5a
[icculus/xz.git] / src / liblzma / common / block_header_encoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       block_header_encoder.c
4 /// \brief      Encodes Block Header for .xz files
5 //
6 //  Copyright (C) 2007 Lasse Collin
7 //
8 //  This library is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2.1 of the License, or (at your option) any later version.
12 //
13 //  This library is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19
20 #include "common.h"
21 #include "check.h"
22
23
24 extern LZMA_API(lzma_ret)
25 lzma_block_header_size(lzma_block *block)
26 {
27         if (block->version != 0)
28                 return LZMA_OPTIONS_ERROR;
29
30         // Block Header Size + Block Flags + CRC32.
31         uint32_t size = 1 + 1 + 4;
32
33         // Compressed Size
34         if (block->compressed_size != LZMA_VLI_UNKNOWN) {
35                 const uint32_t add = lzma_vli_size(block->compressed_size);
36                 if (add == 0 || block->compressed_size == 0)
37                         return LZMA_PROG_ERROR;
38
39                 size += add;
40         }
41
42         // Uncompressed Size
43         if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
44                 const uint32_t add = lzma_vli_size(block->uncompressed_size);
45                 if (add == 0)
46                         return LZMA_PROG_ERROR;
47
48                 size += add;
49         }
50
51         // List of Filter Flags
52         if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
53                 return LZMA_PROG_ERROR;
54
55         for (size_t i = 0; block->filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
56                 // Don't allow too many filters.
57                 if (i == LZMA_FILTERS_MAX)
58                         return LZMA_PROG_ERROR;
59
60                 uint32_t add;
61                 return_if_error(lzma_filter_flags_size(&add,
62                                 block->filters + i));
63
64                 size += add;
65         }
66
67         // Pad to a multiple of four bytes.
68         block->header_size = (size + 3) & ~UINT32_C(3);
69
70         // NOTE: We don't verify that the encoded size of the Block stays
71         // within limits. This is because it is possible that we are called
72         // with exaggerated Compressed Size (e.g. LZMA_VLI_MAX) to reserve
73         // space for Block Header, and later called again with lower,
74         // real values.
75
76         return LZMA_OK;
77 }
78
79
80 extern LZMA_API(lzma_ret)
81 lzma_block_header_encode(const lzma_block *block, uint8_t *out)
82 {
83         // Valdidate everything but filters.
84         if (lzma_block_unpadded_size(block) == 0
85                         || !lzma_vli_is_valid(block->uncompressed_size))
86                 return LZMA_PROG_ERROR;
87
88         // Indicate the size of the buffer _excluding_ the CRC32 field.
89         const size_t out_size = block->header_size - 4;
90
91         // Store the Block Header Size.
92         out[0] = out_size / 4;
93
94         // We write Block Flags in pieces.
95         out[1] = 0x00;
96         size_t out_pos = 2;
97
98         // Compressed Size
99         if (block->compressed_size != LZMA_VLI_UNKNOWN) {
100                 return_if_error(lzma_vli_encode(block->compressed_size, NULL,
101                                 out, &out_pos, out_size));
102
103                 out[1] |= 0x40;
104         }
105
106         // Uncompressed Size
107         if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
108                 return_if_error(lzma_vli_encode(block->uncompressed_size, NULL,
109                                 out, &out_pos, out_size));
110
111                 out[1] |= 0x80;
112         }
113
114         // Filter Flags
115         if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
116                 return LZMA_PROG_ERROR;
117
118         size_t filter_count = 0;
119         do {
120                 // There can be at maximum of four filters.
121                 if (filter_count == LZMA_FILTERS_MAX)
122                         return LZMA_PROG_ERROR;
123
124                 return_if_error(lzma_filter_flags_encode(
125                                 block->filters + filter_count,
126                                 out, &out_pos, out_size));
127
128         } while (block->filters[++filter_count].id != LZMA_VLI_UNKNOWN);
129
130         out[1] |= filter_count - 1;
131
132         // Padding
133         memzero(out + out_pos, out_size - out_pos);
134
135         // CRC32
136         integer_write_32(out + out_size, lzma_crc32(out, out_size, 0));
137
138         return LZMA_OK;
139 }