2 * Copyright (c) 2011, Google Inc.
14 typedef int (*open_istream_fn
)(struct git_istream
*,
16 const unsigned char *,
18 typedef int (*close_istream_fn
)(struct git_istream
*);
19 typedef ssize_t (*read_istream_fn
)(struct git_istream
*, char *, size_t);
22 close_istream_fn close
;
26 #define open_method_decl(name) \
27 int open_istream_ ##name \
28 (struct git_istream *st, struct object_info *oi, \
29 const unsigned char *sha1, \
30 enum object_type *type)
32 #define close_method_decl(name) \
33 int close_istream_ ##name \
34 (struct git_istream *st)
36 #define read_method_decl(name) \
37 ssize_t read_istream_ ##name \
38 (struct git_istream *st, char *buf, size_t sz)
40 /* forward declaration */
41 static open_method_decl(incore
);
42 static open_method_decl(loose
);
43 static open_method_decl(pack_non_delta
);
45 static open_istream_fn open_istream_tbl
[] = {
48 open_istream_pack_non_delta
,
52 const struct stream_vtbl
*vtbl
;
53 unsigned long size
; /* inflated size of full object */
55 enum { z_unused
, z_used
, z_done
, z_error
} z_state
;
59 char *buf
; /* from read_object() */
60 unsigned long read_ptr
;
65 unsigned long mapsize
;
72 struct packed_git
*pack
;
78 int close_istream(struct git_istream
*st
)
80 return st
->vtbl
->close(st
);
83 ssize_t
read_istream(struct git_istream
*st
, char *buf
, size_t sz
)
85 return st
->vtbl
->read(st
, buf
, sz
);
88 static enum input_source
istream_source(const unsigned char *sha1
,
89 enum object_type
*type
,
90 struct object_info
*oi
)
96 status
= sha1_object_info_extended(sha1
, oi
);
101 switch (oi
->whence
) {
105 if (!oi
->u
.packed
.is_delta
&& big_file_threshold
<= size
)
106 return pack_non_delta
;
113 struct git_istream
*open_istream(const unsigned char *sha1
,
114 enum object_type
*type
,
117 struct git_istream
*st
;
118 struct object_info oi
;
119 const unsigned char *real
= lookup_replace_object(sha1
);
120 enum input_source src
= istream_source(real
, type
, &oi
);
125 st
= xmalloc(sizeof(*st
));
126 if (open_istream_tbl
[src
](st
, &oi
, real
, type
)) {
127 if (open_istream_incore(st
, &oi
, real
, type
)) {
137 /*****************************************************************
141 *****************************************************************/
143 static void close_deflated_stream(struct git_istream
*st
)
145 if (st
->z_state
== z_used
)
146 git_inflate_end(&st
->z
);
150 /*****************************************************************
152 * Loose object stream
154 *****************************************************************/
156 static read_method_decl(loose
)
158 size_t total_read
= 0;
160 switch (st
->z_state
) {
169 if (st
->u
.loose
.hdr_used
< st
->u
.loose
.hdr_avail
) {
170 size_t to_copy
= st
->u
.loose
.hdr_avail
- st
->u
.loose
.hdr_used
;
173 memcpy(buf
, st
->u
.loose
.hdr
+ st
->u
.loose
.hdr_used
, to_copy
);
174 st
->u
.loose
.hdr_used
+= to_copy
;
175 total_read
+= to_copy
;
178 while (total_read
< sz
) {
181 st
->z
.next_out
= (unsigned char *)buf
+ total_read
;
182 st
->z
.avail_out
= sz
- total_read
;
183 status
= git_inflate(&st
->z
, Z_FINISH
);
185 total_read
= st
->z
.next_out
- (unsigned char *)buf
;
187 if (status
== Z_STREAM_END
) {
188 git_inflate_end(&st
->z
);
189 st
->z_state
= z_done
;
192 if (status
!= Z_OK
&& status
!= Z_BUF_ERROR
) {
193 git_inflate_end(&st
->z
);
194 st
->z_state
= z_error
;
201 static close_method_decl(loose
)
203 close_deflated_stream(st
);
204 munmap(st
->u
.loose
.mapped
, st
->u
.loose
.mapsize
);
208 static struct stream_vtbl loose_vtbl
= {
213 static open_method_decl(loose
)
215 st
->u
.loose
.mapped
= map_sha1_file(sha1
, &st
->u
.loose
.mapsize
);
216 if (!st
->u
.loose
.mapped
)
218 if (unpack_sha1_header(&st
->z
,
222 sizeof(st
->u
.loose
.hdr
)) < 0) {
223 git_inflate_end(&st
->z
);
224 munmap(st
->u
.loose
.mapped
, st
->u
.loose
.mapsize
);
228 parse_sha1_header(st
->u
.loose
.hdr
, &st
->size
);
229 st
->u
.loose
.hdr_used
= strlen(st
->u
.loose
.hdr
) + 1;
230 st
->u
.loose
.hdr_avail
= st
->z
.total_out
;
231 st
->z_state
= z_used
;
233 st
->vtbl
= &loose_vtbl
;
238 /*****************************************************************
240 * Non-delta packed object stream
242 *****************************************************************/
244 static read_method_decl(pack_non_delta
)
246 size_t total_read
= 0;
248 switch (st
->z_state
) {
250 memset(&st
->z
, 0, sizeof(st
->z
));
251 git_inflate_init(&st
->z
);
252 st
->z_state
= z_used
;
262 while (total_read
< sz
) {
264 struct pack_window
*window
= NULL
;
265 unsigned char *mapped
;
267 mapped
= use_pack(st
->u
.in_pack
.pack
, &window
,
268 st
->u
.in_pack
.pos
, &st
->z
.avail_in
);
270 st
->z
.next_out
= (unsigned char *)buf
+ total_read
;
271 st
->z
.avail_out
= sz
- total_read
;
272 st
->z
.next_in
= mapped
;
273 status
= git_inflate(&st
->z
, Z_FINISH
);
275 st
->u
.in_pack
.pos
+= st
->z
.next_in
- mapped
;
276 total_read
= st
->z
.next_out
- (unsigned char *)buf
;
279 if (status
== Z_STREAM_END
) {
280 git_inflate_end(&st
->z
);
281 st
->z_state
= z_done
;
284 if (status
!= Z_OK
&& status
!= Z_BUF_ERROR
) {
285 git_inflate_end(&st
->z
);
286 st
->z_state
= z_error
;
293 static close_method_decl(pack_non_delta
)
295 close_deflated_stream(st
);
299 static struct stream_vtbl pack_non_delta_vtbl
= {
300 close_istream_pack_non_delta
,
301 read_istream_pack_non_delta
,
304 static open_method_decl(pack_non_delta
)
306 struct pack_window
*window
;
307 enum object_type in_pack_type
;
309 st
->u
.in_pack
.pack
= oi
->u
.packed
.pack
;
310 st
->u
.in_pack
.pos
= oi
->u
.packed
.offset
;
313 in_pack_type
= unpack_object_header(st
->u
.in_pack
.pack
,
318 switch (in_pack_type
) {
320 return -1; /* we do not do deltas for now */
327 st
->z_state
= z_unused
;
328 st
->vtbl
= &pack_non_delta_vtbl
;
333 /*****************************************************************
337 *****************************************************************/
339 static close_method_decl(incore
)
341 free(st
->u
.incore
.buf
);
345 static read_method_decl(incore
)
347 size_t read_size
= sz
;
348 size_t remainder
= st
->size
- st
->u
.incore
.read_ptr
;
350 if (remainder
<= read_size
)
351 read_size
= remainder
;
353 memcpy(buf
, st
->u
.incore
.buf
+ st
->u
.incore
.read_ptr
, read_size
);
354 st
->u
.incore
.read_ptr
+= read_size
;
359 static struct stream_vtbl incore_vtbl
= {
360 close_istream_incore
,
364 static open_method_decl(incore
)
366 st
->u
.incore
.buf
= read_sha1_file_extended(sha1
, type
, &st
->size
, 0);
367 st
->u
.incore
.read_ptr
= 0;
368 st
->vtbl
= &incore_vtbl
;
370 return st
->u
.incore
.buf
? 0 : -1;