File indexing completed on 2025-02-21 10:13:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef RAPIDJSON_URI_H_
0016 #define RAPIDJSON_URI_H_
0017
0018 #include "internal/strfunc.h"
0019
0020 #if defined(__clang__)
0021 RAPIDJSON_DIAG_PUSH
0022 RAPIDJSON_DIAG_OFF(c++98-compat)
0023 #elif defined(_MSC_VER)
0024 RAPIDJSON_DIAG_OFF(4512)
0025 #endif
0026
0027 RAPIDJSON_NAMESPACE_BEGIN
0028
0029
0030
0031
0032 template <typename ValueType, typename Allocator=CrtAllocator>
0033 class GenericUri {
0034 public:
0035 typedef typename ValueType::Ch Ch;
0036 #if RAPIDJSON_HAS_STDSTRING
0037 typedef std::basic_string<Ch> String;
0038 #endif
0039
0040
0041 GenericUri(Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
0042 }
0043
0044 GenericUri(const Ch* uri, SizeType len, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
0045 Parse(uri, len);
0046 }
0047
0048 GenericUri(const Ch* uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
0049 Parse(uri, internal::StrLen<Ch>(uri));
0050 }
0051
0052
0053 template<typename T> GenericUri(const T& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
0054 const Ch* u = uri.template Get<const Ch*>();
0055 Parse(u, internal::StrLen<Ch>(u));
0056 }
0057
0058 #if RAPIDJSON_HAS_STDSTRING
0059 GenericUri(const String& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
0060 Parse(uri.c_str(), internal::StrLen<Ch>(uri.c_str()));
0061 }
0062 #endif
0063
0064
0065 GenericUri(const GenericUri& rhs) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(), ownAllocator_() {
0066 *this = rhs;
0067 }
0068
0069
0070 GenericUri(const GenericUri& rhs, Allocator* allocator) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
0071 *this = rhs;
0072 }
0073
0074
0075 ~GenericUri() {
0076 Free();
0077 RAPIDJSON_DELETE(ownAllocator_);
0078 }
0079
0080
0081 GenericUri& operator=(const GenericUri& rhs) {
0082 if (this != &rhs) {
0083
0084 Free();
0085 Allocate(rhs.GetStringLength());
0086 auth_ = CopyPart(scheme_, rhs.scheme_, rhs.GetSchemeStringLength());
0087 path_ = CopyPart(auth_, rhs.auth_, rhs.GetAuthStringLength());
0088 query_ = CopyPart(path_, rhs.path_, rhs.GetPathStringLength());
0089 frag_ = CopyPart(query_, rhs.query_, rhs.GetQueryStringLength());
0090 base_ = CopyPart(frag_, rhs.frag_, rhs.GetFragStringLength());
0091 uri_ = CopyPart(base_, rhs.base_, rhs.GetBaseStringLength());
0092 CopyPart(uri_, rhs.uri_, rhs.GetStringLength());
0093 }
0094 return *this;
0095 }
0096
0097
0098
0099 template<typename T> void Get(T& uri, Allocator& allocator) {
0100 uri.template Set<const Ch*>(this->GetString(), allocator);
0101 }
0102
0103 const Ch* GetString() const { return uri_; }
0104 SizeType GetStringLength() const { return uri_ == 0 ? 0 : internal::StrLen<Ch>(uri_); }
0105 const Ch* GetBaseString() const { return base_; }
0106 SizeType GetBaseStringLength() const { return base_ == 0 ? 0 : internal::StrLen<Ch>(base_); }
0107 const Ch* GetSchemeString() const { return scheme_; }
0108 SizeType GetSchemeStringLength() const { return scheme_ == 0 ? 0 : internal::StrLen<Ch>(scheme_); }
0109 const Ch* GetAuthString() const { return auth_; }
0110 SizeType GetAuthStringLength() const { return auth_ == 0 ? 0 : internal::StrLen<Ch>(auth_); }
0111 const Ch* GetPathString() const { return path_; }
0112 SizeType GetPathStringLength() const { return path_ == 0 ? 0 : internal::StrLen<Ch>(path_); }
0113 const Ch* GetQueryString() const { return query_; }
0114 SizeType GetQueryStringLength() const { return query_ == 0 ? 0 : internal::StrLen<Ch>(query_); }
0115 const Ch* GetFragString() const { return frag_; }
0116 SizeType GetFragStringLength() const { return frag_ == 0 ? 0 : internal::StrLen<Ch>(frag_); }
0117
0118 #if RAPIDJSON_HAS_STDSTRING
0119 static String Get(const GenericUri& uri) { return String(uri.GetString(), uri.GetStringLength()); }
0120 static String GetBase(const GenericUri& uri) { return String(uri.GetBaseString(), uri.GetBaseStringLength()); }
0121 static String GetScheme(const GenericUri& uri) { return String(uri.GetSchemeString(), uri.GetSchemeStringLength()); }
0122 static String GetAuth(const GenericUri& uri) { return String(uri.GetAuthString(), uri.GetAuthStringLength()); }
0123 static String GetPath(const GenericUri& uri) { return String(uri.GetPathString(), uri.GetPathStringLength()); }
0124 static String GetQuery(const GenericUri& uri) { return String(uri.GetQueryString(), uri.GetQueryStringLength()); }
0125 static String GetFrag(const GenericUri& uri) { return String(uri.GetFragString(), uri.GetFragStringLength()); }
0126 #endif
0127
0128
0129 bool operator==(const GenericUri& rhs) const {
0130 return Match(rhs, true);
0131 }
0132
0133 bool operator!=(const GenericUri& rhs) const {
0134 return !Match(rhs, true);
0135 }
0136
0137 bool Match(const GenericUri& uri, bool full = true) const {
0138 Ch* s1;
0139 Ch* s2;
0140 if (full) {
0141 s1 = uri_;
0142 s2 = uri.uri_;
0143 } else {
0144 s1 = base_;
0145 s2 = uri.base_;
0146 }
0147 if (s1 == s2) return true;
0148 if (s1 == 0 || s2 == 0) return false;
0149 return internal::StrCmp<Ch>(s1, s2) == 0;
0150 }
0151
0152
0153
0154
0155
0156 GenericUri Resolve(const GenericUri& baseuri, Allocator* allocator = 0) {
0157 GenericUri resuri;
0158 resuri.allocator_ = allocator;
0159
0160 resuri.Allocate(GetStringLength() + baseuri.GetStringLength() + 1);
0161
0162 if (!(GetSchemeStringLength() == 0)) {
0163
0164 resuri.auth_ = CopyPart(resuri.scheme_, scheme_, GetSchemeStringLength());
0165 resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength());
0166 resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
0167 resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
0168 resuri.RemoveDotSegments();
0169 } else {
0170
0171 resuri.auth_ = CopyPart(resuri.scheme_, baseuri.scheme_, baseuri.GetSchemeStringLength());
0172 if (!(GetAuthStringLength() == 0)) {
0173
0174 resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength());
0175 resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
0176 resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
0177 resuri.RemoveDotSegments();
0178 } else {
0179
0180 resuri.path_ = CopyPart(resuri.auth_, baseuri.auth_, baseuri.GetAuthStringLength());
0181 if (GetPathStringLength() == 0) {
0182
0183 resuri.query_ = CopyPart(resuri.path_, baseuri.path_, baseuri.GetPathStringLength());
0184 if (GetQueryStringLength() == 0) {
0185
0186 resuri.frag_ = CopyPart(resuri.query_, baseuri.query_, baseuri.GetQueryStringLength());
0187 } else {
0188
0189 resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
0190 }
0191 } else {
0192 if (path_[0] == '/') {
0193
0194 resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
0195 resuri.RemoveDotSegments();
0196 } else {
0197
0198 size_t pos = 0;
0199 if (!(baseuri.GetAuthStringLength() == 0) && baseuri.GetPathStringLength() == 0) {
0200 resuri.path_[pos] = '/';
0201 pos++;
0202 }
0203 size_t lastslashpos = baseuri.GetPathStringLength();
0204 while (lastslashpos > 0) {
0205 if (baseuri.path_[lastslashpos - 1] == '/') break;
0206 lastslashpos--;
0207 }
0208 std::memcpy(&resuri.path_[pos], baseuri.path_, lastslashpos * sizeof(Ch));
0209 pos += lastslashpos;
0210 resuri.query_ = CopyPart(&resuri.path_[pos], path_, GetPathStringLength());
0211 resuri.RemoveDotSegments();
0212 }
0213
0214 resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
0215 }
0216 }
0217 }
0218
0219 resuri.base_ = CopyPart(resuri.frag_, frag_, GetFragStringLength());
0220
0221
0222 resuri.SetBase();
0223 resuri.uri_ = resuri.base_ + resuri.GetBaseStringLength() + 1;
0224 resuri.SetUri();
0225 return resuri;
0226 }
0227
0228
0229 Allocator& GetAllocator() { return *allocator_; }
0230
0231 private:
0232
0233
0234 std::size_t Allocate(std::size_t len) {
0235
0236 if (!allocator_)
0237 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
0238
0239
0240
0241
0242 size_t total = (3 * len + 7) * sizeof(Ch);
0243 scheme_ = static_cast<Ch*>(allocator_->Malloc(total));
0244 *scheme_ = '\0';
0245 auth_ = scheme_;
0246 auth_++;
0247 *auth_ = '\0';
0248 path_ = auth_;
0249 path_++;
0250 *path_ = '\0';
0251 query_ = path_;
0252 query_++;
0253 *query_ = '\0';
0254 frag_ = query_;
0255 frag_++;
0256 *frag_ = '\0';
0257 base_ = frag_;
0258 base_++;
0259 *base_ = '\0';
0260 uri_ = base_;
0261 uri_++;
0262 *uri_ = '\0';
0263 return total;
0264 }
0265
0266
0267 void Free() {
0268 if (scheme_) {
0269 Allocator::Free(scheme_);
0270 scheme_ = 0;
0271 }
0272 }
0273
0274
0275
0276
0277 void Parse(const Ch* uri, std::size_t len) {
0278 std::size_t start = 0, pos1 = 0, pos2 = 0;
0279 Allocate(len);
0280
0281
0282 if (start < len) {
0283 while (pos1 < len) {
0284 if (uri[pos1] == ':') break;
0285 pos1++;
0286 }
0287 if (pos1 != len) {
0288 while (pos2 < len) {
0289 if (uri[pos2] == '/') break;
0290 if (uri[pos2] == '?') break;
0291 if (uri[pos2] == '#') break;
0292 pos2++;
0293 }
0294 if (pos1 < pos2) {
0295 pos1++;
0296 std::memcpy(scheme_, &uri[start], pos1 * sizeof(Ch));
0297 scheme_[pos1] = '\0';
0298 start = pos1;
0299 }
0300 }
0301 }
0302
0303
0304 auth_ = scheme_ + GetSchemeStringLength();
0305 auth_++;
0306 *auth_ = '\0';
0307 if (start < len - 1 && uri[start] == '/' && uri[start + 1] == '/') {
0308 pos2 = start + 2;
0309 while (pos2 < len) {
0310 if (uri[pos2] == '/') break;
0311 if (uri[pos2] == '?') break;
0312 if (uri[pos2] == '#') break;
0313 pos2++;
0314 }
0315 std::memcpy(auth_, &uri[start], (pos2 - start) * sizeof(Ch));
0316 auth_[pos2 - start] = '\0';
0317 start = pos2;
0318 }
0319
0320
0321 path_ = auth_ + GetAuthStringLength();
0322 path_++;
0323 *path_ = '\0';
0324 if (start < len) {
0325 pos2 = start;
0326 while (pos2 < len) {
0327 if (uri[pos2] == '?') break;
0328 if (uri[pos2] == '#') break;
0329 pos2++;
0330 }
0331 if (start != pos2) {
0332 std::memcpy(path_, &uri[start], (pos2 - start) * sizeof(Ch));
0333 path_[pos2 - start] = '\0';
0334 if (path_[0] == '/')
0335 RemoveDotSegments();
0336 start = pos2;
0337 }
0338 }
0339
0340
0341 query_ = path_ + GetPathStringLength();
0342 query_++;
0343 *query_ = '\0';
0344 if (start < len && uri[start] == '?') {
0345 pos2 = start + 1;
0346 while (pos2 < len) {
0347 if (uri[pos2] == '#') break;
0348 pos2++;
0349 }
0350 if (start != pos2) {
0351 std::memcpy(query_, &uri[start], (pos2 - start) * sizeof(Ch));
0352 query_[pos2 - start] = '\0';
0353 start = pos2;
0354 }
0355 }
0356
0357
0358 frag_ = query_ + GetQueryStringLength();
0359 frag_++;
0360 *frag_ = '\0';
0361 if (start < len && uri[start] == '#') {
0362 std::memcpy(frag_, &uri[start], (len - start) * sizeof(Ch));
0363 frag_[len - start] = '\0';
0364 }
0365
0366
0367 base_ = frag_ + GetFragStringLength() + 1;
0368 SetBase();
0369 uri_ = base_ + GetBaseStringLength() + 1;
0370 SetUri();
0371 }
0372
0373
0374 void SetBase() {
0375 Ch* next = base_;
0376 std::memcpy(next, scheme_, GetSchemeStringLength() * sizeof(Ch));
0377 next+= GetSchemeStringLength();
0378 std::memcpy(next, auth_, GetAuthStringLength() * sizeof(Ch));
0379 next+= GetAuthStringLength();
0380 std::memcpy(next, path_, GetPathStringLength() * sizeof(Ch));
0381 next+= GetPathStringLength();
0382 std::memcpy(next, query_, GetQueryStringLength() * sizeof(Ch));
0383 next+= GetQueryStringLength();
0384 *next = '\0';
0385 }
0386
0387
0388 void SetUri() {
0389 Ch* next = uri_;
0390 std::memcpy(next, base_, GetBaseStringLength() * sizeof(Ch));
0391 next+= GetBaseStringLength();
0392 std::memcpy(next, frag_, GetFragStringLength() * sizeof(Ch));
0393 next+= GetFragStringLength();
0394 *next = '\0';
0395 }
0396
0397
0398
0399 Ch* CopyPart(Ch* to, Ch* from, std::size_t len) {
0400 RAPIDJSON_ASSERT(to != 0);
0401 RAPIDJSON_ASSERT(from != 0);
0402 std::memcpy(to, from, len * sizeof(Ch));
0403 to[len] = '\0';
0404 Ch* next = to + len + 1;
0405 return next;
0406 }
0407
0408
0409
0410
0411 void RemoveDotSegments() {
0412 std::size_t pathlen = GetPathStringLength();
0413 std::size_t pathpos = 0;
0414 std::size_t newpos = 0;
0415
0416
0417 while (pathpos < pathlen) {
0418
0419 size_t slashpos = 0;
0420 while ((pathpos + slashpos) < pathlen) {
0421 if (path_[pathpos + slashpos] == '/') break;
0422 slashpos++;
0423 }
0424
0425 if (slashpos == 2 && path_[pathpos] == '.' && path_[pathpos + 1] == '.') {
0426
0427
0428 RAPIDJSON_ASSERT(newpos == 0 || path_[newpos - 1] == '/');
0429 size_t lastslashpos = newpos;
0430
0431 if (lastslashpos > 1) {
0432
0433 lastslashpos--;
0434 while (lastslashpos > 0) {
0435 if (path_[lastslashpos - 1] == '/') break;
0436 lastslashpos--;
0437 }
0438
0439 newpos = lastslashpos;
0440 }
0441 } else if (slashpos == 1 && path_[pathpos] == '.') {
0442
0443 } else {
0444
0445 RAPIDJSON_ASSERT(newpos <= pathpos);
0446 std::memmove(&path_[newpos], &path_[pathpos], slashpos * sizeof(Ch));
0447 newpos += slashpos;
0448
0449 if ((pathpos + slashpos) < pathlen) {
0450 path_[newpos] = '/';
0451 newpos++;
0452 }
0453 }
0454
0455 pathpos += slashpos + 1;
0456 }
0457 path_[newpos] = '\0';
0458 }
0459
0460 Ch* uri_;
0461 Ch* base_;
0462 Ch* scheme_;
0463 Ch* auth_;
0464 Ch* path_;
0465 Ch* query_;
0466 Ch* frag_;
0467
0468 Allocator* allocator_;
0469 Allocator* ownAllocator_;
0470 };
0471
0472
0473 typedef GenericUri<Value> Uri;
0474
0475 RAPIDJSON_NAMESPACE_END
0476
0477 #if defined(__clang__)
0478 RAPIDJSON_DIAG_POP
0479 #endif
0480
0481 #endif