Util: Add string validation to Parser
This commit is contained in:
@@ -51,8 +51,7 @@ Value Parser::parse()
|
|||||||
m_index++;
|
m_index++;
|
||||||
break;
|
break;
|
||||||
case Token::Type::String:
|
case Token::Type::String:
|
||||||
result = Value { token.symbol };
|
result = getString();
|
||||||
m_index++;
|
|
||||||
break;
|
break;
|
||||||
case Token::Type::BracketOpen:
|
case Token::Type::BracketOpen:
|
||||||
result = getArray();
|
result = getArray();
|
||||||
@@ -228,6 +227,81 @@ Value Parser::getNumber()
|
|||||||
return std::stod(token.symbol);
|
return std::stod(token.symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value Parser::getString()
|
||||||
|
{
|
||||||
|
Token token = consume();
|
||||||
|
|
||||||
|
auto reportError = [this](Token token, const std::string& message) -> void {
|
||||||
|
m_job->printErrorLine(token, message.c_str());
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: support \u Unicode character escape sequence
|
||||||
|
auto getPrintableString = [](char character) -> std::string {
|
||||||
|
if (character == '"' || character == '\\' || character == '/'
|
||||||
|
|| (character >= 0 && character <= 31)) {
|
||||||
|
switch (character) {
|
||||||
|
case '"':
|
||||||
|
return "\\\"";
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
return "\\\\";
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
return "\\/";
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
return "\\b";
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
return "\\f";
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
return "\\n";
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
return "\\r";
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
return "\\t";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
char buffer[7];
|
||||||
|
sprintf(buffer, "\\u%0.4X", character);
|
||||||
|
return std::string(buffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string() + character;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string string;
|
||||||
|
|
||||||
|
bool escape = false;
|
||||||
|
for (char character : token.symbol) {
|
||||||
|
if (!escape) {
|
||||||
|
if (character == '\\') {
|
||||||
|
escape = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (character == '"' || character == '\\' || character == '/'
|
||||||
|
|| (character >= 0 && character <= 31)) {
|
||||||
|
reportError(token, "invalid string, unescaped character found");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string += getPrintableString(character);
|
||||||
|
|
||||||
|
if (escape) {
|
||||||
|
escape = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
Value Parser::getArray()
|
Value Parser::getArray()
|
||||||
{
|
{
|
||||||
m_index++;
|
m_index++;
|
||||||
@@ -255,8 +329,7 @@ Value Parser::getArray()
|
|||||||
}
|
}
|
||||||
else if (token.type == Token::Type::String) {
|
else if (token.type == Token::Type::String) {
|
||||||
printf("Adding string to array.. v:{%s}, t:{%d}\n", token.symbol.c_str(), (int)token.type);
|
printf("Adding string to array.. v:{%s}, t:{%d}\n", token.symbol.c_str(), (int)token.type);
|
||||||
array.emplace_back(token.symbol);
|
array.emplace_back(getString());
|
||||||
m_index++;
|
|
||||||
}
|
}
|
||||||
else if (token.type == Token::Type::BracketOpen) {
|
else if (token.type == Token::Type::BracketOpen) {
|
||||||
array.emplace_back(getArray());
|
array.emplace_back(getArray());
|
||||||
@@ -310,23 +383,30 @@ Value Parser::getObject()
|
|||||||
std::string name;
|
std::string name;
|
||||||
std::map<std::string, uint8_t> unique;
|
std::map<std::string, uint8_t> unique;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
token = consume();
|
token = peek();
|
||||||
// Empty object
|
|
||||||
if (token.type == Token::Type::BraceClose) {
|
if (token.type == Token::Type::BraceClose) {
|
||||||
// Trailing comma
|
// Trailing comma
|
||||||
if (object.asObject().size() > 0) {
|
if (object.asObject().size() > 0) {
|
||||||
reportError((*m_tokens)[m_index - 2], "invalid comma, expecting '}'");
|
reportError((*m_tokens)[m_index - 2], "invalid comma, expecting '}'");
|
||||||
}
|
}
|
||||||
|
// Empty object
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Find string name
|
|
||||||
if (token.type != Token::Type::String) {
|
if (token.type != Token::Type::String) {
|
||||||
reportError(token, "expecting string, or '}' not '" + token.symbol + "'");
|
reportError(token, "expecting string, or '}' not '" + token.symbol + "'");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find member name
|
||||||
|
Value tmpName = getString();
|
||||||
|
if (tmpName.type() != Value::Type::String) {
|
||||||
|
seekForward(Token::Type::BraceClose);
|
||||||
|
consumeSpecific(Token::Type::BraceClose);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if name exists in hashmap
|
// Check if name exists in hashmap
|
||||||
name = token.symbol;
|
name = tmpName.asString();
|
||||||
if (unique.find(name) != unique.end()) {
|
if (unique.find(name) != unique.end()) {
|
||||||
reportError(token, "duplicate name '" + token.symbol + "', names should be unique");
|
reportError(token, "duplicate name '" + token.symbol + "', names should be unique");
|
||||||
break;
|
break;
|
||||||
@@ -357,7 +437,8 @@ Value Parser::getObject()
|
|||||||
#ifdef JSON_DEBUG
|
#ifdef JSON_DEBUG
|
||||||
printf("Adding string to object.. k:{%s}, v:{%s}, t:{%d}\n", name.c_str(), token.symbol.c_str(), (int)token.type);
|
printf("Adding string to object.. k:{%s}, v:{%s}, t:{%d}\n", name.c_str(), token.symbol.c_str(), (int)token.type);
|
||||||
#endif
|
#endif
|
||||||
object[name] = token.symbol;
|
m_index--;
|
||||||
|
object[name] = getString();
|
||||||
}
|
}
|
||||||
else if (token.type == Token::Type::BracketOpen) {
|
else if (token.type == Token::Type::BracketOpen) {
|
||||||
m_index--;
|
m_index--;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ private:
|
|||||||
|
|
||||||
Value getLiteral();
|
Value getLiteral();
|
||||||
Value getNumber();
|
Value getNumber();
|
||||||
|
Value getString();
|
||||||
Value getArray();
|
Value getArray();
|
||||||
Value getObject();
|
Value getObject();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user