Commit 2ece55ab authored by miloyip's avatar miloyip

Implement pointer parse error

parent 1ef38058
...@@ -21,6 +21,13 @@ RAPIDJSON_NAMESPACE_BEGIN ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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 '/'
if (length != 0 && source[i] != '/') {
parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;
goto error; 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,14 +314,20 @@ private: ...@@ -290,14 +314,20 @@ 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;
} }
else i++;
}
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
if (c < '0' || c > '9') if (c < '0' || c > '9')
...@@ -330,6 +360,7 @@ private: ...@@ -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: ...@@ -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: ...@@ -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) { ...@@ -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) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment