streaming: filter cascading

This implements an internal "cascade" filter mechanism that plugs two filters in series. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed May 21, 2011 at 18:28 UTC a265a7f95e6e3ebd81df0c6813b17d61a5ab890a
1 file changed +112 -14
convert.c
+112 -14
@@ -914,6 +914,112 @@ static struct stream_filter lf_to_crlf_filter_singleton = {
914 };
915
916
917 +/*
918 + * Cascade filter
919 + */
920 +#define FILTER_BUFFER 1024
921 +struct cascade_filter {
922 + struct stream_filter filter;
923 + struct stream_filter *one;
924 + struct stream_filter *two;
925 + char buf[FILTER_BUFFER];
926 + int end, ptr;
927 +};
928 +
929 +static int cascade_filter_fn(struct stream_filter *filter,
930 + const char *input, size_t *isize_p,
931 + char *output, size_t *osize_p)
932 +{
933 + struct cascade_filter *cas = (struct cascade_filter *) filter;
934 + size_t filled = 0;
935 + size_t sz = *osize_p;
936 + size_t to_feed, remaining;
937 +
938 + /*
939 + * input -- (one) --> buf -- (two) --> output
940 + */
941 + while (filled < sz) {
942 + remaining = sz - filled;
943 +
944 + /* do we already have something to feed two with? */
945 + if (cas->ptr < cas->end) {
946 + to_feed = cas->end - cas->ptr;
947 + if (stream_filter(cas->two,
948 + cas->buf + cas->ptr, &to_feed,
949 + output + filled, &remaining))
950 + return -1;
951 + cas->ptr += (cas->end - cas->ptr) - to_feed;
952 + filled = sz - remaining;
953 + continue;
954 + }
955 +
956 + /* feed one from upstream and have it emit into our buffer */
957 + to_feed = input ? *isize_p : 0;
958 + if (input && !to_feed)
959 + break;
960 + remaining = sizeof(cas->buf);
961 + if (stream_filter(cas->one,
962 + input, &to_feed,
963 + cas->buf, &remaining))
964 + return -1;
965 + cas->end = sizeof(cas->buf) - remaining;
966 + cas->ptr = 0;
967 + if (input) {
968 + size_t fed = *isize_p - to_feed;
969 + *isize_p -= fed;
970 + input += fed;
971 + }
972 +
973 + /* do we know that we drained one completely? */
974 + if (input || cas->end)
975 + continue;
976 +
977 + /* tell two to drain; we have nothing more to give it */
978 + to_feed = 0;
979 + remaining = sz - filled;
980 + if (stream_filter(cas->two,
981 + NULL, &to_feed,
982 + output + filled, &remaining))
983 + return -1;
984 + if (remaining == (sz - filled))
985 + break; /* completely drained two */
986 + filled = sz - remaining;
987 + }
988 + *osize_p -= filled;
989 + return 0;
990 +}
991 +
992 +static void cascade_free_fn(struct stream_filter *filter)
993 +{
994 + struct cascade_filter *cas = (struct cascade_filter *)filter;
995 + free_stream_filter(cas->one);
996 + free_stream_filter(cas->two);
997 + free(filter);
998 +}
999 +
1000 +static struct stream_filter_vtbl cascade_vtbl = {
1001 + cascade_filter_fn,
1002 + cascade_free_fn,
1003 +};
1004 +
1005 +static struct stream_filter *cascade_filter(struct stream_filter *one,
1006 + struct stream_filter *two)
1007 +{
1008 + struct cascade_filter *cascade;
1009 +
1010 + if (!one || is_null_stream_filter(one))
1011 + return two;
1012 + if (!two || is_null_stream_filter(two))
1013 + return one;
1014 +
1015 + cascade = xmalloc(sizeof(*cascade));
1016 + cascade->one = one;
1017 + cascade->two = two;
1018 + cascade->end = cascade->ptr = 0;
1019 + cascade->filter.vtbl = &cascade_vtbl;
1020 + return (struct stream_filter *)cascade;
1021 +}
1022 +
1023 /*
1024 * ident filter
1025 */
@@ -1083,20 +1189,12 @@ struct stream_filter *get_stream_filter(const char *path, const unsigned char *s
1189 crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr);
1190
1191 if ((crlf_action == CRLF_BINARY) || (crlf_action == CRLF_INPUT) ||
1086 - (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE)) {
1087 - if (filter) {
1088 - free_stream_filter(filter);
1089 - return NULL;
1090 - }
1091 - return &null_filter_singleton;
1092 - } else if (output_eol(crlf_action) == EOL_CRLF &&
1093 - !(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS)) {
1094 - if (filter) {
1095 - free_stream_filter(filter);
1096 - return NULL;
1097 - }
1098 - return &lf_to_crlf_filter_singleton;
1099 - }
1192 + (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE))
1193 + filter = cascade_filter(filter, &null_filter_singleton);
1194 +
1195 + else if (output_eol(crlf_action) == EOL_CRLF &&
1196 + !(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS))
1197 + filter = cascade_filter(filter, &lf_to_crlf_filter_singleton);
1198
1199 return filter;
1200 }