Use latest Cygwin setup on AppVeyor
[cygwin-setup.git] / compress_zstd.cc
blobbb17785423a937071ab4412e3127f3fae6cf4895
1 /*
2 * Copyright (c) 2018, Cygwin
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
14 #include "compress_zstd.h"
16 #include <stdexcept>
18 #include <errno.h>
19 #include <memory.h>
20 #include <malloc.h>
23 * Predicate: the stream is open for read.
25 compress_zstd::compress_zstd (io_stream * parent)
27 original(NULL),
28 owns_original(true),
29 lasterr(0)
31 /* read only */
32 if (!parent || parent->error())
34 lasterr = EBADF;
35 return;
37 original = parent;
38 create();
41 void
42 compress_zstd::create (void)
44 state = (struct private_data *)calloc(sizeof(*state), 1);
45 if (state == NULL)
47 free(state);
48 lasterr = ENOMEM;
49 return;
52 state->stream = ZSTD_createDStream();
53 if (state->stream == NULL)
55 free(state);
56 lasterr = ENOMEM;
57 return;
59 ZSTD_initDStream(state->stream);
60 state->out_block.size = state->out_block.pos = state->out_pos = state->out_bsz = ZSTD_DStreamOutSize();
61 state->out_block.dst = (unsigned char *)malloc(state->out_bsz);
62 if (state->out_block.dst == NULL)
64 free(state->out_block.dst);
65 free(state);
66 lasterr = ENOMEM;
67 return;
69 state->in_block.size = state->in_block.pos = state->in_bsz = ZSTD_DStreamInSize();
70 state->in_block.src = (unsigned char *)malloc(state->in_bsz);
71 state->in_pos = 0;
72 if (state->in_block.src == NULL)
74 free(state->out_block.dst);
75 free((void*)state->in_block.src);
76 free(state);
77 lasterr = ENOMEM;
78 return;
82 ssize_t
83 compress_zstd::read (void *buffer, size_t len)
85 /* there is no recovery from a busted stream */
86 if (this->lasterr)
88 return -1;
90 if (len == 0)
92 return 0;
95 size_t lenRemaining = len;
96 size_t lenBuffered = 0;
99 if (state->in_block.size > 0 && state->in_block.pos >= state->in_block.size)
101 /* no compressed data ready; read some more input */
102 state->in_block.size = state->in_bsz;
103 ssize_t got = this->original->read((void *)state->in_block.src, state->in_bsz);
104 if (got >= 0)
106 state->in_block.size = got;
107 state->in_block.pos = 0;
109 else
111 lasterr = EIO;
112 return -1;
114 continue;
117 if (state->out_pos < state->out_block.pos)
119 /* output buffer has unused data */
120 ssize_t tmplen = std::min (state->out_block.pos - state->out_pos, lenRemaining);
121 memcpy (&((char *)buffer)[lenBuffered], &((char *)state->out_block.dst)[state->out_pos], tmplen);
122 state->out_pos += tmplen;
123 lenBuffered += tmplen;
124 lenRemaining -= tmplen;
125 if (state->eof)
127 break;
130 else
132 if (state->eof)
134 break;
136 /* output buffer is empty; decompress more data */
137 state->out_block.size = state->out_bsz;
138 state->out_pos = state->out_block.pos = 0;
139 size_t ret = ZSTD_decompressStream (state->stream, &state->out_block, &state->in_block);
140 if (ZSTD_isError(ret))
142 // TODO return/print error
143 return -1;
145 state->eof = (ret == 0);
148 while (lenRemaining != 0);
150 return (len - lenRemaining);
153 ssize_t
154 compress_zstd::write (const void *buffer, size_t len)
156 throw new std::logic_error("compress_zstd::write is not implemented");
159 ssize_t
160 compress_zstd::peek (void *buffer, size_t len)
162 /* can only peek 512 bytes */
163 if (len > 512)
164 return ENOMEM;
166 // we only peek at the beginning of a file, so no buffer tearing can happen
167 // do a real read first…
168 ssize_t got = read (buffer, len);
169 if (got >= 0)
171 // …then rewind read position for the next read()
172 state->out_pos -= got;
174 /* error */
175 return got;
178 long
179 compress_zstd::tell ()
181 throw new std::logic_error("compress_zstd::tell is not implemented");
185 compress_zstd::seek (long where, io_stream_seek_t whence)
187 if ((whence == IO_SEEK_SET) && (where == 0))
189 int result = original->seek(where, whence);
190 destroy();
191 create();
192 return result;
195 throw new std::logic_error("compress_zstd::seek is not implemented");
199 compress_zstd::error ()
201 return lasterr;
205 compress_zstd::set_mtime (time_t mtime)
207 if (original)
208 return original->set_mtime (mtime);
209 return 1;
212 time_t
213 compress_zstd::get_mtime ()
215 if (original)
216 return original->get_mtime ();
217 return 0;
220 mode_t
221 compress_zstd::get_mode ()
223 if (original)
224 return original->get_mode ();
225 return 0;
228 void
229 compress_zstd::release_original ()
231 owns_original = false;
234 void
235 compress_zstd::destroy ()
237 if (state)
239 ZSTD_freeDStream(state->stream);
241 if (state->out_block.dst)
243 free (state->out_block.dst);
244 state->out_block.dst = NULL;
247 if (state->in_block.src)
249 free ((void*)state->in_block.src);
250 state->in_block.src = NULL;
253 free(state);
254 state = NULL;
258 compress_zstd::~compress_zstd ()
260 destroy ();
262 if (original && owns_original)
263 delete original;
266 bool
267 compress_zstd::is_zstd (void * buffer, size_t len)
269 return (ZSTD_getFrameContentSize(buffer, len) != ZSTD_CONTENTSIZE_ERROR);