Implement pointer parse error
This commit is contained in:
parent
1ef380586d
commit
2ece55abc7
@ -21,6 +21,13 @@ RAPIDJSON_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
static const SizeType kPointerInvalidIndex = ~SizeType(0);
|
static const SizeType kPointerInvalidIndex = ~SizeType(0);
|
||||||
|
|
||||||
|
enum PointerParseErrorCode {
|
||||||
|
kPointerParseErrorNone = 0,
|
||||||
|
|
||||||
|
kPointerParseErrorTokenMustBeginWithSolidus,
|
||||||
|
kPointerParseErrorInvalidEscape
|
||||||
|
};
|
||||||
|
|
||||||
template <typename ValueType, typename Allocator = CrtAllocator>
|
template <typename ValueType, typename Allocator = CrtAllocator>
|
||||||
class GenericPointer {
|
class GenericPointer {
|
||||||
public:
|
public:
|
||||||
@ -33,55 +40,60 @@ public:
|
|||||||
SizeType index; //!< A valid index if not equal to kPointerInvalidIndex.
|
SizeType index; //!< A valid index if not equal to kPointerInvalidIndex.
|
||||||
};
|
};
|
||||||
|
|
||||||
GenericPointer()
|
GenericPointer() :
|
||||||
: allocator_(),
|
allocator_(),
|
||||||
ownAllocator_(),
|
ownAllocator_(),
|
||||||
nameBuffer_(),
|
nameBuffer_(),
|
||||||
tokens_(),
|
tokens_(),
|
||||||
tokenCount_(),
|
tokenCount_(),
|
||||||
valid_(true)
|
parseErrorOffset_(),
|
||||||
|
parseErrorCode_(kPointerParseErrorNone)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit GenericPointer(const Ch* source, Allocator* allocator = 0)
|
explicit GenericPointer(const Ch* source, Allocator* allocator = 0) :
|
||||||
: allocator_(allocator),
|
allocator_(allocator),
|
||||||
ownAllocator_(),
|
ownAllocator_(),
|
||||||
nameBuffer_(),
|
nameBuffer_(),
|
||||||
tokens_(),
|
tokens_(),
|
||||||
tokenCount_(),
|
tokenCount_(),
|
||||||
valid_(true)
|
parseErrorOffset_(),
|
||||||
|
parseErrorCode_(kPointerParseErrorNone)
|
||||||
{
|
{
|
||||||
Parse(source, internal::StrLen(source));
|
Parse(source, internal::StrLen(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0)
|
GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) :
|
||||||
: allocator_(allocator),
|
allocator_(allocator),
|
||||||
ownAllocator_(),
|
ownAllocator_(),
|
||||||
nameBuffer_(),
|
nameBuffer_(),
|
||||||
tokens_(),
|
tokens_(),
|
||||||
tokenCount_(),
|
tokenCount_(),
|
||||||
valid_(true)
|
parseErrorOffset_(),
|
||||||
|
parseErrorCode_(kPointerParseErrorNone)
|
||||||
{
|
{
|
||||||
Parse(source, length);
|
Parse(source, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericPointer(const Token* tokens, size_t tokenCount)
|
GenericPointer(const Token* tokens, size_t tokenCount) :
|
||||||
: allocator_(),
|
allocator_(),
|
||||||
ownAllocator_(),
|
ownAllocator_(),
|
||||||
nameBuffer_(),
|
nameBuffer_(),
|
||||||
tokens_(const_cast<Token*>(tokens)),
|
tokens_(const_cast<Token*>(tokens)),
|
||||||
tokenCount_(tokenCount),
|
tokenCount_(tokenCount),
|
||||||
valid_(true)
|
parseErrorOffset_(),
|
||||||
|
parseErrorCode_(kPointerParseErrorNone)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericPointer(const GenericPointer& rhs)
|
GenericPointer(const GenericPointer& rhs) :
|
||||||
: allocator_(),
|
allocator_(),
|
||||||
ownAllocator_(),
|
ownAllocator_(),
|
||||||
nameBuffer_(),
|
nameBuffer_(),
|
||||||
tokens_(),
|
tokens_(),
|
||||||
tokenCount_(),
|
tokenCount_(),
|
||||||
valid_()
|
parseErrorOffset_(),
|
||||||
|
parseErrorCode_(kPointerParseErrorNone)
|
||||||
{
|
{
|
||||||
*this = rhs;
|
*this = rhs;
|
||||||
}
|
}
|
||||||
@ -98,7 +110,8 @@ public:
|
|||||||
this->~GenericPointer();
|
this->~GenericPointer();
|
||||||
|
|
||||||
tokenCount_ = rhs.tokenCount_;
|
tokenCount_ = rhs.tokenCount_;
|
||||||
valid_ = rhs.valid_;
|
parseErrorOffset_ = rhs.parseErrorOffset_;
|
||||||
|
parseErrorCode_ = rhs.parseErrorCode_;
|
||||||
|
|
||||||
if (rhs.nameBuffer_) {
|
if (rhs.nameBuffer_) {
|
||||||
if (!allocator_)
|
if (!allocator_)
|
||||||
@ -124,7 +137,11 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValid() const { return valid_; }
|
bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
|
||||||
|
|
||||||
|
size_t GetParseErrorOffset() const { return parseErrorOffset_; }
|
||||||
|
|
||||||
|
PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
|
||||||
|
|
||||||
const Token* GetTokens() const { return tokens_; }
|
const Token* GetTokens() const { return tokens_; }
|
||||||
|
|
||||||
@ -276,9 +293,16 @@ private:
|
|||||||
tokenCount_ = 0;
|
tokenCount_ = 0;
|
||||||
Ch* name = nameBuffer_;
|
Ch* name = nameBuffer_;
|
||||||
|
|
||||||
for (size_t i = 0; i < length;) {
|
size_t i = 0;
|
||||||
if (source[i++] != '/') // Consumes '/'
|
|
||||||
goto error;
|
if (length != 0 && source[i] != '/') {
|
||||||
|
parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < length) {
|
||||||
|
RAPIDJSON_ASSERT(source[i] == '/');
|
||||||
|
i++; // consumes '/'
|
||||||
|
|
||||||
Token& token = tokens_[tokenCount_++];
|
Token& token = tokens_[tokenCount_++];
|
||||||
token.name = name;
|
token.name = name;
|
||||||
@ -290,13 +314,19 @@ private:
|
|||||||
// Escaping "~0" -> '~', "~1" -> '/'
|
// Escaping "~0" -> '~', "~1" -> '/'
|
||||||
if (c == '~') {
|
if (c == '~') {
|
||||||
if (i < length) {
|
if (i < length) {
|
||||||
c = source[i++];
|
c = source[i];
|
||||||
if (c == '0') c = '~';
|
if (c == '0') c = '~';
|
||||||
else if (c == '1') c = '/';
|
else if (c == '1') c = '/';
|
||||||
else goto error;
|
else {
|
||||||
|
parseErrorCode_ = kPointerParseErrorInvalidEscape;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
|
parseErrorCode_ = kPointerParseErrorInvalidEscape;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// First check for index: all of characters are digit
|
// First check for index: all of characters are digit
|
||||||
@ -330,6 +360,7 @@ private:
|
|||||||
|
|
||||||
RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
|
RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
|
||||||
tokens_ = (Token*)allocator_->Realloc(tokens_, length * sizeof(Token), tokenCount_ * sizeof(Token)); // Shrink tokens_
|
tokens_ = (Token*)allocator_->Realloc(tokens_, length * sizeof(Token), tokenCount_ * sizeof(Token)); // Shrink tokens_
|
||||||
|
parseErrorCode_ = kPointerParseErrorNone;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@ -338,7 +369,7 @@ private:
|
|||||||
nameBuffer_ = 0;
|
nameBuffer_ = 0;
|
||||||
tokens_ = 0;
|
tokens_ = 0;
|
||||||
tokenCount_ = 0;
|
tokenCount_ = 0;
|
||||||
valid_ = false;
|
parseErrorOffset_ = i;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +378,8 @@ private:
|
|||||||
Ch* nameBuffer_;
|
Ch* nameBuffer_;
|
||||||
Token* tokens_;
|
Token* tokens_;
|
||||||
size_t tokenCount_;
|
size_t tokenCount_;
|
||||||
bool valid_;
|
size_t parseErrorOffset_;
|
||||||
|
PointerParseErrorCode parseErrorCode_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -139,6 +139,30 @@ TEST(Pointer, Parse) {
|
|||||||
EXPECT_STREQ("4294967296", p.GetTokens()[0].name);
|
EXPECT_STREQ("4294967296", p.GetTokens()[0].name);
|
||||||
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
|
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// kPointerParseErrorTokenMustBeginWithSolidus
|
||||||
|
Pointer p(" ");
|
||||||
|
EXPECT_FALSE(p.IsValid());
|
||||||
|
EXPECT_EQ(kPointerParseErrorTokenMustBeginWithSolidus, p.GetParseErrorCode());
|
||||||
|
EXPECT_EQ(0u, p.GetParseErrorOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// kPointerParseErrorInvalidEscape
|
||||||
|
Pointer p("/~");
|
||||||
|
EXPECT_FALSE(p.IsValid());
|
||||||
|
EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode());
|
||||||
|
EXPECT_EQ(2u, p.GetParseErrorOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// kPointerParseErrorInvalidEscape
|
||||||
|
Pointer p("/~2");
|
||||||
|
EXPECT_FALSE(p.IsValid());
|
||||||
|
EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode());
|
||||||
|
EXPECT_EQ(2u, p.GetParseErrorOffset());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Pointer, Stringify) {
|
TEST(Pointer, Stringify) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user