pack: introduce a streaming API for raw objects This allows us to take objects from the packfile as a stream instead of having to keep it all in memory.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
diff --git a/src/pack.c b/src/pack.c
index 6cb46d3..01531d6 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 9fb26b6..3355cd2 100644
--- a/src/pack.h
+++ b/src/pack.h
@@ -8,6 +8,8 @@
#ifndef INCLUDE_pack_h__
#define INCLUDE_pack_h__
+#include <zlib.h>
+
#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);