From d2f9fec0437c9b9bfed5116e0362dba794226d98 Mon Sep 17 00:00:00 2001 From: Wleeaf <179125857+wleeaf@users.noreply.github.com> Date: Mon, 26 Oct 2026 05:46:58 +0000 Subject: [PATCH] fix: skip the indentation after a line continuation in a key The whitespace at the start of a continued line ended the key, so "key\" followed by " part=value" was read as key "key" with the value "part=value" instead of key "keypart". An indented line with only a backslash gave an empty key. The whitespace after a line continuation is now part of the token, like in values, and is skipped when unescaping. --- .../org/codejive/properties/PropertiesParser.java | 6 ++++++ .../org/codejive/properties/TestProperties.java | 8 ++++++++ .../codejive/properties/TestPropertiesParser.java | 13 +++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/main/java/org/codejive/properties/PropertiesParser.java b/src/main/java/org/codejive/properties/PropertiesParser.java index aa14fd6..c9fc70c 100644 --- a/src/main/java/org/codejive/properties/PropertiesParser.java +++ b/src/main/java/org/codejive/properties/PropertiesParser.java @@ -288,6 +288,12 @@ private void addChar(int ch) throws IOException { } } else { readEol(ch2); + if (isEol(ch2)) { + // A line continuation also skips the leading whitespace of the next line + while (isWhitespaceChar(peekChar())) { + str.append((char) readChar()); + } + } } } else { readEol(ch); diff --git a/src/test/java/org/codejive/properties/TestProperties.java b/src/test/java/org/codejive/properties/TestProperties.java index b53273a..5570a79 100644 --- a/src/test/java/org/codejive/properties/TestProperties.java +++ b/src/test/java/org/codejive/properties/TestProperties.java @@ -830,6 +830,14 @@ void testCommentEndingWithBackslash() throws IOException { assertThat(p).containsEntry("alpha", "1"); } + @Test + void testLineContinuationFollowedByIndentation() throws IOException { + Properties p = + Properties.loadProperties(new StringReader("long.\\\n key=1\n \\\n beta=2\n")); + + assertThat(p).containsOnly(entry("long.key", "1"), entry("beta", "2")); + } + @Test void testPutNewTest2() throws IOException, URISyntaxException { Path f = getResource("/test2.properties"); diff --git a/src/test/java/org/codejive/properties/TestPropertiesParser.java b/src/test/java/org/codejive/properties/TestPropertiesParser.java index 79d3d4c..e9ab7cc 100644 --- a/src/test/java/org/codejive/properties/TestPropertiesParser.java +++ b/src/test/java/org/codejive/properties/TestPropertiesParser.java @@ -123,6 +123,19 @@ void testBackslashesInComment() throws IOException { new Token(Type.VALUE, "bar")); } + @Test + void testLineContinuationInKey() throws IOException { + List tokens = + PropertiesParser.tokens(new StringReader("key\\\n part=value")) + .collect(Collectors.toList()); + + assertThat(tokens) + .containsExactly( + new Token(Type.KEY, "key\\\n part", "keypart"), + new Token(Type.SEPARATOR, "="), + new Token(Type.VALUE, "value")); + } + @Test void testEmptySeparatorAndValueAtEof() throws IOException { List tokens =