blob: f02d048c0c6eee82a68db943b2161be9f46ba651 [file] [log] [blame]
Dieter Baronba561a62012-02-13 22:02:46 +01001/*
2 zip_source_window.c -- return part of lower source
Thomas Klausnerea8ba492014-09-23 16:54:47 +02003 Copyright (C) 2012-2014 Dieter Baron and Thomas Klausner
Dieter Baronba561a62012-02-13 22:02:46 +01004
5 This file is part of libzip, a library to manipulate ZIP archives.
6 The authors can be contacted at <libzip@nih.at>
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
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
16 distribution.
17 3. The names of the authors may not be used to endorse or promote
18 products derived from this software without specific prior
19 written permission.
20
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.
32*/
33
Dieter Baronba561a62012-02-13 22:02:46 +010034
35#include <stdlib.h>
36#include <string.h>
37
38#include "zipint.h"
39
40struct window {
Thomas Klausnerea8ba492014-09-23 16:54:47 +020041 zip_uint64_t start;
42 zip_uint64_t end;
43 zip_uint64_t offset;
44 zip_stat_t stat;
45 zip_error_t error;
46 zip_int64_t supports;
Dieter Baron8631d4b2014-10-10 16:28:54 +020047 bool needs_seek;
Dieter Baronba561a62012-02-13 22:02:46 +010048};
49
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020050static zip_int64_t window_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
Dieter Baronba561a62012-02-13 22:02:46 +010051
Dieter Baronba561a62012-02-13 22:02:46 +010052
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020053zip_source_t *
54zip_source_window(zip_t *za, zip_source_t *src, zip_uint64_t start, zip_uint64_t len)
Dieter Baronba561a62012-02-13 22:02:46 +010055{
Thomas Klausnerea8ba492014-09-23 16:54:47 +020056 return _zip_source_window_new(src, start, len, NULL, &za->error);
57}
58
59
60zip_source_t *
61_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_error_t *error)
62{
Dieter Baronba561a62012-02-13 22:02:46 +010063 struct window *ctx;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020064
65 if (src == NULL || start + length < start) {
66 zip_error_set(error, ZIP_ER_INVAL, 0);
67 return NULL;
Dieter Baronba561a62012-02-13 22:02:46 +010068 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +020069
Dieter Baronba561a62012-02-13 22:02:46 +010070 if ((ctx=(struct window *)malloc(sizeof(*ctx))) == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +020071 zip_error_set(error, ZIP_ER_MEMORY, 0);
72 return NULL;
Dieter Baronba561a62012-02-13 22:02:46 +010073 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +020074
75 ctx->start = start;
76 ctx->end = start + length;
77 zip_stat_init(&ctx->stat);
78 zip_error_init(&ctx->error);
Dieter Baron8631d4b2014-10-10 16:28:54 +020079 ctx->supports = (zip_source_supports(src) & ZIP_SOURCE_SUPPORTS_SEEKABLE) | (zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1));
80 ctx->needs_seek = (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) ? true : false;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020081
82 if (st) {
83 if (_zip_stat_merge(&ctx->stat, st, error) < 0) {
84 free(ctx);
85 return NULL;
86 }
87 }
88
89 return zip_source_layered_create(src, window_read, ctx, error);
90}
Dieter Baronba561a62012-02-13 22:02:46 +010091
Dieter Baronba561a62012-02-13 22:02:46 +010092
Thomas Klausnerea8ba492014-09-23 16:54:47 +020093int
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020094_zip_source_set_source_archive(zip_source_t *src, zip_t *za)
Thomas Klausnerea8ba492014-09-23 16:54:47 +020095{
96 src->source_archive = za;
97 return _zip_register_source(za, src);
98}
99
100
101/* called by zip_discard to avoid operating on file from closed archive */
102void
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200103_zip_source_invalidate(zip_source_t *src)
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200104{
105 src->source_closed = 1;
106
107 if (zip_error_code_zip(&src->error) == ZIP_ER_OK) {
108 zip_error_set(&src->error, ZIP_ER_ZIPCLOSED, 0);
109 }
Dieter Baronba561a62012-02-13 22:02:46 +0100110}
111
Dieter Baronba561a62012-02-13 22:02:46 +0100112
113static zip_int64_t
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200114window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
Dieter Baronba561a62012-02-13 22:02:46 +0100115{
116 struct window *ctx;
Dieter Baronabc6fd72012-07-22 15:49:45 +0200117 zip_int64_t ret;
118 zip_uint64_t n, i;
Dieter Baronba561a62012-02-13 22:02:46 +0100119 char b[8192];
120
121 ctx = (struct window *)_ctx;
122
123 switch (cmd) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200124 case ZIP_SOURCE_CLOSE:
125 return 0;
126
127 case ZIP_SOURCE_ERROR:
128 return zip_error_to_data(&ctx->error, data, len);
129
130 case ZIP_SOURCE_FREE:
131 free(ctx);
132 return 0;
133
134 case ZIP_SOURCE_OPEN:
135 if (!ctx->needs_seek) {
136 for (n=0; n<ctx->start; n+=(zip_uint64_t)ret) {
137 i = (ctx->start-n > sizeof(b) ? sizeof(b) : ctx->start-n);
138 if ((ret=zip_source_read(src, b, i)) < 0) {
Thomas Klausnerd97f5442014-09-23 17:02:03 +0200139 _zip_error_set_from_source(&ctx->error, src);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200140 return -1;
141 }
142 if (ret==0) {
143 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
144 return -1;
145 }
146 }
147
148 }
149 ctx->offset = ctx->start;
150 return 0;
151
152 case ZIP_SOURCE_READ:
153 if (len > ctx->end - ctx->offset)
154 len = ctx->end - ctx->offset;
155
156 if (len == 0)
157 return 0;
158
159 if (ctx->needs_seek) {
160 if (zip_source_seek(src, (zip_int64_t)ctx->offset, SEEK_SET) < 0) {
Thomas Klausnerd97f5442014-09-23 17:02:03 +0200161 _zip_error_set_from_source(&ctx->error, src);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200162 return -1;
163 }
164 }
165
166 if ((ret=zip_source_read(src, data, len)) < 0) {
167 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
168 return -1;
169 }
170
171 ctx->offset += (zip_uint64_t)ret;
172
173 if (ret == 0) {
174 if (ctx->offset < ctx->end) {
175 zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
176 return -1;
177 }
178 }
179 return ret;
180
181 case ZIP_SOURCE_SEEK:
182 {
Dieter Baronc548a182014-10-10 18:27:50 +0200183 zip_int64_t new_offset = zip_source_seek_compute_offset(ctx->offset - ctx->start, ctx->end - ctx->start, data, len, &ctx->error);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200184
Dieter Baronc548a182014-10-10 18:27:50 +0200185 if (new_offset < 0) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200186 return -1;
187 }
188
Dieter Baronc548a182014-10-10 18:27:50 +0200189 ctx->offset = (zip_uint64_t)new_offset + ctx->start;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200190 return 0;
191 }
Dieter Baronba561a62012-02-13 22:02:46 +0100192
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200193 case ZIP_SOURCE_STAT:
194 {
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200195 zip_stat_t *st;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200196
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200197 st = (zip_stat_t *)data;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200198
199 if (_zip_stat_merge(st, &ctx->stat, &ctx->error) < 0) {
200 return -1;
201 }
202 return 0;
203 }
204
205 case ZIP_SOURCE_SUPPORTS:
206 return ctx->supports;
207
208 case ZIP_SOURCE_TELL:
209 return (zip_int64_t)(ctx->offset - ctx->start);
210
211 default:
212 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
213 return -1;
214 }
215}
Dieter Baronba561a62012-02-13 22:02:46 +0100216
Dieter Baronba561a62012-02-13 22:02:46 +0100217
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200218void
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200219_zip_deregister_source(zip_t *za, zip_source_t *src)
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200220{
221 unsigned int i;
222
223 for (i=0; i<za->nopen_source; i++) {
224 if (za->open_source[i] == src) {
225 za->open_source[i] = za->open_source[za->nopen_source-1];
226 za->nopen_source--;
227 break;
228 }
229 }
230}
Dieter Baronba561a62012-02-13 22:02:46 +0100231
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200232
233int
234_zip_register_source(zip_t *za, zip_source_t *src)
235{
236 zip_source_t **open_source;
237
238 if (za->nopen_source+1 >= za->nopen_source_alloc) {
239 unsigned int n;
240 n = za->nopen_source_alloc + 10;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200241 open_source = (zip_source_t **)realloc(za->open_source, n*sizeof(zip_source_t *));
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200242 if (open_source == NULL) {
243 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
244 return -1;
245 }
246 za->nopen_source_alloc = n;
247 za->open_source = open_source;
Dieter Baronba561a62012-02-13 22:02:46 +0100248 }
249
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200250 za->open_source[za->nopen_source++] = src;
251
252 return 0;
Dieter Baronba561a62012-02-13 22:02:46 +0100253}