@@ -41,13 +41,27 @@ struct stream_vtbl {
4141static open_method_decl (incore );
4242static open_method_decl (loose );
4343static open_method_decl (pack_non_delta );
44+ static struct git_istream * attach_stream_filter (struct git_istream * st ,
45+ struct stream_filter * filter );
46+
4447
4548static open_istream_fn open_istream_tbl [] = {
4649 open_istream_incore ,
4750 open_istream_loose ,
4851 open_istream_pack_non_delta ,
4952};
5053
54+ #define FILTER_BUFFER (1024*16)
55+
56+ struct filtered_istream {
57+ struct git_istream * upstream ;
58+ struct stream_filter * filter ;
59+ char ibuf [FILTER_BUFFER ];
60+ char obuf [FILTER_BUFFER ];
61+ int i_end , i_ptr ;
62+ int o_end , o_ptr ;
63+ };
64+
5165struct git_istream {
5266 const struct stream_vtbl * vtbl ;
5367 unsigned long size ; /* inflated size of full object */
@@ -72,6 +86,8 @@ struct git_istream {
7286 struct packed_git * pack ;
7387 off_t pos ;
7488 } in_pack ;
89+
90+ struct filtered_istream filtered ;
7591 } u ;
7692};
7793
@@ -112,7 +128,8 @@ static enum input_source istream_source(const unsigned char *sha1,
112128
113129struct git_istream * open_istream (const unsigned char * sha1 ,
114130 enum object_type * type ,
115- unsigned long * size )
131+ unsigned long * size ,
132+ struct stream_filter * filter )
116133{
117134 struct git_istream * st ;
118135 struct object_info oi ;
@@ -129,6 +146,14 @@ struct git_istream *open_istream(const unsigned char *sha1,
129146 return NULL ;
130147 }
131148 }
149+ if (st && filter ) {
150+ /* Add "&& !is_null_stream_filter(filter)" for performance */
151+ struct git_istream * nst = attach_stream_filter (st , filter );
152+ if (!nst )
153+ close_istream (st );
154+ st = nst ;
155+ }
156+
132157 * size = st -> size ;
133158 return st ;
134159}
@@ -147,6 +172,79 @@ static void close_deflated_stream(struct git_istream *st)
147172}
148173
149174
175+ /*****************************************************************
176+ *
177+ * Filtered stream
178+ *
179+ *****************************************************************/
180+
181+ static close_method_decl (filtered )
182+ {
183+ free_stream_filter (st -> u .filtered .filter );
184+ return close_istream (st -> u .filtered .upstream );
185+ }
186+
187+ static read_method_decl (filtered )
188+ {
189+ struct filtered_istream * fs = & (st -> u .filtered );
190+ size_t filled = 0 ;
191+
192+ while (sz ) {
193+ /* do we already have filtered output? */
194+ if (fs -> o_ptr < fs -> o_end ) {
195+ size_t to_move = fs -> o_end - fs -> o_ptr ;
196+ if (sz < to_move )
197+ to_move = sz ;
198+ memcpy (buf + filled , fs -> obuf + fs -> o_ptr , to_move );
199+ fs -> o_ptr += to_move ;
200+ sz -= to_move ;
201+ filled += to_move ;
202+ continue ;
203+ }
204+ fs -> o_end = fs -> o_ptr = 0 ;
205+
206+ /* do we have anything to feed the filter with? */
207+ if (fs -> i_ptr < fs -> i_end ) {
208+ size_t to_feed = fs -> i_end - fs -> i_ptr ;
209+ size_t to_receive = FILTER_BUFFER ;
210+ if (stream_filter (fs -> filter ,
211+ fs -> ibuf + fs -> i_ptr , & to_feed ,
212+ fs -> obuf , & to_receive ))
213+ return -1 ;
214+ fs -> i_ptr = fs -> i_end - to_feed ;
215+ fs -> o_end = FILTER_BUFFER - to_receive ;
216+ continue ;
217+ }
218+ fs -> i_end = fs -> i_ptr = 0 ;
219+
220+ /* refill the input from the upstream */
221+ fs -> i_end = read_istream (fs -> upstream , fs -> ibuf , FILTER_BUFFER );
222+ if (fs -> i_end <= 0 )
223+ break ;
224+ }
225+ return filled ;
226+ }
227+
228+ static struct stream_vtbl filtered_vtbl = {
229+ close_istream_filtered ,
230+ read_istream_filtered ,
231+ };
232+
233+ static struct git_istream * attach_stream_filter (struct git_istream * st ,
234+ struct stream_filter * filter )
235+ {
236+ struct git_istream * ifs = xmalloc (sizeof (* ifs ));
237+ struct filtered_istream * fs = & (ifs -> u .filtered );
238+
239+ ifs -> vtbl = & filtered_vtbl ;
240+ fs -> upstream = st ;
241+ fs -> filter = filter ;
242+ fs -> i_end = fs -> i_ptr = 0 ;
243+ fs -> o_end = fs -> o_ptr = 0 ;
244+ ifs -> size = -1 ; /* unknown */
245+ return ifs ;
246+ }
247+
150248/*****************************************************************
151249 *
152250 * Loose object stream
0 commit comments