diff --git a/src/pack.c b/src/pack.c index 6cb46d37b..01531d631 100644 --- a/src/pack.c +++ b/src/pack.c @@ -391,6 +391,72 @@ static void use_git_free(void *opaq, void *ptr) git__free(ptr); } +int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, git_off_t curpos) +{ + int st; + + memset(obj, 0, sizeof(git_packfile_stream)); + obj->curpos = curpos; + obj->p = p; + obj->zstream.zalloc = use_git_alloc; + obj->zstream.zfree = use_git_free; + obj->zstream.next_in = Z_NULL; + obj->zstream.next_out = Z_NULL; + st = inflateInit(&obj->zstream); + if (st != Z_OK) { + git__free(obj); + giterr_set(GITERR_ZLIB, "Failed to inflate packfile"); + return -1; + } + + return 0; +} + +ssize_t git_packfile_stream_read(git_packfile_stream *obj, void *buffer, size_t len) +{ + unsigned char *in; + size_t written; + int st; + + if (obj->done) + return 0; + + in = pack_window_open(obj->p, &obj->mw, obj->curpos, &obj->zstream.avail_in); + if (in == NULL) + return GIT_EBUFS; + + obj->zstream.next_out = buffer; + obj->zstream.avail_out = len; + obj->zstream.next_in = in; + + st = inflate(&obj->zstream, Z_SYNC_FLUSH); + git_mwindow_close(&obj->mw); + + obj->curpos += obj->zstream.next_in - in; + written = len - obj->zstream.avail_out; + + if (st != Z_OK && st != Z_STREAM_END) { + giterr_set(GITERR_ZLIB, "Failed to inflate packfile"); + return -1; + } + + if (st == Z_STREAM_END) + obj->done = 1; + + + /* If we didn't write anything out but we're not done, we need more data */ + if (!written && st != Z_STREAM_END) + return GIT_EBUFS; + + return written; + +} + +void git_packfile_stream_free(git_packfile_stream *obj) +{ + inflateEnd(&obj->zstream); +} + int packfile_unpack_compressed( git_rawobj *obj, struct git_pack_file *p, diff --git a/src/pack.h b/src/pack.h index 9fb26b6a9..3355cd21f 100644 --- a/src/pack.h +++ b/src/pack.h @@ -8,6 +8,8 @@ #ifndef INCLUDE_pack_h__ #define INCLUDE_pack_h__ +#include + #include "git2/oid.h" #include "common.h" @@ -76,6 +78,14 @@ struct git_pack_entry { struct git_pack_file *p; }; +typedef struct git_packfile_stream { + git_off_t curpos; + int done; + z_stream zstream; + struct git_pack_file *p; + git_mwindow *mw; +} git_packfile_stream; + int git_packfile_unpack_header( size_t *size_p, git_otype *type_p, @@ -92,6 +102,10 @@ int packfile_unpack_compressed( size_t size, git_otype type); +int git_packfile_stream_open(git_packfile_stream *obj, struct git_pack_file *p, git_off_t curpos); +ssize_t git_packfile_stream_read(git_packfile_stream *obj, void *buffer, size_t len); +void git_packfile_stream_free(git_packfile_stream *obj); + git_off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs, git_off_t *curpos, git_otype type, git_off_t delta_obj_offset);