2 zip_source_window.c -- return part of lower source
3 Copyright (C) 2012-2021 Dieter Baron and Thomas Klausner
5 This file is part of libzip, a library to manipulate ZIP archives.
6 The authors can be contacted at <libzip@nih.at>
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in
15 the documentation and/or other materials provided with the
17 3. The names of the authors may not be used to endorse or promote
18 products derived from this software without specific prior
21 THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 zip_uint64_t start; /* where in file we start reading */
42 zip_uint64_t end; /* where in file we stop reading */
43 bool end_valid; /* whether end is set, otherwise read until EOF */
45 /* if not NULL, read file data for this file */
46 zip_t *source_archive;
47 zip_uint64_t source_index;
49 zip_uint64_t offset; /* offset in src for next read */
52 zip_file_attributes_t attributes;
58 static zip_int64_t window_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
61 ZIP_EXTERN zip_source_t *
62 zip_source_window_create(zip_source_t *src, zip_uint64_t start, zip_int64_t len, zip_error_t *error) {
63 return _zip_source_window_new(src, start, len, NULL, 0, NULL, 0, error);
68 _zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_int64_t length, zip_stat_t *st, zip_file_attributes_t *attributes, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error) {
71 if (src == NULL || length < -1 || (source_archive == NULL && source_index != 0)) {
72 zip_error_set(error, ZIP_ER_INVAL, 0);
77 if (start + (zip_uint64_t)length < start) {
78 zip_error_set(error, ZIP_ER_INVAL, 0);
83 if ((ctx = (struct window *)malloc(sizeof(*ctx))) == NULL) {
84 zip_error_set(error, ZIP_ER_MEMORY, 0);
90 ctx->end_valid = false;
93 ctx->end = start + (zip_uint64_t)length;
94 ctx->end_valid = true;
96 zip_stat_init(&ctx->stat);
97 if (attributes != NULL) {
98 memcpy(&ctx->attributes, attributes, sizeof(ctx->attributes));
101 zip_file_attributes_init(&ctx->attributes);
103 ctx->source_archive = source_archive;
104 ctx->source_index = source_index;
105 zip_error_init(&ctx->error);
106 ctx->supports = (zip_source_supports(src) & ZIP_SOURCE_SUPPORTS_SEEKABLE) | (zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1));
107 ctx->needs_seek = (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) ? true : false;
110 if (_zip_stat_merge(&ctx->stat, st, error) < 0) {
116 return zip_source_layered_create(src, window_read, ctx, error);
121 _zip_source_set_source_archive(zip_source_t *src, zip_t *za) {
122 src->source_archive = za;
123 return _zip_register_source(za, src);
127 /* called by zip_discard to avoid operating on file from closed archive */
129 _zip_source_invalidate(zip_source_t *src) {
130 src->source_closed = 1;
132 if (zip_error_code_zip(&src->error) == ZIP_ER_OK) {
133 zip_error_set(&src->error, ZIP_ER_ZIPCLOSED, 0);
139 window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
144 ctx = (struct window *)_ctx;
147 case ZIP_SOURCE_CLOSE:
150 case ZIP_SOURCE_ERROR:
151 return zip_error_to_data(&ctx->error, data, len);
153 case ZIP_SOURCE_FREE:
157 case ZIP_SOURCE_OPEN:
158 if (ctx->source_archive) {
161 if ((offset = _zip_file_get_offset(ctx->source_archive, ctx->source_index, &ctx->error)) == 0) {
164 if (ctx->end + offset < ctx->end) {
165 /* zip archive data claims end of data past zip64 limits */
166 zip_error_set(&ctx->error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_CDIR_ENTRY_INVALID, ctx->source_index));
169 ctx->start += offset;
171 ctx->source_archive = NULL;
174 if (!ctx->needs_seek) {
175 DEFINE_BYTE_ARRAY(b, BUFSIZE);
177 if (!byte_array_init(b, BUFSIZE)) {
178 zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
182 for (n = 0; n < ctx->start; n += (zip_uint64_t)ret) {
183 i = (ctx->start - n > BUFSIZE ? BUFSIZE : ctx->start - n);
184 if ((ret = zip_source_read(src, b, i)) < 0) {
185 _zip_error_set_from_source(&ctx->error, src);
190 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
199 ctx->offset = ctx->start;
202 case ZIP_SOURCE_READ:
203 if (ctx->end_valid && len > ctx->end - ctx->offset) {
204 len = ctx->end - ctx->offset;
211 if (ctx->needs_seek) {
212 if (zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET) < 0) {
213 _zip_error_set_from_source(&ctx->error, src);
218 if ((ret = zip_source_read(src, data, len)) < 0) {
219 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
223 ctx->offset += (zip_uint64_t)ret;
226 if (ctx->end_valid && ctx->offset < ctx->end) {
227 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
233 case ZIP_SOURCE_SEEK: {
234 zip_int64_t new_offset;
236 if (!ctx->end_valid) {
237 zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
242 if (args->whence == SEEK_END) {
243 if (zip_source_seek(src, args->offset, args->whence) < 0) {
244 _zip_error_set_from_source(&ctx->error, src);
247 new_offset = zip_source_tell(src);
248 if (new_offset < 0) {
249 _zip_error_set_from_source(&ctx->error, src);
252 if ((zip_uint64_t)new_offset < ctx->start) {
253 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
254 (void)zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET);
257 ctx->offset = (zip_uint64_t)new_offset;
262 new_offset = zip_source_seek_compute_offset(ctx->offset - ctx->start, ctx->end - ctx->start, data, len, &ctx->error);
264 if (new_offset < 0) {
268 ctx->offset = (zip_uint64_t)new_offset + ctx->start;
272 case ZIP_SOURCE_STAT: {
275 st = (zip_stat_t *)data;
277 if (_zip_stat_merge(st, &ctx->stat, &ctx->error) < 0) {
283 case ZIP_SOURCE_GET_FILE_ATTRIBUTES:
284 if (len < sizeof(ctx->attributes)) {
285 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
289 memcpy(data, &ctx->attributes, sizeof(ctx->attributes));
290 return sizeof(ctx->attributes);
292 case ZIP_SOURCE_SUPPORTS:
293 return ctx->supports;
295 case ZIP_SOURCE_TELL:
296 return (zip_int64_t)(ctx->offset - ctx->start);
299 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
306 _zip_deregister_source(zip_t *za, zip_source_t *src) {
309 for (i = 0; i < za->nopen_source; i++) {
310 if (za->open_source[i] == src) {
311 za->open_source[i] = za->open_source[za->nopen_source - 1];
320 _zip_register_source(zip_t *za, zip_source_t *src) {
321 zip_source_t **open_source;
323 if (za->nopen_source + 1 >= za->nopen_source_alloc) {
325 n = za->nopen_source_alloc + 10;
326 open_source = (zip_source_t **)realloc(za->open_source, n * sizeof(zip_source_t *));
327 if (open_source == NULL) {
328 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
331 za->nopen_source_alloc = n;
332 za->open_source = open_source;
335 za->open_source[za->nopen_source++] = src;