2 zip_source_buffer.c -- create zip data source from buffer
3 Copyright (C) 1999-2022 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.
39 #ifndef WRITE_FRAGMENT_SIZE
40 #define WRITE_FRAGMENT_SIZE (64 * 1024)
44 zip_buffer_fragment_t *fragments; /* fragments */
45 zip_uint64_t *fragment_offsets; /* offset of each fragment from start of buffer, nfragments+1 entries */
46 zip_uint64_t nfragments; /* number of allocated fragments */
47 zip_uint64_t fragments_capacity; /* size of fragments (number of pointers) */
49 zip_uint64_t first_owned_fragment; /* first fragment to free data from */
51 zip_uint64_t shared_fragments; /* number of shared fragments */
52 struct buffer *shared_buffer; /* buffer fragments are shared with */
53 zip_uint64_t size; /* size of buffer */
55 zip_uint64_t offset; /* current offset in buffer */
56 zip_uint64_t current_fragment; /* fragment current offset is in */
59 typedef struct buffer buffer_t;
64 zip_file_attributes_t attributes;
69 #define buffer_capacity(buffer) ((buffer)->fragment_offsets[(buffer)->nfragments])
70 #define buffer_size(buffer) ((buffer)->size)
72 static buffer_t *buffer_clone(buffer_t *buffer, zip_uint64_t length, zip_error_t *error);
73 static zip_uint64_t buffer_find_fragment(const buffer_t *buffer, zip_uint64_t offset);
74 static void buffer_free(buffer_t *buffer);
75 static bool buffer_grow_fragments(buffer_t *buffer, zip_uint64_t capacity, zip_error_t *error);
76 static buffer_t *buffer_new(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int free_data, zip_error_t *error);
77 static zip_int64_t buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length);
78 static int buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error);
79 static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *);
81 static zip_int64_t read_data(void *, void *, zip_uint64_t, zip_source_cmd_t);
83 zip_source_t *zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error);
84 zip_source_t *zip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error);
87 ZIP_EXTERN zip_source_t *
88 zip_source_buffer(zip_t *za, const void *data, zip_uint64_t len, int freep) {
92 return zip_source_buffer_with_attributes_create(data, len, freep, NULL, &za->error);
96 ZIP_EXTERN zip_source_t *
97 zip_source_buffer_create(const void *data, zip_uint64_t len, int freep, zip_error_t *error) {
98 return zip_source_buffer_with_attributes_create(data, len, freep, NULL, error);
103 zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error) {
104 zip_buffer_fragment_t fragment;
108 zip_error_set(error, ZIP_ER_INVAL, 0);
112 return zip_source_buffer_fragment_with_attributes_create(NULL, 0, freep, attributes, error);
115 fragment.data = (zip_uint8_t *)data;
116 fragment.length = len;
118 return zip_source_buffer_fragment_with_attributes_create(&fragment, 1, freep, attributes, error);
122 ZIP_EXTERN zip_source_t *
123 zip_source_buffer_fragment(zip_t *za, const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep) {
128 return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, &za->error);
132 ZIP_EXTERN zip_source_t *
133 zip_source_buffer_fragment_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_error_t *error) {
134 return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, error);
138 zip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error) {
139 struct read_data *ctx;
143 if (fragments == NULL && nfragments > 0) {
144 zip_error_set(error, ZIP_ER_INVAL, 0);
148 if ((buffer = buffer_new(fragments, nfragments, freep, error)) == NULL) {
152 if ((ctx = (struct read_data *)malloc(sizeof(*ctx))) == NULL) {
153 zip_error_set(error, ZIP_ER_MEMORY, 0);
160 ctx->mtime = time(NULL);
162 memcpy(&ctx->attributes, attributes, sizeof(ctx->attributes));
165 zip_file_attributes_init(&ctx->attributes);
167 zip_error_init(&ctx->error);
169 if ((zs = zip_source_function_create(read_data, ctx, error)) == NULL) {
170 buffer_free(ctx->in);
180 zip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes) {
181 return zip_source_buffer_with_attributes_create(data, len, freep, attributes, &za->error);
185 read_data(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
186 struct read_data *ctx = (struct read_data *)state;
189 case ZIP_SOURCE_BEGIN_WRITE:
190 if ((ctx->out = buffer_new(NULL, 0, 0, &ctx->error)) == NULL) {
193 ctx->out->offset = 0;
194 ctx->out->current_fragment = 0;
197 case ZIP_SOURCE_BEGIN_WRITE_CLONING:
198 if ((ctx->out = buffer_clone(ctx->in, len, &ctx->error)) == NULL) {
201 ctx->out->offset = len;
202 ctx->out->current_fragment = ctx->out->nfragments;
205 case ZIP_SOURCE_CLOSE:
208 case ZIP_SOURCE_COMMIT_WRITE:
209 buffer_free(ctx->in);
214 case ZIP_SOURCE_ERROR:
215 return zip_error_to_data(&ctx->error, data, len);
217 case ZIP_SOURCE_FREE:
218 buffer_free(ctx->in);
219 buffer_free(ctx->out);
223 case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {
224 if (len < sizeof(ctx->attributes)) {
225 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
229 memcpy(data, &ctx->attributes, sizeof(ctx->attributes));
231 return sizeof(ctx->attributes);
234 case ZIP_SOURCE_OPEN:
236 ctx->in->current_fragment = 0;
239 case ZIP_SOURCE_READ:
240 if (len > ZIP_INT64_MAX) {
241 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
244 return buffer_read(ctx->in, data, len);
246 case ZIP_SOURCE_REMOVE: {
247 buffer_t *empty = buffer_new(NULL, 0, 0, &ctx->error);
252 buffer_free(ctx->in);
257 case ZIP_SOURCE_ROLLBACK_WRITE:
258 buffer_free(ctx->out);
262 case ZIP_SOURCE_SEEK:
263 return buffer_seek(ctx->in, data, len, &ctx->error);
265 case ZIP_SOURCE_SEEK_WRITE:
266 return buffer_seek(ctx->out, data, len, &ctx->error);
268 case ZIP_SOURCE_STAT: {
271 if (len < sizeof(*st)) {
272 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
276 st = (zip_stat_t *)data;
279 st->mtime = ctx->mtime;
280 st->size = ctx->in->size;
281 st->comp_size = st->size;
282 st->comp_method = ZIP_CM_STORE;
283 st->encryption_method = ZIP_EM_NONE;
284 st->valid = ZIP_STAT_MTIME | ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD;
289 case ZIP_SOURCE_SUPPORTS:
290 return zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, 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_BEGIN_WRITE_CLONING, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, -1);
292 case ZIP_SOURCE_TELL:
293 if (ctx->in->offset > ZIP_INT64_MAX) {
294 zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW);
297 return (zip_int64_t)ctx->in->offset;
300 case ZIP_SOURCE_TELL_WRITE:
301 if (ctx->out->offset > ZIP_INT64_MAX) {
302 zip_error_set(&ctx->error, ZIP_ER_TELL, EOVERFLOW);
305 return (zip_int64_t)ctx->out->offset;
307 case ZIP_SOURCE_WRITE:
308 if (len > ZIP_INT64_MAX) {
309 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
312 return buffer_write(ctx->out, data, len, &ctx->error);
315 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
322 buffer_clone(buffer_t *buffer, zip_uint64_t offset, zip_error_t *error) {
323 zip_uint64_t fragment, fragment_offset, waste;
327 return buffer_new(NULL, 0, 1, error);
330 if (offset > buffer->size) {
331 zip_error_set(error, ZIP_ER_INVAL, 0);
334 if (buffer->shared_buffer != NULL) {
335 zip_error_set(error, ZIP_ER_INUSE, 0);
339 fragment = buffer_find_fragment(buffer, offset);
340 fragment_offset = offset - buffer->fragment_offsets[fragment];
342 if (fragment_offset == 0) {
344 fragment_offset = buffer->fragments[fragment].length;
347 waste = buffer->fragments[fragment].length - fragment_offset;
348 if (waste > offset) {
349 zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
353 if ((clone = buffer_new(buffer->fragments, fragment + 1, 0, error)) == NULL) {
357 #ifndef __clang_analyzer__
358 /* clone->fragments can't be null, since it was created with at least one fragment */
359 clone->fragments[clone->nfragments - 1].length = fragment_offset;
361 clone->fragment_offsets[clone->nfragments] = offset;
362 clone->size = offset;
364 clone->first_owned_fragment = ZIP_MIN(buffer->first_owned_fragment, clone->nfragments);
366 buffer->shared_buffer = clone;
367 clone->shared_buffer = buffer;
368 buffer->shared_fragments = clone->nfragments;
369 clone->shared_fragments = fragment + 1;
376 buffer_find_fragment(const buffer_t *buffer, zip_uint64_t offset) {
377 zip_uint64_t low, high, mid;
380 high = buffer->nfragments - 1;
383 mid = (high - low) / 2 + low;
384 if (buffer->fragment_offsets[mid] > offset) {
387 else if (mid == buffer->nfragments || buffer->fragment_offsets[mid + 1] > offset) {
400 buffer_free(buffer_t *buffer) {
403 if (buffer == NULL) {
407 if (buffer->shared_buffer != NULL) {
408 buffer->shared_buffer->shared_buffer = NULL;
409 buffer->shared_buffer->shared_fragments = 0;
411 buffer->first_owned_fragment = ZIP_MAX(buffer->first_owned_fragment, buffer->shared_fragments);
414 for (i = buffer->first_owned_fragment; i < buffer->nfragments; i++) {
415 free(buffer->fragments[i].data);
417 free(buffer->fragments);
418 free(buffer->fragment_offsets);
424 buffer_grow_fragments(buffer_t *buffer, zip_uint64_t capacity, zip_error_t *error) {
425 zip_buffer_fragment_t *fragments;
426 zip_uint64_t *offsets;
428 if (capacity < buffer->fragments_capacity) {
432 if ((fragments = realloc(buffer->fragments, sizeof(buffer->fragments[0]) * capacity)) == NULL) {
433 zip_error_set(error, ZIP_ER_MEMORY, 0);
436 buffer->fragments = fragments;
437 if ((offsets = realloc(buffer->fragment_offsets, sizeof(buffer->fragment_offsets[0]) * (capacity + 1))) == NULL) {
438 zip_error_set(error, ZIP_ER_MEMORY, 0);
441 buffer->fragment_offsets = offsets;
442 buffer->fragments_capacity = capacity;
449 buffer_new(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int free_data, zip_error_t *error) {
452 if ((buffer = malloc(sizeof(*buffer))) == NULL) {
457 buffer->first_owned_fragment = 0;
459 buffer->fragments = NULL;
460 buffer->fragment_offsets = NULL;
461 buffer->nfragments = 0;
462 buffer->fragments_capacity = 0;
463 buffer->shared_buffer = NULL;
464 buffer->shared_fragments = 0;
466 if (nfragments == 0) {
467 if ((buffer->fragment_offsets = malloc(sizeof(buffer->fragment_offsets[0]))) == NULL) {
469 zip_error_set(error, ZIP_ER_MEMORY, 0);
472 buffer->fragment_offsets[0] = 0;
475 zip_uint64_t i, j, offset;
477 if (!buffer_grow_fragments(buffer, nfragments, NULL)) {
478 zip_error_set(error, ZIP_ER_MEMORY, 0);
484 for (i = 0, j = 0; i < nfragments; i++) {
485 if (fragments[i].length == 0) {
488 if (fragments[i].data == NULL) {
489 zip_error_set(error, ZIP_ER_INVAL, 0);
493 buffer->fragments[j].data = fragments[i].data;
494 buffer->fragments[j].length = fragments[i].length;
495 buffer->fragment_offsets[i] = offset;
496 offset += fragments[i].length;
499 buffer->nfragments = j;
500 buffer->first_owned_fragment = free_data ? 0 : buffer->nfragments;
501 buffer->fragment_offsets[buffer->nfragments] = offset;
502 buffer->size = offset;
509 buffer_read(buffer_t *buffer, zip_uint8_t *data, zip_uint64_t length) {
510 zip_uint64_t n, i, fragment_offset;
512 length = ZIP_MIN(length, buffer->size - buffer->offset);
517 if (length > ZIP_INT64_MAX) {
521 i = buffer->current_fragment;
522 fragment_offset = buffer->offset - buffer->fragment_offsets[i];
525 zip_uint64_t left = ZIP_MIN(length - n, buffer->fragments[i].length - fragment_offset);
527 memcpy(data + n, buffer->fragments[i].data + fragment_offset, left);
529 if (left == buffer->fragments[i].length - fragment_offset) {
537 buffer->current_fragment = i;
538 return (zip_int64_t)n;
543 buffer_seek(buffer_t *buffer, void *data, zip_uint64_t len, zip_error_t *error) {
544 zip_int64_t new_offset = zip_source_seek_compute_offset(buffer->offset, buffer->size, data, len, error);
546 if (new_offset < 0) {
550 buffer->offset = (zip_uint64_t)new_offset;
551 buffer->current_fragment = buffer_find_fragment(buffer, buffer->offset);
557 buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_uint64_t length, zip_error_t *error) {
558 zip_uint64_t n, i, fragment_offset, capacity;
560 if (buffer->offset + length + WRITE_FRAGMENT_SIZE - 1 < length) {
561 zip_error_set(error, ZIP_ER_INVAL, 0);
565 /* grow buffer if needed */
566 capacity = buffer_capacity(buffer);
567 if (buffer->offset + length > capacity) {
568 zip_uint64_t needed_fragments = buffer->nfragments + (length - (capacity - buffer->offset) + WRITE_FRAGMENT_SIZE - 1) / WRITE_FRAGMENT_SIZE;
570 if (needed_fragments > buffer->fragments_capacity) {
571 zip_uint64_t new_capacity = buffer->fragments_capacity;
573 if (new_capacity == 0) {
576 while (new_capacity < needed_fragments) {
580 if (!buffer_grow_fragments(buffer, new_capacity, error)) {
581 zip_error_set(error, ZIP_ER_MEMORY, 0);
586 while (buffer->nfragments < needed_fragments) {
587 if ((buffer->fragments[buffer->nfragments].data = malloc(WRITE_FRAGMENT_SIZE)) == NULL) {
588 zip_error_set(error, ZIP_ER_MEMORY, 0);
591 buffer->fragments[buffer->nfragments].length = WRITE_FRAGMENT_SIZE;
592 buffer->nfragments++;
593 capacity += WRITE_FRAGMENT_SIZE;
594 buffer->fragment_offsets[buffer->nfragments] = capacity;
598 i = buffer->current_fragment;
599 fragment_offset = buffer->offset - buffer->fragment_offsets[i];
602 zip_uint64_t left = ZIP_MIN(length - n, buffer->fragments[i].length - fragment_offset);
604 memcpy(buffer->fragments[i].data + fragment_offset, data + n, left);
606 if (left == buffer->fragments[i].length - fragment_offset) {
614 buffer->current_fragment = i;
615 if (buffer->offset > buffer->size) {
616 buffer->size = buffer->offset;
619 return (zip_int64_t)n;