mirror of
https://github.com/plexusorg/toml4j.git
synced 2024-12-28 19:24:15 +00:00
Improved bare key validation and quoted key support
This commit is contained in:
parent
8a6ca61101
commit
1c87a9e85a
4 changed files with 169 additions and 67 deletions
|
@ -41,6 +41,18 @@ class Identifier {
|
|||
return name;
|
||||
}
|
||||
|
||||
String getBareName() {
|
||||
if (isKey()) {
|
||||
return name;
|
||||
}
|
||||
|
||||
if (isTable()) {
|
||||
return name.substring(1, name.length() - 1);
|
||||
}
|
||||
|
||||
return name.substring(2, name.length() - 2);
|
||||
}
|
||||
|
||||
boolean isKey() {
|
||||
return type == Type.KEY;
|
||||
}
|
||||
|
@ -71,7 +83,7 @@ class Identifier {
|
|||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
return StringConverter.STRING_PARSER.replaceUnicodeCharacters(sb.toString());
|
||||
}
|
||||
|
||||
private static boolean isValidKey(String name, Context context) {
|
||||
|
@ -102,42 +114,72 @@ class Identifier {
|
|||
}
|
||||
|
||||
private static boolean isValidTable(String name, Context context) {
|
||||
boolean valid = true;
|
||||
|
||||
if (!name.endsWith("]")) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
String trimmed = name.substring(1, name.length() - 1).trim();
|
||||
if (trimmed.isEmpty() || trimmed.charAt(0) == '.' || trimmed.endsWith(".")) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
context.errors.invalidTable(name, context.line.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
char[] chars = name.toCharArray();
|
||||
char[] chars = trimmed.toCharArray();
|
||||
boolean quoted = false;
|
||||
boolean terminated = false;
|
||||
int endIndex = -1;
|
||||
boolean preKey = true;
|
||||
boolean valid = true;
|
||||
boolean dotAllowed = false;
|
||||
boolean quoteAllowed = true;
|
||||
boolean charAllowed = true;
|
||||
|
||||
for (int i = 1; i < name.length() - 1; i++) {
|
||||
char c = name.charAt(i);
|
||||
if (c == '"' && chars[i - 1] != '\\') {
|
||||
if (!quoted && i > 1 && chars [i - 1] != '.' && !Character.isWhitespace(chars[i - 1])) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
quoted = !quoted;
|
||||
} else if (!quoted && c == '.') {
|
||||
preKey = true;
|
||||
} else if (!quoted && Character.isWhitespace(c)) {
|
||||
if (preKey && i > 1 && chars[i - 1] != '.' && !Character.isWhitespace(chars[i - 1])) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
if (!preKey && chars.length > i + 1 && chars[i + 1] != '.' && chars[i + 1] != ']' && !Character.isWhitespace(chars[i + 1])) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
} else if (!quoted && (ALLOWED_CHARS.indexOf(c) == -1)) {
|
||||
valid = false;
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
|
||||
if (!valid) {
|
||||
break;
|
||||
} else if (!quoted) {
|
||||
preKey = false;
|
||||
}
|
||||
|
||||
if (c == '"') {
|
||||
if (!quoteAllowed) {
|
||||
valid = false;
|
||||
} else if (quoted && chars[i - 1] != '\\') {
|
||||
charAllowed = false;
|
||||
dotAllowed = true;
|
||||
quoteAllowed = false;
|
||||
} else if (!quoted) {
|
||||
quoted = true;
|
||||
quoteAllowed = true;
|
||||
}
|
||||
} else if (quoted) {
|
||||
continue;
|
||||
} else if (c == '.') {
|
||||
if (dotAllowed) {
|
||||
charAllowed = true;
|
||||
dotAllowed = false;
|
||||
quoteAllowed = true;
|
||||
} else {
|
||||
context.errors.emptyImplicitTable(name, context.line.get());
|
||||
return false;
|
||||
}
|
||||
} else if (Character.isWhitespace(c)) {
|
||||
char prev = chars[i - 1];
|
||||
if (!Character.isWhitespace(prev) && prev != '.' && prev != '"') {
|
||||
charAllowed = false;
|
||||
dotAllowed = true;
|
||||
quoteAllowed = true;
|
||||
}
|
||||
} else {
|
||||
if (charAllowed && ALLOWED_CHARS_KEYS.indexOf(c) > -1) {
|
||||
charAllowed = true;
|
||||
dotAllowed = true;
|
||||
quoteAllowed = false;
|
||||
} else {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,47 +193,81 @@ class Identifier {
|
|||
}
|
||||
|
||||
private static boolean isValidTableArray(String line, Context context) {
|
||||
if (!line.endsWith("]]") || line.substring(2, line.length() - 2).trim().isEmpty()) {
|
||||
context.errors.invalidTableArray(line, context.line.get());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char[] chars = line.toCharArray();
|
||||
boolean quoted = false;
|
||||
boolean preKey = true;
|
||||
boolean valid = true;
|
||||
|
||||
for (int i = 2; i < line.length() - 2; i++) {
|
||||
if (!line.endsWith("]]")) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
String trimmed = line.substring(2, line.length() - 2).trim();
|
||||
if (trimmed.isEmpty() || trimmed.charAt(0) == '.' || trimmed.endsWith(".")) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
context.errors.invalidTableArray(line, context.line.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
char[] chars = trimmed.toCharArray();
|
||||
boolean quoted = false;
|
||||
boolean dotAllowed = false;
|
||||
boolean quoteAllowed = true;
|
||||
boolean charAllowed = true;
|
||||
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
if (c == '"' && chars[i - 1] != '\\') {
|
||||
if (!quoted && i > 1 && chars [i - 1] != '.' && !Character.isWhitespace(chars[i - 1])) {
|
||||
valid = false;
|
||||
}
|
||||
quoted = !quoted;
|
||||
} else if (!quoted && c == '.') {
|
||||
preKey = true;
|
||||
} else if (!quoted && Character.isWhitespace(c)) {
|
||||
if (preKey && i > 2 && chars[i - 1] != '.' && !Character.isWhitespace(chars[i - 1])) {
|
||||
valid = false;
|
||||
}
|
||||
if (!preKey && chars.length > i + 1 && chars[i + 1] != '.' && chars[i + 1] != ']' && !Character.isWhitespace(chars[i + 1])) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
} else if (!quoted && (ALLOWED_CHARS.indexOf(c) == -1)) {
|
||||
valid = false;
|
||||
} else if (!valid) {
|
||||
|
||||
if (!valid) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '"') {
|
||||
if (!quoteAllowed) {
|
||||
valid = false;
|
||||
} else if (quoted && chars[i - 1] != '\\') {
|
||||
charAllowed = false;
|
||||
dotAllowed = true;
|
||||
quoteAllowed = false;
|
||||
} else if (!quoted) {
|
||||
quoted = true;
|
||||
quoteAllowed = true;
|
||||
}
|
||||
} else if (quoted) {
|
||||
continue;
|
||||
} else if (c == '.') {
|
||||
if (dotAllowed) {
|
||||
charAllowed = true;
|
||||
dotAllowed = false;
|
||||
quoteAllowed = true;
|
||||
} else {
|
||||
context.errors.emptyImplicitTable(line, context.line.get());
|
||||
return false;
|
||||
}
|
||||
} else if (Character.isWhitespace(c)) {
|
||||
char prev = chars[i - 1];
|
||||
if (!Character.isWhitespace(prev) && prev != '.' && prev != '"') {
|
||||
charAllowed = false;
|
||||
dotAllowed = true;
|
||||
quoteAllowed = true;
|
||||
}
|
||||
} else {
|
||||
preKey = false;
|
||||
if (charAllowed && ALLOWED_CHARS_KEYS.indexOf(c) > -1) {
|
||||
charAllowed = true;
|
||||
dotAllowed = true;
|
||||
quoteAllowed = false;
|
||||
} else {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
context.errors.invalidTableArray(line, context.line.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
return valid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -162,7 +162,8 @@ class Results {
|
|||
}
|
||||
}
|
||||
|
||||
void startTableArray(String tableName) {
|
||||
void startTableArray(Identifier identifier) {
|
||||
String tableName = identifier.getBareName();
|
||||
while (stack.size() > 1) {
|
||||
stack.pop();
|
||||
}
|
||||
|
@ -201,15 +202,11 @@ class Results {
|
|||
}
|
||||
|
||||
void startTables(Identifier id) {
|
||||
String tableName = id.getName().substring(1, id.getName().length() - 1);
|
||||
String tableName = id.getBareName();
|
||||
if (!tables.add(tableName)) {
|
||||
errors.duplicateTable(tableName, -1);
|
||||
}
|
||||
|
||||
if (tableName.endsWith(".")) {
|
||||
errors.emptyImplicitTable(tableName, -1);
|
||||
}
|
||||
|
||||
while (stack.size() > 1) {
|
||||
stack.pop();
|
||||
}
|
||||
|
@ -219,7 +216,6 @@ class Results {
|
|||
String tablePart = tableParts[i].name;
|
||||
Container currentContainer = stack.peek();
|
||||
if (tablePart.isEmpty()) {
|
||||
errors.emptyImplicitTable(tableName, -1);
|
||||
} else if (currentContainer.get(tablePart) instanceof Container) {
|
||||
Container nextTable = (Container) currentContainer.get(tablePart);
|
||||
stack.push(nextTable);
|
||||
|
|
|
@ -34,7 +34,7 @@ class TomlParser {
|
|||
} else if (id.isTable()) {
|
||||
results.startTables(id);
|
||||
} else if (id.isTableArray()) {
|
||||
results.startTableArray(Keys.getTableArrayName(id.getName()));
|
||||
results.startTableArray(id);
|
||||
}
|
||||
}
|
||||
} else if (c == '\n') {
|
||||
|
|
|
@ -45,6 +45,11 @@ public class BareKeysTest {
|
|||
public void should_fail_when_characters_outside_accept_range_are_used_in_table_name() throws Exception {
|
||||
new Toml().parse("[~]");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void should_fail_when_characters_outside_accept_range_are_used_in_table_array_name() throws Exception {
|
||||
new Toml().parse("[[~]]");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void should_fail_when_dots_in_key_name() throws Exception {
|
||||
|
@ -66,6 +71,16 @@ public class BareKeysTest {
|
|||
new Toml().parse("[valid key]");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void should_fail_on_sharp_sign_in_table_array_name() throws Exception {
|
||||
new Toml().parse("[[group#]]\nkey=1");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void should_fail_on_spaces_in_table_array_name() throws Exception {
|
||||
new Toml().parse("[[valid key]]");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void should_fail_on_question_marks_in_key_name() throws Exception {
|
||||
new Toml().parse("key?=true");
|
||||
|
@ -90,4 +105,19 @@ public class BareKeysTest {
|
|||
public void should_fail_on_nested_table_name_starting_with_empty_table_name() {
|
||||
new Toml().parse("[.b]");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void should_fail_on_nested_table_array_name_ending_with_empty_table_name() {
|
||||
new Toml().parse("[[a.]]");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void should_fail_on_nested_table_array_name_containing_empty_table_name() {
|
||||
new Toml().parse("[[a..b]]");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void should_fail_on_nested_table_array_name_starting_with_empty_table_name() {
|
||||
new Toml().parse("[[.b]]");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue