1 /*
2 zip_source_window.c -- return part of lower source
3 Copyright (C) 2012-2014 Dieter Baron and Thomas Klausner
4
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
34
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "zipint.h"
39
40 struct window {
41 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;
47 bool needs_seek;
48 };
49
50 static zip_int64_t window_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
51
52
53 zip_source_t *
zip_source_window(zip_t * za,zip_source_t * src,zip_uint64_t start,zip_uint64_t len)54 zip_source_window(zip_t *za, zip_source_t *src, zip_uint64_t start, zip_uint64_t len)
55 {
56 return _zip_source_window_new(src, start, len, NULL, &za->error);
57 }
58
59
60 zip_source_t *
_zip_source_window_new(zip_source_t * src,zip_uint64_t start,zip_uint64_t length,zip_stat_t * st,zip_error_t * error)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 {
63 struct window *ctx;
64
65 if (src == NULL || start + length < start) {
66 zip_error_set(error, ZIP_ER_INVAL, 0);
67 return NULL;
68 }
69
70 if ((ctx=(struct window *)malloc(sizeof(*ctx))) == NULL) {
71 zip_error_set(error, ZIP_ER_MEMORY, 0);
72 return NULL;
73 }
74
75 ctx->start = start;
76 ctx->end = start + length;
77 zip_stat_init(&ctx->stat);
78 zip_error_init(&ctx->error);
79 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;
81
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 }
91
92
93 int
_zip_source_set_source_archive(zip_source_t * src,zip_t * za)94 _zip_source_set_source_archive(zip_source_t *src, zip_t *za)
95 {
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 */
102 void
_zip_source_invalidate(zip_source_t * src)103 _zip_source_invalidate(zip_source_t *src)
104 {
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 }
110 }
111
112
113 static zip_int64_t
window_read(zip_source_t * src,void * _ctx,void * data,zip_uint64_t len,zip_source_cmd_t cmd)114 window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
115 {
116 struct window *ctx;
117 zip_int64_t ret;
118 zip_uint64_t n, i;
119 char b[8192];
120
121 ctx = (struct window *)_ctx;
122
123 switch (cmd) {
124 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) {
139 _zip_error_set_from_source(&ctx->error, src);
140 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) {
161 _zip_error_set_from_source(&ctx->error, src);
162 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 {
183 zip_int64_t new_offset = zip_source_seek_compute_offset(ctx->offset - ctx->start, ctx->end - ctx->start, data, len, &ctx->error);
184
185 if (new_offset < 0) {
186 return -1;
187 }
188
189 ctx->offset = (zip_uint64_t)new_offset + ctx->start;
190 return 0;
191 }
192
193 case ZIP_SOURCE_STAT:
194 {
195 zip_stat_t *st;
196
197 st = (zip_stat_t *)data;
198
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 }
216
217
218 void
_zip_deregister_source(zip_t * za,zip_source_t * src)219 _zip_deregister_source(zip_t *za, zip_source_t *src)
220 {
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 }
231
232
233 int
_zip_register_source(zip_t * za,zip_source_t * src)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;
241 open_source = (zip_source_t **)realloc(za->open_source, n*sizeof(zip_source_t *));
242 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;
248 }
249
250 za->open_source[za->nopen_source++] = src;
251
252 return 0;
253 }
254