static int copy_source(struct zip *za, struct zip_source *src, FILE *ft) { char buf[BUFSIZE]; zip_int64_t n; int ret; if (zip_source_open(src) < 0) { _zip_error_set_from_source(&za->error, src); return -1; } ret = 0; while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) { if (fwrite(buf, 1, (size_t)n, ft) != (size_t)n) { _zip_error_set(&za->error, ZIP_ER_WRITE, errno); ret = -1; break; } } if (n < 0) { if (ret == 0) _zip_error_set_from_source(&za->error, src); ret = -1; } zip_source_close(src); return ret; }
static int copy_source(zip_t *za, zip_source_t *src) { zip_uint8_t buf[BUFSIZE]; zip_int64_t n; int ret; if (zip_source_open(src) < 0) { _zip_error_set_from_source(&za->error, src); return -1; } ret = 0; while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) { if (_zip_write(za, buf, (zip_uint64_t)n) < 0) { ret = -1; break; } } if (n < 0) { _zip_error_set_from_source(&za->error, src); ret = -1; } zip_source_close(src); return ret; }
zip_fread(struct zip_file *zf, void *outbuf, zip_uint64_t toread) { zip_int64_t n; if (!zf) return -1; if (zf->error.zip_err != 0) return -1; if (toread > ZIP_INT64_MAX) { _zip_error_set(&zf->error, ZIP_ER_INVAL, 0); return -1; } if ((zf->eof) || (toread == 0)) return 0; if ((n=zip_source_read(zf->src, outbuf, toread)) < 0) { _zip_error_set_from_source(&zf->error, zf->src); return -1; } return n; }
static int decrypt_header(zip_source_t *src, struct winzip_aes *ctx) { zip_uint8_t header[MAX_HEADER_LENGTH]; zip_uint8_t password_verification[PWD_VER_LENGTH]; zip_uint8_t headerlen; zip_int64_t n; headerlen = PWD_VER_LENGTH + salt_length[ctx->mode]; if ((n=zip_source_read(src, header, headerlen)) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } if (n != headerlen) { zip_error_set(&ctx->error, ZIP_ER_EOF, 0); return -1; } if (_zip_fcrypt_init(ctx->mode, ctx->password, strlen(ctx->password), header, password_verification, &ctx->fcrypt_ctx) != 0) { zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0); return -1; } if (memcmp(password_verification, header + salt_length[ctx->mode], PWD_VER_LENGTH) != 0) { zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0); return -1; } return 0; }
static bool verify_hmac(zip_source_t *src, struct winzip_aes *ctx) { unsigned char computed[HMAC_LENGTH], from_file[HMAC_LENGTH]; if (zip_source_read(src, from_file, HMAC_LENGTH) < HMAC_LENGTH) { _zip_error_set_from_source(&ctx->error, src); return false; } _zip_fcrypt_end(computed, &ctx->fcrypt_ctx); if (memcmp(from_file, computed, HMAC_LENGTH) != 0) { zip_error_set(&ctx->error, ZIP_ER_CRC, 0); return false; } return true; }
int main() { zip_source_t *zsrc = loadFromFile(); if (!zsrc) return 1; fprintf(stderr, "zip_open_from_source...\n"); zip_error_t error; zip_error_init(&error); zip_t *archive = zip_open_from_source(zsrc, 0, &error); if (!archive) return 2; zip_error_fini(&error); show(archive, "after zip_open_from_source"); const char *name = "y.txt"; zip_flags_t flags = 0; zip_source_t *otherZsrc = zip_source_buffer_create("hello", 5, 0, &error); fprintf(stderr, "zip_file_add...\n"); zip_int64_t i = zip_file_add(archive, name, otherZsrc, flags); fprintf(stderr, "zip_file_add(): i=%lld\n", i); // show(archive, "after zip_file_add"); zip_source_keep(zsrc); int ret; ret = zip_close(archive); // print to stdout zip_stat_t zst; ret = zip_source_stat(zsrc, &zst); fprintf(stderr, "zip_source_stat: ret=%d, zst.size=%d\n", ret, zst.size); ret = zip_source_open(zsrc); fprintf(stderr, "zip_source_open: ret=%d\n", ret); unsigned char data[10000]; zip_uint64_t n = zip_source_read(zsrc, data, sizeof(data)); fprintf(stderr, "zip_source_read: n=%d\n", n); write(1, data, n); // print to stdout }
int _zip_read(zip_source_t *src, zip_uint8_t *b, zip_uint64_t length, zip_error_t *error) { zip_int64_t n; if (length > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_INTERNAL, 0); return -1; } if ((n = zip_source_read(src, b, length)) < 0) { _zip_error_set_from_source(error, src); return -1; } if (n < (zip_int64_t)length) { zip_error_set(error, ZIP_ER_EOF, 0); return -1; } return 0; }
int _zip_filerange_crc(zip_source_t *src, zip_uint64_t start, zip_uint64_t len, uLong *crcp, zip_error_t *error) { Bytef buf[BUFSIZE]; zip_int64_t n; *crcp = crc32(0L, Z_NULL, 0); if (start > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_SEEK, EFBIG); return -1; } if (zip_source_seek(src, (zip_int64_t)start, SEEK_SET) != 0) { _zip_error_set_from_source(error, src); return -1; } while (len > 0) { n = (zip_int64_t)(len > BUFSIZE ? BUFSIZE : len); if ((n = zip_source_read(src, buf, (zip_uint64_t)n)) < 0) { _zip_error_set_from_source(error, src); return -1; } if (n == 0) { zip_error_set(error, ZIP_ER_EOF, 0); return -1; } *crcp = crc32(*crcp, buf, (uInt)n); len -= (zip_uint64_t)n; } return 0; }
static zip_int64_t compress_read(zip_source_t *src, struct deflate *ctx, void *data, zip_uint64_t len) { int end, ret; zip_int64_t n; zip_uint64_t out_offset; uInt out_len; if (zip_error_code_zip(&ctx->error) != ZIP_ER_OK) return -1; if (len == 0 || ctx->is_stored) { return 0; } out_offset = 0; out_len = (uInt)ZIP_MIN(UINT_MAX, len); ctx->zstr.next_out = (Bytef *)data; ctx->zstr.avail_out = out_len; end = 0; while (!end) { ret = deflate(&ctx->zstr, ctx->eof ? Z_FINISH : 0); switch (ret) { case Z_STREAM_END: if (ctx->can_store && ctx->zstr.total_in <= ctx->zstr.total_out) { ctx->is_stored = true; ctx->size = ctx->zstr.total_in; memcpy(data, ctx->buffer, ctx->size); return (zip_int64_t)ctx->size; } /* fallthrough */ case Z_OK: /* all ok */ if (ctx->zstr.avail_out == 0) { out_offset += out_len; if (out_offset < len) { out_len = (uInt)ZIP_MIN(UINT_MAX, len-out_offset); ctx->zstr.next_out = (Bytef *)data+out_offset; ctx->zstr.avail_out = out_len; } else { ctx->can_store = false; end = 1; } } else if (ctx->eof && ctx->zstr.avail_in == 0) end = 1; break; case Z_BUF_ERROR: if (ctx->zstr.avail_in == 0) { if (ctx->eof) { end = 1; break; } if ((n=zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) { _zip_error_set_from_source(&ctx->error, src); end = 1; break; } else if (n == 0) { ctx->eof = true; /* TODO: check against stat of src? */ ctx->size = ctx->zstr.total_in; } else { if (ctx->zstr.total_in > 0) { /* we overwrote a previously filled ctx->buffer */ ctx->can_store = false; } ctx->zstr.next_in = (Bytef *)ctx->buffer; ctx->zstr.avail_in = (uInt)n; } continue; } /* fallthrough */ case Z_NEED_DICT: case Z_DATA_ERROR: case Z_STREAM_ERROR: case Z_MEM_ERROR: zip_error_set(&ctx->error, ZIP_ER_ZLIB, ret); end = 1; break; } } if (ctx->zstr.avail_out < len) { ctx->can_store = false; return (zip_int64_t)(len - ctx->zstr.avail_out); } return (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1; }
static zip_int64_t deflate_decompress(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct deflate *ctx; zip_int64_t n; int ret; ctx = (struct deflate *)ud; switch (cmd) { case ZIP_SOURCE_OPEN: if ((n=zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } ctx->zstr.zalloc = Z_NULL; ctx->zstr.zfree = Z_NULL; ctx->zstr.opaque = NULL; ctx->zstr.next_in = (Bytef *)ctx->buffer; ctx->zstr.avail_in = (uInt)n; /* negative value to tell zlib that there is no header */ if ((ret=inflateInit2(&ctx->zstr, -MAX_WBITS)) != Z_OK) { zip_error_set(&ctx->error, ZIP_ER_ZLIB, ret); return -1; } return 0; case ZIP_SOURCE_READ: return decompress_read(src, ctx, data, len); case ZIP_SOURCE_CLOSE: inflateEnd(&ctx->zstr); return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; st->comp_method = ZIP_CM_STORE; if (st->comp_size > 0 && st->size > 0) st->comp_size = st->size; 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; } }
static zip_int64_t decompress_read(zip_source_t *src, struct deflate *ctx, void *data, zip_uint64_t len) { int end, ret; zip_int64_t n; zip_uint64_t out_offset; uInt out_len; if (zip_error_code_zip(&ctx->error) != ZIP_ER_OK) return -1; if (len == 0) return 0; out_offset = 0; out_len = (uInt)ZIP_MIN(UINT_MAX, len); ctx->zstr.next_out = (Bytef *)data; ctx->zstr.avail_out = out_len; end = 0; while (!end) { ret = inflate(&ctx->zstr, Z_SYNC_FLUSH); switch (ret) { case Z_OK: if (ctx->zstr.avail_out == 0) { out_offset += out_len; if (out_offset < len) { out_len = (uInt)ZIP_MIN(UINT_MAX, len-out_offset); ctx->zstr.next_out = (Bytef *)data+out_offset; ctx->zstr.avail_out = out_len; } else { end = 1; } } break; case Z_STREAM_END: ctx->eof = 1; end = 1; break; case Z_BUF_ERROR: if (ctx->zstr.avail_in == 0) { if (ctx->eof) { end = 1; break; } if ((n=zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) { _zip_error_set_from_source(&ctx->error, src); end = 1; break; } else if (n == 0) { ctx->eof = 1; } else { ctx->zstr.next_in = (Bytef *)ctx->buffer; ctx->zstr.avail_in = (uInt)n; } continue; } /* fallthrough */ case Z_NEED_DICT: case Z_DATA_ERROR: case Z_STREAM_ERROR: case Z_MEM_ERROR: zip_error_set(&ctx->error, ZIP_ER_ZLIB, ret); end = 1; break; } } if (ctx->zstr.avail_out < len) return (zip_int64_t)(len - ctx->zstr.avail_out); return (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1; }
static zip_int64_t window_read(struct zip_source *src, void *_ctx, void *data, zip_uint64_t len, enum zip_source_cmd cmd) { struct window *ctx; zip_int64_t ret; zip_uint64_t n, i; char b[8192]; ctx = (struct window *)_ctx; switch (cmd) { case ZIP_SOURCE_OPEN: for (n=0; n<ctx->skip; n+=(zip_uint64_t)ret) { i = (ctx->skip-n > sizeof(b) ? sizeof(b) : ctx->skip-n); if ((ret=zip_source_read(src, b, i)) < 0) return ZIP_SOURCE_ERR_LOWER; if (ret==0) { ctx->e[0] = ZIP_ER_EOF; ctx->e[1] = 0; return -1; } } return 0; case ZIP_SOURCE_READ: if (len > ctx->left) len = ctx->left; if (len <= 0) return 0; if ((ret=zip_source_read(src, data, len)) < 0) return ZIP_SOURCE_ERR_LOWER; ctx->left -= (zip_uint64_t)ret; if (ret == 0) { if (ctx->left > 0) { ctx->e[0] = ZIP_ER_EOF; ctx->e[1] = 0; return -1; } } return ret; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_STAT: { struct zip_stat *st; st = (struct zip_stat *)data; st->size = ctx->len; st->valid |= ZIP_STAT_SIZE; st->valid &= ~(ZIP_STAT_CRC|ZIP_STAT_COMP_SIZE); } return 0; case ZIP_SOURCE_ERROR: memcpy(data, ctx->e, sizeof(ctx->e)); return 0; case ZIP_SOURCE_FREE: free(ctx); return 0; default: return -1; } }
static zip_int64_t compress_read(struct zip_source *src, struct deflate *ctx, void *data, zip_uint64_t len) { int end, ret; zip_int64_t n; if (ctx->e[0] != 0) return -1; if (len == 0) return 0; ctx->zstr.next_out = (Bytef *)data; ctx->zstr.avail_out = (uInt)len; /* TODO: check for overflow */ end = 0; while (!end) { ret = deflate(&ctx->zstr, ctx->eof ? Z_FINISH : 0); switch (ret) { case Z_OK: case Z_STREAM_END: /* all ok */ if (ctx->zstr.avail_out == 0 || (ctx->eof && ctx->zstr.avail_in == 0)) end = 1; break; case Z_BUF_ERROR: if (ctx->zstr.avail_in == 0) { if (ctx->eof) { end = 1; break; } if ((n=zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) { zip_source_error(src, ctx->e, ctx->e+1); end = 1; break; } else if (n == 0) { ctx->eof = 1; ctx->size = ctx->zstr.total_in; /* TODO: check against stat of src? */ } else { ctx->zstr.next_in = (Bytef *)ctx->buffer; ctx->zstr.avail_in = (uInt)n; } continue; } /* fallthrough */ case Z_NEED_DICT: case Z_DATA_ERROR: case Z_STREAM_ERROR: case Z_MEM_ERROR: ctx->e[0] = ZIP_ER_ZLIB; ctx->e[1] = ret; end = 1; break; } } if (ctx->zstr.avail_out < len) return (zip_int64_t)(len - ctx->zstr.avail_out); return (ctx->e[0] == 0) ? 0 : -1; }
static zip_int64_t deflate_decompress(struct zip_source *src, void *ud, void *data, zip_uint64_t len, enum zip_source_cmd cmd) { struct deflate *ctx; zip_int64_t n; int ret; ctx = (struct deflate *)ud; switch (cmd) { case ZIP_SOURCE_OPEN: if ((n=zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) return ZIP_SOURCE_ERR_LOWER; ctx->zstr.zalloc = Z_NULL; ctx->zstr.zfree = Z_NULL; ctx->zstr.opaque = NULL; ctx->zstr.next_in = (Bytef *)ctx->buffer; ctx->zstr.avail_in = (uInt)n /* TODO: check for overflow */; /* negative value to tell zlib that there is no header */ if ((ret=inflateInit2(&ctx->zstr, -MAX_WBITS)) != Z_OK) { ctx->e[0] = ZIP_ER_ZLIB; ctx->e[1] = ret; return -1; } return 0; case ZIP_SOURCE_READ: return decompress_read(src, ctx, data, len); case ZIP_SOURCE_CLOSE: inflateEnd(&ctx->zstr); return 0; case ZIP_SOURCE_STAT: { struct zip_stat *st; st = (struct zip_stat *)data; st->comp_method = ZIP_CM_STORE; if (st->comp_size > 0 && st->size > 0) st->comp_size = st->size; } return 0; case ZIP_SOURCE_ERROR: if (len < sizeof(int)*2) return -1; memcpy(data, ctx->e, sizeof(int)*2); return sizeof(int)*2; case ZIP_SOURCE_FREE: /* TODO: inflateEnd if close was not called */ free(ctx); return 0; default: ctx->e[0] = ZIP_ER_INVAL; ctx->e[1] = 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->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_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); return -1; } }
static zip_int64_t winzip_aes_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct winzip_aes *ctx; zip_int64_t n; zip_uint64_t total, offset; ctx = (struct winzip_aes *)ud; switch (cmd) { case ZIP_SOURCE_OPEN: if (decrypt_header(src, ctx) < 0) { return -1; } ctx->current_position = 0; return 0; case ZIP_SOURCE_READ: if (len > ctx->data_length - ctx->current_position) { len = ctx->data_length - ctx->current_position; } if (len == 0) { if (!verify_hmac(src, ctx)) { return -1; } return 0; } if ((n=zip_source_read(src, data, len)) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } ctx->current_position += n; total = (zip_uint64_t)n; for (offset = 0; offset < total; offset += ZIP_MIN(total - offset, UINT_MAX)) { _zip_fcrypt_decrypt(data + offset, ZIP_MIN(total - offset, UINT_MAX), &ctx->fcrypt_ctx); } return n; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; st->encryption_method = ZIP_EM_NONE; st->valid |= ZIP_STAT_ENCRYPTION_METHOD; if (st->valid & ZIP_STAT_COMP_SIZE) { st->comp_size -= 12 + salt_length[ctx->mode]; } 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); case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: winzip_aes_free(ctx); return 0; default: zip_error_set(&ctx->error, ZIP_ER_INVAL, 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; } }