1 // Tencent is pleased to support the open source community by making RapidJSON available.
2 //
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 //
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // http://opensource.org/licenses/MIT
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
14 
15 #ifndef RAPIDJSON_POINTER_H_
16 #define RAPIDJSON_POINTER_H_
17 
18 #include "document.h"
19 #include "internal/itoa.h"
20 
21 #ifdef __clang__
22 RAPIDJSON_DIAG_PUSH
23 RAPIDJSON_DIAG_OFF(switch-enum)
24 #endif
25 
26 #ifdef _MSC_VER
27 RAPIDJSON_DIAG_PUSH
28 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
29 #endif
30 
31 RAPIDJSON_NAMESPACE_BEGIN
32 
33 static const SizeType kPointerInvalidIndex = ~SizeType(0);  //!< Represents an invalid index in GenericPointer::Token
34 
35 //! Error code of parsing.
36 /*! \ingroup RAPIDJSON_ERRORS
37     \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
38 */
39 enum PointerParseErrorCode {
40     kPointerParseErrorNone = 0,                     //!< The parse is successful
41 
42     kPointerParseErrorTokenMustBeginWithSolidus,    //!< A token must begin with a '/'
43     kPointerParseErrorInvalidEscape,                //!< Invalid escape
44     kPointerParseErrorInvalidPercentEncoding,       //!< Invalid percent encoding in URI fragment
45     kPointerParseErrorCharacterMustPercentEncode    //!< A character must percent encoded in URI fragment
46 };
47 
48 ///////////////////////////////////////////////////////////////////////////////
49 // GenericPointer
50 
51 //! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
52 /*!
53     This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer"
54     (https://tools.ietf.org/html/rfc6901).
55 
56     A JSON pointer is for identifying a specific value in a JSON document
57     (GenericDocument). It can simplify coding of DOM tree manipulation, because it
58     can access multiple-level depth of DOM tree with single API call.
59 
60     After it parses a string representation (e.g. "/foo/0" or URI fragment
61     representation (e.g. "#/foo/0") into its internal representation (tokens),
62     it can be used to resolve a specific value in multiple documents, or sub-tree
63     of documents.
64 
65     Contrary to GenericValue, Pointer can be copy constructed and copy assigned.
66     Apart from assignment, a Pointer cannot be modified after construction.
67 
68     Although Pointer is very convenient, please aware that constructing Pointer
69     involves parsing and dynamic memory allocation. A special constructor with user-
70     supplied tokens eliminates these.
71 
72     GenericPointer depends on GenericDocument and GenericValue.
73 
74     \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >
75     \tparam Allocator The allocator type for allocating memory for internal representation.
76 
77     \note GenericPointer uses same encoding of ValueType.
78     However, Allocator of GenericPointer is independent of Allocator of Value.
79 */
80 template <typename ValueType, typename Allocator = CrtAllocator>
81 class GenericPointer {
82 public:
83     typedef typename ValueType::EncodingType EncodingType;  //!< Encoding type from Value
84     typedef typename ValueType::Ch Ch;                      //!< Character type from Value
85 
86     //! A token is the basic units of internal representation.
87     /*!
88         A JSON pointer string representation "/foo/123" is parsed to two tokens:
89         "foo" and 123. 123 will be represented in both numeric form and string form.
90         They are resolved according to the actual value type (object or array).
91 
92         For token that are not numbers, or the numeric value is out of bound
93         (greater than limits of SizeType), they are only treated as string form
94         (i.e. the token's index will be equal to kPointerInvalidIndex).
95 
96         This struct is public so that user can create a Pointer without parsing and
97         allocation, using a special constructor.
98     */
99     struct Token {
100         const Ch* name;             //!< Name of the token. It has null character at the end but it can contain null character.
101         SizeType length;            //!< Length of the name.
102         SizeType index;             //!< A valid array index, if it is not equal to kPointerInvalidIndex.
103     };
104 
105     //!@name Constructors and destructor.
106     //@{
107 
108     //! Default constructor.
allocator_(allocator)109     GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
110 
111     //! Constructor that parses a string or URI fragment representation.
112     /*!
113         \param source A null-terminated, string or URI fragment representation of JSON pointer.
114         \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
115     */
allocator_(allocator)116     explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
117         Parse(source, internal::StrLen(source));
118     }
119 
120 #if RAPIDJSON_HAS_STDSTRING
121     //! Constructor that parses a string or URI fragment representation.
122     /*!
123         \param source A string or URI fragment representation of JSON pointer.
124         \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
125         \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
126     */
allocator_(allocator)127     explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
128         Parse(source.c_str(), source.size());
129     }
130 #endif
131 
132     //! Constructor that parses a string or URI fragment representation, with length of the source string.
133     /*!
134         \param source A string or URI fragment representation of JSON pointer.
135         \param length Length of source.
136         \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
137         \note Slightly faster than the overload without length.
138     */
allocator_(allocator)139     GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
140         Parse(source, length);
141     }
142 
143     //! Constructor with user-supplied tokens.
144     /*!
145         This constructor let user supplies const array of tokens.
146         This prevents the parsing process and eliminates allocation.
147         This is preferred for memory constrained environments.
148 
149         \param tokens An constant array of tokens representing the JSON pointer.
150         \param tokenCount Number of tokens.
151 
152         \b Example
153         \code
154         #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
155         #define INDEX(i) { #i, sizeof(#i) - 1, i }
156 
157         static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
158         static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
159         // Equivalent to static const Pointer p("/foo/123");
160 
161         #undef NAME
162         #undef INDEX
163         \endcode
164     */
GenericPointer(const Token * tokens,size_t tokenCount)165     GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
166 
167     //! Copy constructor.
allocator_(allocator)168     GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
169         *this = rhs;
170     }
171 
172     //! Destructor.
~GenericPointer()173     ~GenericPointer() {
174         if (nameBuffer_)    // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
175             Allocator::Free(tokens_);
176         RAPIDJSON_DELETE(ownAllocator_);
177     }
178 
179     //! Assignment operator.
180     GenericPointer& operator=(const GenericPointer& rhs) {
181         if (this != &rhs) {
182             // Do not delete ownAllcator
183             if (nameBuffer_)
184                 Allocator::Free(tokens_);
185 
186             tokenCount_ = rhs.tokenCount_;
187             parseErrorOffset_ = rhs.parseErrorOffset_;
188             parseErrorCode_ = rhs.parseErrorCode_;
189 
190             if (rhs.nameBuffer_)
191                 CopyFromRaw(rhs); // Normally parsed tokens.
192             else {
193                 tokens_ = rhs.tokens_; // User supplied const tokens.
194                 nameBuffer_ = 0;
195             }
196         }
197         return *this;
198     }
199 
200     //@}
201 
202     //!@name Append token
203     //@{
204 
205     //! Append a token and return a new Pointer
206     /*!
207         \param token Token to be appended.
208         \param allocator Allocator for the newly return Pointer.
209         \return A new Pointer with appended token.
210     */
211     GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
212         GenericPointer r;
213         r.allocator_ = allocator;
214         Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);
215         std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
216         r.tokens_[tokenCount_].name = p;
217         r.tokens_[tokenCount_].length = token.length;
218         r.tokens_[tokenCount_].index = token.index;
219         return r;
220     }
221 
222     //! Append a name token with length, and return a new Pointer
223     /*!
224         \param name Name to be appended.
225         \param length Length of name.
226         \param allocator Allocator for the newly return Pointer.
227         \return A new Pointer with appended token.
228     */
229     GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {
230         Token token = { name, length, kPointerInvalidIndex };
231         return Append(token, allocator);
232     }
233 
234     //! Append a name token without length, and return a new Pointer
235     /*!
236         \param name Name (const Ch*) to be appended.
237         \param allocator Allocator for the newly return Pointer.
238         \return A new Pointer with appended token.
239     */
240     template <typename T>
241     RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
242     Append(T* name, Allocator* allocator = 0) const {
243         return Append(name, StrLen(name), allocator);
244     }
245 
246 #if RAPIDJSON_HAS_STDSTRING
247     //! Append a name token, and return a new Pointer
248     /*!
249         \param name Name to be appended.
250         \param allocator Allocator for the newly return Pointer.
251         \return A new Pointer with appended token.
252     */
253     GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {
254         return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);
255     }
256 #endif
257 
258     //! Append a index token, and return a new Pointer
259     /*!
260         \param index Index to be appended.
261         \param allocator Allocator for the newly return Pointer.
262         \return A new Pointer with appended token.
263     */
264     GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
265         char buffer[21];
266         char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);
267         SizeType length = static_cast<SizeType>(end - buffer);
268         buffer[length] = '\0';
269 
270         if (sizeof(Ch) == 1) {
271             Token token = { reinterpret_cast<Ch*>(buffer), length, index };
272             return Append(token, allocator);
273         }
274         else {
275             Ch name[21];
276             for (size_t i = 0; i <= length; i++)
277                 name[i] = static_cast<Ch>(buffer[i]);
278             Token token = { name, length, index };
279             return Append(token, allocator);
280         }
281     }
282 
283     //! Append a token by value, and return a new Pointer
284     /*!
285         \param token token to be appended.
286         \param allocator Allocator for the newly return Pointer.
287         \return A new Pointer with appended token.
288     */
289     GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {
290         if (token.IsString())
291             return Append(token.GetString(), token.GetStringLength(), allocator);
292         else {
293             RAPIDJSON_ASSERT(token.IsUint64());
294             RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));
295             return Append(static_cast<SizeType>(token.GetUint64()), allocator);
296         }
297     }
298 
299     //!@name Handling Parse Error
300     //@{
301 
302     //! Check whether this is a valid pointer.
IsValid()303     bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
304 
305     //! Get the parsing error offset in code unit.
GetParseErrorOffset()306     size_t GetParseErrorOffset() const { return parseErrorOffset_; }
307 
308     //! Get the parsing error code.
GetParseErrorCode()309     PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
310 
311     //@}
312 
313     //! Get the allocator of this pointer.
GetAllocator()314     Allocator& GetAllocator() { return *allocator_; }
315 
316     //!@name Tokens
317     //@{
318 
319     //! Get the token array (const version only).
GetTokens()320     const Token* GetTokens() const { return tokens_; }
321 
322     //! Get the number of tokens.
GetTokenCount()323     size_t GetTokenCount() const { return tokenCount_; }
324 
325     //@}
326 
327     //!@name Equality/inequality operators
328     //@{
329 
330     //! Equality operator.
331     /*!
332         \note When any pointers are invalid, always returns false.
333     */
334     bool operator==(const GenericPointer& rhs) const {
335         if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)
336             return false;
337 
338         for (size_t i = 0; i < tokenCount_; i++) {
339             if (tokens_[i].index != rhs.tokens_[i].index ||
340                 tokens_[i].length != rhs.tokens_[i].length ||
341                 (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))
342             {
343                 return false;
344             }
345         }
346 
347         return true;
348     }
349 
350     //! Inequality operator.
351     /*!
352         \note When any pointers are invalid, always returns true.
353     */
354     bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
355 
356     //@}
357 
358     //!@name Stringify
359     //@{
360 
361     //! Stringify the pointer into string representation.
362     /*!
363         \tparam OutputStream Type of output stream.
364         \param os The output stream.
365     */
366     template<typename OutputStream>
Stringify(OutputStream & os)367     bool Stringify(OutputStream& os) const {
368         return Stringify<false, OutputStream>(os);
369     }
370 
371     //! Stringify the pointer into URI fragment representation.
372     /*!
373         \tparam OutputStream Type of output stream.
374         \param os The output stream.
375     */
376     template<typename OutputStream>
StringifyUriFragment(OutputStream & os)377     bool StringifyUriFragment(OutputStream& os) const {
378         return Stringify<true, OutputStream>(os);
379     }
380 
381     //@}
382 
383     //!@name Create value
384     //@{
385 
386     //! Create a value in a subtree.
387     /*!
388         If the value is not exist, it creates all parent values and a JSON Null value.
389         So it always succeed and return the newly created or existing value.
390 
391         Remind that it may change types of parents according to tokens, so it
392         potentially removes previously stored values. For example, if a document
393         was an array, and "/foo" is used to create a value, then the document
394         will be changed to an object, and all existing array elements are lost.
395 
396         \param root Root value of a DOM subtree to be resolved. It can be any value other than document root.
397         \param allocator Allocator for creating the values if the specified value or its parents are not exist.
398         \param alreadyExist If non-null, it stores whether the resolved value is already exist.
399         \return The resolved newly created (a JSON Null value), or already exists value.
400     */
401     ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {
402         RAPIDJSON_ASSERT(IsValid());
403         ValueType* v = &root;
404         bool exist = true;
405         for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
406             if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
407 //NCBI: added SetValueAllocator
408                 v->PushBack(ValueType().SetValueAllocator(&allocator).Move(), allocator);
409                 v = &((*v)[v->Size() - 1]);
410                 exist = false;
411             }
412             else {
413                 if (t->index == kPointerInvalidIndex) { // must be object name
414                     if (!v->IsObject())
415                         v->SetObject(); // Change to Object
416                 }
417                 else { // object name or array index
418                     if (!v->IsArray() && !v->IsObject())
419                         v->SetArray(); // Change to Array
420                 }
421 
422                 if (v->IsArray()) {
423                     if (t->index >= v->Size()) {
424                         v->Reserve(t->index + 1, allocator);
425 //NCBI: added SetValueAllocator
426                         while (t->index >= v->Size())
427                             v->PushBack(ValueType().SetValueAllocator(&allocator).Move(), allocator);
428                         exist = false;
429                     }
430                     v = &((*v)[t->index]);
431                 }
432                 else {
433                     typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
434                     if (m == v->MemberEnd()) {
435 //NCBI: added SetValueAllocator
436                         v->AddMember(ValueType(t->name, t->length, allocator).SetValueAllocator(&allocator).Move(), ValueType().SetValueAllocator(&allocator).Move(), allocator);
437                         m = v->MemberEnd();
438                         v = &(--m)->value; // Assumes AddMember() appends at the end
439 //                        v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end
440                         exist = false;
441                     }
442                     else
443                         v = &m->value;
444                 }
445             }
446         }
447 
448         if (alreadyExist)
449             *alreadyExist = exist;
450 
451         return *v;
452     }
453 
454     //! Creates a value in a document.
455     /*!
456         \param document A document to be resolved.
457         \param alreadyExist If non-null, it stores whether the resolved value is already exist.
458         \return The resolved newly created, or already exists value.
459     */
460     template <typename stackAllocator>
461     ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const {
462         return Create(document, document.GetAllocator(), alreadyExist);
463     }
464 
465     //@}
466 
467     //!@name Query value
468     //@{
469 
470     //! Query a value in a subtree.
471     /*!
472         \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
473         \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
474         \return Pointer to the value if it can be resolved. Otherwise null.
475 
476         \note
477         There are only 3 situations when a value cannot be resolved:
478         1. A value in the path is not an array nor object.
479         2. An object value does not contain the token.
480         3. A token is out of range of an array value.
481 
482         Use unresolvedTokenIndex to retrieve the token index.
483     */
484     ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
485         RAPIDJSON_ASSERT(IsValid());
486         ValueType* v = &root;
487         for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
488             switch (v->GetType()) {
489             case kObjectType:
490                 {
491                     typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
492                     if (m == v->MemberEnd())
493                         break;
494                     v = &m->value;
495                 }
496                 continue;
497             case kArrayType:
498                 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
499                     break;
500                 v = &((*v)[t->index]);
501                 continue;
502             default:
503                 break;
504             }
505 
506             // Error: unresolved token
507             if (unresolvedTokenIndex)
508                 *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
509             return 0;
510         }
511         return v;
512     }
513 
514     //! Query a const value in a const subtree.
515     /*!
516         \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
517         \return Pointer to the value if it can be resolved. Otherwise null.
518     */
519     const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
520         return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
521     }
522 
523     //@}
524 
525     //!@name Query a value with default
526     //@{
527 
528     //! Query a value in a subtree with default value.
529     /*!
530         Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value.
531         So that this function always succeed.
532 
533         \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
534         \param defaultValue Default value to be cloned if the value was not exists.
535         \param allocator Allocator for creating the values if the specified value or its parents are not exist.
536         \see Create()
537     */
GetWithDefault(ValueType & root,const ValueType & defaultValue,typename ValueType::AllocatorType & allocator)538     ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
539         bool alreadyExist;
540         Value& v = Create(root, allocator, &alreadyExist);
541         return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
542     }
543 
544     //! Query a value in a subtree with default null-terminated string.
GetWithDefault(ValueType & root,const Ch * defaultValue,typename ValueType::AllocatorType & allocator)545     ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
546         bool alreadyExist;
547         Value& v = Create(root, allocator, &alreadyExist);
548         return alreadyExist ? v : v.SetString(defaultValue, allocator);
549     }
550 
551 #if RAPIDJSON_HAS_STDSTRING
552     //! Query a value in a subtree with default std::basic_string.
GetWithDefault(ValueType & root,const std::basic_string<Ch> & defaultValue,typename ValueType::AllocatorType & allocator)553     ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
554         bool alreadyExist;
555         Value& v = Create(root, allocator, &alreadyExist);
556         return alreadyExist ? v : v.SetString(defaultValue, allocator);
557     }
558 #endif
559 
560     //! Query a value in a subtree with default primitive value.
561     /*!
562         \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
563     */
564     template <typename T>
565     RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
GetWithDefault(ValueType & root,T defaultValue,typename ValueType::AllocatorType & allocator)566     GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {
567         return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);
568     }
569 
570     //! Query a value in a document with default value.
571     template <typename stackAllocator>
GetWithDefault(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const ValueType & defaultValue)572     ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const {
573         return GetWithDefault(document, defaultValue, document.GetAllocator());
574     }
575 
576     //! Query a value in a document with default null-terminated string.
577     template <typename stackAllocator>
GetWithDefault(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const Ch * defaultValue)578     ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {
579         return GetWithDefault(document, defaultValue, document.GetAllocator());
580     }
581 
582 #if RAPIDJSON_HAS_STDSTRING
583     //! Query a value in a document with default std::basic_string.
584     template <typename stackAllocator>
GetWithDefault(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const std::basic_string<Ch> & defaultValue)585     ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const {
586         return GetWithDefault(document, defaultValue, document.GetAllocator());
587     }
588 #endif
589 
590     //! Query a value in a document with default primitive value.
591     /*!
592         \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
593     */
594     template <typename T, typename stackAllocator>
595     RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
GetWithDefault(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,T defaultValue)596     GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {
597         return GetWithDefault(document, defaultValue, document.GetAllocator());
598     }
599 
600     //@}
601 
602     //!@name Set a value
603     //@{
604 
605     //! Set a value in a subtree, with move semantics.
606     /*!
607         It creates all parents if they are not exist or types are different to the tokens.
608         So this function always succeeds but potentially remove existing values.
609 
610         \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
611         \param value Value to be set.
612         \param allocator Allocator for creating the values if the specified value or its parents are not exist.
613         \see Create()
614     */
Set(ValueType & root,ValueType & value,typename ValueType::AllocatorType & allocator)615     ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
616         return Create(root, allocator) = value;
617     }
618 
619     //! Set a value in a subtree, with copy semantics.
Set(ValueType & root,const ValueType & value,typename ValueType::AllocatorType & allocator)620     ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const {
621         return Create(root, allocator).CopyFrom(value, allocator);
622     }
623 
624     //! Set a null-terminated string in a subtree.
Set(ValueType & root,const Ch * value,typename ValueType::AllocatorType & allocator)625     ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const {
626         return Create(root, allocator) = ValueType(value, allocator).Move();
627     }
628 
629 #if RAPIDJSON_HAS_STDSTRING
630     //! Set a std::basic_string in a subtree.
Set(ValueType & root,const std::basic_string<Ch> & value,typename ValueType::AllocatorType & allocator)631     ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const {
632         return Create(root, allocator) = ValueType(value, allocator).Move();
633     }
634 #endif
635 
636     //! Set a primitive value in a subtree.
637     /*!
638         \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
639     */
640     template <typename T>
641     RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
Set(ValueType & root,T value,typename ValueType::AllocatorType & allocator)642     Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {
643         return Create(root, allocator) = ValueType(value).Move();
644     }
645 
646     //! Set a value in a document, with move semantics.
647     template <typename stackAllocator>
Set(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,ValueType & value)648     ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
649         return Create(document) = value;
650     }
651 
652     //! Set a value in a document, with copy semantics.
653     template <typename stackAllocator>
Set(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const ValueType & value)654     ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const {
655         return Create(document).CopyFrom(value, document.GetAllocator());
656     }
657 
658     //! Set a null-terminated string in a document.
659     template <typename stackAllocator>
Set(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const Ch * value)660     ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const {
661         return Create(document) = ValueType(value, document.GetAllocator()).Move();
662     }
663 
664 #if RAPIDJSON_HAS_STDSTRING
665     //! Sets a std::basic_string in a document.
666     template <typename stackAllocator>
Set(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,const std::basic_string<Ch> & value)667     ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const {
668         return Create(document) = ValueType(value, document.GetAllocator()).Move();
669     }
670 #endif
671 
672     //! Set a primitive value in a document.
673     /*!
674     \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
675     */
676     template <typename T, typename stackAllocator>
677     RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
Set(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,T value)678         Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {
679             return Create(document) = value;
680     }
681 
682     //@}
683 
684     //!@name Swap a value
685     //@{
686 
687     //! Swap a value with a value in a subtree.
688     /*!
689         It creates all parents if they are not exist or types are different to the tokens.
690         So this function always succeeds but potentially remove existing values.
691 
692         \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
693         \param value Value to be swapped.
694         \param allocator Allocator for creating the values if the specified value or its parents are not exist.
695         \see Create()
696     */
Swap(ValueType & root,ValueType & value,typename ValueType::AllocatorType & allocator)697     ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
698         return Create(root, allocator).Swap(value);
699     }
700 
701     //! Swap a value with a value in a document.
702     template <typename stackAllocator>
Swap(GenericDocument<EncodingType,typename ValueType::AllocatorType,stackAllocator> & document,ValueType & value)703     ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
704         return Create(document).Swap(value);
705     }
706 
707     //@}
708 
709     //! Erase a value in a subtree.
710     /*!
711         \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
712         \return Whether the resolved value is found and erased.
713 
714         \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false.
715     */
Erase(ValueType & root)716     bool Erase(ValueType& root) const {
717         RAPIDJSON_ASSERT(IsValid());
718         if (tokenCount_ == 0) // Cannot erase the root
719             return false;
720 
721         ValueType* v = &root;
722         const Token* last = tokens_ + (tokenCount_ - 1);
723         for (const Token *t = tokens_; t != last; ++t) {
724             switch (v->GetType()) {
725             case kObjectType:
726                 {
727                     typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
728                     if (m == v->MemberEnd())
729                         return false;
730                     v = &m->value;
731                 }
732                 break;
733             case kArrayType:
734                 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
735                     return false;
736                 v = &((*v)[t->index]);
737                 break;
738             default:
739                 return false;
740             }
741         }
742 
743         switch (v->GetType()) {
744         case kObjectType:
745             return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));
746         case kArrayType:
747             if (last->index == kPointerInvalidIndex || last->index >= v->Size())
748                 return false;
749             v->Erase(v->Begin() + last->index);
750             return true;
751         default:
752             return false;
753         }
754     }
755 
756 private:
757     //! Clone the content from rhs to this.
758     /*!
759         \param rhs Source pointer.
760         \param extraToken Extra tokens to be allocated.
761         \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated.
762         \return Start of non-occupied name buffer, for storing extra names.
763     */
764     Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {
765         if (!allocator_) // allocator is independently owned.
766             ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
767 
768         size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
769         for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
770             nameBufferSize += t->length;
771 
772         tokenCount_ = rhs.tokenCount_ + extraToken;
773         tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
774         nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
775         if (rhs.tokenCount_ > 0) {
776             std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
777         }
778         if (nameBufferSize > 0) {
779             std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
780         }
781 
782         // Adjust pointers to name buffer
783         std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
784         for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
785             t->name += diff;
786 
787         return nameBuffer_ + nameBufferSize;
788     }
789 
790     //! Check whether a character should be percent-encoded.
791     /*!
792         According to RFC 3986 2.3 Unreserved Characters.
793         \param c The character (code unit) to be tested.
794     */
NeedPercentEncode(Ch c)795     bool NeedPercentEncode(Ch c) const {
796         return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~');
797     }
798 
799     //! Parse a JSON String or its URI fragment representation into tokens.
800 #ifndef __clang__ // -Wdocumentation
801     /*!
802         \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated.
803         \param length Length of the source string.
804         \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped.
805     */
806 #endif
Parse(const Ch * source,size_t length)807     void Parse(const Ch* source, size_t length) {
808         RAPIDJSON_ASSERT(source != NULL);
809         RAPIDJSON_ASSERT(nameBuffer_ == 0);
810         RAPIDJSON_ASSERT(tokens_ == 0);
811 
812         // Create own allocator if user did not supply.
813         if (!allocator_)
814             ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
815 
816         // Count number of '/' as tokenCount
817         tokenCount_ = 0;
818         for (const Ch* s = source; s != source + length; s++)
819             if (*s == '/')
820                 tokenCount_++;
821 
822         Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));
823         Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
824         size_t i = 0;
825 
826         // Detect if it is a URI fragment
827         bool uriFragment = false;
828         if (source[i] == '#') {
829             uriFragment = true;
830             i++;
831         }
832 
833         if (i != length && source[i] != '/') {
834             parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;
835             goto error;
836         }
837 
838         while (i < length) {
839             RAPIDJSON_ASSERT(source[i] == '/');
840             i++; // consumes '/'
841 
842             token->name = name;
843             bool isNumber = true;
844 
845             while (i < length && source[i] != '/') {
846                 Ch c = source[i];
847                 if (uriFragment) {
848                     // Decoding percent-encoding for URI fragment
849                     if (c == '%') {
850                         PercentDecodeStream is(&source[i], source + length);
851                         GenericInsituStringStream<EncodingType> os(name);
852                         Ch* begin = os.PutBegin();
853                         if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) {
854                             parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding;
855                             goto error;
856                         }
857                         size_t len = os.PutEnd(begin);
858                         i += is.Tell() - 1;
859                         if (len == 1)
860                             c = *name;
861                         else {
862                             name += len;
863                             isNumber = false;
864                             i++;
865                             continue;
866                         }
867                     }
868                     else if (NeedPercentEncode(c)) {
869                         parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode;
870                         goto error;
871                     }
872                 }
873 
874                 i++;
875 
876                 // Escaping "~0" -> '~', "~1" -> '/'
877                 if (c == '~') {
878                     if (i < length) {
879                         c = source[i];
880                         if (c == '0')       c = '~';
881                         else if (c == '1')  c = '/';
882                         else {
883                             parseErrorCode_ = kPointerParseErrorInvalidEscape;
884                             goto error;
885                         }
886                         i++;
887                     }
888                     else {
889                         parseErrorCode_ = kPointerParseErrorInvalidEscape;
890                         goto error;
891                     }
892                 }
893 
894                 // First check for index: all of characters are digit
895                 if (c < '0' || c > '9')
896                     isNumber = false;
897 
898                 *name++ = c;
899             }
900             token->length = static_cast<SizeType>(name - token->name);
901             if (token->length == 0)
902                 isNumber = false;
903             *name++ = '\0'; // Null terminator
904 
905             // Second check for index: more than one digit cannot have leading zero
906             if (isNumber && token->length > 1 && token->name[0] == '0')
907                 isNumber = false;
908 
909             // String to SizeType conversion
910             SizeType n = 0;
911             if (isNumber) {
912                 for (size_t j = 0; j < token->length; j++) {
913                     SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');
914                     if (m < n) {   // overflow detection
915                         isNumber = false;
916                         break;
917                     }
918                     n = m;
919                 }
920             }
921 
922             token->index = isNumber ? n : kPointerInvalidIndex;
923             token++;
924         }
925 
926         RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
927         parseErrorCode_ = kPointerParseErrorNone;
928         return;
929 
930     error:
931         Allocator::Free(tokens_);
932         nameBuffer_ = 0;
933         tokens_ = 0;
934         tokenCount_ = 0;
935         parseErrorOffset_ = i;
936         return;
937     }
938 
939     //! Stringify to string or URI fragment representation.
940     /*!
941         \tparam uriFragment True for stringifying to URI fragment representation. False for string representation.
942         \tparam OutputStream type of output stream.
943         \param os The output stream.
944     */
945     template<bool uriFragment, typename OutputStream>
Stringify(OutputStream & os)946     bool Stringify(OutputStream& os) const {
947         RAPIDJSON_ASSERT(IsValid());
948 
949         if (uriFragment)
950             os.Put('#');
951 
952         for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
953             os.Put('/');
954             for (size_t j = 0; j < t->length; j++) {
955                 Ch c = t->name[j];
956                 if (c == '~') {
957                     os.Put('~');
958                     os.Put('0');
959                 }
960                 else if (c == '/') {
961                     os.Put('~');
962                     os.Put('1');
963                 }
964                 else if (uriFragment && NeedPercentEncode(c)) {
965                     // Transcode to UTF8 sequence
966                     GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]);
967                     PercentEncodeStream<OutputStream> target(os);
968                     if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target))
969                         return false;
970                     j += source.Tell() - 1;
971                 }
972                 else
973                     os.Put(c);
974             }
975         }
976         return true;
977     }
978 
979     //! A helper stream for decoding a percent-encoded sequence into code unit.
980     /*!
981         This stream decodes %XY triplet into code unit (0-255).
982         If it encounters invalid characters, it sets output code unit as 0 and
983         mark invalid, and to be checked by IsValid().
984     */
985     class PercentDecodeStream {
986     public:
987         typedef typename ValueType::Ch Ch;
988 
989         //! Constructor
990         /*!
991             \param source Start of the stream
992             \param end Past-the-end of the stream.
993         */
PercentDecodeStream(const Ch * source,const Ch * end)994         PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}
995 
Take()996         Ch Take() {
997             if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet
998                 valid_ = false;
999                 return 0;
1000             }
1001             src_++;
1002             Ch c = 0;
1003             for (int j = 0; j < 2; j++) {
1004                 c = static_cast<Ch>(c << 4);
1005                 Ch h = *src_;
1006                 if      (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0');
1007                 else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10);
1008                 else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10);
1009                 else {
1010                     valid_ = false;
1011                     return 0;
1012                 }
1013                 src_++;
1014             }
1015             return c;
1016         }
1017 
Tell()1018         size_t Tell() const { return static_cast<size_t>(src_ - head_); }
IsValid()1019         bool IsValid() const { return valid_; }
1020 
1021     private:
1022         const Ch* src_;     //!< Current read position.
1023         const Ch* head_;    //!< Original head of the string.
1024         const Ch* end_;     //!< Past-the-end position.
1025         bool valid_;        //!< Whether the parsing is valid.
1026     };
1027 
1028     //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.
1029     template <typename OutputStream>
1030     class PercentEncodeStream {
1031     public:
PercentEncodeStream(OutputStream & os)1032         PercentEncodeStream(OutputStream& os) : os_(os) {}
Put(char c)1033         void Put(char c) { // UTF-8 must be byte
1034             unsigned char u = static_cast<unsigned char>(c);
1035             static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
1036             os_.Put('%');
1037             os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u >> 4]));
1038             os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u & 15]));
1039         }
1040     private:
1041         OutputStream& os_;
1042     };
1043 
1044     Allocator* allocator_;                  //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
1045     Allocator* ownAllocator_;               //!< Allocator owned by this Pointer.
1046     Ch* nameBuffer_;                        //!< A buffer containing all names in tokens.
1047     Token* tokens_;                         //!< A list of tokens.
1048     size_t tokenCount_;                     //!< Number of tokens in tokens_.
1049     size_t parseErrorOffset_;               //!< Offset in code unit when parsing fail.
1050     PointerParseErrorCode parseErrorCode_;  //!< Parsing error code.
1051 };
1052 
1053 //! GenericPointer for Value (UTF-8, default allocator).
1054 typedef GenericPointer<Value> Pointer;
1055 
1056 //!@name Helper functions for GenericPointer
1057 //@{
1058 
1059 //////////////////////////////////////////////////////////////////////////////
1060 
1061 template <typename T>
CreateValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,typename T::AllocatorType & a)1062 typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {
1063     return pointer.Create(root, a);
1064 }
1065 
1066 template <typename T, typename CharType, size_t N>
CreateValueByPointer(T & root,const CharType (& source)[N],typename T::AllocatorType & a)1067 typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) {
1068     return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);
1069 }
1070 
1071 // No allocator parameter
1072 
1073 template <typename DocumentType>
CreateValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer)1074 typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {
1075     return pointer.Create(document);
1076 }
1077 
1078 template <typename DocumentType, typename CharType, size_t N>
CreateValueByPointer(DocumentType & document,const CharType (& source)[N])1079 typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {
1080     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);
1081 }
1082 
1083 //////////////////////////////////////////////////////////////////////////////
1084 
1085 template <typename T>
1086 typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
1087     return pointer.Get(root, unresolvedTokenIndex);
1088 }
1089 
1090 template <typename T>
1091 const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
1092     return pointer.Get(root, unresolvedTokenIndex);
1093 }
1094 
1095 template <typename T, typename CharType, size_t N>
1096 typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {
1097     return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
1098 }
1099 
1100 template <typename T, typename CharType, size_t N>
1101 const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {
1102     return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
1103 }
1104 
1105 //////////////////////////////////////////////////////////////////////////////
1106 
1107 template <typename T>
GetValueByPointerWithDefault(T & root,const GenericPointer<typename T::ValueType> & pointer,const typename T::ValueType & defaultValue,typename T::AllocatorType & a)1108 typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
1109     return pointer.GetWithDefault(root, defaultValue, a);
1110 }
1111 
1112 template <typename T>
GetValueByPointerWithDefault(T & root,const GenericPointer<typename T::ValueType> & pointer,const typename T::Ch * defaultValue,typename T::AllocatorType & a)1113 typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
1114     return pointer.GetWithDefault(root, defaultValue, a);
1115 }
1116 
1117 #if RAPIDJSON_HAS_STDSTRING
1118 template <typename T>
GetValueByPointerWithDefault(T & root,const GenericPointer<typename T::ValueType> & pointer,const std::basic_string<typename T::Ch> & defaultValue,typename T::AllocatorType & a)1119 typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
1120     return pointer.GetWithDefault(root, defaultValue, a);
1121 }
1122 #endif
1123 
1124 template <typename T, typename T2>
1125 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
GetValueByPointerWithDefault(T & root,const GenericPointer<typename T::ValueType> & pointer,T2 defaultValue,typename T::AllocatorType & a)1126 GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {
1127     return pointer.GetWithDefault(root, defaultValue, a);
1128 }
1129 
1130 template <typename T, typename CharType, size_t N>
GetValueByPointerWithDefault(T & root,const CharType (& source)[N],const typename T::ValueType & defaultValue,typename T::AllocatorType & a)1131 typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
1132     return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1133 }
1134 
1135 template <typename T, typename CharType, size_t N>
GetValueByPointerWithDefault(T & root,const CharType (& source)[N],const typename T::Ch * defaultValue,typename T::AllocatorType & a)1136 typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
1137     return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1138 }
1139 
1140 #if RAPIDJSON_HAS_STDSTRING
1141 template <typename T, typename CharType, size_t N>
GetValueByPointerWithDefault(T & root,const CharType (& source)[N],const std::basic_string<typename T::Ch> & defaultValue,typename T::AllocatorType & a)1142 typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
1143     return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1144 }
1145 #endif
1146 
1147 template <typename T, typename CharType, size_t N, typename T2>
1148 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
GetValueByPointerWithDefault(T & root,const CharType (& source)[N],T2 defaultValue,typename T::AllocatorType & a)1149 GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) {
1150     return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1151 }
1152 
1153 // No allocator parameter
1154 
1155 template <typename DocumentType>
GetValueByPointerWithDefault(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const typename DocumentType::ValueType & defaultValue)1156 typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {
1157     return pointer.GetWithDefault(document, defaultValue);
1158 }
1159 
1160 template <typename DocumentType>
GetValueByPointerWithDefault(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const typename DocumentType::Ch * defaultValue)1161 typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) {
1162     return pointer.GetWithDefault(document, defaultValue);
1163 }
1164 
1165 #if RAPIDJSON_HAS_STDSTRING
1166 template <typename DocumentType>
GetValueByPointerWithDefault(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const std::basic_string<typename DocumentType::Ch> & defaultValue)1167 typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) {
1168     return pointer.GetWithDefault(document, defaultValue);
1169 }
1170 #endif
1171 
1172 template <typename DocumentType, typename T2>
1173 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
GetValueByPointerWithDefault(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,T2 defaultValue)1174 GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {
1175     return pointer.GetWithDefault(document, defaultValue);
1176 }
1177 
1178 template <typename DocumentType, typename CharType, size_t N>
GetValueByPointerWithDefault(DocumentType & document,const CharType (& source)[N],const typename DocumentType::ValueType & defaultValue)1179 typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) {
1180     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1181 }
1182 
1183 template <typename DocumentType, typename CharType, size_t N>
GetValueByPointerWithDefault(DocumentType & document,const CharType (& source)[N],const typename DocumentType::Ch * defaultValue)1184 typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) {
1185     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1186 }
1187 
1188 #if RAPIDJSON_HAS_STDSTRING
1189 template <typename DocumentType, typename CharType, size_t N>
GetValueByPointerWithDefault(DocumentType & document,const CharType (& source)[N],const std::basic_string<typename DocumentType::Ch> & defaultValue)1190 typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {
1191     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1192 }
1193 #endif
1194 
1195 template <typename DocumentType, typename CharType, size_t N, typename T2>
1196 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
GetValueByPointerWithDefault(DocumentType & document,const CharType (& source)[N],T2 defaultValue)1197 GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {
1198     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1199 }
1200 
1201 //////////////////////////////////////////////////////////////////////////////
1202 
1203 template <typename T>
SetValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,typename T::ValueType & value,typename T::AllocatorType & a)1204 typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
1205     return pointer.Set(root, value, a);
1206 }
1207 
1208 template <typename T>
SetValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,const typename T::ValueType & value,typename T::AllocatorType & a)1209 typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) {
1210     return pointer.Set(root, value, a);
1211 }
1212 
1213 template <typename T>
SetValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,const typename T::Ch * value,typename T::AllocatorType & a)1214 typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) {
1215     return pointer.Set(root, value, a);
1216 }
1217 
1218 #if RAPIDJSON_HAS_STDSTRING
1219 template <typename T>
SetValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,const std::basic_string<typename T::Ch> & value,typename T::AllocatorType & a)1220 typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
1221     return pointer.Set(root, value, a);
1222 }
1223 #endif
1224 
1225 template <typename T, typename T2>
1226 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
SetValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,T2 value,typename T::AllocatorType & a)1227 SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {
1228     return pointer.Set(root, value, a);
1229 }
1230 
1231 template <typename T, typename CharType, size_t N>
SetValueByPointer(T & root,const CharType (& source)[N],typename T::ValueType & value,typename T::AllocatorType & a)1232 typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
1233     return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1234 }
1235 
1236 template <typename T, typename CharType, size_t N>
SetValueByPointer(T & root,const CharType (& source)[N],const typename T::ValueType & value,typename T::AllocatorType & a)1237 typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) {
1238     return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1239 }
1240 
1241 template <typename T, typename CharType, size_t N>
SetValueByPointer(T & root,const CharType (& source)[N],const typename T::Ch * value,typename T::AllocatorType & a)1242 typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) {
1243     return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1244 }
1245 
1246 #if RAPIDJSON_HAS_STDSTRING
1247 template <typename T, typename CharType, size_t N>
SetValueByPointer(T & root,const CharType (& source)[N],const std::basic_string<typename T::Ch> & value,typename T::AllocatorType & a)1248 typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
1249     return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1250 }
1251 #endif
1252 
1253 template <typename T, typename CharType, size_t N, typename T2>
1254 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
SetValueByPointer(T & root,const CharType (& source)[N],T2 value,typename T::AllocatorType & a)1255 SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) {
1256     return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1257 }
1258 
1259 // No allocator parameter
1260 
1261 template <typename DocumentType>
SetValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,typename DocumentType::ValueType & value)1262 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
1263     return pointer.Set(document, value);
1264 }
1265 
1266 template <typename DocumentType>
SetValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const typename DocumentType::ValueType & value)1267 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {
1268     return pointer.Set(document, value);
1269 }
1270 
1271 template <typename DocumentType>
SetValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const typename DocumentType::Ch * value)1272 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) {
1273     return pointer.Set(document, value);
1274 }
1275 
1276 #if RAPIDJSON_HAS_STDSTRING
1277 template <typename DocumentType>
SetValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,const std::basic_string<typename DocumentType::Ch> & value)1278 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) {
1279     return pointer.Set(document, value);
1280 }
1281 #endif
1282 
1283 template <typename DocumentType, typename T2>
1284 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
SetValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,T2 value)1285 SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {
1286     return pointer.Set(document, value);
1287 }
1288 
1289 template <typename DocumentType, typename CharType, size_t N>
SetValueByPointer(DocumentType & document,const CharType (& source)[N],typename DocumentType::ValueType & value)1290 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
1291     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1292 }
1293 
1294 template <typename DocumentType, typename CharType, size_t N>
SetValueByPointer(DocumentType & document,const CharType (& source)[N],const typename DocumentType::ValueType & value)1295 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) {
1296     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1297 }
1298 
1299 template <typename DocumentType, typename CharType, size_t N>
SetValueByPointer(DocumentType & document,const CharType (& source)[N],const typename DocumentType::Ch * value)1300 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) {
1301     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1302 }
1303 
1304 #if RAPIDJSON_HAS_STDSTRING
1305 template <typename DocumentType, typename CharType, size_t N>
SetValueByPointer(DocumentType & document,const CharType (& source)[N],const std::basic_string<typename DocumentType::Ch> & value)1306 typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {
1307     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1308 }
1309 #endif
1310 
1311 template <typename DocumentType, typename CharType, size_t N, typename T2>
1312 RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
SetValueByPointer(DocumentType & document,const CharType (& source)[N],T2 value)1313 SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {
1314     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1315 }
1316 
1317 //////////////////////////////////////////////////////////////////////////////
1318 
1319 template <typename T>
SwapValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer,typename T::ValueType & value,typename T::AllocatorType & a)1320 typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
1321     return pointer.Swap(root, value, a);
1322 }
1323 
1324 template <typename T, typename CharType, size_t N>
SwapValueByPointer(T & root,const CharType (& source)[N],typename T::ValueType & value,typename T::AllocatorType & a)1325 typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
1326     return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a);
1327 }
1328 
1329 template <typename DocumentType>
SwapValueByPointer(DocumentType & document,const GenericPointer<typename DocumentType::ValueType> & pointer,typename DocumentType::ValueType & value)1330 typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
1331     return pointer.Swap(document, value);
1332 }
1333 
1334 template <typename DocumentType, typename CharType, size_t N>
SwapValueByPointer(DocumentType & document,const CharType (& source)[N],typename DocumentType::ValueType & value)1335 typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
1336     return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);
1337 }
1338 
1339 //////////////////////////////////////////////////////////////////////////////
1340 
1341 template <typename T>
EraseValueByPointer(T & root,const GenericPointer<typename T::ValueType> & pointer)1342 bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
1343     return pointer.Erase(root);
1344 }
1345 
1346 template <typename T, typename CharType, size_t N>
EraseValueByPointer(T & root,const CharType (& source)[N])1347 bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
1348     return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
1349 }
1350 
1351 //@}
1352 
1353 RAPIDJSON_NAMESPACE_END
1354 
1355 #ifdef __clang__
1356 RAPIDJSON_DIAG_POP
1357 #endif
1358 
1359 #ifdef _MSC_VER
1360 RAPIDJSON_DIAG_POP
1361 #endif
1362 
1363 #endif // RAPIDJSON_POINTER_H_
1364