rj_schema 1.0.0 → 1.0.1
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.
- checksums.yaml +4 -4
- data/ext/rj_schema/rapidjson/CMakeLists.txt +23 -1
- data/ext/rj_schema/rapidjson/appveyor.yml +49 -1
- data/ext/rj_schema/rapidjson/bin/types/alotofkeys.json +502 -0
- data/ext/rj_schema/rapidjson/bin/unittestschema/idandref.json +69 -0
- data/ext/rj_schema/rapidjson/doc/stream.md +7 -7
- data/ext/rj_schema/rapidjson/doc/stream.zh-cn.md +1 -1
- data/ext/rj_schema/rapidjson/doc/tutorial.md +15 -15
- data/ext/rj_schema/rapidjson/example/schemavalidator/schemavalidator.cpp +2 -0
- data/ext/rj_schema/rapidjson/example/traverseaspointer.cpp +39 -0
- data/ext/rj_schema/rapidjson/include/rapidjson/allocators.h +460 -52
- data/ext/rj_schema/rapidjson/include/rapidjson/document.h +350 -60
- data/ext/rj_schema/rapidjson/include/rapidjson/internal/strfunc.h +14 -0
- data/ext/rj_schema/rapidjson/include/rapidjson/pointer.h +68 -1
- data/ext/rj_schema/rapidjson/include/rapidjson/rapidjson.h +60 -11
- data/ext/rj_schema/rapidjson/include/rapidjson/schema.h +249 -102
- data/ext/rj_schema/rapidjson/include/rapidjson/uri.h +466 -0
- data/ext/rj_schema/rapidjson/test/perftest/perftest.h +5 -4
- data/ext/rj_schema/rapidjson/test/perftest/rapidjsontest.cpp +20 -2
- data/ext/rj_schema/rapidjson/test/unittest/CMakeLists.txt +2 -0
- data/ext/rj_schema/rapidjson/test/unittest/allocatorstest.cpp +193 -1
- data/ext/rj_schema/rapidjson/test/unittest/documenttest.cpp +2 -0
- data/ext/rj_schema/rapidjson/test/unittest/platformtest.cpp +40 -0
- data/ext/rj_schema/rapidjson/test/unittest/pointertest.cpp +62 -2
- data/ext/rj_schema/rapidjson/test/unittest/schematest.cpp +372 -7
- data/ext/rj_schema/rapidjson/test/unittest/uritest.cpp +718 -0
- data/ext/rj_schema/rapidjson/test/unittest/valuetest.cpp +12 -2
- data/ext/rj_schema/rj_schema.cpp +1 -1
- data/lib/rj_schema.rb +1 -1
- metadata +9 -3
@@ -0,0 +1,466 @@
|
|
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
|
+
size_t total = (3 * len + 7) * sizeof(Ch);
|
242
|
+
scheme_ = static_cast<Ch*>(allocator_->Malloc(total));
|
243
|
+
*scheme_ = '\0';
|
244
|
+
auth_ = scheme_ + 1;
|
245
|
+
*auth_ = '\0';
|
246
|
+
path_ = auth_ + 1;
|
247
|
+
*path_ = '\0';
|
248
|
+
query_ = path_ + 1;
|
249
|
+
*query_ = '\0';
|
250
|
+
frag_ = query_ + 1;
|
251
|
+
*frag_ = '\0';
|
252
|
+
base_ = frag_ + 1;
|
253
|
+
*base_ = '\0';
|
254
|
+
uri_ = base_ + 1;
|
255
|
+
*uri_ = '\0';
|
256
|
+
return total;
|
257
|
+
}
|
258
|
+
|
259
|
+
// Free memory for a URI
|
260
|
+
void Free() {
|
261
|
+
if (scheme_) {
|
262
|
+
Allocator::Free(scheme_);
|
263
|
+
scheme_ = 0;
|
264
|
+
}
|
265
|
+
}
|
266
|
+
|
267
|
+
// Parse a URI into constituent scheme, authority, path, query, & fragment parts
|
268
|
+
// Supports URIs that match regex ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? as per
|
269
|
+
// https://tools.ietf.org/html/rfc3986
|
270
|
+
void Parse(const Ch* uri, std::size_t len) {
|
271
|
+
std::size_t start = 0, pos1 = 0, pos2 = 0;
|
272
|
+
Allocate(len);
|
273
|
+
|
274
|
+
// Look for scheme ([^:/?#]+):)?
|
275
|
+
if (start < len) {
|
276
|
+
while (pos1 < len) {
|
277
|
+
if (uri[pos1] == ':') break;
|
278
|
+
pos1++;
|
279
|
+
}
|
280
|
+
if (pos1 != len) {
|
281
|
+
while (pos2 < len) {
|
282
|
+
if (uri[pos2] == '/') break;
|
283
|
+
if (uri[pos2] == '?') break;
|
284
|
+
if (uri[pos2] == '#') break;
|
285
|
+
pos2++;
|
286
|
+
}
|
287
|
+
if (pos1 < pos2) {
|
288
|
+
pos1++;
|
289
|
+
std::memcpy(scheme_, &uri[start], pos1 * sizeof(Ch));
|
290
|
+
scheme_[pos1] = '\0';
|
291
|
+
start = pos1;
|
292
|
+
}
|
293
|
+
}
|
294
|
+
}
|
295
|
+
// Look for auth (//([^/?#]*))?
|
296
|
+
auth_ = scheme_ + GetSchemeStringLength() + 1;
|
297
|
+
*auth_ = '\0';
|
298
|
+
if (start < len - 1 && uri[start] == '/' && uri[start + 1] == '/') {
|
299
|
+
pos2 = start + 2;
|
300
|
+
while (pos2 < len) {
|
301
|
+
if (uri[pos2] == '/') break;
|
302
|
+
if (uri[pos2] == '?') break;
|
303
|
+
if (uri[pos2] == '#') break;
|
304
|
+
pos2++;
|
305
|
+
}
|
306
|
+
std::memcpy(auth_, &uri[start], (pos2 - start) * sizeof(Ch));
|
307
|
+
auth_[pos2 - start] = '\0';
|
308
|
+
start = pos2;
|
309
|
+
}
|
310
|
+
// Look for path ([^?#]*)
|
311
|
+
path_ = auth_ + GetAuthStringLength() + 1;
|
312
|
+
*path_ = '\0';
|
313
|
+
if (start < len) {
|
314
|
+
pos2 = start;
|
315
|
+
while (pos2 < len) {
|
316
|
+
if (uri[pos2] == '?') break;
|
317
|
+
if (uri[pos2] == '#') break;
|
318
|
+
pos2++;
|
319
|
+
}
|
320
|
+
if (start != pos2) {
|
321
|
+
std::memcpy(path_, &uri[start], (pos2 - start) * sizeof(Ch));
|
322
|
+
path_[pos2 - start] = '\0';
|
323
|
+
if (path_[0] == '/')
|
324
|
+
RemoveDotSegments(); // absolute path - normalize
|
325
|
+
start = pos2;
|
326
|
+
}
|
327
|
+
}
|
328
|
+
// Look for query (\?([^#]*))?
|
329
|
+
query_ = path_ + GetPathStringLength() + 1;
|
330
|
+
*query_ = '\0';
|
331
|
+
if (start < len && uri[start] == '?') {
|
332
|
+
pos2 = start + 1;
|
333
|
+
while (pos2 < len) {
|
334
|
+
if (uri[pos2] == '#') break;
|
335
|
+
pos2++;
|
336
|
+
}
|
337
|
+
if (start != pos2) {
|
338
|
+
std::memcpy(query_, &uri[start], (pos2 - start) * sizeof(Ch));
|
339
|
+
query_[pos2 - start] = '\0';
|
340
|
+
start = pos2;
|
341
|
+
}
|
342
|
+
}
|
343
|
+
// Look for fragment (#(.*))?
|
344
|
+
frag_ = query_ + GetQueryStringLength() + 1;
|
345
|
+
*frag_ = '\0';
|
346
|
+
if (start < len && uri[start] == '#') {
|
347
|
+
std::memcpy(frag_, &uri[start], (len - start) * sizeof(Ch));
|
348
|
+
frag_[len - start] = '\0';
|
349
|
+
}
|
350
|
+
|
351
|
+
// Re-constitute base_ and uri_
|
352
|
+
base_ = frag_ + GetFragStringLength() + 1;
|
353
|
+
SetBase();
|
354
|
+
uri_ = base_ + GetBaseStringLength() + 1;
|
355
|
+
SetUri();
|
356
|
+
}
|
357
|
+
|
358
|
+
// Reconstitute base
|
359
|
+
void SetBase() {
|
360
|
+
Ch* next = base_;
|
361
|
+
std::memcpy(next, scheme_, GetSchemeStringLength() * sizeof(Ch));
|
362
|
+
next+= GetSchemeStringLength();
|
363
|
+
std::memcpy(next, auth_, GetAuthStringLength() * sizeof(Ch));
|
364
|
+
next+= GetAuthStringLength();
|
365
|
+
std::memcpy(next, path_, GetPathStringLength() * sizeof(Ch));
|
366
|
+
next+= GetPathStringLength();
|
367
|
+
std::memcpy(next, query_, GetQueryStringLength() * sizeof(Ch));
|
368
|
+
next+= GetQueryStringLength();
|
369
|
+
*next = '\0';
|
370
|
+
}
|
371
|
+
|
372
|
+
// Reconstitute uri
|
373
|
+
void SetUri() {
|
374
|
+
Ch* next = uri_;
|
375
|
+
std::memcpy(next, base_, GetBaseStringLength() * sizeof(Ch));
|
376
|
+
next+= GetBaseStringLength();
|
377
|
+
std::memcpy(next, frag_, GetFragStringLength() * sizeof(Ch));
|
378
|
+
next+= GetFragStringLength();
|
379
|
+
*next = '\0';
|
380
|
+
}
|
381
|
+
|
382
|
+
// Copy a part from one GenericUri to another
|
383
|
+
// Return the pointer to the next part to be copied to
|
384
|
+
Ch* CopyPart(Ch* to, Ch* from, std::size_t len) {
|
385
|
+
RAPIDJSON_ASSERT(to != 0);
|
386
|
+
RAPIDJSON_ASSERT(from != 0);
|
387
|
+
std::memcpy(to, from, len * sizeof(Ch));
|
388
|
+
to[len] = '\0';
|
389
|
+
Ch* next = to + len + 1;
|
390
|
+
return next;
|
391
|
+
}
|
392
|
+
|
393
|
+
// Remove . and .. segments from the path_ member.
|
394
|
+
// https://tools.ietf.org/html/rfc3986
|
395
|
+
// This is done in place as we are only removing segments.
|
396
|
+
void RemoveDotSegments() {
|
397
|
+
std::size_t pathlen = GetPathStringLength();
|
398
|
+
std::size_t pathpos = 0; // Position in path_
|
399
|
+
std::size_t newpos = 0; // Position in new path_
|
400
|
+
|
401
|
+
// Loop through each segment in original path_
|
402
|
+
while (pathpos < pathlen) {
|
403
|
+
// Get next segment, bounded by '/' or end
|
404
|
+
size_t slashpos = 0;
|
405
|
+
while ((pathpos + slashpos) < pathlen) {
|
406
|
+
if (path_[pathpos + slashpos] == '/') break;
|
407
|
+
slashpos++;
|
408
|
+
}
|
409
|
+
// Check for .. and . segments
|
410
|
+
if (slashpos == 2 && path_[pathpos] == '.' && path_[pathpos + 1] == '.') {
|
411
|
+
// Backup a .. segment in the new path_
|
412
|
+
// We expect to find a previously added slash at the end or nothing
|
413
|
+
RAPIDJSON_ASSERT(newpos == 0 || path_[newpos - 1] == '/');
|
414
|
+
size_t lastslashpos = newpos;
|
415
|
+
// Make sure we don't go beyond the start segment
|
416
|
+
if (lastslashpos > 1) {
|
417
|
+
// Find the next to last slash and back up to it
|
418
|
+
lastslashpos--;
|
419
|
+
while (lastslashpos > 0) {
|
420
|
+
if (path_[lastslashpos - 1] == '/') break;
|
421
|
+
lastslashpos--;
|
422
|
+
}
|
423
|
+
// Set the new path_ position
|
424
|
+
newpos = lastslashpos;
|
425
|
+
}
|
426
|
+
} else if (slashpos == 1 && path_[pathpos] == '.') {
|
427
|
+
// Discard . segment, leaves new path_ unchanged
|
428
|
+
} else {
|
429
|
+
// Move any other kind of segment to the new path_
|
430
|
+
RAPIDJSON_ASSERT(newpos <= pathpos);
|
431
|
+
std::memmove(&path_[newpos], &path_[pathpos], slashpos * sizeof(Ch));
|
432
|
+
newpos += slashpos;
|
433
|
+
// Add slash if not at end
|
434
|
+
if ((pathpos + slashpos) < pathlen) {
|
435
|
+
path_[newpos] = '/';
|
436
|
+
newpos++;
|
437
|
+
}
|
438
|
+
}
|
439
|
+
// Move to next segment
|
440
|
+
pathpos += slashpos + 1;
|
441
|
+
}
|
442
|
+
path_[newpos] = '\0';
|
443
|
+
}
|
444
|
+
|
445
|
+
Ch* uri_; // Everything
|
446
|
+
Ch* base_; // Everything except fragment
|
447
|
+
Ch* scheme_; // Includes the :
|
448
|
+
Ch* auth_; // Includes the //
|
449
|
+
Ch* path_; // Absolute if starts with /
|
450
|
+
Ch* query_; // Includes the ?
|
451
|
+
Ch* frag_; // Includes the #
|
452
|
+
|
453
|
+
Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
|
454
|
+
Allocator* ownAllocator_; //!< Allocator owned by this Uri.
|
455
|
+
};
|
456
|
+
|
457
|
+
//! GenericUri for Value (UTF-8, default allocator).
|
458
|
+
typedef GenericUri<Value> Uri;
|
459
|
+
|
460
|
+
RAPIDJSON_NAMESPACE_END
|
461
|
+
|
462
|
+
#if defined(__clang__)
|
463
|
+
RAPIDJSON_DIAG_POP
|
464
|
+
#endif
|
465
|
+
|
466
|
+
#endif // RAPIDJSON_URI_H_
|