1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
///////////////////////////////////////////////////////////////////////////////
//
/// \file stream_buffer_encoder.c
/// \brief Single-call .xz Stream encoder
//
// Copyright (C) 2009 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "index.h"
/// Maximum size of Index that has exactly one Record.
/// Index Indicator + Number of Records + Record + CRC32 rounded up to
/// the next multiple of four.
#define INDEX_BOUND ((1 + 1 + 2 * LZMA_VLI_BYTES_MAX + 4 + 3) & ~3)
/// Stream Header, Stream Footer, and Index
#define HEADERS_BOUND (2 * LZMA_STREAM_HEADER_SIZE + INDEX_BOUND)
extern LZMA_API size_t
lzma_stream_buffer_bound(size_t uncompressed_size)
{
// Get the maximum possible size of a Block.
const size_t block_bound = lzma_block_buffer_bound(uncompressed_size);
if (block_bound == 0)
return 0;
// Catch the possible integer overflow and also prevent the size of
// the Stream exceeding LZMA_VLI_MAX (theoretically possible on
// 64-bit systems).
if (MIN(SIZE_MAX, LZMA_VLI_MAX) - block_bound < HEADERS_BOUND)
return 0;
return block_bound + HEADERS_BOUND;
}
extern LZMA_API lzma_ret
lzma_stream_buffer_encode(lzma_filter *filters, lzma_check check,
lzma_allocator *allocator, const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos_ptr, size_t out_size)
{
// Sanity checks
if (filters == NULL || (unsigned int)(check) > LZMA_CHECK_ID_MAX
|| (in == NULL && in_size != 0) || out == NULL
|| out_pos_ptr == NULL || *out_pos_ptr > out_size)
return LZMA_PROG_ERROR;
// Note for the paranoids: Index encoder prevents the Stream from
// getting too big and still being accepted with LZMA_OK, and Block
// encoder catches if the input is too big. So we don't need to
// separately check if the buffers are too big.
// Use a local copy. We update *out_pos_ptr only if everything
// succeeds.
size_t out_pos = *out_pos_ptr;
// Check that there's enough space for both Stream Header and
// Stream Footer.
if (out_size - out_pos <= 2 * LZMA_STREAM_HEADER_SIZE)
return LZMA_BUF_ERROR;
// Reserve space for Stream Footer so we don't need to check for
// available space again before encoding Stream Footer.
out_size -= LZMA_STREAM_HEADER_SIZE;
// Encode the Stream Header.
lzma_stream_flags stream_flags = {
.version = 0,
.check = check,
};
if (lzma_stream_header_encode(&stream_flags, out + out_pos)
!= LZMA_OK)
return LZMA_PROG_ERROR;
out_pos += LZMA_STREAM_HEADER_SIZE;
// Block
lzma_block block = {
.version = 0,
.check = check,
.filters = filters,
};
return_if_error(lzma_block_buffer_encode(&block, allocator,
in, in_size, out, &out_pos, out_size));
// Index
{
// Create an Index with one Record.
lzma_index *i = lzma_index_init(NULL, NULL);
if (i == NULL)
return LZMA_MEM_ERROR;
lzma_ret ret = lzma_index_append(i, NULL,
lzma_block_unpadded_size(&block),
block.uncompressed_size);
// If adding the Record was successful, encode the Index
// and get its size which will be stored into Stream Footer.
if (ret == LZMA_OK) {
ret = lzma_index_buffer_encode(
i, out, &out_pos, out_size);
stream_flags.backward_size = lzma_index_size(i);
}
lzma_index_end(i, NULL);
if (ret != LZMA_OK)
return ret;
}
// Stream Footer. We have already reserved space for this.
if (lzma_stream_footer_encode(&stream_flags, out + out_pos)
!= LZMA_OK)
return LZMA_PROG_ERROR;
out_pos += LZMA_STREAM_HEADER_SIZE;
// Everything went fine, make the new output position available
// to the application.
*out_pos_ptr = out_pos;
return LZMA_OK;
}
|