package info parser: improve string parsing
* Instead of two string token types (TOKEN_WORD, TOKEN_QUOTED_STRING), there's now only one (TOKEN_STRING). Whether the string meets the criteria is checked where needed. In most cases the check was already done or not necessary anyway. * Strings can now consist of an arbitrary sequence of quoted and unquoted strings and escaping is also supported in unquoted string segments. * Among other things this fixes incorrect restrictions for resolvable names and should also make quoting paths superfluous (unless they contain separator characters).
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
namespace BPackageKit {
|
namespace BPackageKit {
|
||||||
@@ -84,7 +85,7 @@ BPackageInfo::Parser::ParseVersion(const BString& versionString,
|
|||||||
fPos = versionString.String();
|
fPos = versionString.String();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Token token(TOKEN_WORD, fPos, versionString.Length());
|
Token token(TOKEN_STRING, fPos, versionString.Length());
|
||||||
_ParseVersionValue(token, &_version, revisionIsOptional);
|
_ParseVersionValue(token, &_version, revisionIsOptional);
|
||||||
} catch (const ParseError& error) {
|
} catch (const ParseError& error) {
|
||||||
if (fListener != NULL) {
|
if (fListener != NULL) {
|
||||||
@@ -175,38 +176,76 @@ BPackageInfo::Parser::_NextToken()
|
|||||||
}
|
}
|
||||||
return Token(TOKEN_OPERATOR_GREATER, tokenPos, 1);
|
return Token(TOKEN_OPERATOR_GREATER, tokenPos, 1);
|
||||||
|
|
||||||
case '"':
|
|
||||||
case '\'':
|
|
||||||
{
|
|
||||||
char quoteChar = *fPos;
|
|
||||||
fPos++;
|
|
||||||
const char* start = fPos;
|
|
||||||
// anything until the next quote is part of the value
|
|
||||||
bool lastWasEscape = false;
|
|
||||||
while ((*fPos != quoteChar || lastWasEscape) && *fPos != '\0') {
|
|
||||||
if (lastWasEscape)
|
|
||||||
lastWasEscape = false;
|
|
||||||
else if (*fPos == '\\')
|
|
||||||
lastWasEscape = true;
|
|
||||||
fPos++;
|
|
||||||
}
|
|
||||||
if (*fPos != quoteChar)
|
|
||||||
throw ParseError("unterminated quoted-string", tokenPos);
|
|
||||||
const char* end = fPos++;
|
|
||||||
return Token(TOKEN_QUOTED_STRING, start, end - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
const char* start = fPos;
|
std::string string;
|
||||||
while (isalnum(*fPos) || *fPos == '.' || *fPos == '-'
|
char quoteChar = '\0';
|
||||||
|| *fPos == '_' || *fPos == ':' || *fPos == '+'
|
|
||||||
|| *fPos == '~') {
|
for (; *fPos != '\0'; fPos++) {
|
||||||
fPos++;
|
char c = *fPos;
|
||||||
|
if (quoteChar != '\0') {
|
||||||
|
// within a quoted string segment
|
||||||
|
if (c == quoteChar) {
|
||||||
|
quoteChar = '\0';
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (fPos == start)
|
|
||||||
|
if (c == '\\') {
|
||||||
|
// next char is escaped
|
||||||
|
c = *++fPos;
|
||||||
|
if (c == '\0') {
|
||||||
|
throw ParseError("unterminated quoted-string",
|
||||||
|
tokenPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 'n')
|
||||||
|
c = '\n';
|
||||||
|
else if (c == 't')
|
||||||
|
c = '\t';
|
||||||
|
}
|
||||||
|
|
||||||
|
string += c;
|
||||||
|
} else {
|
||||||
|
// unquoted string segment
|
||||||
|
switch (c) {
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
// quoted string start
|
||||||
|
quoteChar = c;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
case '<':
|
||||||
|
case '=':
|
||||||
|
case '!':
|
||||||
|
case '>':
|
||||||
|
// a separator character -- this ends the string
|
||||||
break;
|
break;
|
||||||
return Token(TOKEN_WORD, start, fPos - start);
|
|
||||||
|
case '\\':
|
||||||
|
// next char is escaped
|
||||||
|
c = *++fPos;
|
||||||
|
if (c == '\0') {
|
||||||
|
throw ParseError("'\\' at end of string",
|
||||||
|
tokenPos);
|
||||||
|
}
|
||||||
|
string += c;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (isspace(c))
|
||||||
|
break;
|
||||||
|
string += c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Token(TOKEN_STRING, tokenPos, fPos - tokenPos,
|
||||||
|
string.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,8 +265,8 @@ void
|
|||||||
BPackageInfo::Parser::_ParseStringValue(BString* value, const char** _tokenPos)
|
BPackageInfo::Parser::_ParseStringValue(BString* value, const char** _tokenPos)
|
||||||
{
|
{
|
||||||
Token string = _NextToken();
|
Token string = _NextToken();
|
||||||
if (string.type != TOKEN_QUOTED_STRING && string.type != TOKEN_WORD)
|
if (string.type != TOKEN_STRING)
|
||||||
throw ParseError("expected quoted-string or word", string.pos);
|
throw ParseError("expected string", string.pos);
|
||||||
|
|
||||||
*value = string.text;
|
*value = string.text;
|
||||||
if (_tokenPos != NULL)
|
if (_tokenPos != NULL)
|
||||||
@@ -239,7 +278,7 @@ void
|
|||||||
BPackageInfo::Parser::_ParseArchitectureValue(BPackageArchitecture* value)
|
BPackageInfo::Parser::_ParseArchitectureValue(BPackageArchitecture* value)
|
||||||
{
|
{
|
||||||
Token arch = _NextToken();
|
Token arch = _NextToken();
|
||||||
if (arch.type == TOKEN_WORD) {
|
if (arch.type == TOKEN_STRING) {
|
||||||
for (int i = 0; i < B_PACKAGE_ARCHITECTURE_ENUM_COUNT; ++i) {
|
for (int i = 0; i < B_PACKAGE_ARCHITECTURE_ENUM_COUNT; ++i) {
|
||||||
if (arch.text.ICompare(BPackageInfo::kArchitectureNames[i]) == 0) {
|
if (arch.text.ICompare(BPackageInfo::kArchitectureNames[i]) == 0) {
|
||||||
*value = (BPackageArchitecture)i;
|
*value = (BPackageArchitecture)i;
|
||||||
@@ -272,8 +311,8 @@ BPackageInfo::Parser::_ParseVersionValue(BPackageVersion* value,
|
|||||||
BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
|
BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
|
||||||
bool revisionIsOptional)
|
bool revisionIsOptional)
|
||||||
{
|
{
|
||||||
if (word.type != TOKEN_WORD)
|
if (word.type != TOKEN_STRING)
|
||||||
throw ParseError("expected word (a version)", word.pos);
|
throw ParseError("expected string (a version)", word.pos);
|
||||||
|
|
||||||
// get the revision number
|
// get the revision number
|
||||||
uint32 revision = 0;
|
uint32 revision = 0;
|
||||||
@@ -388,33 +427,33 @@ BPackageInfo::Parser::_ParseList(ListElementParser& elementParser,
|
|||||||
|
|
||||||
void
|
void
|
||||||
BPackageInfo::Parser::_ParseStringList(BStringList* value,
|
BPackageInfo::Parser::_ParseStringList(BStringList* value,
|
||||||
bool allowQuotedStrings, bool convertToLowerCase)
|
bool requireResolvableName, bool convertToLowerCase)
|
||||||
{
|
{
|
||||||
struct StringParser : public ListElementParser {
|
struct StringParser : public ListElementParser {
|
||||||
BStringList* value;
|
BStringList* value;
|
||||||
bool allowQuotedStrings;
|
bool requireResolvableName;
|
||||||
bool convertToLowerCase;
|
bool convertToLowerCase;
|
||||||
|
|
||||||
StringParser(BStringList* value, bool allowQuotedStrings,
|
StringParser(BStringList* value, bool requireResolvableName,
|
||||||
bool convertToLowerCase)
|
bool convertToLowerCase)
|
||||||
:
|
:
|
||||||
value(value),
|
value(value),
|
||||||
allowQuotedStrings(allowQuotedStrings),
|
requireResolvableName(requireResolvableName),
|
||||||
convertToLowerCase(convertToLowerCase)
|
convertToLowerCase(convertToLowerCase)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void operator()(const Token& token)
|
virtual void operator()(const Token& token)
|
||||||
{
|
{
|
||||||
if (allowQuotedStrings) {
|
if (token.type != TOKEN_STRING)
|
||||||
if (token.type != TOKEN_QUOTED_STRING
|
throw ParseError("expected string", token.pos);
|
||||||
&& token.type != TOKEN_WORD) {
|
|
||||||
throw ParseError("expected quoted-string or word",
|
if (requireResolvableName) {
|
||||||
token.pos);
|
int32 errorPos;
|
||||||
|
if (!_IsValidResolvableName(token.text, &errorPos)) {
|
||||||
|
throw ParseError("invalid character in resolvable name",
|
||||||
|
token.pos + errorPos);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (token.type != TOKEN_WORD)
|
|
||||||
throw ParseError("expected word", token.pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BString element(token.text);
|
BString element(token.text);
|
||||||
@@ -423,7 +462,7 @@ BPackageInfo::Parser::_ParseStringList(BStringList* value,
|
|||||||
|
|
||||||
value->Add(element);
|
value->Add(element);
|
||||||
}
|
}
|
||||||
} stringParser(value, allowQuotedStrings, convertToLowerCase);
|
} stringParser(value, requireResolvableName, convertToLowerCase);
|
||||||
|
|
||||||
_ParseList(stringParser, true);
|
_ParseList(stringParser, true);
|
||||||
}
|
}
|
||||||
@@ -443,7 +482,7 @@ BPackageInfo::Parser::_ParseFlags()
|
|||||||
|
|
||||||
virtual void operator()(const Token& token)
|
virtual void operator()(const Token& token)
|
||||||
{
|
{
|
||||||
if (token.type != TOKEN_WORD)
|
if (token.type != TOKEN_STRING)
|
||||||
throw ParseError("expected word (a flag)", token.pos);
|
throw ParseError("expected word (a flag)", token.pos);
|
||||||
|
|
||||||
if (token.text.ICompare("approve_license") == 0)
|
if (token.text.ICompare("approve_license") == 0)
|
||||||
@@ -482,7 +521,7 @@ BPackageInfo::Parser::_ParseResolvableList(
|
|||||||
|
|
||||||
virtual void operator()(const Token& token)
|
virtual void operator()(const Token& token)
|
||||||
{
|
{
|
||||||
if (token.type != TOKEN_WORD) {
|
if (token.type != TOKEN_STRING) {
|
||||||
throw ParseError("expected word (a resolvable name)",
|
throw ParseError("expected word (a resolvable name)",
|
||||||
token.pos);
|
token.pos);
|
||||||
}
|
}
|
||||||
@@ -507,7 +546,7 @@ BPackageInfo::Parser::_ParseResolvableList(
|
|||||||
// parse compatible version
|
// parse compatible version
|
||||||
BPackageVersion compatibleVersion;
|
BPackageVersion compatibleVersion;
|
||||||
Token compatible = parser._NextToken();
|
Token compatible = parser._NextToken();
|
||||||
if (compatible.type == TOKEN_WORD
|
if (compatible.type == TOKEN_STRING
|
||||||
&& (compatible.text == "compat"
|
&& (compatible.text == "compat"
|
||||||
|| compatible.text == "compatible")) {
|
|| compatible.text == "compatible")) {
|
||||||
op = parser._NextToken();
|
op = parser._NextToken();
|
||||||
@@ -548,7 +587,7 @@ BPackageInfo::Parser::_ParseResolvableExprList(
|
|||||||
|
|
||||||
virtual void operator()(const Token& token)
|
virtual void operator()(const Token& token)
|
||||||
{
|
{
|
||||||
if (token.type != TOKEN_WORD) {
|
if (token.type != TOKEN_STRING) {
|
||||||
throw ParseError("expected word (a resolvable name)",
|
throw ParseError("expected word (a resolvable name)",
|
||||||
token.pos);
|
token.pos);
|
||||||
}
|
}
|
||||||
@@ -571,7 +610,7 @@ BPackageInfo::Parser::_ParseResolvableExprList(
|
|||||||
|
|
||||||
if (basePackage != NULL) {
|
if (basePackage != NULL) {
|
||||||
Token base = parser._NextToken();
|
Token base = parser._NextToken();
|
||||||
if (base.type == TOKEN_WORD && base.text == "base") {
|
if (base.type == TOKEN_STRING && base.text == "base") {
|
||||||
if (!basePackage->IsEmpty()) {
|
if (!basePackage->IsEmpty()) {
|
||||||
throw ParseError(
|
throw ParseError(
|
||||||
"multiple packages marked as base package",
|
"multiple packages marked as base package",
|
||||||
@@ -621,8 +660,8 @@ BPackageInfo::Parser::_ParseGlobalWritableFileInfos(
|
|||||||
|
|
||||||
virtual void operator()(const Token& token)
|
virtual void operator()(const Token& token)
|
||||||
{
|
{
|
||||||
if (token.type != TOKEN_WORD && token.type != TOKEN_QUOTED_STRING) {
|
if (token.type != TOKEN_STRING) {
|
||||||
throw ParseError("expected string (a settings file path)",
|
throw ParseError("expected string (a file path)",
|
||||||
token.pos);
|
token.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,12 +670,13 @@ BPackageInfo::Parser::_ParseGlobalWritableFileInfos(
|
|||||||
bool isDirectory = false;
|
bool isDirectory = false;
|
||||||
|
|
||||||
Token nextToken = parser._NextToken();
|
Token nextToken = parser._NextToken();
|
||||||
if (nextToken.type == TOKEN_WORD && nextToken.text == "directory") {
|
if (nextToken.type == TOKEN_STRING
|
||||||
|
&& nextToken.text == "directory") {
|
||||||
isDirectory = true;
|
isDirectory = true;
|
||||||
nextToken = parser._NextToken();
|
nextToken = parser._NextToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextToken.type == TOKEN_WORD) {
|
if (nextToken.type == TOKEN_STRING) {
|
||||||
const char* const* end = kWritableFileUpdateTypes
|
const char* const* end = kWritableFileUpdateTypes
|
||||||
+ B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT;
|
+ B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT;
|
||||||
const char* const* found = std::find(kWritableFileUpdateTypes,
|
const char* const* found = std::find(kWritableFileUpdateTypes,
|
||||||
@@ -685,7 +725,7 @@ BPackageInfo::Parser::_ParseUserSettingsFileInfos(
|
|||||||
|
|
||||||
virtual void operator()(const Token& token)
|
virtual void operator()(const Token& token)
|
||||||
{
|
{
|
||||||
if (token.type != TOKEN_WORD && token.type != TOKEN_QUOTED_STRING) {
|
if (token.type != TOKEN_STRING) {
|
||||||
throw ParseError("expected string (a settings file path)",
|
throw ParseError("expected string (a settings file path)",
|
||||||
token.pos);
|
token.pos);
|
||||||
}
|
}
|
||||||
@@ -694,13 +734,13 @@ BPackageInfo::Parser::_ParseUserSettingsFileInfos(
|
|||||||
bool isDirectory = false;
|
bool isDirectory = false;
|
||||||
|
|
||||||
Token nextToken = parser._NextToken();
|
Token nextToken = parser._NextToken();
|
||||||
if (nextToken.type == TOKEN_WORD && nextToken.text == "directory") {
|
if (nextToken.type == TOKEN_STRING
|
||||||
|
&& nextToken.text == "directory") {
|
||||||
isDirectory = true;
|
isDirectory = true;
|
||||||
} else if (nextToken.type == TOKEN_WORD
|
} else if (nextToken.type == TOKEN_STRING
|
||||||
&& nextToken.text == "template") {
|
&& nextToken.text == "template") {
|
||||||
nextToken = parser._NextToken();
|
nextToken = parser._NextToken();
|
||||||
if (nextToken.type != TOKEN_WORD
|
if (nextToken.type != TOKEN_STRING) {
|
||||||
&& nextToken.type != TOKEN_QUOTED_STRING) {
|
|
||||||
throw ParseError(
|
throw ParseError(
|
||||||
"expected string (a settings template file path)",
|
"expected string (a settings template file path)",
|
||||||
nextToken.pos);
|
nextToken.pos);
|
||||||
@@ -744,9 +784,9 @@ BPackageInfo::Parser::_ParseUsers(UserList* users)
|
|||||||
|
|
||||||
virtual void operator()(const Token& token)
|
virtual void operator()(const Token& token)
|
||||||
{
|
{
|
||||||
if (token.type != TOKEN_WORD) {
|
if (token.type != TOKEN_STRING
|
||||||
throw ParseError("expected a user name",
|
|| !BUser::IsValidUserName(token.text)) {
|
||||||
token.pos);
|
throw ParseError("expected a user name", token.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
BString realName;
|
BString realName;
|
||||||
@@ -756,31 +796,28 @@ BPackageInfo::Parser::_ParseUsers(UserList* users)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
Token nextToken = parser._NextToken();
|
Token nextToken = parser._NextToken();
|
||||||
if (nextToken.type != TOKEN_WORD) {
|
if (nextToken.type != TOKEN_STRING) {
|
||||||
parser._RewindTo(nextToken);
|
parser._RewindTo(nextToken);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextToken.text == "real-name") {
|
if (nextToken.text == "real-name") {
|
||||||
nextToken = parser._NextToken();
|
nextToken = parser._NextToken();
|
||||||
if (nextToken.type != TOKEN_WORD
|
if (nextToken.type != TOKEN_STRING) {
|
||||||
&& nextToken.type != TOKEN_QUOTED_STRING) {
|
|
||||||
throw ParseError("expected string (a user real name)",
|
throw ParseError("expected string (a user real name)",
|
||||||
nextToken.pos);
|
nextToken.pos);
|
||||||
}
|
}
|
||||||
realName = nextToken.text;
|
realName = nextToken.text;
|
||||||
} else if (nextToken.text == "home") {
|
} else if (nextToken.text == "home") {
|
||||||
nextToken = parser._NextToken();
|
nextToken = parser._NextToken();
|
||||||
if (nextToken.type != TOKEN_WORD
|
if (nextToken.type != TOKEN_STRING) {
|
||||||
&& nextToken.type != TOKEN_QUOTED_STRING) {
|
|
||||||
throw ParseError("expected string (a home path)",
|
throw ParseError("expected string (a home path)",
|
||||||
nextToken.pos);
|
nextToken.pos);
|
||||||
}
|
}
|
||||||
home = nextToken.text;
|
home = nextToken.text;
|
||||||
} else if (nextToken.text == "shell") {
|
} else if (nextToken.text == "shell") {
|
||||||
nextToken = parser._NextToken();
|
nextToken = parser._NextToken();
|
||||||
if (nextToken.type != TOKEN_WORD
|
if (nextToken.type != TOKEN_STRING) {
|
||||||
&& nextToken.type != TOKEN_QUOTED_STRING) {
|
|
||||||
throw ParseError("expected string (a shell path)",
|
throw ParseError("expected string (a shell path)",
|
||||||
nextToken.pos);
|
nextToken.pos);
|
||||||
}
|
}
|
||||||
@@ -788,7 +825,8 @@ BPackageInfo::Parser::_ParseUsers(UserList* users)
|
|||||||
} else if (nextToken.text == "groups") {
|
} else if (nextToken.text == "groups") {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
nextToken = parser._NextToken();
|
nextToken = parser._NextToken();
|
||||||
if (nextToken.type == TOKEN_WORD) {
|
if (nextToken.type == TOKEN_STRING
|
||||||
|
&& BUser::IsValidUserName(nextToken.text)) {
|
||||||
if (!groups.Add(nextToken.text))
|
if (!groups.Add(nextToken.text))
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
} else if (nextToken.type == TOKEN_ITEM_SEPARATOR
|
} else if (nextToken.type == TOKEN_ITEM_SEPARATOR
|
||||||
@@ -811,10 +849,10 @@ BPackageInfo::Parser::_ParseUsers(UserList* users)
|
|||||||
BString templatePath;
|
BString templatePath;
|
||||||
|
|
||||||
Token nextToken = parser._NextToken();
|
Token nextToken = parser._NextToken();
|
||||||
if (nextToken.type == TOKEN_WORD && nextToken.text == "template") {
|
if (nextToken.type == TOKEN_STRING
|
||||||
|
&& nextToken.text == "template") {
|
||||||
nextToken = parser._NextToken();
|
nextToken = parser._NextToken();
|
||||||
if (nextToken.type != TOKEN_WORD
|
if (nextToken.type != TOKEN_STRING) {
|
||||||
&& nextToken.type != TOKEN_QUOTED_STRING) {
|
|
||||||
throw ParseError(
|
throw ParseError(
|
||||||
"expected string (a settings template file path)",
|
"expected string (a settings template file path)",
|
||||||
nextToken.pos);
|
nextToken.pos);
|
||||||
@@ -853,8 +891,8 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
|
|||||||
if (t.type == TOKEN_ITEM_SEPARATOR)
|
if (t.type == TOKEN_ITEM_SEPARATOR)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (t.type != TOKEN_WORD)
|
if (t.type != TOKEN_STRING)
|
||||||
throw ParseError("expected word (a variable name)", t.pos);
|
throw ParseError("expected string (a variable name)", t.pos);
|
||||||
|
|
||||||
BPackageInfoAttributeID attribute = B_PACKAGE_INFO_ENUM_COUNT;
|
BPackageInfoAttributeID attribute = B_PACKAGE_INFO_ENUM_COUNT;
|
||||||
for (int i = 0; i < B_PACKAGE_INFO_ENUM_COUNT; i++) {
|
for (int i = 0; i < B_PACKAGE_INFO_ENUM_COUNT; i++) {
|
||||||
@@ -986,7 +1024,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case B_PACKAGE_INFO_REPLACES:
|
case B_PACKAGE_INFO_REPLACES:
|
||||||
_ParseStringList(&packageInfo->fReplacesList, false, true);
|
_ParseStringList(&packageInfo->fReplacesList, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case B_PACKAGE_INFO_FLAGS:
|
case B_PACKAGE_INFO_FLAGS:
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ private:
|
|||||||
friend struct ListElementParser;
|
friend struct ListElementParser;
|
||||||
|
|
||||||
enum TokenType {
|
enum TokenType {
|
||||||
TOKEN_WORD,
|
TOKEN_STRING,
|
||||||
TOKEN_QUOTED_STRING,
|
|
||||||
TOKEN_OPERATOR_ASSIGN,
|
TOKEN_OPERATOR_ASSIGN,
|
||||||
TOKEN_OPERATOR_LESS,
|
TOKEN_OPERATOR_LESS,
|
||||||
TOKEN_OPERATOR_LESS_EQUAL,
|
TOKEN_OPERATOR_LESS_EQUAL,
|
||||||
@@ -67,7 +66,7 @@ private:
|
|||||||
void _ParseList(ListElementParser& elementParser,
|
void _ParseList(ListElementParser& elementParser,
|
||||||
bool allowSingleNonListElement);
|
bool allowSingleNonListElement);
|
||||||
void _ParseStringList(BStringList* value,
|
void _ParseStringList(BStringList* value,
|
||||||
bool allowQuotedStrings = true,
|
bool requireResolvableName = false,
|
||||||
bool convertToLowerCase = false);
|
bool convertToLowerCase = false);
|
||||||
void _ParseResolvableList(
|
void _ParseResolvableList(
|
||||||
BObjectList<BPackageResolvable>* value);
|
BObjectList<BPackageResolvable>* value);
|
||||||
@@ -118,38 +117,16 @@ struct BPackageInfo::Parser::Token {
|
|||||||
BString text;
|
BString text;
|
||||||
const char* pos;
|
const char* pos;
|
||||||
|
|
||||||
Token(TokenType _type, const char* _pos, int length = 0)
|
Token(TokenType _type, const char* _pos, int length = 0,
|
||||||
: type(_type), pos(_pos)
|
const char* text = NULL)
|
||||||
|
:
|
||||||
|
type(_type),
|
||||||
|
pos(_pos)
|
||||||
{
|
{
|
||||||
if (length != 0) {
|
if (text != NULL)
|
||||||
text.SetTo(pos, length);
|
this->text = text;
|
||||||
|
else if (length != 0)
|
||||||
if (type == TOKEN_QUOTED_STRING) {
|
this->text.SetTo(pos, length);
|
||||||
// unescape value of quoted string
|
|
||||||
char* value = text.LockBuffer(length);
|
|
||||||
if (value == NULL)
|
|
||||||
return;
|
|
||||||
int index = 0;
|
|
||||||
int newIndex = 0;
|
|
||||||
bool lastWasEscape = false;
|
|
||||||
while (char c = value[index++]) {
|
|
||||||
if (lastWasEscape) {
|
|
||||||
lastWasEscape = false;
|
|
||||||
// map \n to newline and \t to tab
|
|
||||||
if (c == 'n')
|
|
||||||
c = '\n';
|
|
||||||
else if (c == 't')
|
|
||||||
c = '\t';
|
|
||||||
} else if (c == '\\') {
|
|
||||||
lastWasEscape = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
value[newIndex++] = c;
|
|
||||||
}
|
|
||||||
value[newIndex] = '\0';
|
|
||||||
text.UnlockBuffer(newIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
operator bool() const
|
operator bool() const
|
||||||
|
|||||||
Reference in New Issue
Block a user