From 436625f83cbeabc8c6c30b7a7a099b7406f1aee8 Mon Sep 17 00:00:00 2001 From: miloyip Date: Mon, 4 May 2015 15:02:43 +0800 Subject: [PATCH] Fix ambiguous cases in Pointer::Create() --- include/rapidjson/pointer.h | 44 +++++++++++++++++------------------ test/unittest/pointertest.cpp | 25 +++++++++++++++++++- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h index 3ba9e1c..89dfa48 100644 --- a/include/rapidjson/pointer.h +++ b/include/rapidjson/pointer.h @@ -305,19 +305,31 @@ public: ValueType* v = &root; bool exist = true; for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { - if (t->index == kPointerInvalidIndex) { // object name - // Handling of '-' for last element of array - if (t->name[0] == '-' && t->length == 1) { - if (!v->IsArray()) - v->SetArray(); // Change to Array - v->PushBack(Value().Move(), allocator); - v = &((*v)[v->Size() - 1]); - exist = false; - } - else { + if (v->IsArray() && t->name[0] == '-' && t->length == 1) { + v->PushBack(Value().Move(), allocator); + v = &((*v)[v->Size() - 1]); + exist = false; + } + else { + if (t->index == kPointerInvalidIndex) { // must be object name if (!v->IsObject()) v->SetObject(); // Change to Object + } + else { // object name or array index + if (!v->IsArray() && !v->IsObject()) + v->SetArray(); // Change to Array + } + if (v->IsArray()) { + if (t->index >= v->Size()) { + v->Reserve(t->index + 1, allocator); + while (t->index >= v->Size()) + v->PushBack(Value().Move(), allocator); + exist = false; + } + v = &((*v)[t->index]); + } + else { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) { v->AddMember(Value(t->name, t->length, allocator).Move(), Value().Move(), allocator); @@ -328,18 +340,6 @@ public: v = &m->value; } } - else { // array index - if (!v->IsArray()) - v->SetArray(); // Change to Array - - if (t->index >= v->Size()) { - v->Reserve(t->index + 1, allocator); - while (t->index >= v->Size()) - v->PushBack(Value().Move(), allocator); - exist = false; - } - v = &((*v)[t->index]); - } } if (alreadyExist) diff --git a/test/unittest/pointertest.cpp b/test/unittest/pointertest.cpp index 004fa22..72bfdbf 100644 --- a/test/unittest/pointertest.cpp +++ b/test/unittest/pointertest.cpp @@ -532,9 +532,13 @@ TEST(Pointer, Create) { Value* v = &Pointer("/foo/-").Create(d, d.GetAllocator()); EXPECT_EQ(&d["foo"][1], v); } + { Value* v = &Pointer("/foo/-/-").Create(d, d.GetAllocator()); - EXPECT_EQ(&d["foo"][2][0], v); + // "foo/-" is a newly created null value x. + // "foo/-/-" finds that x is not an array, it converts x to empty object + // and treats - as "-" member name + EXPECT_EQ(&d["foo"][2]["-"], v); } { @@ -1314,3 +1318,22 @@ TEST(Pointer, SwapValueByPointer_NoAllocator) { EXPECT_STREQ("bar", d["foo"][0].GetString()); EXPECT_STREQ("baz", d["foo"][1].GetString()); } + +TEST(Pointer, Ambiguity) { + { + Document d; + d.Parse("{\"0\" : [123]}"); + EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt()); + Pointer("/0/a").Set(d, 456); // Change array [123] to object {456} + EXPECT_EQ(456, Pointer("/0/a").Get(d)->GetInt()); + } + + { + Document d; + EXPECT_FALSE(d.Parse("[{\"0\": 123}]").HasParseError()); + EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt()); + Pointer("/0/1").Set(d, 456); // 1 is treated as "1" to index object + EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt()); + EXPECT_EQ(456, Pointer("/0/1").Get(d)->GetInt()); + } +}