rapidjson 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +84 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +110 -0
  5. data/Rakefile +20 -0
  6. data/ext/rapidjson/buffer.hh +66 -0
  7. data/ext/rapidjson/cext.cc +77 -0
  8. data/ext/rapidjson/cext.hh +20 -0
  9. data/ext/rapidjson/encoder.hh +150 -0
  10. data/ext/rapidjson/extconf.rb +19 -0
  11. data/ext/rapidjson/parser.hh +149 -0
  12. data/ext/rapidjson/rapidjson/include/rapidjson/allocators.h +692 -0
  13. data/ext/rapidjson/rapidjson/include/rapidjson/cursorstreamwrapper.h +78 -0
  14. data/ext/rapidjson/rapidjson/include/rapidjson/document.h +3027 -0
  15. data/ext/rapidjson/rapidjson/include/rapidjson/encodedstream.h +299 -0
  16. data/ext/rapidjson/rapidjson/include/rapidjson/encodings.h +716 -0
  17. data/ext/rapidjson/rapidjson/include/rapidjson/error/en.h +122 -0
  18. data/ext/rapidjson/rapidjson/include/rapidjson/error/error.h +216 -0
  19. data/ext/rapidjson/rapidjson/include/rapidjson/filereadstream.h +99 -0
  20. data/ext/rapidjson/rapidjson/include/rapidjson/filewritestream.h +104 -0
  21. data/ext/rapidjson/rapidjson/include/rapidjson/fwd.h +151 -0
  22. data/ext/rapidjson/rapidjson/include/rapidjson/internal/biginteger.h +297 -0
  23. data/ext/rapidjson/rapidjson/include/rapidjson/internal/clzll.h +71 -0
  24. data/ext/rapidjson/rapidjson/include/rapidjson/internal/diyfp.h +261 -0
  25. data/ext/rapidjson/rapidjson/include/rapidjson/internal/dtoa.h +249 -0
  26. data/ext/rapidjson/rapidjson/include/rapidjson/internal/ieee754.h +78 -0
  27. data/ext/rapidjson/rapidjson/include/rapidjson/internal/itoa.h +308 -0
  28. data/ext/rapidjson/rapidjson/include/rapidjson/internal/meta.h +186 -0
  29. data/ext/rapidjson/rapidjson/include/rapidjson/internal/pow10.h +55 -0
  30. data/ext/rapidjson/rapidjson/include/rapidjson/internal/regex.h +739 -0
  31. data/ext/rapidjson/rapidjson/include/rapidjson/internal/stack.h +232 -0
  32. data/ext/rapidjson/rapidjson/include/rapidjson/internal/strfunc.h +83 -0
  33. data/ext/rapidjson/rapidjson/include/rapidjson/internal/strtod.h +293 -0
  34. data/ext/rapidjson/rapidjson/include/rapidjson/internal/swap.h +46 -0
  35. data/ext/rapidjson/rapidjson/include/rapidjson/istreamwrapper.h +128 -0
  36. data/ext/rapidjson/rapidjson/include/rapidjson/memorybuffer.h +70 -0
  37. data/ext/rapidjson/rapidjson/include/rapidjson/memorystream.h +71 -0
  38. data/ext/rapidjson/rapidjson/include/rapidjson/msinttypes/inttypes.h +316 -0
  39. data/ext/rapidjson/rapidjson/include/rapidjson/msinttypes/stdint.h +300 -0
  40. data/ext/rapidjson/rapidjson/include/rapidjson/ostreamwrapper.h +81 -0
  41. data/ext/rapidjson/rapidjson/include/rapidjson/pointer.h +1482 -0
  42. data/ext/rapidjson/rapidjson/include/rapidjson/prettywriter.h +277 -0
  43. data/ext/rapidjson/rapidjson/include/rapidjson/rapidjson.h +741 -0
  44. data/ext/rapidjson/rapidjson/include/rapidjson/reader.h +2246 -0
  45. data/ext/rapidjson/rapidjson/include/rapidjson/schema.h +2795 -0
  46. data/ext/rapidjson/rapidjson/include/rapidjson/stream.h +223 -0
  47. data/ext/rapidjson/rapidjson/include/rapidjson/stringbuffer.h +121 -0
  48. data/ext/rapidjson/rapidjson/include/rapidjson/uri.h +481 -0
  49. data/ext/rapidjson/rapidjson/include/rapidjson/writer.h +710 -0
  50. data/lib/rapidjson/json_gem.rb +36 -0
  51. data/lib/rapidjson/version.rb +5 -0
  52. data/lib/rapidjson.rb +9 -0
  53. metadata +98 -0
@@ -0,0 +1,481 @@
1
+ // Tencent is pleased to support the open source community by making RapidJSON available.
2
+ //
3
+ // (C) Copyright IBM Corporation 2021
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_URI_H_
16
+ #define RAPIDJSON_URI_H_
17
+
18
+ #include "internal/strfunc.h"
19
+
20
+ #if defined(__clang__)
21
+ RAPIDJSON_DIAG_PUSH
22
+ RAPIDJSON_DIAG_OFF(c++98-compat)
23
+ #elif defined(_MSC_VER)
24
+ RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
25
+ #endif
26
+
27
+ RAPIDJSON_NAMESPACE_BEGIN
28
+
29
+ ///////////////////////////////////////////////////////////////////////////////
30
+ // GenericUri
31
+
32
+ template <typename ValueType, typename Allocator=CrtAllocator>
33
+ class GenericUri {
34
+ public:
35
+ typedef typename ValueType::Ch Ch;
36
+ #if RAPIDJSON_HAS_STDSTRING
37
+ typedef std::basic_string<Ch> String;
38
+ #endif
39
+
40
+ //! Constructors
41
+ GenericUri(Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
42
+ }
43
+
44
+ GenericUri(const Ch* uri, SizeType len, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
45
+ Parse(uri, len);
46
+ }
47
+
48
+ GenericUri(const Ch* uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
49
+ Parse(uri, internal::StrLen<Ch>(uri));
50
+ }
51
+
52
+ // Use with specializations of GenericValue
53
+ template<typename T> GenericUri(const T& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
54
+ const Ch* u = uri.template Get<const Ch*>(); // TypeHelper from document.h
55
+ Parse(u, internal::StrLen<Ch>(u));
56
+ }
57
+
58
+ #if RAPIDJSON_HAS_STDSTRING
59
+ GenericUri(const String& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
60
+ Parse(uri.c_str(), internal::StrLen<Ch>(uri.c_str()));
61
+ }
62
+ #endif
63
+
64
+ //! Copy constructor
65
+ GenericUri(const GenericUri& rhs) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(), ownAllocator_() {
66
+ *this = rhs;
67
+ }
68
+
69
+ //! Copy constructor
70
+ GenericUri(const GenericUri& rhs, Allocator* allocator) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
71
+ *this = rhs;
72
+ }
73
+
74
+ //! Destructor.
75
+ ~GenericUri() {
76
+ Free();
77
+ RAPIDJSON_DELETE(ownAllocator_);
78
+ }
79
+
80
+ //! Assignment operator
81
+ GenericUri& operator=(const GenericUri& rhs) {
82
+ if (this != &rhs) {
83
+ // Do not delete ownAllocator
84
+ Free();
85
+ Allocate(rhs.GetStringLength());
86
+ auth_ = CopyPart(scheme_, rhs.scheme_, rhs.GetSchemeStringLength());
87
+ path_ = CopyPart(auth_, rhs.auth_, rhs.GetAuthStringLength());
88
+ query_ = CopyPart(path_, rhs.path_, rhs.GetPathStringLength());
89
+ frag_ = CopyPart(query_, rhs.query_, rhs.GetQueryStringLength());
90
+ base_ = CopyPart(frag_, rhs.frag_, rhs.GetFragStringLength());
91
+ uri_ = CopyPart(base_, rhs.base_, rhs.GetBaseStringLength());
92
+ CopyPart(uri_, rhs.uri_, rhs.GetStringLength());
93
+ }
94
+ return *this;
95
+ }
96
+
97
+ //! Getters
98
+ // Use with specializations of GenericValue
99
+ template<typename T> void Get(T& uri, Allocator& allocator) {
100
+ uri.template Set<const Ch*>(this->GetString(), allocator); // TypeHelper from document.h
101
+ }
102
+
103
+ const Ch* GetString() const { return uri_; }
104
+ SizeType GetStringLength() const { return uri_ == 0 ? 0 : internal::StrLen<Ch>(uri_); }
105
+ const Ch* GetBaseString() const { return base_; }
106
+ SizeType GetBaseStringLength() const { return base_ == 0 ? 0 : internal::StrLen<Ch>(base_); }
107
+ const Ch* GetSchemeString() const { return scheme_; }
108
+ SizeType GetSchemeStringLength() const { return scheme_ == 0 ? 0 : internal::StrLen<Ch>(scheme_); }
109
+ const Ch* GetAuthString() const { return auth_; }
110
+ SizeType GetAuthStringLength() const { return auth_ == 0 ? 0 : internal::StrLen<Ch>(auth_); }
111
+ const Ch* GetPathString() const { return path_; }
112
+ SizeType GetPathStringLength() const { return path_ == 0 ? 0 : internal::StrLen<Ch>(path_); }
113
+ const Ch* GetQueryString() const { return query_; }
114
+ SizeType GetQueryStringLength() const { return query_ == 0 ? 0 : internal::StrLen<Ch>(query_); }
115
+ const Ch* GetFragString() const { return frag_; }
116
+ SizeType GetFragStringLength() const { return frag_ == 0 ? 0 : internal::StrLen<Ch>(frag_); }
117
+
118
+ #if RAPIDJSON_HAS_STDSTRING
119
+ static String Get(const GenericUri& uri) { return String(uri.GetString(), uri.GetStringLength()); }
120
+ static String GetBase(const GenericUri& uri) { return String(uri.GetBaseString(), uri.GetBaseStringLength()); }
121
+ static String GetScheme(const GenericUri& uri) { return String(uri.GetSchemeString(), uri.GetSchemeStringLength()); }
122
+ static String GetAuth(const GenericUri& uri) { return String(uri.GetAuthString(), uri.GetAuthStringLength()); }
123
+ static String GetPath(const GenericUri& uri) { return String(uri.GetPathString(), uri.GetPathStringLength()); }
124
+ static String GetQuery(const GenericUri& uri) { return String(uri.GetQueryString(), uri.GetQueryStringLength()); }
125
+ static String GetFrag(const GenericUri& uri) { return String(uri.GetFragString(), uri.GetFragStringLength()); }
126
+ #endif
127
+
128
+ //! Equality operators
129
+ bool operator==(const GenericUri& rhs) const {
130
+ return Match(rhs, true);
131
+ }
132
+
133
+ bool operator!=(const GenericUri& rhs) const {
134
+ return !Match(rhs, true);
135
+ }
136
+
137
+ bool Match(const GenericUri& uri, bool full = true) const {
138
+ Ch* s1;
139
+ Ch* s2;
140
+ if (full) {
141
+ s1 = uri_;
142
+ s2 = uri.uri_;
143
+ } else {
144
+ s1 = base_;
145
+ s2 = uri.base_;
146
+ }
147
+ if (s1 == s2) return true;
148
+ if (s1 == 0 || s2 == 0) return false;
149
+ return internal::StrCmp<Ch>(s1, s2) == 0;
150
+ }
151
+
152
+ //! Resolve this URI against another (base) URI in accordance with URI resolution rules.
153
+ // See https://tools.ietf.org/html/rfc3986
154
+ // Use for resolving an id or $ref with an in-scope id.
155
+ // Returns a new GenericUri for the resolved URI.
156
+ GenericUri Resolve(const GenericUri& baseuri, Allocator* allocator = 0) {
157
+ GenericUri resuri;
158
+ resuri.allocator_ = allocator;
159
+ // Ensure enough space for combining paths
160
+ resuri.Allocate(GetStringLength() + baseuri.GetStringLength() + 1); // + 1 for joining slash
161
+
162
+ if (!(GetSchemeStringLength() == 0)) {
163
+ // Use all of this URI
164
+ resuri.auth_ = CopyPart(resuri.scheme_, scheme_, GetSchemeStringLength());
165
+ resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength());
166
+ resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
167
+ resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
168
+ resuri.RemoveDotSegments();
169
+ } else {
170
+ // Use the base scheme
171
+ resuri.auth_ = CopyPart(resuri.scheme_, baseuri.scheme_, baseuri.GetSchemeStringLength());
172
+ if (!(GetAuthStringLength() == 0)) {
173
+ // Use this auth, path, query
174
+ resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength());
175
+ resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
176
+ resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
177
+ resuri.RemoveDotSegments();
178
+ } else {
179
+ // Use the base auth
180
+ resuri.path_ = CopyPart(resuri.auth_, baseuri.auth_, baseuri.GetAuthStringLength());
181
+ if (GetPathStringLength() == 0) {
182
+ // Use the base path
183
+ resuri.query_ = CopyPart(resuri.path_, baseuri.path_, baseuri.GetPathStringLength());
184
+ if (GetQueryStringLength() == 0) {
185
+ // Use the base query
186
+ resuri.frag_ = CopyPart(resuri.query_, baseuri.query_, baseuri.GetQueryStringLength());
187
+ } else {
188
+ // Use this query
189
+ resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
190
+ }
191
+ } else {
192
+ if (path_[0] == '/') {
193
+ // Absolute path - use all of this path
194
+ resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
195
+ resuri.RemoveDotSegments();
196
+ } else {
197
+ // Relative path - append this path to base path after base path's last slash
198
+ size_t pos = 0;
199
+ if (!(baseuri.GetAuthStringLength() == 0) && baseuri.GetPathStringLength() == 0) {
200
+ resuri.path_[pos] = '/';
201
+ pos++;
202
+ }
203
+ size_t lastslashpos = baseuri.GetPathStringLength();
204
+ while (lastslashpos > 0) {
205
+ if (baseuri.path_[lastslashpos - 1] == '/') break;
206
+ lastslashpos--;
207
+ }
208
+ std::memcpy(&resuri.path_[pos], baseuri.path_, lastslashpos * sizeof(Ch));
209
+ pos += lastslashpos;
210
+ resuri.query_ = CopyPart(&resuri.path_[pos], path_, GetPathStringLength());
211
+ resuri.RemoveDotSegments();
212
+ }
213
+ // Use this query
214
+ resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
215
+ }
216
+ }
217
+ }
218
+ // Always use this frag
219
+ resuri.base_ = CopyPart(resuri.frag_, frag_, GetFragStringLength());
220
+
221
+ // Re-constitute base_ and uri_
222
+ resuri.SetBase();
223
+ resuri.uri_ = resuri.base_ + resuri.GetBaseStringLength() + 1;
224
+ resuri.SetUri();
225
+ return resuri;
226
+ }
227
+
228
+ //! Get the allocator of this GenericUri.
229
+ Allocator& GetAllocator() { return *allocator_; }
230
+
231
+ private:
232
+ // Allocate memory for a URI
233
+ // Returns total amount allocated
234
+ std::size_t Allocate(std::size_t len) {
235
+ // Create own allocator if user did not supply.
236
+ if (!allocator_)
237
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
238
+
239
+ // Allocate one block containing each part of the URI (5) plus base plus full URI, all null terminated.
240
+ // Order: scheme, auth, path, query, frag, base, uri
241
+ // Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
242
+ size_t total = (3 * len + 7) * sizeof(Ch);
243
+ scheme_ = static_cast<Ch*>(allocator_->Malloc(total));
244
+ *scheme_ = '\0';
245
+ auth_ = scheme_;
246
+ auth_++;
247
+ *auth_ = '\0';
248
+ path_ = auth_;
249
+ path_++;
250
+ *path_ = '\0';
251
+ query_ = path_;
252
+ query_++;
253
+ *query_ = '\0';
254
+ frag_ = query_;
255
+ frag_++;
256
+ *frag_ = '\0';
257
+ base_ = frag_;
258
+ base_++;
259
+ *base_ = '\0';
260
+ uri_ = base_;
261
+ uri_++;
262
+ *uri_ = '\0';
263
+ return total;
264
+ }
265
+
266
+ // Free memory for a URI
267
+ void Free() {
268
+ if (scheme_) {
269
+ Allocator::Free(scheme_);
270
+ scheme_ = 0;
271
+ }
272
+ }
273
+
274
+ // Parse a URI into constituent scheme, authority, path, query, & fragment parts
275
+ // Supports URIs that match regex ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? as per
276
+ // https://tools.ietf.org/html/rfc3986
277
+ void Parse(const Ch* uri, std::size_t len) {
278
+ std::size_t start = 0, pos1 = 0, pos2 = 0;
279
+ Allocate(len);
280
+
281
+ // Look for scheme ([^:/?#]+):)?
282
+ if (start < len) {
283
+ while (pos1 < len) {
284
+ if (uri[pos1] == ':') break;
285
+ pos1++;
286
+ }
287
+ if (pos1 != len) {
288
+ while (pos2 < len) {
289
+ if (uri[pos2] == '/') break;
290
+ if (uri[pos2] == '?') break;
291
+ if (uri[pos2] == '#') break;
292
+ pos2++;
293
+ }
294
+ if (pos1 < pos2) {
295
+ pos1++;
296
+ std::memcpy(scheme_, &uri[start], pos1 * sizeof(Ch));
297
+ scheme_[pos1] = '\0';
298
+ start = pos1;
299
+ }
300
+ }
301
+ }
302
+ // Look for auth (//([^/?#]*))?
303
+ // Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
304
+ auth_ = scheme_ + GetSchemeStringLength();
305
+ auth_++;
306
+ *auth_ = '\0';
307
+ if (start < len - 1 && uri[start] == '/' && uri[start + 1] == '/') {
308
+ pos2 = start + 2;
309
+ while (pos2 < len) {
310
+ if (uri[pos2] == '/') break;
311
+ if (uri[pos2] == '?') break;
312
+ if (uri[pos2] == '#') break;
313
+ pos2++;
314
+ }
315
+ std::memcpy(auth_, &uri[start], (pos2 - start) * sizeof(Ch));
316
+ auth_[pos2 - start] = '\0';
317
+ start = pos2;
318
+ }
319
+ // Look for path ([^?#]*)
320
+ // Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
321
+ path_ = auth_ + GetAuthStringLength();
322
+ path_++;
323
+ *path_ = '\0';
324
+ if (start < len) {
325
+ pos2 = start;
326
+ while (pos2 < len) {
327
+ if (uri[pos2] == '?') break;
328
+ if (uri[pos2] == '#') break;
329
+ pos2++;
330
+ }
331
+ if (start != pos2) {
332
+ std::memcpy(path_, &uri[start], (pos2 - start) * sizeof(Ch));
333
+ path_[pos2 - start] = '\0';
334
+ if (path_[0] == '/')
335
+ RemoveDotSegments(); // absolute path - normalize
336
+ start = pos2;
337
+ }
338
+ }
339
+ // Look for query (\?([^#]*))?
340
+ // Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
341
+ query_ = path_ + GetPathStringLength();
342
+ query_++;
343
+ *query_ = '\0';
344
+ if (start < len && uri[start] == '?') {
345
+ pos2 = start + 1;
346
+ while (pos2 < len) {
347
+ if (uri[pos2] == '#') break;
348
+ pos2++;
349
+ }
350
+ if (start != pos2) {
351
+ std::memcpy(query_, &uri[start], (pos2 - start) * sizeof(Ch));
352
+ query_[pos2 - start] = '\0';
353
+ start = pos2;
354
+ }
355
+ }
356
+ // Look for fragment (#(.*))?
357
+ // Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
358
+ frag_ = query_ + GetQueryStringLength();
359
+ frag_++;
360
+ *frag_ = '\0';
361
+ if (start < len && uri[start] == '#') {
362
+ std::memcpy(frag_, &uri[start], (len - start) * sizeof(Ch));
363
+ frag_[len - start] = '\0';
364
+ }
365
+
366
+ // Re-constitute base_ and uri_
367
+ base_ = frag_ + GetFragStringLength() + 1;
368
+ SetBase();
369
+ uri_ = base_ + GetBaseStringLength() + 1;
370
+ SetUri();
371
+ }
372
+
373
+ // Reconstitute base
374
+ void SetBase() {
375
+ Ch* next = base_;
376
+ std::memcpy(next, scheme_, GetSchemeStringLength() * sizeof(Ch));
377
+ next+= GetSchemeStringLength();
378
+ std::memcpy(next, auth_, GetAuthStringLength() * sizeof(Ch));
379
+ next+= GetAuthStringLength();
380
+ std::memcpy(next, path_, GetPathStringLength() * sizeof(Ch));
381
+ next+= GetPathStringLength();
382
+ std::memcpy(next, query_, GetQueryStringLength() * sizeof(Ch));
383
+ next+= GetQueryStringLength();
384
+ *next = '\0';
385
+ }
386
+
387
+ // Reconstitute uri
388
+ void SetUri() {
389
+ Ch* next = uri_;
390
+ std::memcpy(next, base_, GetBaseStringLength() * sizeof(Ch));
391
+ next+= GetBaseStringLength();
392
+ std::memcpy(next, frag_, GetFragStringLength() * sizeof(Ch));
393
+ next+= GetFragStringLength();
394
+ *next = '\0';
395
+ }
396
+
397
+ // Copy a part from one GenericUri to another
398
+ // Return the pointer to the next part to be copied to
399
+ Ch* CopyPart(Ch* to, Ch* from, std::size_t len) {
400
+ RAPIDJSON_ASSERT(to != 0);
401
+ RAPIDJSON_ASSERT(from != 0);
402
+ std::memcpy(to, from, len * sizeof(Ch));
403
+ to[len] = '\0';
404
+ Ch* next = to + len + 1;
405
+ return next;
406
+ }
407
+
408
+ // Remove . and .. segments from the path_ member.
409
+ // https://tools.ietf.org/html/rfc3986
410
+ // This is done in place as we are only removing segments.
411
+ void RemoveDotSegments() {
412
+ std::size_t pathlen = GetPathStringLength();
413
+ std::size_t pathpos = 0; // Position in path_
414
+ std::size_t newpos = 0; // Position in new path_
415
+
416
+ // Loop through each segment in original path_
417
+ while (pathpos < pathlen) {
418
+ // Get next segment, bounded by '/' or end
419
+ size_t slashpos = 0;
420
+ while ((pathpos + slashpos) < pathlen) {
421
+ if (path_[pathpos + slashpos] == '/') break;
422
+ slashpos++;
423
+ }
424
+ // Check for .. and . segments
425
+ if (slashpos == 2 && path_[pathpos] == '.' && path_[pathpos + 1] == '.') {
426
+ // Backup a .. segment in the new path_
427
+ // We expect to find a previously added slash at the end or nothing
428
+ RAPIDJSON_ASSERT(newpos == 0 || path_[newpos - 1] == '/');
429
+ size_t lastslashpos = newpos;
430
+ // Make sure we don't go beyond the start segment
431
+ if (lastslashpos > 1) {
432
+ // Find the next to last slash and back up to it
433
+ lastslashpos--;
434
+ while (lastslashpos > 0) {
435
+ if (path_[lastslashpos - 1] == '/') break;
436
+ lastslashpos--;
437
+ }
438
+ // Set the new path_ position
439
+ newpos = lastslashpos;
440
+ }
441
+ } else if (slashpos == 1 && path_[pathpos] == '.') {
442
+ // Discard . segment, leaves new path_ unchanged
443
+ } else {
444
+ // Move any other kind of segment to the new path_
445
+ RAPIDJSON_ASSERT(newpos <= pathpos);
446
+ std::memmove(&path_[newpos], &path_[pathpos], slashpos * sizeof(Ch));
447
+ newpos += slashpos;
448
+ // Add slash if not at end
449
+ if ((pathpos + slashpos) < pathlen) {
450
+ path_[newpos] = '/';
451
+ newpos++;
452
+ }
453
+ }
454
+ // Move to next segment
455
+ pathpos += slashpos + 1;
456
+ }
457
+ path_[newpos] = '\0';
458
+ }
459
+
460
+ Ch* uri_; // Everything
461
+ Ch* base_; // Everything except fragment
462
+ Ch* scheme_; // Includes the :
463
+ Ch* auth_; // Includes the //
464
+ Ch* path_; // Absolute if starts with /
465
+ Ch* query_; // Includes the ?
466
+ Ch* frag_; // Includes the #
467
+
468
+ Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
469
+ Allocator* ownAllocator_; //!< Allocator owned by this Uri.
470
+ };
471
+
472
+ //! GenericUri for Value (UTF-8, default allocator).
473
+ typedef GenericUri<Value> Uri;
474
+
475
+ RAPIDJSON_NAMESPACE_END
476
+
477
+ #if defined(__clang__)
478
+ RAPIDJSON_DIAG_POP
479
+ #endif
480
+
481
+ #endif // RAPIDJSON_URI_H_