]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/block_header_encoder.c
Oh well, big messy commit again. Some highlights:
[icculus/xz.git] / src / liblzma / common / block_header_encoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       block_header_encoder.c
4 /// \brief      Encodes Block Header for .lzma 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 *options)
26 {
27         // Block Header Size + Block Flags + CRC32.
28         uint32_t size = 1 + 1 + 4;
29
30         // Compressed Size
31         if (options->compressed_size != LZMA_VLI_UNKNOWN) {
32                 const uint32_t add = lzma_vli_size(options->compressed_size);
33                 if (add == 0 || options->compressed_size == 0)
34                         return LZMA_PROG_ERROR;
35
36                 size += add;
37         }
38
39         // Uncompressed Size
40         if (options->uncompressed_size != LZMA_VLI_UNKNOWN) {
41                 const uint32_t add = lzma_vli_size(options->uncompressed_size);
42                 if (add == 0)
43                         return LZMA_PROG_ERROR;
44
45                 size += add;
46         }
47
48         // List of Filter Flags
49         if (options->filters == NULL
50                         || options->filters[0].id == LZMA_VLI_UNKNOWN)
51                 return LZMA_PROG_ERROR;
52
53         for (size_t i = 0; options->filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
54                 // Don't allow too many filters.
55                 if (i == LZMA_FILTERS_MAX)
56                         return LZMA_PROG_ERROR;
57
58                 uint32_t add;
59                 return_if_error(lzma_filter_flags_size(&add,
60                                 options->filters + i));
61
62                 size += add;
63         }
64
65         // Pad to a multiple of four bytes.
66         options->header_size = (size + 3) & ~UINT32_C(3);
67
68         // NOTE: We don't verify that the encoded size of the Block stays
69         // within limits. This is because it is possible that we are called
70         // with exaggerated Compressed Size (e.g. LZMA_VLI_MAX) to reserve
71         // space for Block Header, and later called again with lower,
72         // real values.
73
74         return LZMA_OK;
75 }
76
77
78 extern LZMA_API lzma_ret
79 lzma_block_header_encode(const lzma_block *options, uint8_t *out)
80 {
81         // Valdidate everything but filters.
82         if (lzma_block_unpadded_size(options) == 0
83                         || !lzma_vli_is_valid(options->uncompressed_size))
84                 return LZMA_PROG_ERROR;
85
86         // Indicate the size of the buffer _excluding_ the CRC32 field.
87         const size_t out_size = options->header_size - 4;
88
89         // Store the Block Header Size.
90         out[0] = out_size / 4;
91
92         // We write Block Flags in pieces.
93         out[1] = 0x00;
94         size_t out_pos = 2;
95
96         // Compressed Size
97         if (options->compressed_size != LZMA_VLI_UNKNOWN) {
98                 return_if_error(lzma_vli_encode(
99                                 options->compressed_size, NULL,
100                                 out, &out_pos, out_size));
101
102                 out[1] |= 0x40;
103         }
104
105         // Uncompressed Size
106         if (options->uncompressed_size != LZMA_VLI_UNKNOWN) {
107                 return_if_error(lzma_vli_encode(
108                                 options->uncompressed_size, NULL,
109                                 out, &out_pos, out_size));
110
111                 out[1] |= 0x80;
112         }
113
114         // Filter Flags
115         if (options->filters == NULL
116                         || options->filters[0].id == LZMA_VLI_UNKNOWN)
117                 return LZMA_PROG_ERROR;
118
119         size_t filter_count = 0;
120         do {
121                 // There can be at maximum of four filters.
122                 if (filter_count == LZMA_FILTERS_MAX)
123                         return LZMA_PROG_ERROR;
124
125                 return_if_error(lzma_filter_flags_encode(
126                                 options->filters + filter_count,
127                                 out, &out_pos, out_size));
128
129         } while (options->filters[++filter_count].id != LZMA_VLI_UNKNOWN);
130
131         out[1] |= filter_count - 1;
132
133         // Padding
134         memzero(out + out_pos, out_size - out_pos);
135
136         // CRC32
137         integer_write_32(out + out_size, lzma_crc32(out, out_size, 0));
138
139         return LZMA_OK;
140 }