Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ private static class CommentRemovingReader extends FilterReader {
private boolean insideLineComment = false;
private boolean insideString = false;
private boolean isSkippedSlash = false;
private int trailingBackslashCount = 0;
private char oldChar = 0; // priming with 0 as it is not part of comment or string escaping chars

public CommentRemovingReader(Reader reader) {
Expand All @@ -258,7 +259,9 @@ public int read() throws IOException {

@Override
public int read(char[] cbuf, int off, int len) throws IOException {
int charsRead = super.read(cbuf, off, len);
// When a slash is pending from a prior read, reserve one slot so that the
// recovered '/' plus the new chars never exceeds len and no char is truncated.
int charsRead = super.read(cbuf, off, isSkippedSlash ? Math.max(1, len - 1) : len);
if (charsRead > 0) {
StringBuilder filteredContent = new StringBuilder();
StringBuilder currentLine = new StringBuilder();
Expand All @@ -270,11 +273,12 @@ public int read(char[] cbuf, int off, int len) throws IOException {
// Detect String start/end if not inside a comment
if (!insideComment && !insideLineComment) {
if (c == '"') {
// only flip if not escaped quotes
if (oldChar != '\\') {
// Quotes are escaped only when preceded by an odd number of backslashes.
if (trailingBackslashCount % 2 == 0) {
insideString = !insideString;
}
currentLine.append(c);
trailingBackslashCount = 0;
oldChar = c;
continue;
}
Expand Down Expand Up @@ -350,6 +354,12 @@ public int read(char[] cbuf, int off, int len) throws IOException {
if (!insideComment && !insideLineComment) {
currentLine.append(c);
}

if (insideString && c == '\\') {
trailingBackslashCount++;
} else {
trailingBackslashCount = 0;
}
oldChar = c;
}

Expand All @@ -373,6 +383,7 @@ public void close() throws IOException {
insideLineComment = false;
insideString = false;
isSkippedSlash = false;
trailingBackslashCount = 0;
in.close();
super.close();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,44 @@ public void testEscapedQuotes() throws IOException {
+ "}\n", parse(input));
}

@Test
public void testMultiLineStartTokenAfterSingleBackslashString() throws IOException {
final String input = "{\n"
+ " \"illegal.characters\" : [\n"
+ " \"\\\\\"\n"
+ " ],\n"
+ " \"filter.safe.user.agents\" : [\n"
+ " \"Apache-HttpClient/*\"\n"
+ " ]\n"
+ "}\n";

assertEquals(input, parse(input));
}

@Test
public void testQuoteAfterEvenNumberOfBackslashesEndsString() throws IOException {
final String input = "{\n"
+ " \"a\" : \"\\\\\\\\\",\n"
+ " \"b\" : \"value/*\"\n"
+ "}\n";

assertEquals(input, parse(input));
}

@Test
public void testSkippedSlashAtBufferBoundaryDoesNotDropLastChar() throws Exception {
String input = "abc/xyz";
Reader reader = JsonSupport.createCommentRemovingReader(new StringReader(input));

char[] buffer = new char[4];
int numRead = reader.read(buffer, 0, 4);
assertEquals("abc", new String(buffer, 0, numRead));

buffer = new char[4];
numRead = reader.read(buffer, 0, 4);
assertEquals("/xyz", new String(buffer, 0, numRead));
}

@Test
public void testSlashAtEndOfRead() throws Exception {
String input = "This is a test string // Next string \n"
Expand Down