static zip_int64_t crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct crc_context *ctx; zip_int64_t n; ctx = (struct crc_context *)_ctx; switch (cmd) { case ZIP_SOURCE_OPEN: ctx->position = 0; return 0; case ZIP_SOURCE_READ: if ((n = zip_source_read(src, data, len)) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } if (n == 0) { 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 ((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 if (!ctx->crc_complete && ctx->position <= ctx->crc_position) { zip_uint64_t 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->position += (zip_uint64_t)n; return n; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; if (ctx->crc_complete) { /* TODO: Set comp_size, comp_method, encryption_method? After all, this only works for uncompressed data. */ st->size = ctx->size; st->crc = ctx->crc; st->comp_size = ctx->size; st->comp_method = ZIP_CM_STORE; st->encryption_method = ZIP_EM_NONE; st->valid |= ZIP_STAT_SIZE|ZIP_STAT_CRC|ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD|ZIP_STAT_ENCRYPTION_METHOD;; } return 0; } case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: free(ctx); return 0; case ZIP_SOURCE_SUPPORTS: { 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_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); zip_int64_t new_position; 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); return -1; } }
static zip_int64_t crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct crc_context *ctx; zip_int64_t n; ctx = (struct crc_context *)_ctx; switch (cmd) { case ZIP_SOURCE_OPEN: ctx->eof = 0; ctx->crc = (zip_uint32_t)crc32(0, NULL, 0); ctx->size = 0; return 0; case ZIP_SOURCE_READ: if (ctx->eof || len == 0) return 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 (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; } } } else { zip_uint64_t i, nn; for (i=0; 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->size += (zip_uint64_t)n; } return n; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; if (ctx->eof) { /* TODO: Set comp_size, comp_method, encryption_method? After all, this only works for uncompressed data. */ st->size = ctx->size; st->crc = ctx->crc; st->comp_size = ctx->size; st->comp_method = ZIP_CM_STORE; st->encryption_method = ZIP_EM_NONE; st->valid |= ZIP_STAT_SIZE|ZIP_STAT_CRC|ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD|ZIP_STAT_ENCRYPTION_METHOD;; } return 0; } case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: free(ctx); 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); default: zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); return -1; } }