@@ -879,7 +879,8 @@ int is_null_stream_filter(struct stream_filter *filter)
879879
880880struct lf_to_crlf_filter {
881881 struct stream_filter filter ;
882- unsigned want_lf :1 ;
882+ unsigned has_held :1 ;
883+ char held ;
883884};
884885
885886static int lf_to_crlf_filter_fn (struct stream_filter * filter ,
@@ -889,10 +890,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,
889890 size_t count , o = 0 ;
890891 struct lf_to_crlf_filter * lf_to_crlf = (struct lf_to_crlf_filter * )filter ;
891892
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 ;
893+ /*
894+ * We may be holding onto the CR to see if it is followed by a
895+ * LF, in which case we would need to go to the main loop.
896+ * Otherwise, just emit it to the output stream.
897+ */
898+ if (lf_to_crlf -> has_held && (lf_to_crlf -> held != '\r' || !input )) {
899+ output [o ++ ] = lf_to_crlf -> held ;
900+ lf_to_crlf -> has_held = 0 ;
896901 }
897902
898903 /* We are told to drain */
@@ -902,22 +907,57 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,
902907 }
903908
904909 count = * isize_p ;
905- if (count ) {
910+ if (count || lf_to_crlf -> has_held ) {
906911 size_t i ;
912+ int was_cr = 0 ;
913+
914+ if (lf_to_crlf -> has_held ) {
915+ was_cr = 1 ;
916+ lf_to_crlf -> has_held = 0 ;
917+ }
918+
907919 for (i = 0 ; o < * osize_p && i < count ; i ++ ) {
908920 char ch = input [i ];
921+
909922 if (ch == '\n' ) {
910923 output [o ++ ] = '\r' ;
911- if (o >= * osize_p ) {
912- lf_to_crlf -> want_lf = 1 ;
913- continue ; /* We need to increase i */
914- }
924+ } else if (was_cr ) {
925+ /*
926+ * Previous round saw CR and it is not followed
927+ * by a LF; emit the CR before processing the
928+ * current character.
929+ */
930+ output [o ++ ] = '\r' ;
915931 }
932+
933+ /*
934+ * We may have consumed the last output slot,
935+ * in which case we need to break out of this
936+ * loop; hold the current character before
937+ * returning.
938+ */
939+ if (* osize_p <= o ) {
940+ lf_to_crlf -> has_held = 1 ;
941+ lf_to_crlf -> held = ch ;
942+ continue ; /* break but increment i */
943+ }
944+
945+ if (ch == '\r' ) {
946+ was_cr = 1 ;
947+ continue ;
948+ }
949+
950+ was_cr = 0 ;
916951 output [o ++ ] = ch ;
917952 }
918953
919954 * osize_p -= o ;
920955 * isize_p -= i ;
956+
957+ if (!lf_to_crlf -> has_held && was_cr ) {
958+ lf_to_crlf -> has_held = 1 ;
959+ lf_to_crlf -> held = '\r' ;
960+ }
921961 }
922962 return 0 ;
923963}
0 commit comments