Skip to content

Commit ccdce2a

Browse files
committed
[IO-670] refine IOUtils.contentEquals(Reader, Reader)
1 parent 4b5db34 commit ccdce2a

File tree

4 files changed

+887
-8
lines changed

4 files changed

+887
-8
lines changed

src/main/java/org/apache/commons/io/IOUtils.java

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import java.util.function.Consumer;
5353

5454
import org.apache.commons.io.function.IOConsumer;
55+
import org.apache.commons.io.input.buffer.LineEndUnifiedBufferedReader;
5556
import org.apache.commons.io.input.QueueInputStream;
5657
import org.apache.commons.io.output.AppendableWriter;
5758
import org.apache.commons.io.output.ByteArrayOutputStream;
@@ -935,16 +936,90 @@ public static boolean contentEqualsIgnoreEOL(final Reader reader1, final Reader
935936
if (reader1 == null ^ reader2 == null) {
936937
return false;
937938
}
938-
final BufferedReader br1 = toBufferedReader(reader1);
939-
final BufferedReader br2 = toBufferedReader(reader2);
940939

941-
String line1 = br1.readLine();
942-
String line2 = br2.readLine();
943-
while (line1 != null && line1.equals(line2)) {
944-
line1 = br1.readLine();
945-
line2 = br2.readLine();
940+
final LineEndUnifiedBufferedReader bufferedInput1;
941+
if (reader1 instanceof LineEndUnifiedBufferedReader) {
942+
bufferedInput1 = (LineEndUnifiedBufferedReader) reader1;
943+
} else {
944+
bufferedInput1 = new LineEndUnifiedBufferedReader(reader1);
946945
}
947-
return Objects.equals(line1, line2);
946+
947+
final LineEndUnifiedBufferedReader bufferedInput2;
948+
if (reader2 instanceof LineEndUnifiedBufferedReader) {
949+
bufferedInput2 = (LineEndUnifiedBufferedReader) reader2;
950+
} else {
951+
bufferedInput2 = new LineEndUnifiedBufferedReader(reader2);
952+
}
953+
954+
/*
955+
* We use this variable to mark if last char be '\n'.
956+
* Because "a" and "a\n" is thought contentEqualsIgnoreEOL,
957+
* but "\n" and "\n\n" is thought not contentEqualsIgnoreEOL.
958+
*/
959+
boolean justNewLine = true;
960+
961+
int currentChar1;
962+
int currentChar2;
963+
964+
while (true) {
965+
currentChar1 = bufferedInput1.peek();
966+
currentChar2 = bufferedInput2.peek();
967+
968+
if (currentChar1 == EOF) {
969+
if (currentChar2 == EOF) {
970+
return true;
971+
} else {
972+
if (!justNewLine) {
973+
return inputOnlyHaveCRLForEOF( bufferedInput2, currentChar2);
974+
}
975+
return false;
976+
}
977+
} else if (currentChar2 == EOF) {
978+
if (!justNewLine) {
979+
return inputOnlyHaveCRLForEOF(bufferedInput1, currentChar1);
980+
}
981+
return false;
982+
}
983+
if (currentChar1 != currentChar2) {
984+
return false;
985+
}
986+
justNewLine = currentChar1 == '\n';
987+
bufferedInput1.eat();
988+
bufferedInput2.eat();
989+
}
990+
}
991+
992+
/**
993+
* private function used only in contentEqualsIgnoreEOL.
994+
* used in contentEqualsIgnoreEOL to detect whether a input only have CRLF or EOF.
995+
* @param input input reader
996+
* @param currentChar current peek char of input
997+
* @return true/false
998+
* @throws IOException by input.read(), not me.
999+
* @see #contentEqualsIgnoreEOL(Reader, Reader)
1000+
*/
1001+
private static boolean inputOnlyHaveCRLForEOF(LineEndUnifiedBufferedReader input, int currentChar) throws IOException {
1002+
1003+
/*
1004+
* logically there should be some code like
1005+
*
1006+
* if (char1 == EOF) {
1007+
* return true;
1008+
* }
1009+
*
1010+
* here.
1011+
*
1012+
* But actually, if this input's read() is EOF, then we will not invoke this function at all.
1013+
* So the check is deleted.
1014+
*
1015+
* You can go contentEqualsIgnoreEOL for details.
1016+
*/
1017+
1018+
if (currentChar == '\n') {
1019+
input.eat();
1020+
return input.read() == EOF;
1021+
}
1022+
return false;
9481023
}
9491024

9501025
/**

0 commit comments

Comments
 (0)