rapidjson 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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_