This source file includes following definitions.
- zip_source_buffer
- zip_source_buffer_create
- read_data
- buffer_free
- buffer_new
- buffer_new_read
- buffer_new_write
- buffer_read
- buffer_seek
- buffer_write
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "zipint.h"
38
39 #ifndef WRITE_FRAGMENT_SIZE
40 #define WRITE_FRAGMENT_SIZE 64*1024
41 #endif
42
43 struct buffer {
44 zip_uint64_t fragment_size;
45
46 zip_uint8_t **fragments;
47 zip_uint64_t nfragments;
48 zip_uint64_t fragments_capacity;
49 zip_uint64_t size;
50 zip_uint64_t offset;
51 int free_data;
52 };
53
54 typedef struct buffer buffer_t;
55
56 struct read_data {
57 zip_error_t error;
58 time_t mtime;
59 buffer_t *in;
60 buffer_t *out;
61 };
62
63 static void buffer_free(buffer_t *buffer);
64 static buffer_t *buffer_new(zip_uint64_t fragment_size);
65 static buffer_t *buffer_new_read(const void *data, zip_uint64_t length, int free_data);
66 static buffer_t *buffer_new_write(zip_uint64_t fragment_size);
67 static zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length);
68 static int buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error);
69 static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *);
70
71 static zip_int64_t read_data(void *, void *, zip_uint64_t, zip_source_cmd_t);
72
73
74 ZIP_EXTERN zip_source_t *
75 zip_source_buffer(zip_t *za, const void *data, zip_uint64_t len, int freep)
76 {
77 if (za == NULL)
78 return NULL;
79
80 return zip_source_buffer_create(data, len, freep, &za->error);
81 }
82
83
84 ZIP_EXTERN zip_source_t *
85 zip_source_buffer_create(const void *data, zip_uint64_t len, int freep, zip_error_t *error)
86 {
87 struct read_data *ctx;
88 zip_source_t *zs;
89
90 if (data == NULL && len > 0) {
91 zip_error_set(error, ZIP_ER_INVAL, 0);
92 return NULL;
93 }
94
95 if ((ctx=(struct read_data *)malloc(sizeof(*ctx))) == NULL) {
96 zip_error_set(error, ZIP_ER_MEMORY, 0);
97 return NULL;
98 }
99
100 if ((ctx->in = buffer_new_read(data, len, freep)) == NULL) {
101 zip_error_set(error, ZIP_ER_MEMORY, 0);
102 free(ctx);
103 return NULL;
104 }
105
106 ctx->out = NULL;
107 ctx->mtime = time(NULL);
108 zip_error_init(&ctx->error);
109
110 if ((zs=zip_source_function_create(read_data, ctx, error)) == NULL) {
111 buffer_free(ctx->in);
112 free(ctx);
113 return NULL;
114 }
115
116 return zs;
117 }
118
119
120 static zip_int64_t
121 read_data(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
122 {
123 struct read_data *ctx = (struct read_data *)state;
124
125 switch (cmd) {
126 case ZIP_SOURCE_BEGIN_WRITE:
127 if ((ctx->out = buffer_new_write(WRITE_FRAGMENT_SIZE)) == NULL) {
128 zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
129 return -1;
130 }
131 return 0;
132
133 case ZIP_SOURCE_CLOSE:
134 return 0;
135
136 case ZIP_SOURCE_COMMIT_WRITE:
137 buffer_free(ctx->in);
138 ctx->in = ctx->out;
139 ctx->out = NULL;
140 return 0;
141
142 case ZIP_SOURCE_ERROR:
143 return zip_error_to_data(&ctx->error, data, len);
144
145 case ZIP_SOURCE_FREE:
146 buffer_free(ctx->in);
147 buffer_free(ctx->out);
148 free(ctx);
149 return 0;
150
151 case ZIP_SOURCE_OPEN:
152 ctx->in->offset = 0;
153 return 0;
154
155 case ZIP_SOURCE_READ:
156 if (len > ZIP_INT64_MAX) {
157 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
158 return -1;
159 }
160 return buffer_read(ctx->in, data, len);
161
162 case ZIP_SOURCE_REMOVE:
163 {
164 buffer_t *empty = buffer_new_read(NULL, 0, 0);
165 if (empty == 0) {
166 zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
167 return -1;
168 }
169
170 buffer_free(ctx->in);
171 ctx->in = empty;
172 return 0;
173 }
174
175 case ZIP_SOURCE_ROLLBACK_WRITE:
176 buffer_free(ctx->out);
177 ctx->out = NULL;
178 return 0;
179
180 case ZIP_SOURCE_SEEK:
181 return buffer_seek(ctx->in, data, len, &ctx->error);
182
183 case ZIP_SOURCE_SEEK_WRITE:
184 return buffer_seek(ctx->out, data, len, &ctx->error);
185
186 case ZIP_SOURCE_STAT:
187 {
188 zip_stat_t *st;
189
190 if (len < sizeof(*st)) {
191 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
192 return -1;
193 }
194
195 st = (zip_stat_t *)data;
196
197 zip_stat_init(st);
198 st->mtime = ctx->mtime;
199 st->size = ctx->in->size;
200 st->comp_size = st->size;
201 st->comp_method = ZIP_CM_STORE;
202 st->encryption_method = ZIP_EM_NONE;
203 st->valid = ZIP_STAT_MTIME|ZIP_STAT_SIZE|ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD|ZIP_STAT_ENCRYPTION_METHOD;
204
205 return sizeof(*st);
206 }
207
208 case ZIP_SOURCE_SUPPORTS:
209 return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, -1);
210
211 case ZIP_SOURCE_TELL:
212 if (ctx->in->offset > ZIP_INT64_MAX) {
213 zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW);
214 return -1;
215 }
216 return (zip_int64_t)ctx->in->offset;
217
218
219 case ZIP_SOURCE_TELL_WRITE:
220 if (ctx->out->offset > ZIP_INT64_MAX) {
221 zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW);
222 return -1;
223 }
224 return (zip_int64_t)ctx->out->offset;
225
226 case ZIP_SOURCE_WRITE:
227 if (len > ZIP_INT64_MAX) {
228 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
229 return -1;
230 }
231 return buffer_write(ctx->out, data, len, &ctx->error);
232
233 default:
234 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
235 return -1;
236 }
237 }
238
239
240 static void
241 buffer_free(buffer_t *buffer)
242 {
243 if (buffer == NULL) {
244 return;
245 }
246
247 if (buffer->free_data) {
248 zip_uint64_t i;
249
250 for (i=0; i < buffer->nfragments; i++) {
251 free(buffer->fragments[i]);
252 }
253 }
254 free(buffer->fragments);
255 free(buffer);
256 }
257
258
259 static buffer_t *
260 buffer_new(zip_uint64_t fragment_size)
261 {
262 buffer_t *buffer;
263
264 if ((buffer = malloc(sizeof(*buffer))) == NULL) {
265 return NULL;
266 }
267
268 buffer->fragment_size = fragment_size;
269 buffer->offset = 0;
270 buffer->free_data = 0;
271 buffer->nfragments = 0;
272 buffer->fragments_capacity = 0;
273 buffer->fragments = NULL;
274 buffer->size = 0;
275
276 return buffer;
277 }
278
279
280 static buffer_t *
281 buffer_new_read(const void *data, zip_uint64_t length, int free_data)
282 {
283 buffer_t *buffer;
284
285 if ((buffer = buffer_new(length)) == NULL) {
286 return NULL;
287 }
288
289 buffer->size = length;
290
291 if (length > 0) {
292 if ((buffer->fragments = malloc(sizeof(*(buffer->fragments)))) == NULL) {
293 buffer_free(buffer);
294 return NULL;
295 }
296 buffer->fragments_capacity = 1;
297
298 buffer->nfragments = 1;
299 buffer->fragments[0] = (zip_uint8_t *)data;
300 buffer->free_data = free_data;
301 }
302
303 return buffer;
304 }
305
306
307 static buffer_t *
308 buffer_new_write(zip_uint64_t fragment_size)
309 {
310 buffer_t *buffer;
311
312 if ((buffer = buffer_new(fragment_size)) == NULL) {
313 return NULL;
314 }
315
316 if ((buffer->fragments = malloc(sizeof(*(buffer->fragments)))) == NULL) {
317 buffer_free(buffer);
318 return NULL;
319 }
320 buffer->fragments_capacity = 1;
321 buffer->nfragments = 0;
322 buffer->free_data = 1;
323
324 return buffer;
325 }
326
327
328 static zip_int64_t
329 buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length)
330 {
331 zip_uint64_t n, i, fragment_offset;
332
333 length = ZIP_MIN(length, buffer->size - buffer->offset);
334
335 if (length == 0) {
336 return 0;
337 }
338 if (length > ZIP_INT64_MAX) {
339 return -1;
340 }
341
342 i = buffer->offset / buffer->fragment_size;
343 fragment_offset = buffer->offset % buffer->fragment_size;
344 n = 0;
345 while (n < length) {
346 zip_uint64_t left = ZIP_MIN(length - n, buffer->fragment_size - fragment_offset);
347
348 memcpy(data + n, buffer->fragments[i] + fragment_offset, left);
349
350 n += left;
351 i++;
352 fragment_offset = 0;
353 }
354
355 buffer->offset += n;
356 return (zip_int64_t)n;
357 }
358
359
360 static int
361 buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error)
362 {
363 zip_int64_t new_offset = zip_source_seek_compute_offset(buffer->offset, buffer->size, data, len, error);
364
365 if (new_offset < 0) {
366 return -1;
367 }
368
369 buffer->offset = (zip_uint64_t)new_offset;
370 return 0;
371 }
372
373
374 static zip_int64_t
375 buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error)
376 {
377 zip_uint64_t n, i, fragment_offset;
378 zip_uint8_t **fragments;
379
380 if (buffer->offset + length + buffer->fragment_size - 1 < length) {
381 zip_error_set(error, ZIP_ER_INVAL, 0);
382 return -1;
383 }
384
385
386 if (buffer->offset + length > buffer->nfragments * buffer->fragment_size) {
387 zip_uint64_t needed_fragments = (buffer->offset + length + buffer->fragment_size - 1) / buffer->fragment_size;
388
389 if (needed_fragments > buffer->fragments_capacity) {
390 zip_uint64_t new_capacity = buffer->fragments_capacity;
391
392 while (new_capacity < needed_fragments) {
393 new_capacity *= 2;
394 }
395
396 fragments = realloc(buffer->fragments, new_capacity * sizeof(*fragments));
397
398 if (fragments == NULL) {
399 zip_error_set(error, ZIP_ER_MEMORY, 0);
400 return -1;
401 }
402
403 buffer->fragments = fragments;
404 buffer->fragments_capacity = new_capacity;
405 }
406
407 while (buffer->nfragments < needed_fragments) {
408 if ((buffer->fragments[buffer->nfragments] = malloc(buffer->fragment_size)) == NULL) {
409 zip_error_set(error, ZIP_ER_MEMORY, 0);
410 return -1;
411 }
412 buffer->nfragments++;
413 }
414 }
415
416 i = buffer->offset / buffer->fragment_size;
417 fragment_offset = buffer->offset % buffer->fragment_size;
418 n = 0;
419 while (n < length) {
420 zip_uint64_t left = ZIP_MIN(length - n, buffer->fragment_size - fragment_offset);
421
422 memcpy(buffer->fragments[i] + fragment_offset, data + n, left);
423
424 n += left;
425 i++;
426 fragment_offset = 0;
427 }
428
429 buffer->offset += n;
430 if (buffer->offset > buffer->size) {
431 buffer->size = buffer->offset;
432 }
433
434 return (zip_int64_t)n;
435 }