2 zip_source_window.c -- return part of lower source
3 Copyright (C) 2012-2014 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 */
44 /* if not NULL, read file data for this file */
45 zip_t *source_archive;
46 zip_uint64_t source_index;
48 zip_uint64_t offset; /* offset in src for next read */
51 zip_int8_t compression_flags;
57 static zip_int64_t window_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
61 zip_source_window(zip_t *za, zip_source_t *src, zip_uint64_t start, zip_uint64_t len)
63 return _zip_source_window_new(src, start, len, NULL, 0, NULL, 0, &za->error);
68 _zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_int8_t compression_flags, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error)
72 if (src == NULL || start + length < start || (source_archive == NULL && source_index != 0)) {
73 zip_error_set(error, ZIP_ER_INVAL, 0);
77 if ((ctx=(struct window *)malloc(sizeof(*ctx))) == NULL) {
78 zip_error_set(error, ZIP_ER_MEMORY, 0);
83 ctx->end = start + length;
84 zip_stat_init(&ctx->stat);
85 ctx->compression_flags = compression_flags;
86 ctx->source_archive = source_archive;
87 ctx->source_index = source_index;
88 zip_error_init(&ctx->error);
89 ctx->supports = (zip_source_supports(src) & ZIP_SOURCE_SUPPORTS_SEEKABLE) | (zip_source_make_command_bitmap(ZIP_SOURCE_GET_COMPRESSION_FLAGS, ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1));
90 ctx->needs_seek = (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) ? true : false;
93 if (_zip_stat_merge(&ctx->stat, st, error) < 0) {
99 return zip_source_layered_create(src, window_read, ctx, error);
104 _zip_source_set_source_archive(zip_source_t *src, zip_t *za)
106 src->source_archive = za;
107 return _zip_register_source(za, src);
111 /* called by zip_discard to avoid operating on file from closed archive */
113 _zip_source_invalidate(zip_source_t *src)
115 src->source_closed = 1;
117 if (zip_error_code_zip(&src->error) == ZIP_ER_OK) {
118 zip_error_set(&src->error, ZIP_ER_ZIPCLOSED, 0);
124 window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
131 ctx = (struct window *)_ctx;
134 case ZIP_SOURCE_CLOSE:
137 case ZIP_SOURCE_ERROR:
138 return zip_error_to_data(&ctx->error, data, len);
140 case ZIP_SOURCE_FREE:
144 case ZIP_SOURCE_OPEN:
145 if (ctx->source_archive) {
148 if ((offset = _zip_file_get_offset(ctx->source_archive, ctx->source_index, &ctx->error)) == 0) {
151 if (ctx->end + offset < ctx->end) {
152 /* zip archive data claims end of data past zip64 limits */
153 zip_error_set(&ctx->error, ZIP_ER_INCONS, 0);
156 ctx->start += offset;
158 ctx->source_archive = NULL;
161 if (!ctx->needs_seek) {
162 for (n=0; n<ctx->start; n+=(zip_uint64_t)ret) {
163 i = (ctx->start-n > sizeof(b) ? sizeof(b) : ctx->start-n);
164 if ((ret=zip_source_read(src, b, i)) < 0) {
165 _zip_error_set_from_source(&ctx->error, src);
169 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
175 ctx->offset = ctx->start;
178 case ZIP_SOURCE_READ:
179 if (len > ctx->end - ctx->offset)
180 len = ctx->end - ctx->offset;
185 if (ctx->needs_seek) {
186 if (zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET) < 0) {
187 _zip_error_set_from_source(&ctx->error, src);
192 if ((ret=zip_source_read(src, data, len)) < 0) {
193 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
197 ctx->offset += (zip_uint64_t)ret;
200 if (ctx->offset < ctx->end) {
201 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
207 case ZIP_SOURCE_SEEK:
209 zip_int64_t new_offset = zip_source_seek_compute_offset(ctx->offset - ctx->start, ctx->end - ctx->start, data, len, &ctx->error);
211 if (new_offset < 0) {
215 ctx->offset = (zip_uint64_t)new_offset + ctx->start;
219 case ZIP_SOURCE_STAT:
223 st = (zip_stat_t *)data;
225 if (_zip_stat_merge(st, &ctx->stat, &ctx->error) < 0) {
231 case ZIP_SOURCE_GET_COMPRESSION_FLAGS:
232 return ctx->compression_flags;
234 case ZIP_SOURCE_SUPPORTS:
235 return ctx->supports;
237 case ZIP_SOURCE_TELL:
238 return (zip_int64_t)(ctx->offset - ctx->start);
241 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
248 _zip_deregister_source(zip_t *za, zip_source_t *src)
252 for (i=0; i<za->nopen_source; i++) {
253 if (za->open_source[i] == src) {
254 za->open_source[i] = za->open_source[za->nopen_source-1];
263 _zip_register_source(zip_t *za, zip_source_t *src)
265 zip_source_t **open_source;
267 if (za->nopen_source+1 >= za->nopen_source_alloc) {
269 n = za->nopen_source_alloc + 10;
270 open_source = (zip_source_t **)realloc(za->open_source, n*sizeof(zip_source_t *));
271 if (open_source == NULL) {
272 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
275 za->nopen_source_alloc = n;
276 za->open_source = open_source;
279 za->open_source[za->nopen_source++] = src;