convert: track state in LF-to-CRLF filter
There may not be enough space to store CRLF in the output. If we don't fill the buffer, then the filter will keep getting called with the same short buffer and will loop forever. Instead, always store the CR and record whether there's a missing LF if so we store it in the output buffer the next time the function gets called. Reported-by: Henrik Grubbström <grubba@roxen.com> Signed-off-by: Carlos Martín Nieto <cmn@elego.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Carlos Martín Nieto committed
Nov 28, 2011 at 11:48 UTC
284e3d280ea84957f5bedcb302848dbdcdbb9a62
1 file changed
+37
-13
convert.c
+37
-13
@@ -876,24 +876,39 @@ int is_null_stream_filter(struct stream_filter *filter)
876
/*
877
* LF-to-CRLF filter
878
*/
879
+
880
+struct lf_to_crlf_filter {
881
+ struct stream_filter filter;
882
+ int want_lf;
883
+};
884
+
885
static int lf_to_crlf_filter_fn(struct stream_filter *filter,
886
const char *input, size_t *isize_p,
887
char *output, size_t *osize_p)
888
{
883
- size_t count;
889
+ size_t count, o = 0;
890
+ struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter;
891
+
892
+ /* Output a pending LF if we need to */
893
+ if (lf_to_crlf->want_lf) {
894
+ output[o++] = '\n';
895
+ lf_to_crlf->want_lf = 0;
896
+ }
897
898
if (!input)
886
- return 0; /* we do not keep any states */
899
+ return 0; /* We've already dealt with the state */
900
+
901
count = *isize_p;
902
if (count) {
889
- size_t i, o;
890
- for (i = o = 0; o < *osize_p && i < count; i++) {
903
+ size_t i;
904
+ for (i = 0; o < *osize_p && i < count; i++) {
905
char ch = input[i];
906
if (ch == '\n') {
893
- if (o + 1 < *osize_p)
894
- output[o++] = '\r';
895
- else
896
- break;
907
+ output[o++] = '\r';
908
+ if (o >= *osize_p) {
909
+ lf_to_crlf->want_lf = 1;
910
+ continue; /* We need to increase i */
911
+ }
912
}
913
output[o++] = ch;
914
}
@@ -904,15 +919,24 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,
919
return 0;
920
}
921
922
+static void lf_to_crlf_free_fn(struct stream_filter *filter)
923
+{
924
+ free(filter);
925
+}
926
+
927
static struct stream_filter_vtbl lf_to_crlf_vtbl = {
928
lf_to_crlf_filter_fn,
909
- null_free_fn,
929
+ lf_to_crlf_free_fn,
930
};
931
912
-static struct stream_filter lf_to_crlf_filter_singleton = {
913
- &lf_to_crlf_vtbl,
914
-};
932
+static struct stream_filter *lf_to_crlf_filter(void)
933
+{
934
+ struct lf_to_crlf_filter *lf_to_crlf = xmalloc(sizeof(*lf_to_crlf));
935
936
+ lf_to_crlf->filter.vtbl = &lf_to_crlf_vtbl;
937
+ lf_to_crlf->want_lf = 0;
938
+ return (struct stream_filter *)lf_to_crlf;
939
+}
940
941
/*
942
* Cascade filter
@@ -1194,7 +1218,7 @@ struct stream_filter *get_stream_filter(const char *path, const unsigned char *s
1218
1219
else if (output_eol(crlf_action) == EOL_CRLF &&
1220
!(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS))
1197
- filter = cascade_filter(filter, &lf_to_crlf_filter_singleton);
1221
+ filter = cascade_filter(filter, lf_to_crlf_filter());
1222
1223
return filter;
1224
}