Skip to content

Commit 620bc26

Browse files
committed
[IO-670] refine IOUtils.contentEquals(Reader, Reader)
1 parent 40b9af5 commit 620bc26

File tree

5 files changed

+1238
-8
lines changed

5 files changed

+1238
-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
@@ -51,6 +51,7 @@
5151
import java.util.function.Consumer;
5252

5353
import org.apache.commons.io.function.IOConsumer;
54+
import org.apache.commons.io.input.buffer.LineEndUnifiedBufferedReader;
5455
import org.apache.commons.io.output.AppendableWriter;
5556
import org.apache.commons.io.output.ByteArrayOutputStream;
5657
import org.apache.commons.io.output.NullOutputStream;
@@ -897,16 +898,90 @@ public static boolean contentEqualsIgnoreEOL(final Reader reader1, final Reader
897898
if (reader1 == null ^ reader2 == null) {
898899
return false;
899900
}
900-
final BufferedReader br1 = toBufferedReader(reader1);
901-
final BufferedReader br2 = toBufferedReader(reader2);
902901

903-
String line1 = br1.readLine();
904-
String line2 = br2.readLine();
905-
while (line1 != null && line1.equals(line2)) {
906-
line1 = br1.readLine();
907-
line2 = br2.readLine();
902+
final LineEndUnifiedBufferedReader bufferedInput1;
903+
if (reader1 instanceof LineEndUnifiedBufferedReader) {
904+
bufferedInput1 = (LineEndUnifiedBufferedReader) reader1;
905+
} else {
906+
bufferedInput1 = new LineEndUnifiedBufferedReader(reader1);
908907
}
909-
return Objects.equals(line1, line2);
908+
909+
final LineEndUnifiedBufferedReader bufferedInput2;
910+
if (reader2 instanceof LineEndUnifiedBufferedReader) {
911+
bufferedInput2 = (LineEndUnifiedBufferedReader) reader2;
912+
} else {
913+
bufferedInput2 = new LineEndUnifiedBufferedReader(reader2);
914+
}
915+
916+
/*
917+
* We use this variable to mark if last char be '\n'.
918+
* Because "a" and "a\n" is thought contentEqualsIgnoreEOL,
919+
* but "\n" and "\n\n" is thought not contentEqualsIgnoreEOL.
920+
*/
921+
boolean justNewLine = true;
922+
923+
int currentChar1;
924+
int currentChar2;
925+
926+
while (true) {
927+
currentChar1 = bufferedInput1.peek();
928+
currentChar2 = bufferedInput2.peek();
929+
930+
if (currentChar1 == EOF) {
931+
if (currentChar2 == EOF) {
932+
return true;
933+
} else {
934+
if (!justNewLine) {
935+
return inputOnlyHaveCRLForEOF( bufferedInput2, currentChar2);
936+
}
937+
return false;
938+
}
939+
} else if (currentChar2 == EOF) {
940+
if (!justNewLine) {
941+
return inputOnlyHaveCRLForEOF(bufferedInput1, currentChar1);
942+
}
943+
return false;
944+
}
945+
if (currentChar1 != currentChar2) {
946+
return false;
947+
}
948+
justNewLine = currentChar1 == '\n';
949+
bufferedInput1.eat();
950+
bufferedInput2.eat();
951+
}
952+
}
953+
954+
/**
955+
* private function used only in contentEqualsIgnoreEOL.
956+
* used in contentEqualsIgnoreEOL to detect whether a input only have CRLF or EOF.
957+
* @param input input reader
958+
* @param currentChar current peek char of input
959+
* @return true/false
960+
* @throws IOException by input.read(), not me.
961+
* @see #contentEqualsIgnoreEOL(Reader, Reader)
962+
*/
963+
private static boolean inputOnlyHaveCRLForEOF(LineEndUnifiedBufferedReader input, int currentChar) throws IOException {
964+
965+
/*
966+
* logically there should be some code like
967+
*
968+
* if (char1 == EOF) {
969+
* return true;
970+
* }
971+
*
972+
* here.
973+
*
974+
* But actually, if this input's read() is EOF, then we will not invoke this function at all.
975+
* So the check is deleted.
976+
*
977+
* You can go contentEqualsIgnoreEOL for details.
978+
*/
979+
980+
if (currentChar == '\n') {
981+
input.eat();
982+
return input.read() == EOF;
983+
}
984+
return false;
910985
}
911986

912987
/**

0 commit comments

Comments
 (0)