summaryrefslogtreecommitdiff
path: root/ext/zip/lib/zip_source_crc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/zip/lib/zip_source_crc.c')
-rw-r--r--ext/zip/lib/zip_source_crc.c100
1 files changed, 66 insertions, 34 deletions
diff --git a/ext/zip/lib/zip_source_crc.c b/ext/zip/lib/zip_source_crc.c
index eed726616a..01f526c647 100644
--- a/ext/zip/lib/zip_source_crc.c
+++ b/ext/zip/lib/zip_source_crc.c
@@ -1,6 +1,6 @@
/*
zip_source_crc.c -- pass-through source that calculates CRC32 and size
- Copyright (C) 2009-2014 Dieter Baron and Thomas Klausner
+ Copyright (C) 2009-2016 Dieter Baron and Thomas Klausner
This file is part of libzip, a library to manipulate ZIP archives.
The authors can be contacted at <libzip@nih.at>
@@ -39,10 +39,12 @@
#include "zipint.h"
struct crc_context {
- int eof;
- int validate;
+ int validate; /* whether to check CRC on EOF and return error on mismatch */
+ int crc_complete; /* whether CRC was computed for complete file */
zip_error_t error;
zip_uint64_t size;
+ zip_uint64_t position; /* current reading position */
+ zip_uint64_t crc_position; /* how far we've computed the CRC */
zip_uint32_t crc;
};
@@ -64,12 +66,13 @@ zip_source_crc(zip_t *za, zip_source_t *src, int validate)
return NULL;
}
- ctx->eof = 0;
- ctx->validate = validate;
zip_error_init(&ctx->error);
+ ctx->validate = validate;
+ ctx->crc_complete = 0;
+ ctx->crc_position = 0;
+ ctx->crc = (zip_uint32_t)crc32(0, NULL, 0);
ctx->size = 0;
- ctx->crc = 0;
-
+
return zip_source_layered(za, src, crc_read, ctx);
}
@@ -84,51 +87,50 @@ crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source
switch (cmd) {
case ZIP_SOURCE_OPEN:
- ctx->eof = 0;
- ctx->crc = (zip_uint32_t)crc32(0, NULL, 0);
- ctx->size = 0;
-
+ ctx->position = 0;
return 0;
case ZIP_SOURCE_READ:
- if (ctx->eof || len == 0)
- return 0;
-
- if ((n=zip_source_read(src, data, len)) < 0) {
+ if ((n = zip_source_read(src, data, len)) < 0) {
_zip_error_set_from_source(&ctx->error, src);
return -1;
}
if (n == 0) {
- ctx->eof = 1;
- if (ctx->validate) {
- struct zip_stat st;
+ if (ctx->crc_position == ctx->position) {
+ ctx->crc_complete = 1;
+ ctx->size = ctx->position;
+
+ if (ctx->validate) {
+ struct zip_stat st;
- if (zip_source_stat(src, &st) < 0) {
- _zip_error_set_from_source(&ctx->error, src);
- return -1;
- }
+ if (zip_source_stat(src, &st) < 0) {
+ _zip_error_set_from_source(&ctx->error, src);
+ return -1;
+ }
- if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) {
- zip_error_set(&ctx->error, ZIP_ER_CRC, 0);
- return -1;
- }
- if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) {
- zip_error_set(&ctx->error, ZIP_ER_INCONS, 0);
- return -1;
+ if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) {
+ zip_error_set(&ctx->error, ZIP_ER_CRC, 0);
+ return -1;
+ }
+ if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) {
+ zip_error_set(&ctx->error, ZIP_ER_INCONS, 0);
+ return -1;
+ }
}
}
}
- else {
+ else if (!ctx->crc_complete && ctx->position <= ctx->crc_position) {
zip_uint64_t i, nn;
- for (i=0; i < (zip_uint64_t)n; i += nn) {
+ for (i = ctx->crc_position - ctx->position; i < (zip_uint64_t)n; i += nn) {
nn = ZIP_MIN(UINT_MAX, (zip_uint64_t)n-i);
ctx->crc = (zip_uint32_t)crc32(ctx->crc, (const Bytef *)data+i, (uInt)nn);
+ ctx->crc_position += nn;
}
- ctx->size += (zip_uint64_t)n;
}
+ ctx->position += (zip_uint64_t)n;
return n;
case ZIP_SOURCE_CLOSE:
@@ -140,7 +142,7 @@ crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source
st = (zip_stat_t *)data;
- if (ctx->eof) {
+ if (ctx->crc_complete) {
/* TODO: Set comp_size, comp_method, encryption_method?
After all, this only works for uncompressed data. */
st->size = ctx->size;
@@ -161,7 +163,37 @@ crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source
return 0;
case ZIP_SOURCE_SUPPORTS:
- return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, -1);
+ {
+ zip_int64_t mask = zip_source_supports(src);
+
+ if (mask < 0) {
+ _zip_error_set_from_source(&ctx->error, src);
+ return -1;
+ }
+
+ return mask & ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, -1);
+ }
+
+ case ZIP_SOURCE_SEEK:
+ {
+ zip_int64_t new_position;
+ zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
+
+ if (args == NULL) {
+ return -1;
+ }
+ if (zip_source_seek(src, args->offset, args->whence) < 0 || (new_position = zip_source_tell(src)) < 0) {
+ _zip_error_set_from_source(&ctx->error, src);
+ return -1;
+ }
+
+ ctx->position = (zip_uint64_t)new_position;
+
+ return 0;
+ }
+
+ case ZIP_SOURCE_TELL:
+ return (zip_int64_t)ctx->position;
default:
zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);