2 * Copyright (c) 2009-2011 Sean Purcell
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "archive_platform.h"
28 __FBSDID("$FreeBSD$");
52 #include "archive_endian.h"
53 #include "archive_private.h"
54 #include "archive_read_private.h"
56 #if HAVE_ZSTD_H && HAVE_LIBZSTD
59 ZSTD_DStream *dstream;
60 unsigned char *out_block;
61 size_t out_block_size;
63 char in_frame; /* True = in the middle of a zstd frame. */
64 char eof; /* True = found end of compressed data. */
68 static ssize_t zstd_filter_read(struct archive_read_filter *, const void**);
69 static int zstd_filter_close(struct archive_read_filter *);
73 * Note that we can detect zstd compressed files even if we can't decompress
74 * them. (In fact, we like detecting them because we can give better error
75 * messages.) So the bid framework here gets compiled even if no zstd library
78 static int zstd_bidder_bid(struct archive_read_filter_bidder *,
79 struct archive_read_filter *);
80 static int zstd_bidder_init(struct archive_read_filter *);
83 archive_read_support_filter_zstd(struct archive *_a)
85 struct archive_read *a = (struct archive_read *)_a;
86 struct archive_read_filter_bidder *bidder;
88 archive_check_magic(_a, ARCHIVE_READ_MAGIC,
89 ARCHIVE_STATE_NEW, "archive_read_support_filter_zstd");
91 if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
92 return (ARCHIVE_FATAL);
95 bidder->name = "zstd";
96 bidder->bid = zstd_bidder_bid;
97 bidder->init = zstd_bidder_init;
98 bidder->options = NULL;
100 #if HAVE_ZSTD_H && HAVE_LIBZSTD
103 archive_set_error(_a, ARCHIVE_ERRNO_MISC,
104 "Using external zstd program for zstd decompression");
105 return (ARCHIVE_WARN);
110 * Test whether we can handle this data.
113 zstd_bidder_bid(struct archive_read_filter_bidder *self,
114 struct archive_read_filter *filter)
116 const unsigned char *buffer;
120 /* Zstd frame magic values */
121 const unsigned zstd_magic = 0xFD2FB528U;
122 const unsigned zstd_magic_skippable_start = 0x184D2A50U;
123 const unsigned zstd_magic_skippable_mask = 0xFFFFFFF0;
125 (void) self; /* UNUSED */
127 buffer = __archive_read_filter_ahead(filter, 4, &avail);
131 prefix = archive_le32dec(buffer);
132 if (prefix == zstd_magic)
134 if ((prefix & zstd_magic_skippable_mask) == zstd_magic_skippable_start)
140 #if !(HAVE_ZSTD_H && HAVE_LIBZSTD)
143 * If we don't have the library on this system, we can't do the
144 * decompression directly. We can, however, try to run "zstd -d"
145 * in case that's available.
148 zstd_bidder_init(struct archive_read_filter *self)
152 r = __archive_read_program(self, "zstd -d -qq");
153 /* Note: We set the format here even if __archive_read_program()
154 * above fails. We do, after all, know what the format is
155 * even if we weren't able to read it. */
156 self->code = ARCHIVE_FILTER_ZSTD;
164 * Initialize the filter object
167 zstd_bidder_init(struct archive_read_filter *self)
169 struct private_data *state;
170 const size_t out_block_size = ZSTD_DStreamOutSize();
172 ZSTD_DStream *dstream;
174 self->code = ARCHIVE_FILTER_ZSTD;
177 state = (struct private_data *)calloc(sizeof(*state), 1);
178 out_block = (unsigned char *)malloc(out_block_size);
179 dstream = ZSTD_createDStream();
181 if (state == NULL || out_block == NULL || dstream == NULL) {
184 ZSTD_freeDStream(dstream); /* supports free on NULL */
185 archive_set_error(&self->archive->archive, ENOMEM,
186 "Can't allocate data for zstd decompression");
187 return (ARCHIVE_FATAL);
192 state->out_block_size = out_block_size;
193 state->out_block = out_block;
194 state->dstream = dstream;
195 self->read = zstd_filter_read;
196 self->skip = NULL; /* not supported */
197 self->close = zstd_filter_close;
206 zstd_filter_read(struct archive_read_filter *self, const void **p)
208 struct private_data *state;
214 state = (struct private_data *)self->data;
216 out = (ZSTD_outBuffer) { state->out_block, state->out_block_size, 0 };
218 /* Try to fill the output buffer. */
219 while (out.pos < out.size && !state->eof) {
220 if (!state->in_frame) {
221 const size_t ret = ZSTD_initDStream(state->dstream);
222 if (ZSTD_isError(ret)) {
223 archive_set_error(&self->archive->archive,
225 "Error initializing zstd decompressor: %s",
226 ZSTD_getErrorName(ret));
227 return (ARCHIVE_FATAL);
230 in.src = __archive_read_filter_ahead(self->upstream, 1,
235 if (in.src == NULL && avail_in == 0) {
236 if (!state->in_frame) {
241 archive_set_error(&self->archive->archive,
243 "Truncated zstd input");
244 return (ARCHIVE_FATAL);
252 ZSTD_decompressStream(state->dstream, &out, &in);
254 if (ZSTD_isError(ret)) {
255 archive_set_error(&self->archive->archive,
257 "Zstd decompression failed: %s",
258 ZSTD_getErrorName(ret));
259 return (ARCHIVE_FATAL);
262 /* Decompressor made some progress */
263 __archive_read_filter_consume(self->upstream, in.pos);
265 /* ret guaranteed to be > 0 if frame isn't done yet */
266 state->in_frame = (ret != 0);
270 decompressed = out.pos;
271 state->total_out += decompressed;
272 if (decompressed == 0)
275 *p = state->out_block;
276 return (decompressed);
280 * Clean up the decompressor.
283 zstd_filter_close(struct archive_read_filter *self)
285 struct private_data *state;
287 state = (struct private_data *)self->data;
289 ZSTD_freeDStream(state->dstream);
290 free(state->out_block);
296 #endif /* HAVE_ZLIB_H && HAVE_LIBZSTD */