]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/copy_coder.c
Imported to git.
[icculus/xz.git] / src / liblzma / common / copy_coder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       copy_coder.c
4 /// \brief      The Copy filter encoder and decoder
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 "copy_coder.h"
21
22
23 struct lzma_coder_s {
24         lzma_next_coder next;
25         lzma_vli uncompressed_size;
26         bool is_encoder;
27 };
28
29
30 static lzma_ret
31 copy_code(lzma_coder *coder, lzma_allocator *allocator,
32                 const uint8_t *restrict in, size_t *restrict in_pos,
33                 size_t in_size, uint8_t *restrict out,
34                 size_t *restrict out_pos, size_t out_size, lzma_action action)
35 {
36         // If we aren't the last filter in the chain, the Copy filter
37         // is totally useless. Note that it is job of the next coder to
38         // take care of Uncompressed Size, so we don't need to update our
39         // coder->uncompressed_size at all.
40         if (coder->next.code != NULL)
41                 return coder->next.code(coder->next.coder, allocator,
42                                 in, in_pos, in_size, out, out_pos, out_size,
43                                 action);
44
45         // If we get here, we are the last filter in the chain.
46
47         const size_t in_avail = in_size - *in_pos;
48
49         if (coder->is_encoder) {
50                 // Check that we don't have too much input.
51                 if ((lzma_vli)(in_avail) > coder->uncompressed_size)
52                         return LZMA_DATA_ERROR;
53
54                 // Check that once LZMA_FINISH has been given, the
55                 // amount of input matches uncompressed_size if it
56                 // is known.
57                 if (action == LZMA_FINISH && coder->uncompressed_size
58                                         != LZMA_VLI_VALUE_UNKNOWN
59                                 && coder->uncompressed_size
60                                         != (lzma_vli)(in_avail))
61                         return LZMA_DATA_ERROR;
62
63         } else {
64                 // Limit in_size so that we don't copy too much.
65                 if ((lzma_vli)(in_avail) > coder->uncompressed_size)
66                         in_size = *in_pos + (size_t)(coder->uncompressed_size);
67         }
68
69         // Store the old input position, which is needed to update
70         // coder->uncompressed_size.
71         const size_t in_start = *in_pos;
72
73         // We are the last coder in the chain.
74         // Just copy as much data as possible.
75         bufcpy(in, in_pos, in_size, out, out_pos, out_size);
76
77         // Update uncompressed_size if it is known.
78         if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
79                 coder->uncompressed_size -= *in_pos - in_start;
80
81         // action can be LZMA_FINISH only in the encoder.
82         if ((action == LZMA_FINISH && *in_pos == in_size)
83                         || coder->uncompressed_size == 0)
84                 return LZMA_STREAM_END;
85
86         return LZMA_OK;
87 }
88
89
90 static void
91 copy_coder_end(lzma_coder *coder, lzma_allocator *allocator)
92 {
93         lzma_next_coder_end(&coder->next, allocator);
94         lzma_free(coder, allocator);
95         return;
96 }
97
98
99 static lzma_ret
100 copy_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
101                 const lzma_filter_info *filters, bool is_encoder)
102 {
103         // Allocate memory for the decoder if needed.
104         if (next->coder == NULL) {
105                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
106                 if (next->coder == NULL)
107                         return LZMA_MEM_ERROR;
108
109                 next->code = &copy_code;
110                 next->end = &copy_coder_end;
111                 next->coder->next = LZMA_NEXT_CODER_INIT;
112         }
113
114         // Copy Uncompressed Size which is used to limit the output size.
115         next->coder->uncompressed_size = filters[0].uncompressed_size;
116
117         // The coder acts slightly differently as encoder and decoder.
118         next->coder->is_encoder = is_encoder;
119
120         // Initialize the next decoder in the chain, if any.
121         return lzma_next_filter_init(
122                         &next->coder->next, allocator, filters + 1);
123 }
124
125
126 #ifdef HAVE_ENCODER
127 extern lzma_ret
128 lzma_copy_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
129                 const lzma_filter_info *filters)
130 {
131         lzma_next_coder_init(copy_coder_init, next, allocator, filters, true);
132 }
133 #endif
134
135
136 #ifdef HAVE_DECODER
137 extern lzma_ret
138 lzma_copy_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
139                 const lzma_filter_info *filters)
140 {
141         lzma_next_coder_init(copy_coder_init, next, allocator, filters, false);
142 }
143 #endif