stdex
Additional custom or not Standard C++ covered algorithms
Loading...
Searching...
No Matches
parser.hpp
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 2023 Amebis
4*/
5
6#pragma once
7
8#include "compat.hpp"
9#include "interval.hpp"
10#include "memory.hpp"
11#include "sgml.hpp"
12#include "string.hpp"
13#include "system.hpp"
14#include <assert.h>
15#include <stdarg.h>
16#include <stdint.h>
17#include <math.h>
18#if defined(_WIN32)
19#ifndef _WINSOCKAPI_
20#include <winsock2.h>
21#include <ws2ipdef.h>
22#endif
23#elif defined(__APPLE__)
24#include <netinet/in.h>
25#else
26#include <inaddr.h>
27#include <in6addr.h>
28#endif
29#include <limits>
30#include <list>
31#include <locale>
32#include <memory>
33#include <set>
34#include <string>
35
36#ifdef _MSC_VER
37#pragma warning(push)
38#pragma warning(disable: 4100)
39#endif
40
41#define ENUM_FLAG_OPERATOR(T,X) \
42inline T operator X (const T lhs, const T rhs) { return static_cast<T>(static_cast<std::underlying_type_t<T>>(lhs) X static_cast<std::underlying_type_t<T>>(rhs)); } \
43inline T operator X (const T lhs, const std::underlying_type_t<T> rhs) { return static_cast<T>(static_cast<std::underlying_type_t<T>>(lhs) X rhs); } \
44inline T operator X (const std::underlying_type_t<T> lhs, const T rhs) { return static_cast<T>(lhs X static_cast<std::underlying_type_t<T>>(rhs)); } \
45inline T& operator X= (T& lhs, const T rhs) { return lhs = lhs X rhs; } \
46inline T& operator X= (T& lhs, const std::underlying_type_t<T> rhs) { return lhs = lhs X rhs; }
47#define ENUM_FLAGS(T, type) \
48enum class T : type; \
49inline T operator ~ (T t) { return (T) (~static_cast<std::underlying_type_t <T>>(t)); } \
50ENUM_FLAG_OPERATOR(T,|) \
51ENUM_FLAG_OPERATOR(T,^) \
52ENUM_FLAG_OPERATOR(T,&) \
53enum class T : type
54
55#ifndef s6_words
56#ifdef __APPLE__
57#define s6_words __u6_addr.__u6_addr16
58#else
59#error Unsupported platform
60#endif
61#endif
62
63namespace stdex
64{
65 namespace parser
66 {
70 constexpr int match_default = 0;
71 constexpr int match_case_insensitive = 0x1;
72 constexpr int match_multiline = 0x2;
73
77 template <class T>
79 {
80 public:
81 basic_parser(_In_ const std::locale& locale = std::locale()) : m_locale(locale) {}
82 virtual ~basic_parser() {}
83
84 bool search(
85 _In_reads_or_z_(end) const T* text,
86 _In_ size_t start = 0,
87 _In_ size_t end = (size_t)-1,
88 _In_ int flags = match_default)
89 {
90 for (size_t i = start; i < end && text[i]; i++)
91 if (match(text, i, end, flags))
92 return true;
93 return false;
94 }
95
96 virtual bool match(
97 _In_reads_or_z_(end) const T* text,
98 _In_ size_t start = 0,
99 _In_ size_t end = (size_t)-1,
100 _In_ int flags = match_default) = 0;
101
102 template<class _Traits, class _Ax>
103 inline bool match(
104 const std::basic_string<T, _Traits, _Ax>& text,
105 _In_ size_t start = 0,
106 _In_ size_t end = (size_t)-1,
107 _In_ int flags = match_default)
108 {
109 return match(text.c_str(), start, std::min<size_t>(end, text.size()), flags);
110 }
111
112 virtual void invalidate()
113 {
114 this->interval.start = 1;
115 this->interval.end = 0;
116 }
117
118 protected:
120 const wchar_t* next_sgml_cp(_In_ const char* text, _In_ size_t start, _In_ size_t end, _Out_ size_t& chr_end, _Out_ wchar_t(&buf)[3])
121 {
122 if (text[start] == '&') {
123 // Potential entity start
124 const auto& ctype = std::use_facet<std::ctype<T>>(m_locale);
125 for (chr_end = start + 1;; chr_end++) {
126 if (chr_end >= end || text[chr_end] == 0) {
127 // Unterminated entity
128 break;
129 }
130 if (text[chr_end] == ';') {
131 // Entity end
132 size_t n = chr_end - start - 1;
133 if (n >= 2 && text[start + 1] == '#') {
134 // Numerical entity
135 char32_t unicode;
136 if (text[start + 2] == 'x' || text[start + 2] == 'X')
137 unicode = strtou32(text + start + 3, n - 2, nullptr, 16);
138 else
139 unicode = strtou32(text + start + 2, n - 1, nullptr, 10);
140#ifdef _WIN32
141 if (unicode < 0x10000) {
142 buf[0] = (wchar_t)unicode;
143 buf[1] = 0;
144 }
145 else {
146 ucs4_to_surrogate_pair(buf, unicode);
147 buf[2] = 0;
148 }
149#else
150 buf[0] = (wchar_t)unicode;
151 buf[1] = 0;
152#endif
153 chr_end++;
154 return buf;
155 }
156 const wchar_t* entity_w = sgml2uni(text + start + 1, n);
157 if (entity_w) {
158 chr_end++;
159 return entity_w;
160 }
161 // Unknown entity.
162 break;
163 }
164 else if (text[chr_end] == '&' || ctype.is(ctype.space, text[chr_end])) {
165 // This char cannot possibly be a part of entity.
166 break;
167 }
168 }
169 }
170 buf[0] = text[start];
171 buf[1] = 0;
172 chr_end = start + 1;
173 return buf;
174 }
176
177 public:
179
180 protected:
181 std::locale m_locale;
182 };
183
186#ifdef _UNICODE
187 using tparser = wparser;
188#else
189 using tparser = parser;
190#endif
192
196 template <class T>
197 class basic_noop : public basic_parser<T>
198 {
199 public:
200 virtual bool match(
201 _In_reads_or_z_(end) const T* text,
202 _In_ size_t start = 0,
203 _In_ size_t end = (size_t)-1,
204 _In_ int flags = match_default)
205 {
206 assert(text || start >= end);
207 if (start < end && text[start]) {
208 this->interval.start = this->interval.end = start;
209 return true;
210 }
211 this->interval.start = (this->interval.end = start) + 1;
212 return false;
213 }
214 };
215
216 using noop = basic_noop<char>;
218#ifdef _UNICODE
219 using tnoop = wnoop;
220#else
221 using tnoop = noop;
222#endif
224
228 template <class T>
229 class basic_any_cu : public basic_parser<T>
230 {
231 public:
232 basic_any_cu(_In_ const std::locale& locale = std::locale()) : basic_parser<T>(locale) {}
233
234 virtual bool match(
235 _In_reads_or_z_(end) const T* text,
236 _In_ size_t start = 0,
237 _In_ size_t end = (size_t)-1,
238 _In_ int flags = match_default)
239 {
240 assert(text || start >= end);
241 if (start < end && text[start]) {
242 this->interval.end = (this->interval.start = start) + 1;
243 return true;
244 }
245 this->interval.start = (this->interval.end = start) + 1;
246 return false;
247 }
248 };
249
252#ifdef _UNICODE
253 using tany_cu = wany_cu;
254#else
255 using tany_cu = any_cu;
256#endif
257
261 class sgml_any_cp : public basic_any_cu<char>
262 {
263 public:
264 sgml_any_cp(_In_ const std::locale& locale = std::locale()) : basic_any_cu<char>(locale) {}
265
266 virtual bool match(
267 _In_reads_or_z_(end) const char* text,
268 _In_ size_t start = 0,
269 _In_ size_t end = (size_t)-1,
270 _In_ int flags = match_default)
271 {
272 assert(text || start >= end);
273 if (start < end && text[start]) {
274 if (text[start] == '&') {
275 // SGML entity
276 const auto& ctype = std::use_facet<std::ctype<char>>(m_locale);
277 for (this->interval.end = start + 1; this->interval.end < end && text[this->interval.end]; this->interval.end++)
278 if (text[this->interval.end] == ';') {
279 this->interval.end++;
280 this->interval.start = start;
281 return true;
282 }
283 else if (text[this->interval.end] == '&' || ctype.is(ctype.space, text[this->interval.end]))
284 break;
285 // Unterminated entity
286 }
287 this->interval.end = (this->interval.start = start) + 1;
288 return true;
289 }
290 this->interval.start = (this->interval.end = start) + 1;
291 return false;
292 }
293 };
294
298 template <class T>
299 class basic_cu : public basic_parser<T>
300 {
301 public:
302 basic_cu(T chr, bool invert = false, _In_ const std::locale& locale = std::locale()) :
303 basic_parser<T>(locale),
304 m_chr(chr),
305 m_invert(invert)
306 {}
307
308 virtual bool match(
309 _In_reads_or_z_(end) const T* text,
310 _In_ size_t start = 0,
311 _In_ size_t end = (size_t)-1,
312 _In_ int flags = match_default)
313 {
314 assert(text || start >= end);
315 if (start < end && text[start]) {
316 bool r;
317 if (flags & match_case_insensitive) {
318 const auto& ctype = std::use_facet<std::ctype<T>>(this->m_locale);
319 r = ctype.tolower(text[start]) == ctype.tolower(m_chr);
320 }
321 else
322 r = text[start] == m_chr;
323 if ((r && !m_invert) || (!r && m_invert)) {
324 this->interval.end = (this->interval.start = start) + 1;
325 return true;
326 }
327 }
328 this->interval.start = (this->interval.end = start) + 1;
329 return false;
330 }
331
332 protected:
333 T m_chr;
334 bool m_invert;
335 };
336
337 using cu = basic_cu<char>;
338 using wcu = basic_cu<wchar_t>;
339#ifdef _UNICODE
340 using tcu = wcu;
341#else
342 using tcu = cu;
343#endif
344
348 class sgml_cp : public sgml_parser
349 {
350 public:
351 sgml_cp(const char* chr, size_t count = (size_t)-1, bool invert = false, _In_ const std::locale& locale = std::locale()) :
352 sgml_parser(locale),
353 m_invert(invert)
354 {
355 assert(chr || !count);
356 wchar_t buf[3];
357 size_t chr_end;
358 m_chr.assign(count ? next_sgml_cp(chr, 0, count, chr_end, buf) : L"");
359 }
360
361 virtual bool match(
362 _In_reads_or_z_(end) const char* text,
363 _In_ size_t start = 0,
364 _In_ size_t end = (size_t)-1,
365 _In_ int flags = match_default)
366 {
367 assert(text || start >= end);
368 if (start < end && text[start]) {
369 wchar_t buf[3];
370 const wchar_t* chr = next_sgml_cp(text, start, end, this->interval.end, buf);
371 bool r = ((flags & match_case_insensitive) ?
372 stdex::strnicmp(chr, (size_t)-1, m_chr.c_str(), m_chr.size(), m_locale) :
373 stdex::strncmp(chr, (size_t)-1, m_chr.c_str(), m_chr.size())) == 0;
374 if ((r && !m_invert) || (!r && m_invert)) {
375 this->interval.start = start;
376 return true;
377 }
378 }
379 this->interval.start = (this->interval.end = start) + 1;
380 return false;
381 }
382
383 protected:
384 std::wstring m_chr;
385 bool m_invert;
386 };
387
391 template <class T>
392 class basic_space_cu : public basic_parser<T>
393 {
394 public:
395 basic_space_cu(bool invert = false, _In_ const std::locale& locale = std::locale()) :
396 basic_parser<T>(locale),
397 m_invert(invert)
398 {}
399
400 virtual bool match(
401 _In_reads_or_z_(end) const T* text,
402 _In_ size_t start = 0,
403 _In_ size_t end = (size_t)-1,
404 _In_ int flags = match_default)
405 {
406 assert(text || start >= end);
407 if (start < end && text[start]) {
408 bool r =
409 ((flags & match_multiline) || !islbreak(text[start])) &&
410 std::use_facet<std::ctype<T>>(this->m_locale).is(std::ctype_base::space, text[start]);
411 if ((r && !m_invert) || (!r && m_invert)) {
412 this->interval.end = (this->interval.start = start) + 1;
413 return true;
414 }
415 }
416 this->interval.start = (this->interval.end = start) + 1;
417 return false;
418 }
419
420 protected:
421 bool m_invert;
422 };
423
426#ifdef _UNICODE
427 using tspace_cu = wspace_cu;
428#else
429 using tspace_cu = space_cu;
430#endif
431
435 class sgml_space_cp : public basic_space_cu<char>
436 {
437 public:
438 sgml_space_cp(_In_ bool invert = false, _In_ const std::locale& locale = std::locale()) :
440 {}
441
442 virtual bool match(
443 _In_reads_or_z_(end) const char* text,
444 _In_ size_t start = 0,
445 _In_ size_t end = (size_t)-1,
446 _In_ int flags = match_default)
447 {
448 assert(text || start >= end);
449 if (start < end && text[start]) {
450 wchar_t buf[3];
451 const wchar_t* chr = next_sgml_cp(text, start, end, this->interval.end, buf);
452 const wchar_t* chr_end = chr + stdex::strlen(chr);
453 bool r =
454 ((flags & match_multiline) || !islbreak(chr, (size_t)-1)) &&
455 std::use_facet<std::ctype<wchar_t>>(m_locale).scan_not(std::ctype_base::space, chr, chr_end) == chr_end;
456 if ((r && !m_invert) || (!r && m_invert)) {
457 this->interval.start = start;
458 return true;
459 }
460 }
461
462 this->interval.start = (this->interval.end = start) + 1;
463 return false;
464 }
465 };
466
470 template <class T>
471 class basic_punct_cu : public basic_parser<T>
472 {
473 public:
474 basic_punct_cu(bool invert = false, _In_ const std::locale& locale = std::locale()) :
475 basic_parser<T>(locale),
476 m_invert(invert)
477 {}
478
479 virtual bool match(
480 _In_reads_or_z_(end) const T* text,
481 _In_ size_t start = 0,
482 _In_ size_t end = (size_t)-1,
483 _In_ int flags = match_default)
484 {
485 assert(text || start >= end);
486 if (start < end && text[start]) {
487 bool r = std::use_facet<std::ctype<T>>(this->m_locale).is(std::ctype_base::punct, text[start]);
488 if ((r && !m_invert) || (!r && m_invert)) {
489 this->interval.end = (this->interval.start = start) + 1;
490 return true;
491 }
492 }
493 this->interval.start = (this->interval.end = start) + 1;
494 return false;
495 }
496
497 protected:
498 bool m_invert;
499 };
500
503#ifdef _UNICODE
504 using tpunct_cu = wpunct_cu;
505#else
506 using tpunct_cu = punct_cu;
507#endif
508
512 class sgml_punct_cp : public basic_punct_cu<char>
513 {
514 public:
515 sgml_punct_cp(bool invert = false, _In_ const std::locale& locale = std::locale()) :
517 {}
518
519 virtual bool match(
520 _In_reads_or_z_(end) const char* text,
521 _In_ size_t start = 0,
522 _In_ size_t end = (size_t)-1,
523 _In_ int flags = match_default)
524 {
525 assert(text || start >= end);
526 if (start < end && text[start]) {
527 wchar_t buf[3];
528 const wchar_t* chr = next_sgml_cp(text, start, end, this->interval.end, buf);
529 const wchar_t* chr_end = chr + stdex::strlen(chr);
530 bool r = std::use_facet<std::ctype<wchar_t>>(m_locale).scan_not(std::ctype_base::punct, chr, chr_end) == chr_end;
531 if ((r && !m_invert) || (!r && m_invert)) {
532 this->interval.start = start;
533 return true;
534 }
535 }
536 this->interval.start = (this->interval.end = start) + 1;
537 return false;
538 }
539 };
540
544 template <class T>
546 {
547 public:
548 basic_space_or_punct_cu(bool invert = false, _In_ const std::locale& locale = std::locale()) :
549 basic_parser<T>(locale),
550 m_invert(invert)
551 {}
552
553 virtual bool match(
554 _In_reads_or_z_(end) const T* text,
555 _In_ size_t start = 0,
556 _In_ size_t end = (size_t)-1,
557 _In_ int flags = match_default)
558 {
559 assert(text || start >= end);
560 if (start < end && text[start]) {
561 bool r =
562 ((flags & match_multiline) || !islbreak(text[start])) &&
563 std::use_facet<std::ctype<T>>(this->m_locale).is(std::ctype_base::space | std::ctype_base::punct, text[start]);
564 if ((r && !m_invert) || (!r && m_invert)) {
565 this->interval.end = (this->interval.start = start) + 1;
566 return true;
567 }
568 }
569 this->interval.start = (this->interval.end = start) + 1;
570 return false;
571 }
572
573 protected:
574 bool m_invert;
575 };
576
579#ifdef _UNICODE
581#else
583#endif
584
589 {
590 public:
591 sgml_space_or_punct_cp(bool invert = false, _In_ const std::locale& locale = std::locale()) :
593 {}
594
595 virtual bool match(
596 _In_reads_or_z_(end) const char* text,
597 _In_ size_t start = 0,
598 _In_ size_t end = (size_t)-1,
599 _In_ int flags = match_default)
600 {
601 assert(text || start >= end);
602 if (start < end && text[start]) {
603 wchar_t buf[3];
604 const wchar_t* chr = next_sgml_cp(text, start, end, this->interval.end, buf);
605 const wchar_t* chr_end = chr + stdex::strlen(chr);
606 bool r =
607 ((flags & match_multiline) || !islbreak(chr, (size_t)-1)) &&
608 std::use_facet<std::ctype<wchar_t>>(m_locale).scan_not(std::ctype_base::space | std::ctype_base::punct, chr, chr_end) == chr_end;
609 if ((r && !m_invert) || (!r && m_invert)) {
610 this->interval.start = start;
611 return true;
612 }
613 }
614 this->interval.start = (this->interval.end = start) + 1;
615 return false;
616 }
617 };
618
622 template <class T>
623 class basic_bol : public basic_parser<T>
624 {
625 public:
626 basic_bol(bool invert = false) : m_invert(invert) {}
627
628 virtual bool match(
629 _In_reads_or_z_(end) const T* text,
630 _In_ size_t start = 0,
631 _In_ size_t end = (size_t)-1,
632 _In_ int flags = match_default)
633 {
634 assert(text || start >= end);
635 bool r = start == 0 || (start <= end && islbreak(text[start - 1]));
636 if ((r && !m_invert) || (!r && m_invert)) {
637 this->interval.end = this->interval.start = start;
638 return true;
639 }
640 this->interval.start = (this->interval.end = start) + 1;
641 return false;
642 }
643
644 protected:
645 bool m_invert;
646 };
647
648 using bol = basic_bol<char>;
649 using wbol = basic_bol<wchar_t>;
650#ifdef _UNICODE
651 using tbol = wbol;
652#else
653 using tbol = bol;
654#endif
656
660 template <class T>
661 class basic_eol : public basic_parser<T>
662 {
663 public:
664 basic_eol(bool invert = false) : m_invert(invert) {}
665
666 virtual bool match(
667 _In_reads_or_z_(end) const T* text,
668 _In_ size_t start = 0,
669 _In_ size_t end = (size_t)-1,
670 _In_ int flags = match_default)
671 {
672 assert(text || start >= end);
673 bool r = islbreak(text[start]);
674 if ((r && !m_invert) || (!r && m_invert)) {
675 this->interval.end = this->interval.start = start;
676 return true;
677 }
678 this->interval.start = (this->interval.end = start) + 1;
679 return false;
680 }
681
682 protected:
683 bool m_invert;
684 };
685
686 using eol = basic_eol<char>;
687 using weol = basic_eol<wchar_t>;
688#ifdef _UNICODE
689 using teol = weol;
690#else
691 using teol = eol;
692#endif
694
695 template <class T>
696 class basic_set : public basic_parser<T>
697 {
698 public:
699 basic_set(bool invert = false, _In_ const std::locale& locale = std::locale()) :
700 basic_parser<T>(locale),
701 hit_offset((size_t)-1),
702 m_invert(invert)
703 {}
704
705 virtual bool match(
706 _In_reads_or_z_(end) const T* text,
707 _In_ size_t start = 0,
708 _In_ size_t end = (size_t)-1,
709 _In_ int flags = match_default) = 0;
710
711 virtual void invalidate()
712 {
713 hit_offset = (size_t)-1;
715 }
716
717 public:
718 size_t hit_offset;
719
720 protected:
721 bool m_invert;
722 };
723
727 template <class T>
728 class basic_cu_set : public basic_set<T>
729 {
730 public:
732 _In_reads_or_z_(count) const T* set,
733 _In_ size_t count = (size_t)-1,
734 _In_ bool invert = false,
735 _In_ const std::locale& locale = std::locale()) :
736 basic_set<T>(invert, locale)
737 {
738 if (set)
739 m_set.assign(set, set + stdex::strnlen(set, count));
740 }
741
742 virtual bool match(
743 _In_reads_or_z_(end) const T* text,
744 _In_ size_t start = 0,
745 _In_ size_t end = (size_t)-1,
746 _In_ int flags = match_default)
747 {
748 assert(text || start >= end);
749 if (start < end && text[start]) {
750 const T* set = m_set.c_str();
751 size_t r = (flags & match_case_insensitive) ?
752 stdex::strnichr(set, m_set.size(), text[start], this->m_locale) :
753 stdex::strnchr(set, m_set.size(), text[start]);
754 if ((r != stdex::npos && !this->m_invert) || (r == stdex::npos && this->m_invert)) {
755 this->hit_offset = r;
756 this->interval.end = (this->interval.start = start) + 1;
757 return true;
758 }
759 }
760 this->hit_offset = (size_t)-1;
761 this->interval.start = (this->interval.end = start) + 1;
762 return false;
763 }
764
765 protected:
766 std::basic_string<T> m_set;
767 };
768
771#ifdef _UNICODE
772 using tcu_set = wcu_set;
773#else
774 using tcu_set = cu_set;
775#endif
776
780 class sgml_cp_set : public basic_set<char>
781 {
782 public:
783 sgml_cp_set(const char* set, size_t count = (size_t)-1, bool invert = false, _In_ const std::locale& locale = std::locale()) :
784 basic_set<char>(invert, locale)
785 {
786 if (set)
787 m_set = sgml2wstr(set, count);
788 }
789
790 virtual bool match(
791 _In_reads_or_z_(end) const char* text,
792 _In_ size_t start = 0,
793 _In_ size_t end = (size_t)-1,
794 _In_ int flags = match_default)
795 {
796 assert(text || start >= end);
797 if (start < end && text[start]) {
798 wchar_t buf[3];
799 const wchar_t* chr = next_sgml_cp(text, start, end, this->interval.end, buf);
800 const wchar_t* set = m_set.c_str();
801 size_t r = (flags & match_case_insensitive) ?
802 stdex::strnistr(set, m_set.size(), chr, m_locale) :
803 stdex::strnstr(set, m_set.size(), chr);
804 if ((r != stdex::npos && !m_invert) || (r == stdex::npos && m_invert)) {
805 hit_offset = r;
806 this->interval.start = start;
807 return true;
808 }
809 }
810 hit_offset = (size_t)-1;
811 this->interval.start = (this->interval.end = start) + 1;
812 return false;
813 }
814
815 protected:
816 std::wstring m_set;
817 };
818
822 template <class T>
823 class basic_string : public basic_parser<T>
824 {
825 public:
827 _In_reads_or_z_(count) const T* str,
828 _In_ size_t count = (size_t)-1,
829 _In_ const std::locale& locale = std::locale()) :
830 basic_parser<T>(locale),
831 m_str(str, str + stdex::strnlen(str, count))
832 {}
833
834 virtual bool match(
835 _In_reads_or_z_(end) const T* text,
836 _In_ size_t start = 0,
837 _In_ size_t end = (size_t)-1,
838 _In_ int flags = match_default)
839 {
840 assert(text || start >= end);
841 size_t
842 m = m_str.size(),
843 n = std::min<size_t>(end - start, m);
844 bool r = ((flags & match_case_insensitive) ?
845 stdex::strnicmp(text + start, n, m_str.c_str(), m, this->m_locale) :
846 stdex::strncmp(text + start, n, m_str.c_str(), m)) == 0;
847 if (r) {
848 this->interval.end = (this->interval.start = start) + n;
849 return true;
850 }
851 this->interval.start = (this->interval.end = start) + 1;
852 return false;
853 }
854
855 protected:
856 std::basic_string<T> m_str;
857 };
858
861#ifdef _UNICODE
862 using tstring = wstring;
863#else
864 using tstring = string;
865#endif
866
871 {
872 public:
873 sgml_string(const char* str, size_t count = (size_t)-1, _In_ const std::locale& locale = std::locale()) :
874 sgml_parser(locale),
875 m_str(sgml2wstr(str, count))
876 {}
877
878 virtual bool match(
879 _In_reads_or_z_(end) const char* text,
880 _In_ size_t start = 0,
881 _In_ size_t end = (size_t)-1,
882 _In_ int flags = match_default)
883 {
884 assert(text || start >= end);
885 const wchar_t* str = m_str.c_str();
886 const bool case_insensitive = flags & match_case_insensitive ? true : false;
887 const auto& ctype = std::use_facet<std::ctype<wchar_t>>(m_locale);
888 for (this->interval.end = start;;) {
889 if (!*str) {
890 this->interval.start = start;
891 return true;
892 }
893 if (this->interval.end >= end || !text[this->interval.end]) {
894 this->interval.start = (this->interval.end = start) + 1;
895 return false;
896 }
897 wchar_t buf[3];
898 const wchar_t* chr = next_sgml_cp(text, this->interval.end, end, this->interval.end, buf);
899 for (; *chr; ++str, ++chr) {
900 if (!*str ||
901 (case_insensitive ? ctype.tolower(*str) != ctype.tolower(*chr) : *str != *chr))
902 {
903 this->interval.start = (this->interval.end = start) + 1;
904 return false;
905 }
906 }
907 }
908 }
909
910 protected:
911 std::wstring m_str;
912 };
913
917 template <class T>
919 {
920 public:
921 basic_iterations(const std::shared_ptr<basic_parser<T>>& el, size_t min_iterations = 0, size_t max_iterations = (size_t)-1, bool greedy = true) :
922 m_el(el),
926 {}
927
928 virtual bool match(
929 _In_reads_or_z_(end) const T* text,
930 _In_ size_t start = 0,
931 _In_ size_t end = (size_t)-1,
932 _In_ int flags = match_default)
933 {
934 assert(text || start >= end);
935 this->interval.start = this->interval.end = start;
936 for (size_t i = 0; ; i++) {
937 if ((!m_greedy && i >= m_min_iterations) || i >= m_max_iterations)
938 return true;
939 if (!m_el->match(text, this->interval.end, end, flags)) {
940 if (i >= m_min_iterations)
941 return true;
942 break;
943 }
944 if (m_el->interval.end == this->interval.end) {
945 // Element did match, but the matching interval was empty. Quit instead of spinning.
946 return true;
947 }
948 this->interval.end = m_el->interval.end;
949 }
950 this->interval.start = (this->interval.end = start) + 1;
951 return false;
952 }
953
954 protected:
955 std::shared_ptr<basic_parser<T>> m_el;
958 bool m_greedy;
959 };
960
963#ifdef _UNICODE
964 using titerations = witerations;
965#else
966 using titerations = iterations;
967#endif
969
973 template <class T>
975 {
976 protected:
977 parser_collection(_In_ const std::locale& locale) : basic_parser<T>(locale) {}
978
979 public:
981 _In_count_(count) const std::shared_ptr<basic_parser<T>>* el,
982 _In_ size_t count,
983 _In_ const std::locale& locale = std::locale()) :
984 basic_parser<T>(locale)
985 {
986 assert(el || !count);
987 m_collection.reserve(count);
988 for (size_t i = 0; i < count; i++)
989 m_collection.push_back(el[i]);
990 }
991
993 _Inout_ std::vector<std::shared_ptr<basic_parser<T>>>&& collection,
994 _In_ const std::locale& locale = std::locale()) :
995 basic_parser<T>(locale),
996 m_collection(std::move(collection))
997 {}
998
999 virtual void invalidate()
1000 {
1001 for (auto& el: m_collection)
1002 el->invalidate();
1004 }
1005
1006 protected:
1007 std::vector<std::shared_ptr<basic_parser<T>>> m_collection;
1008 };
1009
1013 template <class T>
1015 {
1016 public:
1018 _In_count_(count) const std::shared_ptr<basic_parser<T>>* el = nullptr,
1019 _In_ size_t count = 0,
1020 _In_ const std::locale& locale = std::locale()) :
1021 parser_collection<T>(el, count, locale)
1022 {}
1023
1025 _Inout_ std::vector<std::shared_ptr<basic_parser<T>>>&& collection,
1026 _In_ const std::locale& locale = std::locale()) :
1027 parser_collection<T>(std::move(collection), locale)
1028 {}
1029
1030 virtual bool match(
1031 _In_reads_or_z_(end) const T* text,
1032 _In_ size_t start = 0,
1033 _In_ size_t end = (size_t)-1,
1034 _In_ int flags = match_default)
1035 {
1036 assert(text || start >= end);
1037 this->interval.end = start;
1038 for (auto i = this->m_collection.begin(); i != this->m_collection.end(); ++i) {
1039 if (!(*i)->match(text, this->interval.end, end, flags)) {
1040 for (++i; i != this->m_collection.end(); ++i)
1041 (*i)->invalidate();
1042 this->interval.start = (this->interval.end = start) + 1;
1043 return false;
1044 }
1045 this->interval.end = (*i)->interval.end;
1046 }
1047 this->interval.start = start;
1048 return true;
1049 }
1050 };
1051
1054#ifdef _UNICODE
1055 using tsequence = wsequence;
1056#else
1057 using tsequence = sequence;
1058#endif
1060
1064 template <class T>
1066 {
1067 protected:
1068 basic_branch(_In_ const std::locale& locale) :
1069 parser_collection<T>(locale),
1070 hit_offset((size_t)-1)
1071 {}
1072
1073 public:
1075 _In_count_(count) const std::shared_ptr<basic_parser<T>>* el = nullptr,
1076 _In_ size_t count = 0,
1077 _In_ const std::locale& locale = std::locale()) :
1078 parser_collection<T>(el, count, locale),
1079 hit_offset((size_t)-1)
1080 {}
1081
1083 _Inout_ std::vector<std::shared_ptr<basic_parser<T>>>&& collection,
1084 _In_ const std::locale& locale = std::locale()) :
1085 parser_collection<T>(std::move(collection), locale),
1086 hit_offset((size_t)-1)
1087 {}
1088
1089 virtual bool match(
1090 _In_reads_or_z_(end) const T* text,
1091 _In_ size_t start = 0,
1092 _In_ size_t end = (size_t)-1,
1093 _In_ int flags = match_default)
1094 {
1095 assert(text || start >= end);
1096 hit_offset = 0;
1097 for (auto i = this->m_collection.begin(); i != this->m_collection.end(); ++i, ++hit_offset) {
1098 if ((*i)->match(text, start, end, flags)) {
1099 this->interval = (*i)->interval;
1100 for (++i; i != this->m_collection.end(); ++i)
1101 (*i)->invalidate();
1102 return true;
1103 }
1104 }
1105 hit_offset = (size_t)-1;
1106 this->interval.start = (this->interval.end = start) + 1;
1107 return false;
1108 }
1109
1110 virtual void invalidate()
1111 {
1112 hit_offset = (size_t)-1;
1114 }
1115
1116 public:
1117 size_t hit_offset;
1118 };
1119
1120 using branch = basic_branch<char>;
1122#ifdef _UNICODE
1123 using tbranch = wbranch;
1124#else
1125 using tbranch = branch;
1126#endif
1128
1132 template <class T, class T_parser = basic_string<T>>
1134 {
1135 public:
1136 inline basic_string_branch(
1137 _In_reads_(count) const T* str_z = nullptr,
1138 _In_ size_t count = 0,
1139 _In_ const std::locale& locale = std::locale()) :
1140 basic_branch<T>(locale)
1141 {
1142 build(str_z, count);
1143 }
1144
1145 inline basic_string_branch(_In_z_ const T* str, ...) :
1146 basic_branch<T>(std::locale())
1147 {
1148 va_list params;
1149 va_start(params, str);
1150 build(str, params);
1151 va_end(params);
1152 }
1153
1154 inline basic_string_branch(_In_ const std::locale& locale, _In_z_ const T* str, ...) :
1155 basic_branch<T>(locale)
1156 {
1157 va_list params;
1158 va_start(params, str);
1159 build(str, params);
1160 va_end(params);
1161 }
1162
1163 protected:
1164 void build(_In_reads_(count) const T* str_z, _In_ size_t count)
1165 {
1166 assert(str_z || !count);
1167 if (count) {
1168 size_t offset, n;
1169 for (
1170 offset = n = 0;
1171 offset < count && str_z[offset];
1172 offset += stdex::strnlen(str_z + offset, count - offset) + 1, ++n);
1173 this->m_collection.reserve(n);
1174 for (
1175 offset = 0;
1176 offset < count && str_z[offset];
1177 offset += stdex::strnlen(str_z + offset, count - offset) + 1)
1178 this->m_collection.push_back(std::move(std::make_shared<T_parser>(str_z + offset, count - offset, this->m_locale)));
1179 }
1180 }
1181
1182 void build(_In_z_ const T* str, _In_ va_list params)
1183 {
1184 const T* p;
1185 for (
1186 this->m_collection.push_back(std::move(std::make_shared<T_parser>(str, (size_t)-1, this->m_locale)));
1187 (p = va_arg(params, const T*)) != nullptr;
1188 this->m_collection.push_back(std::move(std::make_shared<T_parser>(p, (size_t)-1, this->m_locale))));
1189 }
1190 };
1191
1194#ifdef _UNICODE
1196#else
1198#endif
1200
1204 template <class T>
1206 {
1207 public:
1209 _In_count_(count) const std::shared_ptr<basic_parser<T>>* el = nullptr,
1210 _In_ size_t count = 0,
1211 _In_ const std::locale& locale = std::locale()) :
1212 parser_collection<T>(el, count, locale)
1213 {}
1214
1216 _Inout_ std::vector<std::shared_ptr<basic_parser<T>>>&& collection,
1217 _In_ const std::locale& locale = std::locale()) :
1218 parser_collection<T>(std::move(collection), locale)
1219 {}
1220
1221 virtual bool match(
1222 _In_reads_or_z_(end) const T* text,
1223 _In_ size_t start = 0,
1224 _In_ size_t end = (size_t)-1,
1225 _In_ int flags = match_default)
1226 {
1227 assert(text || start >= end);
1228 for (auto& el: this->m_collection)
1229 el->invalidate();
1230 if (match_recursively(text, start, end, flags)) {
1231 this->interval.start = start;
1232 return true;
1233 }
1234 this->interval.start = (this->interval.end = start) + 1;
1235 return false;
1236 }
1237
1238 protected:
1239 bool match_recursively(
1240 _In_reads_or_z_(end) const T* text,
1241 _In_ size_t start = 0,
1242 _In_ size_t end = (size_t)-1,
1243 _In_ int flags = match_default)
1244 {
1245 bool all_matched = true;
1246 for (auto& el: this->m_collection) {
1247 if (!el->interval) {
1248 // Element was not matched in permutatuion yet.
1249 all_matched = false;
1250 if (el->match(text, start, end, flags)) {
1251 // Element matched for the first time.
1252 if (match_recursively(text, el->interval.end, end, flags)) {
1253 // Rest of the elements matched too.
1254 return true;
1255 }
1256 el->invalidate();
1257 }
1258 }
1259 }
1260 if (all_matched) {
1261 this->interval.end = start;
1262 return true;
1263 }
1264 return false;
1265 }
1266 };
1267
1270#ifdef _UNICODE
1271 using tpermutation = wpermutation;
1272#else
1273 using tpermutation = permutation;
1274#endif
1276
1280 template <class T>
1281 class basic_integer : public basic_parser<T>
1282 {
1283 public:
1284 basic_integer(_In_ const std::locale& locale = std::locale()) :
1285 basic_parser<T>(locale),
1286 value(0)
1287 {}
1288
1289 virtual void invalidate()
1290 {
1291 value = 0;
1293 }
1294
1295 public:
1296 size_t value;
1297 };
1298
1302 template <class T>
1304 {
1305 public:
1307 _In_ const std::shared_ptr<basic_parser<T>>& digit_0,
1308 _In_ const std::shared_ptr<basic_parser<T>>& digit_1,
1309 _In_ const std::shared_ptr<basic_parser<T>>& digit_2,
1310 _In_ const std::shared_ptr<basic_parser<T>>& digit_3,
1311 _In_ const std::shared_ptr<basic_parser<T>>& digit_4,
1312 _In_ const std::shared_ptr<basic_parser<T>>& digit_5,
1313 _In_ const std::shared_ptr<basic_parser<T>>& digit_6,
1314 _In_ const std::shared_ptr<basic_parser<T>>& digit_7,
1315 _In_ const std::shared_ptr<basic_parser<T>>& digit_8,
1316 _In_ const std::shared_ptr<basic_parser<T>>& digit_9,
1317 _In_ const std::locale& locale = std::locale()) :
1318 basic_integer<T>(locale),
1319 m_digit_0(digit_0),
1320 m_digit_1(digit_1),
1321 m_digit_2(digit_2),
1322 m_digit_3(digit_3),
1323 m_digit_4(digit_4),
1324 m_digit_5(digit_5),
1325 m_digit_6(digit_6),
1326 m_digit_7(digit_7),
1327 m_digit_8(digit_8),
1328 m_digit_9(digit_9)
1329 {}
1330
1331 virtual bool match(
1332 _In_reads_or_z_(end) const T* text,
1333 _In_ size_t start = 0,
1334 _In_ size_t end = (size_t)-1,
1335 _In_ int flags = match_default)
1336 {
1337 assert(text || start >= end);
1338 for (this->interval.end = start, this->value = 0; this->interval.end < end && text[this->interval.end];) {
1339 size_t dig;
1340 if (m_digit_0->match(text, this->interval.end, end, flags)) { dig = 0; this->interval.end = m_digit_0->interval.end; }
1341 else if (m_digit_1->match(text, this->interval.end, end, flags)) { dig = 1; this->interval.end = m_digit_1->interval.end; }
1342 else if (m_digit_2->match(text, this->interval.end, end, flags)) { dig = 2; this->interval.end = m_digit_2->interval.end; }
1343 else if (m_digit_3->match(text, this->interval.end, end, flags)) { dig = 3; this->interval.end = m_digit_3->interval.end; }
1344 else if (m_digit_4->match(text, this->interval.end, end, flags)) { dig = 4; this->interval.end = m_digit_4->interval.end; }
1345 else if (m_digit_5->match(text, this->interval.end, end, flags)) { dig = 5; this->interval.end = m_digit_5->interval.end; }
1346 else if (m_digit_6->match(text, this->interval.end, end, flags)) { dig = 6; this->interval.end = m_digit_6->interval.end; }
1347 else if (m_digit_7->match(text, this->interval.end, end, flags)) { dig = 7; this->interval.end = m_digit_7->interval.end; }
1348 else if (m_digit_8->match(text, this->interval.end, end, flags)) { dig = 8; this->interval.end = m_digit_8->interval.end; }
1349 else if (m_digit_9->match(text, this->interval.end, end, flags)) { dig = 9; this->interval.end = m_digit_9->interval.end; }
1350 else break;
1351 this->value = this->value * 10 + dig;
1352 }
1354 this->interval.start = start;
1355 return true;
1356 }
1357 this->interval.start = (this->interval.end = start) + 1;
1358 return false;
1359 }
1360
1361 protected:
1362 std::shared_ptr<basic_parser<T>>
1363 m_digit_0,
1364 m_digit_1,
1365 m_digit_2,
1366 m_digit_3,
1367 m_digit_4,
1368 m_digit_5,
1369 m_digit_6,
1370 m_digit_7,
1371 m_digit_8,
1372 m_digit_9;
1373 };
1374
1377#ifdef _UNICODE
1378 using tinteger10 = winteger10;
1379#else
1380 using tinteger10 = integer10;
1381#endif
1383
1387 template <class T>
1389 {
1390 public:
1392 _In_ const std::shared_ptr<basic_integer10<T>>& digits,
1393 _In_ const std::shared_ptr<basic_set<T>>& separator,
1394 _In_ const std::locale& locale = std::locale()) :
1395 basic_integer<T>(locale),
1396 digit_count(0),
1397 has_separators(false),
1398 m_digits(digits),
1399 m_separator(separator)
1400 {}
1401
1402 virtual bool match(
1403 _In_reads_or_z_(end) const T* text,
1404 _In_ size_t start = 0,
1405 _In_ size_t end = (size_t)-1,
1406 _In_ int flags = match_default)
1407 {
1408 assert(text || start >= end);
1409 if (m_digits->match(text, start, end, flags)) {
1410 // Leading part match.
1411 this->value = m_digits->value;
1412 digit_count = m_digits->interval.size();
1413 has_separators = false;
1414 this->interval.start = start;
1415 this->interval.end = m_digits->interval.end;
1416 if (m_digits->interval.size() <= 3) {
1417 // Maybe separated with thousand separators?
1418 size_t hit_offset = (size_t)-1;
1419 while (m_separator->match(text, this->interval.end, end, flags) &&
1420 (hit_offset == (size_t)-1 || hit_offset == m_separator->hit_offset) && // All separators must be the same, no mixing.
1421 m_digits->match(text, m_separator->interval.end, end, flags) &&
1422 m_digits->interval.size() == 3)
1423 {
1424 // Thousand separator and three-digit integer followed.
1425 this->value = this->value * 1000 + m_digits->value;
1426 digit_count += 3;
1427 has_separators = true;
1428 this->interval.end = m_digits->interval.end;
1429 hit_offset = m_separator->hit_offset;
1430 }
1431 }
1432
1433 return true;
1434 }
1435 this->value = 0;
1436 this->interval.start = (this->interval.end = start) + 1;
1437 return false;
1438 }
1439
1440 virtual void invalidate()
1441 {
1442 digit_count = 0;
1443 has_separators = false;
1445 }
1446
1447 public:
1450
1451 protected:
1452 std::shared_ptr<basic_integer10<T>> m_digits;
1453 std::shared_ptr<basic_set<T>> m_separator;
1454 };
1455
1458#ifdef _UNICODE
1459 using tinteger10ts = winteger10ts;
1460#else
1461 using tinteger10ts = integer10ts;
1462#endif
1464
1468 template <class T>
1470 {
1471 public:
1473 _In_ const std::shared_ptr<basic_parser<T>>& digit_0,
1474 _In_ const std::shared_ptr<basic_parser<T>>& digit_1,
1475 _In_ const std::shared_ptr<basic_parser<T>>& digit_2,
1476 _In_ const std::shared_ptr<basic_parser<T>>& digit_3,
1477 _In_ const std::shared_ptr<basic_parser<T>>& digit_4,
1478 _In_ const std::shared_ptr<basic_parser<T>>& digit_5,
1479 _In_ const std::shared_ptr<basic_parser<T>>& digit_6,
1480 _In_ const std::shared_ptr<basic_parser<T>>& digit_7,
1481 _In_ const std::shared_ptr<basic_parser<T>>& digit_8,
1482 _In_ const std::shared_ptr<basic_parser<T>>& digit_9,
1483 _In_ const std::shared_ptr<basic_parser<T>>& digit_10,
1484 _In_ const std::shared_ptr<basic_parser<T>>& digit_11,
1485 _In_ const std::shared_ptr<basic_parser<T>>& digit_12,
1486 _In_ const std::shared_ptr<basic_parser<T>>& digit_13,
1487 _In_ const std::shared_ptr<basic_parser<T>>& digit_14,
1488 _In_ const std::shared_ptr<basic_parser<T>>& digit_15,
1489 _In_ const std::locale& locale = std::locale()) :
1490 basic_integer<T>(locale),
1491 m_digit_0(digit_0),
1492 m_digit_1(digit_1),
1493 m_digit_2(digit_2),
1494 m_digit_3(digit_3),
1495 m_digit_4(digit_4),
1496 m_digit_5(digit_5),
1497 m_digit_6(digit_6),
1498 m_digit_7(digit_7),
1499 m_digit_8(digit_8),
1500 m_digit_9(digit_9),
1501 m_digit_10(digit_10),
1502 m_digit_11(digit_11),
1503 m_digit_12(digit_12),
1504 m_digit_13(digit_13),
1505 m_digit_14(digit_14),
1506 m_digit_15(digit_15)
1507 {}
1508
1509 virtual bool match(
1510 _In_reads_or_z_(end) const T* text,
1511 _In_ size_t start = 0,
1512 _In_ size_t end = (size_t)-1,
1513 _In_ int flags = match_default)
1514 {
1515 assert(text || start >= end);
1516 for (this->interval.end = start, this->value = 0; this->interval.end < end && text[this->interval.end];) {
1517 size_t dig;
1518 if (m_digit_0->match(text, this->interval.end, end, flags)) { dig = 0; this->interval.end = m_digit_0->interval.end; }
1519 else if (m_digit_1->match(text, this->interval.end, end, flags)) { dig = 1; this->interval.end = m_digit_1->interval.end; }
1520 else if (m_digit_2->match(text, this->interval.end, end, flags)) { dig = 2; this->interval.end = m_digit_2->interval.end; }
1521 else if (m_digit_3->match(text, this->interval.end, end, flags)) { dig = 3; this->interval.end = m_digit_3->interval.end; }
1522 else if (m_digit_4->match(text, this->interval.end, end, flags)) { dig = 4; this->interval.end = m_digit_4->interval.end; }
1523 else if (m_digit_5->match(text, this->interval.end, end, flags)) { dig = 5; this->interval.end = m_digit_5->interval.end; }
1524 else if (m_digit_6->match(text, this->interval.end, end, flags)) { dig = 6; this->interval.end = m_digit_6->interval.end; }
1525 else if (m_digit_7->match(text, this->interval.end, end, flags)) { dig = 7; this->interval.end = m_digit_7->interval.end; }
1526 else if (m_digit_8->match(text, this->interval.end, end, flags)) { dig = 8; this->interval.end = m_digit_8->interval.end; }
1527 else if (m_digit_9->match(text, this->interval.end, end, flags)) { dig = 9; this->interval.end = m_digit_9->interval.end; }
1528 else if (m_digit_10->match(text, this->interval.end, end, flags)) { dig = 10; this->interval.end = m_digit_10->interval.end; }
1529 else if (m_digit_11->match(text, this->interval.end, end, flags)) { dig = 11; this->interval.end = m_digit_11->interval.end; }
1530 else if (m_digit_12->match(text, this->interval.end, end, flags)) { dig = 12; this->interval.end = m_digit_12->interval.end; }
1531 else if (m_digit_13->match(text, this->interval.end, end, flags)) { dig = 13; this->interval.end = m_digit_13->interval.end; }
1532 else if (m_digit_14->match(text, this->interval.end, end, flags)) { dig = 14; this->interval.end = m_digit_14->interval.end; }
1533 else if (m_digit_15->match(text, this->interval.end, end, flags)) { dig = 15; this->interval.end = m_digit_15->interval.end; }
1534 else break;
1535 this->value = this->value * 16 + dig;
1536 }
1538 this->interval.start = start;
1539 return true;
1540 }
1541 this->interval.start = (this->interval.end = start) + 1;
1542 return false;
1543 }
1544
1545 protected:
1546 std::shared_ptr<basic_parser<T>>
1547 m_digit_0,
1548 m_digit_1,
1549 m_digit_2,
1550 m_digit_3,
1551 m_digit_4,
1552 m_digit_5,
1553 m_digit_6,
1554 m_digit_7,
1555 m_digit_8,
1556 m_digit_9,
1557 m_digit_10,
1558 m_digit_11,
1559 m_digit_12,
1560 m_digit_13,
1561 m_digit_14,
1562 m_digit_15;
1563 };
1564
1567#ifdef _UNICODE
1568 using tinteger16 = winteger16;
1569#else
1570 using tinteger16 = integer16;
1571#endif
1573
1577 template <class T>
1579 {
1580 public:
1582 _In_ const std::shared_ptr<basic_parser<T>>& digit_1,
1583 _In_ const std::shared_ptr<basic_parser<T>>& digit_5,
1584 _In_ const std::shared_ptr<basic_parser<T>>& digit_10,
1585 _In_ const std::shared_ptr<basic_parser<T>>& digit_50,
1586 _In_ const std::shared_ptr<basic_parser<T>>& digit_100,
1587 _In_ const std::shared_ptr<basic_parser<T>>& digit_500,
1588 _In_ const std::shared_ptr<basic_parser<T>>& digit_1000,
1589 _In_ const std::shared_ptr<basic_parser<T>>& digit_5000,
1590 _In_ const std::shared_ptr<basic_parser<T>>& digit_10000,
1591 _In_ const std::locale& locale = std::locale()) :
1592 basic_integer<T>(locale),
1593 m_digit_1(digit_1),
1594 m_digit_5(digit_5),
1595 m_digit_10(digit_10),
1596 m_digit_50(digit_50),
1597 m_digit_100(digit_100),
1598 m_digit_500(digit_500),
1599 m_digit_1000(digit_1000),
1600 m_digit_5000(digit_5000),
1601 m_digit_10000(digit_10000)
1602 {}
1603
1604 virtual bool match(
1605 _In_reads_or_z_(end) const T* text,
1606 _In_ size_t start = 0,
1607 _In_ size_t end = (size_t)-1,
1608 _In_ int flags = match_default)
1609 {
1610 assert(text || start >= end);
1611 size_t
1612 dig[5] = { (size_t)-1, (size_t)-1, (size_t)-1, (size_t)-1, (size_t)-1 },
1613 end2;
1614
1615 for (this->interval.end = start, this->value = 0; this->interval.end < end && text[this->interval.end]; dig[3] = dig[2], dig[2] = dig[1], dig[1] = dig[0], this->interval.end = end2) {
1616 if (m_digit_1 && m_digit_1->match(text, this->interval.end, end, flags)) { dig[0] = 1; end2 = m_digit_1->interval.end; }
1617 else if (m_digit_5 && m_digit_5->match(text, this->interval.end, end, flags)) { dig[0] = 5; end2 = m_digit_5->interval.end; }
1618 else if (m_digit_10 && m_digit_10->match(text, this->interval.end, end, flags)) { dig[0] = 10; end2 = m_digit_10->interval.end; }
1619 else if (m_digit_50 && m_digit_50->match(text, this->interval.end, end, flags)) { dig[0] = 50; end2 = m_digit_50->interval.end; }
1620 else if (m_digit_100 && m_digit_100->match(text, this->interval.end, end, flags)) { dig[0] = 100; end2 = m_digit_100->interval.end; }
1621 else if (m_digit_500 && m_digit_500->match(text, this->interval.end, end, flags)) { dig[0] = 500; end2 = m_digit_500->interval.end; }
1622 else if (m_digit_1000 && m_digit_1000->match(text, this->interval.end, end, flags)) { dig[0] = 1000; end2 = m_digit_1000->interval.end; }
1623 else if (m_digit_5000 && m_digit_5000->match(text, this->interval.end, end, flags)) { dig[0] = 5000; end2 = m_digit_5000->interval.end; }
1624 else if (m_digit_10000 && m_digit_10000->match(text, this->interval.end, end, flags)) { dig[0] = 10000; end2 = m_digit_10000->interval.end; }
1625 else break;
1626
1627 // Store first digit.
1628 if (dig[4] == (size_t)-1) dig[4] = dig[0];
1629
1630 if (dig[3] == dig[2] && dig[2] == dig[1] && dig[1] == dig[0] && dig[0] != dig[4]) {
1631 // Same digit repeated four times. No-go, unless first digit. E.g. XIIII vs. XIV. MMMMMCD allowed, IIII also...
1632 break;
1633 }
1634 if (dig[0] <= dig[1]) {
1635 // Digit is less or equal previous one: add.
1636 this->value += dig[0];
1637 }
1638 else if (
1639 (dig[1] == 1 && (dig[0] == 5 || dig[0] == 10)) ||
1640 (dig[1] == 10 && (dig[0] == 50 || dig[0] == 100)) ||
1641 (dig[1] == 100 && (dig[0] == 500 || dig[0] == 1000)) ||
1642 (dig[1] == 1000 && (dig[0] == 5000 || dig[0] == 10000)))
1643 {
1644 // Digit is up to two orders bigger than previous one: subtract. But...
1645 if (dig[2] < dig[0]) {
1646 // Digit is also bigger than pre-previous one. E.g. VIX (V < X => invalid)
1647 break;
1648 }
1649 this->value -= dig[1]; // Cancel addition in the previous step.
1650 dig[0] -= dig[1]; // Combine last two digits.
1651 dig[1] = dig[2]; // The true previous digit is now pre-previous one. :)
1652 dig[2] = dig[3]; // The true pre-previous digit is now pre-pre-previous one. :)
1653 this->value += dig[0]; // Add combined value.
1654 }
1655 else {
1656 // New digit is too big than the previous one. E.g. VX (V < X => invalid)
1657 break;
1658 }
1659 }
1660 if (this->value) {
1661 this->interval.start = start;
1662 return true;
1663 }
1664 this->interval.start = (this->interval.end = start) + 1;
1665 return false;
1666 }
1667
1668 protected:
1669 std::shared_ptr<basic_parser<T>>
1670 m_digit_1,
1671 m_digit_5,
1672 m_digit_10,
1673 m_digit_50,
1674 m_digit_100,
1675 m_digit_500,
1676 m_digit_1000,
1677 m_digit_5000,
1678 m_digit_10000;
1679 };
1680
1683#ifdef _UNICODE
1685#else
1687#endif
1689
1693 template <class T>
1695 {
1696 public:
1698 _In_ const std::shared_ptr<basic_parser<T>>& _numerator,
1699 _In_ const std::shared_ptr<basic_parser<T>>& _fraction_line,
1700 _In_ const std::shared_ptr<basic_parser<T>>& _denominator,
1701 _In_ const std::locale& locale = std::locale()) :
1702 basic_parser<T>(locale),
1703 numerator(_numerator),
1704 fraction_line(_fraction_line),
1705 denominator(_denominator)
1706 {}
1707
1708 virtual bool match(
1709 _In_reads_or_z_(end) const T* text,
1710 _In_ size_t start = 0,
1711 _In_ size_t end = (size_t)-1,
1712 _In_ int flags = match_default)
1713 {
1714 assert(text || start >= end);
1715 if (numerator->match(text, start, end, flags) &&
1716 fraction_line->match(text, numerator->interval.end, end, flags) &&
1717 denominator->match(text, fraction_line->interval.end, end, flags))
1718 {
1719 this->interval.start = start;
1720 this->interval.end = denominator->interval.end;
1721 return true;
1722 }
1723 numerator->invalidate();
1724 fraction_line->invalidate();
1725 denominator->invalidate();
1726 this->interval.start = (this->interval.end = start) + 1;
1727 return false;
1728 }
1729
1730 virtual void invalidate()
1731 {
1732 numerator->invalidate();
1733 fraction_line->invalidate();
1734 denominator->invalidate();
1736 }
1737
1738 public:
1739 std::shared_ptr<basic_parser<T>> numerator;
1740 std::shared_ptr<basic_parser<T>> fraction_line;
1741 std::shared_ptr<basic_parser<T>> denominator;
1742 };
1743
1746#ifdef _UNICODE
1747 using tfraction = wfraction;
1748#else
1749 using tfraction = fraction;
1750#endif
1752
1756 template <class T>
1757 class basic_score : public basic_parser<T>
1758 {
1759 public:
1761 _In_ const std::shared_ptr<basic_parser<T>>& _home,
1762 _In_ const std::shared_ptr<basic_parser<T>>& _separator,
1763 _In_ const std::shared_ptr<basic_parser<T>>& _guest,
1764 _In_ const std::shared_ptr<basic_parser<T>>& space,
1765 _In_ const std::locale& locale = std::locale()) :
1766 basic_parser<T>(locale),
1767 home(_home),
1768 separator(_separator),
1769 guest(_guest),
1770 m_space(space)
1771 {}
1772
1773 virtual bool match(
1774 _In_reads_or_z_(end) const T* text,
1775 _In_ size_t start = 0,
1776 _In_ size_t end = (size_t)-1,
1777 _In_ int flags = match_default)
1778 {
1779 assert(text || start >= end);
1780 this->interval.end = start;
1781
1782 const int space_match_flags = flags & ~match_multiline; // Spaces in score must never be broken in new line.
1783
1784 if (home->match(text, this->interval.end, end, flags))
1785 this->interval.end = home->interval.end;
1786 else
1787 goto end;
1788
1789 for (; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
1790
1791 if (separator->match(text, this->interval.end, end, flags))
1792 this->interval.end = separator->interval.end;
1793 else
1794 goto end;
1795
1796 for (; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
1797
1798 if (guest->match(text, this->interval.end, end, flags))
1799 this->interval.end = guest->interval.end;
1800 else
1801 goto end;
1802
1803 this->interval.start = start;
1804 return true;
1805
1806 end:
1807 home->invalidate();
1808 separator->invalidate();
1809 guest->invalidate();
1810 this->interval.start = (this->interval.end = start) + 1;
1811 return false;
1812 }
1813
1814 virtual void invalidate()
1815 {
1816 home->invalidate();
1817 separator->invalidate();
1818 guest->invalidate();
1820 }
1821
1822 public:
1823 std::shared_ptr<basic_parser<T>> home;
1824 std::shared_ptr<basic_parser<T>> separator;
1825 std::shared_ptr<basic_parser<T>> guest;
1826
1827 protected:
1828 std::shared_ptr<basic_parser<T>> m_space;
1829 };
1830
1831 using score = basic_score<char>;
1833#ifdef _UNICODE
1834 using tscore = wscore;
1835#else
1836 using tscore = score;
1837#endif
1839
1843 template <class T>
1845 {
1846 public:
1848 _In_ const std::shared_ptr<basic_parser<T>>& _positive_sign,
1849 _In_ const std::shared_ptr<basic_parser<T>>& _negative_sign,
1850 _In_ const std::shared_ptr<basic_parser<T>>& _special_sign,
1851 _In_ const std::shared_ptr<basic_parser<T>>& _number,
1852 _In_ const std::locale& locale = std::locale()) :
1853 basic_parser<T>(locale),
1858 {}
1859
1860 virtual bool match(
1861 _In_reads_or_z_(end) const T* text,
1862 _In_ size_t start = 0,
1863 _In_ size_t end = (size_t)-1,
1864 _In_ int flags = match_default)
1865 {
1866 assert(text || start >= end);
1867 this->interval.end = start;
1868 if (positive_sign && positive_sign->match(text, this->interval.end, end, flags)) {
1869 this->interval.end = positive_sign->interval.end;
1870 if (negative_sign) negative_sign->invalidate();
1871 if (special_sign) special_sign->invalidate();
1872 }
1873 else if (negative_sign && negative_sign->match(text, this->interval.end, end, flags)) {
1874 this->interval.end = negative_sign->interval.end;
1875 if (positive_sign) positive_sign->invalidate();
1876 if (special_sign) special_sign->invalidate();
1877 }
1878 else if (special_sign && special_sign->match(text, this->interval.end, end, flags)) {
1879 this->interval.end = special_sign->interval.end;
1880 if (positive_sign) positive_sign->invalidate();
1881 if (negative_sign) negative_sign->invalidate();
1882 }
1883 else {
1884 if (positive_sign) positive_sign->invalidate();
1885 if (negative_sign) negative_sign->invalidate();
1886 if (special_sign) special_sign->invalidate();
1887 }
1888 if (number->match(text, this->interval.end, end, flags)) {
1889 this->interval.start = start;
1890 this->interval.end = number->interval.end;
1891 return true;
1892 }
1893 if (positive_sign) positive_sign->invalidate();
1894 if (negative_sign) negative_sign->invalidate();
1895 if (special_sign) special_sign->invalidate();
1896 number->invalidate();
1897 this->interval.start = (this->interval.end = start) + 1;
1898 return false;
1899 }
1900
1901 virtual void invalidate()
1902 {
1903 if (positive_sign) positive_sign->invalidate();
1904 if (negative_sign) negative_sign->invalidate();
1905 if (special_sign) special_sign->invalidate();
1906 number->invalidate();
1908 }
1909
1910 public:
1911 std::shared_ptr<basic_parser<T>> positive_sign;
1912 std::shared_ptr<basic_parser<T>> negative_sign;
1913 std::shared_ptr<basic_parser<T>> special_sign;
1914 std::shared_ptr<basic_parser<T>> number;
1915 };
1916
1919#ifdef _UNICODE
1921#else
1923#endif
1925
1929 template <class T>
1931 {
1932 public:
1934 _In_ const std::shared_ptr<basic_parser<T>>& _positive_sign,
1935 _In_ const std::shared_ptr<basic_parser<T>>& _negative_sign,
1936 _In_ const std::shared_ptr<basic_parser<T>>& _special_sign,
1937 _In_ const std::shared_ptr<basic_parser<T>>& _integer,
1938 _In_ const std::shared_ptr<basic_parser<T>>& space,
1939 _In_ const std::shared_ptr<basic_parser<T>>& _fraction,
1940 _In_ const std::locale& locale = std::locale()) :
1941 basic_parser<T>(locale),
1947 m_space(space)
1948 {}
1949
1950 virtual bool match(
1951 _In_reads_or_z_(end) const T* text,
1952 _In_ size_t start = 0,
1953 _In_ size_t end = (size_t)-1,
1954 _In_ int flags = match_default)
1955 {
1956 assert(text || start >= end);
1957 this->interval.end = start;
1958
1959 if (positive_sign && positive_sign->match(text, this->interval.end, end, flags)) {
1960 this->interval.end = positive_sign->interval.end;
1961 if (negative_sign) negative_sign->invalidate();
1962 if (special_sign) special_sign->invalidate();
1963 }
1964 else if (negative_sign && negative_sign->match(text, this->interval.end, end, flags)) {
1965 this->interval.end = negative_sign->interval.end;
1966 if (positive_sign) positive_sign->invalidate();
1967 if (special_sign) special_sign->invalidate();
1968 }
1969 else if (special_sign && special_sign->match(text, this->interval.end, end, flags)) {
1970 this->interval.end = special_sign->interval.end;
1971 if (positive_sign) positive_sign->invalidate();
1972 if (negative_sign) negative_sign->invalidate();
1973 }
1974 else {
1975 if (positive_sign) positive_sign->invalidate();
1976 if (negative_sign) negative_sign->invalidate();
1977 if (special_sign) special_sign->invalidate();
1978 }
1979
1980 // Check for <integer> <fraction>
1981 const int space_match_flags = flags & ~match_multiline; // Spaces in fractions must never be broken in new line.
1982 if (integer->match(text, this->interval.end, end, flags) &&
1983 m_space->match(text, integer->interval.end, end, space_match_flags))
1984 {
1985 for (this->interval.end = m_space->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
1986 if (fraction->match(text, this->interval.end, end, flags)) {
1987 this->interval.start = start;
1988 this->interval.end = fraction->interval.end;
1989 return true;
1990 }
1991 fraction->invalidate();
1992 this->interval.start = start;
1993 this->interval.end = integer->interval.end;
1994 return true;
1995 }
1996
1997 // Check for <fraction>
1998 if (fraction->match(text, this->interval.end, end, flags)) {
1999 integer->invalidate();
2000 this->interval.start = start;
2001 this->interval.end = fraction->interval.end;
2002 return true;
2003 }
2004
2005 // Check for <integer>
2006 if (integer->match(text, this->interval.end, end, flags)) {
2007 fraction->invalidate();
2008 this->interval.start = start;
2009 this->interval.end = integer->interval.end;
2010 return true;
2011 }
2012
2013 if (positive_sign) positive_sign->invalidate();
2014 if (negative_sign) negative_sign->invalidate();
2015 if (special_sign) special_sign->invalidate();
2016 integer->invalidate();
2017 fraction->invalidate();
2018 this->interval.start = (this->interval.end = start) + 1;
2019 return false;
2020 }
2021
2022 virtual void invalidate()
2023 {
2024 if (positive_sign) positive_sign->invalidate();
2025 if (negative_sign) negative_sign->invalidate();
2026 if (special_sign) special_sign->invalidate();
2027 integer->invalidate();
2028 fraction->invalidate();
2030 }
2031
2032 public:
2033 std::shared_ptr<basic_parser<T>> positive_sign;
2034 std::shared_ptr<basic_parser<T>> negative_sign;
2035 std::shared_ptr<basic_parser<T>> special_sign;
2036 std::shared_ptr<basic_parser<T>> integer;
2037 std::shared_ptr<basic_parser<T>> fraction;
2038
2039 protected:
2040 std::shared_ptr<basic_parser<T>> m_space;
2041 };
2042
2045#ifdef _UNICODE
2047#else
2049#endif
2051
2055 template <class T>
2057 {
2058 public:
2060 _In_ const std::shared_ptr<basic_parser<T>>& _positive_sign,
2061 _In_ const std::shared_ptr<basic_parser<T>>& _negative_sign,
2062 _In_ const std::shared_ptr<basic_parser<T>>& _special_sign,
2063 _In_ const std::shared_ptr<basic_integer<T>>& _integer,
2064 _In_ const std::shared_ptr<basic_parser<T>>& _decimal_separator,
2065 _In_ const std::shared_ptr<basic_integer<T>>& _decimal,
2066 _In_ const std::shared_ptr<basic_parser<T>>& _exponent_symbol,
2067 _In_ const std::shared_ptr<basic_parser<T>>& _positive_exp_sign,
2068 _In_ const std::shared_ptr<basic_parser<T>>& _negative_exp_sign,
2069 _In_ const std::shared_ptr<basic_integer<T>>& _exponent,
2070 _In_ const std::locale& locale = std::locale()) :
2071 basic_parser<T>(locale),
2082 value(std::numeric_limits<double>::quiet_NaN())
2083 {}
2084
2085 virtual bool match(
2086 _In_reads_or_z_(end) const T* text,
2087 _In_ size_t start = 0,
2088 _In_ size_t end = (size_t)-1,
2089 _In_ int flags = match_default)
2090 {
2091 assert(text || start >= end);
2092 this->interval.end = start;
2093
2094 if (positive_sign && positive_sign->match(text, this->interval.end, end, flags)) {
2095 this->interval.end = positive_sign->interval.end;
2096 if (negative_sign) negative_sign->invalidate();
2097 if (special_sign) special_sign->invalidate();
2098 }
2099 else if (negative_sign && negative_sign->match(text, this->interval.end, end, flags)) {
2100 this->interval.end = negative_sign->interval.end;
2101 if (positive_sign) positive_sign->invalidate();
2102 if (special_sign) special_sign->invalidate();
2103 }
2104 else if (special_sign && special_sign->match(text, this->interval.end, end, flags)) {
2105 this->interval.end = special_sign->interval.end;
2106 if (positive_sign) positive_sign->invalidate();
2107 if (negative_sign) negative_sign->invalidate();
2108 }
2109 else {
2110 if (positive_sign) positive_sign->invalidate();
2111 if (negative_sign) negative_sign->invalidate();
2112 if (special_sign) special_sign->invalidate();
2113 }
2114
2115 if (integer->match(text, this->interval.end, end, flags))
2116 this->interval.end = integer->interval.end;
2117
2118 if (decimal_separator->match(text, this->interval.end, end, flags) &&
2120 this->interval.end = decimal->interval.end;
2121 else {
2122 decimal_separator->invalidate();
2123 decimal->invalidate();
2124 }
2125
2126 if (integer->interval.empty() &&
2127 decimal->interval.empty())
2128 {
2129 // No integer part, no decimal part.
2130 if (positive_sign) positive_sign->invalidate();
2131 if (negative_sign) negative_sign->invalidate();
2132 if (special_sign) special_sign->invalidate();
2133 integer->invalidate();
2134 decimal_separator->invalidate();
2135 decimal->invalidate();
2136 if (exponent_symbol) exponent_symbol->invalidate();
2137 if (positive_exp_sign) positive_exp_sign->invalidate();
2138 if (negative_exp_sign) negative_exp_sign->invalidate();
2139 if (exponent) exponent->invalidate();
2140 this->interval.start = (this->interval.end = start) + 1;
2141 return false;
2142 }
2143
2144 if (exponent_symbol && exponent_symbol->match(text, this->interval.end, end, flags) &&
2147 (exponent && exponent->match(text, exponent_symbol->interval.end, end, flags))))
2148 {
2149 this->interval.end = exponent->interval.end;
2150 if (negative_exp_sign) negative_exp_sign->invalidate();
2151 }
2152 else if (exponent_symbol && exponent_symbol->match(text, this->interval.end, end, flags) &&
2155 {
2156 this->interval.end = exponent->interval.end;
2157 if (positive_exp_sign) positive_exp_sign->invalidate();
2158 }
2159 else {
2160 if (exponent_symbol) exponent_symbol->invalidate();
2161 if (positive_exp_sign) positive_exp_sign->invalidate();
2162 if (negative_exp_sign) negative_exp_sign->invalidate();
2163 if (exponent) exponent->invalidate();
2164 }
2165
2166 value = (double)integer->value;
2167 if (decimal->interval)
2168 value += (double)decimal->value * pow(10.0, -(double)decimal->interval.size());
2169 if (negative_sign && negative_sign->interval)
2170 value = -value;
2171 if (exponent && exponent->interval) {
2172 double e = (double)exponent->value;
2173 if (negative_exp_sign && negative_exp_sign->interval)
2174 e = -e;
2175 value *= pow(10.0, e);
2176 }
2177
2178 this->interval.start = start;
2179 return true;
2180 }
2181
2182 virtual void invalidate()
2183 {
2184 if (positive_sign) positive_sign->invalidate();
2185 if (negative_sign) negative_sign->invalidate();
2186 if (special_sign) special_sign->invalidate();
2187 integer->invalidate();
2188 decimal_separator->invalidate();
2189 decimal->invalidate();
2190 if (exponent_symbol) exponent_symbol->invalidate();
2191 if (positive_exp_sign) positive_exp_sign->invalidate();
2192 if (negative_exp_sign) negative_exp_sign->invalidate();
2193 if (exponent) exponent->invalidate();
2194 value = std::numeric_limits<double>::quiet_NaN();
2196 }
2197
2198 public:
2199 std::shared_ptr<basic_parser<T>> positive_sign;
2200 std::shared_ptr<basic_parser<T>> negative_sign;
2201 std::shared_ptr<basic_parser<T>> special_sign;
2202 std::shared_ptr<basic_integer<T>> integer;
2203 std::shared_ptr<basic_parser<T>> decimal_separator;
2204 std::shared_ptr<basic_integer<T>> decimal;
2205 std::shared_ptr<basic_parser<T>> exponent_symbol;
2206 std::shared_ptr<basic_parser<T>> positive_exp_sign;
2207 std::shared_ptr<basic_parser<T>> negative_exp_sign;
2208 std::shared_ptr<basic_integer<T>> exponent;
2209 double value;
2210 };
2211
2214#ifdef _UNICODE
2216#else
2218#endif
2220
2224 template <class T>
2226 {
2227 public:
2229 _In_ const std::shared_ptr<basic_parser<T>>& _positive_sign,
2230 _In_ const std::shared_ptr<basic_parser<T>>& _negative_sign,
2231 _In_ const std::shared_ptr<basic_parser<T>>& _special_sign,
2232 _In_ const std::shared_ptr<basic_parser<T>>& _currency,
2233 _In_ const std::shared_ptr<basic_parser<T>>& _integer,
2234 _In_ const std::shared_ptr<basic_parser<T>>& _decimal_separator,
2235 _In_ const std::shared_ptr<basic_parser<T>>& _decimal,
2236 _In_ const std::locale& locale = std::locale()) :
2237 basic_parser<T>(locale),
2245 {}
2246
2247 virtual bool match(
2248 _In_reads_or_z_(end) const T* text,
2249 _In_ size_t start = 0,
2250 _In_ size_t end = (size_t)-1,
2251 _In_ int flags = match_default)
2252 {
2253 assert(text || start >= end);
2254 this->interval.end = start;
2255
2256 if (positive_sign->match(text, this->interval.end, end, flags)) {
2257 this->interval.end = positive_sign->interval.end;
2258 if (negative_sign) negative_sign->invalidate();
2259 if (special_sign) special_sign->invalidate();
2260 }
2261 else if (negative_sign->match(text, this->interval.end, end, flags)) {
2262 this->interval.end = negative_sign->interval.end;
2263 if (positive_sign) positive_sign->invalidate();
2264 if (special_sign) special_sign->invalidate();
2265 }
2266 else if (special_sign->match(text, this->interval.end, end, flags)) {
2267 this->interval.end = special_sign->interval.end;
2268 if (positive_sign) positive_sign->invalidate();
2269 if (negative_sign) negative_sign->invalidate();
2270 }
2271 else {
2272 if (positive_sign) positive_sign->invalidate();
2273 if (negative_sign) negative_sign->invalidate();
2274 if (special_sign) special_sign->invalidate();
2275 }
2276
2277 if (currency->match(text, this->interval.end, end, flags))
2278 this->interval.end = currency->interval.end;
2279 else {
2280 if (positive_sign) positive_sign->invalidate();
2281 if (negative_sign) negative_sign->invalidate();
2282 if (special_sign) special_sign->invalidate();
2283 integer->invalidate();
2284 decimal_separator->invalidate();
2285 decimal->invalidate();
2286 this->interval.start = (this->interval.end = start) + 1;
2287 return false;
2288 }
2289
2290 if (integer->match(text, this->interval.end, end, flags))
2291 this->interval.end = integer->interval.end;
2292 if (decimal_separator->match(text, this->interval.end, end, flags) &&
2294 this->interval.end = decimal->interval.end;
2295 else {
2296 decimal_separator->invalidate();
2297 decimal->invalidate();
2298 }
2299
2300 if (integer->interval.empty() &&
2301 decimal->interval.empty())
2302 {
2303 // No integer part, no decimal part.
2304 if (positive_sign) positive_sign->invalidate();
2305 if (negative_sign) negative_sign->invalidate();
2306 if (special_sign) special_sign->invalidate();
2307 currency->invalidate();
2308 integer->invalidate();
2309 decimal_separator->invalidate();
2310 decimal->invalidate();
2311 this->interval.start = (this->interval.end = start) + 1;
2312 return false;
2313 }
2314
2315 this->interval.start = start;
2316 return true;
2317 }
2318
2319 virtual void invalidate()
2320 {
2321 if (positive_sign) positive_sign->invalidate();
2322 if (negative_sign) negative_sign->invalidate();
2323 if (special_sign) special_sign->invalidate();
2324 currency->invalidate();
2325 integer->invalidate();
2326 decimal_separator->invalidate();
2327 decimal->invalidate();
2329 }
2330
2331 public:
2332 std::shared_ptr<basic_parser<T>> positive_sign;
2333 std::shared_ptr<basic_parser<T>> negative_sign;
2334 std::shared_ptr<basic_parser<T>> special_sign;
2335 std::shared_ptr<basic_parser<T>> currency;
2336 std::shared_ptr<basic_parser<T>> integer;
2337 std::shared_ptr<basic_parser<T>> decimal_separator;
2338 std::shared_ptr<basic_parser<T>> decimal;
2339 };
2340
2343#ifdef _UNICODE
2345#else
2347#endif
2349
2353 template <class T>
2355 {
2356 public:
2358 _In_ const std::shared_ptr<basic_parser<T>>& digit_0,
2359 _In_ const std::shared_ptr<basic_parser<T>>& digit_1,
2360 _In_ const std::shared_ptr<basic_parser<T>>& digit_2,
2361 _In_ const std::shared_ptr<basic_parser<T>>& digit_3,
2362 _In_ const std::shared_ptr<basic_parser<T>>& digit_4,
2363 _In_ const std::shared_ptr<basic_parser<T>>& digit_5,
2364 _In_ const std::shared_ptr<basic_parser<T>>& digit_6,
2365 _In_ const std::shared_ptr<basic_parser<T>>& digit_7,
2366 _In_ const std::shared_ptr<basic_parser<T>>& digit_8,
2367 _In_ const std::shared_ptr<basic_parser<T>>& digit_9,
2368 _In_ const std::shared_ptr<basic_parser<T>>& separator,
2369 _In_ const std::locale& locale = std::locale()) :
2370 basic_parser<T>(locale),
2371 m_digit_0(digit_0),
2372 m_digit_1(digit_1),
2373 m_digit_2(digit_2),
2374 m_digit_3(digit_3),
2375 m_digit_4(digit_4),
2376 m_digit_5(digit_5),
2377 m_digit_6(digit_6),
2378 m_digit_7(digit_7),
2379 m_digit_8(digit_8),
2380 m_digit_9(digit_9),
2381 m_separator(separator)
2382 {
2383 value.s_addr = 0;
2384 }
2385
2386 virtual bool match(
2387 _In_reads_or_z_(end) const T* text,
2388 _In_ size_t start = 0,
2389 _In_ size_t end = (size_t)-1,
2390 _In_ int flags = match_default)
2391 {
2392 assert(text || start >= end);
2393 this->interval.end = start;
2394 value.s_addr = 0;
2395
2396 size_t i;
2397 for (i = 0; i < 4; i++) {
2398 if (i) {
2399 if (m_separator->match(text, this->interval.end, end, flags))
2400 this->interval.end = m_separator->interval.end;
2401 else
2402 goto error;
2403 }
2404
2405 components[i].start = this->interval.end;
2406 bool is_empty = true;
2407 size_t x;
2408 for (x = 0; this->interval.end < end && text[this->interval.end];) {
2409 size_t dig, digit_end;
2410 if (m_digit_0->match(text, this->interval.end, end, flags)) { dig = 0; digit_end = m_digit_0->interval.end; }
2411 else if (m_digit_1->match(text, this->interval.end, end, flags)) { dig = 1; digit_end = m_digit_1->interval.end; }
2412 else if (m_digit_2->match(text, this->interval.end, end, flags)) { dig = 2; digit_end = m_digit_2->interval.end; }
2413 else if (m_digit_3->match(text, this->interval.end, end, flags)) { dig = 3; digit_end = m_digit_3->interval.end; }
2414 else if (m_digit_4->match(text, this->interval.end, end, flags)) { dig = 4; digit_end = m_digit_4->interval.end; }
2415 else if (m_digit_5->match(text, this->interval.end, end, flags)) { dig = 5; digit_end = m_digit_5->interval.end; }
2416 else if (m_digit_6->match(text, this->interval.end, end, flags)) { dig = 6; digit_end = m_digit_6->interval.end; }
2417 else if (m_digit_7->match(text, this->interval.end, end, flags)) { dig = 7; digit_end = m_digit_7->interval.end; }
2418 else if (m_digit_8->match(text, this->interval.end, end, flags)) { dig = 8; digit_end = m_digit_8->interval.end; }
2419 else if (m_digit_9->match(text, this->interval.end, end, flags)) { dig = 9; digit_end = m_digit_9->interval.end; }
2420 else break;
2421 size_t x_n = x * 10 + dig;
2422 if (x_n <= 255) {
2423 x = x_n;
2424 this->interval.end = digit_end;
2425 is_empty = false;
2426 }
2427 else
2428 break;
2429 }
2430 if (is_empty)
2431 goto error;
2432 components[i].end = this->interval.end;
2433 value.s_addr = (value.s_addr << 8) | (uint8_t)x;
2434 }
2435 if (i < 4)
2436 goto error;
2437
2438 this->interval.start = start;
2439 return true;
2440
2441 error:
2442 components[0].start = 1;
2443 components[0].end = 0;
2444 components[1].start = 1;
2445 components[1].end = 0;
2446 components[2].start = 1;
2447 components[2].end = 0;
2448 components[3].start = 1;
2449 components[3].end = 0;
2450 value.s_addr = 0;
2451 this->interval.start = (this->interval.end = start) + 1;
2452 return false;
2453 }
2454
2455 virtual void invalidate()
2456 {
2457 components[0].start = 1;
2458 components[0].end = 0;
2459 components[1].start = 1;
2460 components[1].end = 0;
2461 components[2].start = 1;
2462 components[2].end = 0;
2463 components[3].start = 1;
2464 components[3].end = 0;
2465 value.s_addr = 0;
2467 }
2468
2469 public:
2472
2473 protected:
2474 std::shared_ptr<basic_parser<T>>
2475 m_digit_0,
2476 m_digit_1,
2477 m_digit_2,
2478 m_digit_3,
2479 m_digit_4,
2480 m_digit_5,
2481 m_digit_6,
2482 m_digit_7,
2483 m_digit_8,
2484 m_digit_9;
2485 std::shared_ptr<basic_parser<T>> m_separator;
2486 };
2487
2490#ifdef _UNICODE
2492#else
2494#endif
2496
2500 template <class T>
2502 {
2503 public:
2504 basic_ipv6_scope_id_char(_In_ const std::locale& locale = std::locale()) : basic_parser<T>(locale) {}
2505
2506 virtual bool match(
2507 _In_reads_or_z_(end) const T* text,
2508 _In_ size_t start = 0,
2509 _In_ size_t end = (size_t)-1,
2510 _In_ int flags = match_default)
2511 {
2512 assert(text || start >= end);
2513 if (start < end && text[start]) {
2514 if (text[start] == '-' ||
2515 text[start] == '_' ||
2516 text[start] == ':' ||
2517 std::use_facet<std::ctype<T>>(this->m_locale).is(std::ctype_base::alnum, text[start]))
2518 {
2519 this->interval.end = (this->interval.start = start) + 1;
2520 return true;
2521 }
2522 }
2523 this->interval.start = (this->interval.end = start) + 1;
2524 return false;
2525 }
2526 };
2527
2530#ifdef _UNICODE
2532#else
2534#endif
2535
2540 {
2541 public:
2542 sgml_ipv6_scope_id_char(_In_ const std::locale& locale = std::locale()) : sgml_parser(locale) {}
2543
2544 virtual bool match(
2545 _In_reads_or_z_(end) const char* text,
2546 _In_ size_t start = 0,
2547 _In_ size_t end = (size_t)-1,
2548 _In_ int flags = match_default)
2549 {
2550 assert(text || start >= end);
2551 if (start < end && text[start]) {
2552 wchar_t buf[3];
2553 const wchar_t* chr = next_sgml_cp(text, start, end, this->interval.end, buf);
2554 const wchar_t* chr_end = chr + stdex::strlen(chr);
2555 if (((chr[0] == L'-' ||
2556 chr[0] == L'_' ||
2557 chr[0] == L':') && chr[1] == 0) ||
2558 std::use_facet<std::ctype<wchar_t>>(m_locale).scan_not(std::ctype_base::alnum, chr, chr_end) == chr_end)
2559 {
2560 this->interval.start = start;
2561 return true;
2562 }
2563 }
2564 this->interval.start = (this->interval.end = start) + 1;
2565 return false;
2566 }
2567 };
2568
2572 template <class T>
2574 {
2575 public:
2577 _In_ const std::shared_ptr<basic_parser<T>>& digit_0,
2578 _In_ const std::shared_ptr<basic_parser<T>>& digit_1,
2579 _In_ const std::shared_ptr<basic_parser<T>>& digit_2,
2580 _In_ const std::shared_ptr<basic_parser<T>>& digit_3,
2581 _In_ const std::shared_ptr<basic_parser<T>>& digit_4,
2582 _In_ const std::shared_ptr<basic_parser<T>>& digit_5,
2583 _In_ const std::shared_ptr<basic_parser<T>>& digit_6,
2584 _In_ const std::shared_ptr<basic_parser<T>>& digit_7,
2585 _In_ const std::shared_ptr<basic_parser<T>>& digit_8,
2586 _In_ const std::shared_ptr<basic_parser<T>>& digit_9,
2587 _In_ const std::shared_ptr<basic_parser<T>>& digit_10,
2588 _In_ const std::shared_ptr<basic_parser<T>>& digit_11,
2589 _In_ const std::shared_ptr<basic_parser<T>>& digit_12,
2590 _In_ const std::shared_ptr<basic_parser<T>>& digit_13,
2591 _In_ const std::shared_ptr<basic_parser<T>>& digit_14,
2592 _In_ const std::shared_ptr<basic_parser<T>>& digit_15,
2593 _In_ const std::shared_ptr<basic_parser<T>>& separator,
2594 _In_ const std::shared_ptr<basic_parser<T>>& scope_id_separator = nullptr,
2595 _In_ const std::shared_ptr<basic_parser<T>>& _scope_id = nullptr,
2596 _In_ const std::locale& locale = std::locale()) :
2597 basic_parser<T>(locale),
2598 m_digit_0(digit_0),
2599 m_digit_1(digit_1),
2600 m_digit_2(digit_2),
2601 m_digit_3(digit_3),
2602 m_digit_4(digit_4),
2603 m_digit_5(digit_5),
2604 m_digit_6(digit_6),
2605 m_digit_7(digit_7),
2606 m_digit_8(digit_8),
2607 m_digit_9(digit_9),
2608 m_digit_10(digit_10),
2609 m_digit_11(digit_11),
2610 m_digit_12(digit_12),
2611 m_digit_13(digit_13),
2612 m_digit_14(digit_14),
2613 m_digit_15(digit_15),
2614 m_separator(separator),
2615 m_scope_id_separator(scope_id_separator),
2617 {
2618 memset(&value, 0, sizeof(value));
2619 }
2620
2621 virtual bool match(
2622 _In_reads_or_z_(end) const T* text,
2623 _In_ size_t start = 0,
2624 _In_ size_t end = (size_t)-1,
2625 _In_ int flags = match_default)
2626 {
2627 assert(text || start >= end);
2628 this->interval.end = start;
2629 memset(&value, 0, sizeof(value));
2630
2631 size_t i, compaction_i = (size_t)-1, compaction_start = start;
2632 for (i = 0; i < 8; i++) {
2633 bool is_empty = true;
2634
2635 if (m_separator->match(text, this->interval.end, end, flags)) {
2636 if (m_separator->match(text, m_separator->interval.end, end, flags)) {
2637 // :: found
2638 if (compaction_i == (size_t)-1) {
2639 // Zero compaction start
2640 compaction_i = i;
2641 compaction_start = m_separator->interval.start;
2642 this->interval.end = m_separator->interval.end;
2643 }
2644 else {
2645 // More than one zero compaction
2646 break;
2647 }
2648 }
2649 else if (i) {
2650 // Inner : found
2651 this->interval.end = m_separator->interval.end;
2652 }
2653 else {
2654 // Leading : found
2655 goto error;
2656 }
2657 }
2658 else if (i) {
2659 // : missing
2660 break;
2661 }
2662
2663 components[i].start = this->interval.end;
2664 size_t x;
2665 for (x = 0; this->interval.end < end && text[this->interval.end];) {
2666 size_t dig, digit_end;
2667 if (m_digit_0->match(text, this->interval.end, end, flags)) { dig = 0; digit_end = m_digit_0->interval.end; }
2668 else if (m_digit_1->match(text, this->interval.end, end, flags)) { dig = 1; digit_end = m_digit_1->interval.end; }
2669 else if (m_digit_2->match(text, this->interval.end, end, flags)) { dig = 2; digit_end = m_digit_2->interval.end; }
2670 else if (m_digit_3->match(text, this->interval.end, end, flags)) { dig = 3; digit_end = m_digit_3->interval.end; }
2671 else if (m_digit_4->match(text, this->interval.end, end, flags)) { dig = 4; digit_end = m_digit_4->interval.end; }
2672 else if (m_digit_5->match(text, this->interval.end, end, flags)) { dig = 5; digit_end = m_digit_5->interval.end; }
2673 else if (m_digit_6->match(text, this->interval.end, end, flags)) { dig = 6; digit_end = m_digit_6->interval.end; }
2674 else if (m_digit_7->match(text, this->interval.end, end, flags)) { dig = 7; digit_end = m_digit_7->interval.end; }
2675 else if (m_digit_8->match(text, this->interval.end, end, flags)) { dig = 8; digit_end = m_digit_8->interval.end; }
2676 else if (m_digit_9->match(text, this->interval.end, end, flags)) { dig = 9; digit_end = m_digit_9->interval.end; }
2677 else if (m_digit_10->match(text, this->interval.end, end, flags)) { dig = 10; digit_end = m_digit_10->interval.end; }
2678 else if (m_digit_11->match(text, this->interval.end, end, flags)) { dig = 11; digit_end = m_digit_11->interval.end; }
2679 else if (m_digit_12->match(text, this->interval.end, end, flags)) { dig = 12; digit_end = m_digit_12->interval.end; }
2680 else if (m_digit_13->match(text, this->interval.end, end, flags)) { dig = 13; digit_end = m_digit_13->interval.end; }
2681 else if (m_digit_14->match(text, this->interval.end, end, flags)) { dig = 14; digit_end = m_digit_14->interval.end; }
2682 else if (m_digit_15->match(text, this->interval.end, end, flags)) { dig = 15; digit_end = m_digit_15->interval.end; }
2683 else break;
2684 size_t x_n = x * 16 + dig;
2685 if (x_n <= 0xffff) {
2686 x = x_n;
2687 this->interval.end = digit_end;
2688 is_empty = false;
2689 }
2690 else
2691 break;
2692 }
2693 if (is_empty) {
2694 if (compaction_i != (size_t)-1) {
2695 // Zero compaction active: no sweat.
2696 break;
2697 }
2698 goto error;
2699 }
2700 components[i].end = this->interval.end;
2701 this->value.s6_words[i] = (uint16_t)x;
2702 }
2703
2704 if (compaction_i != (size_t)-1) {
2705 // Align components right due to zero compaction.
2706 size_t j, k;
2707 for (j = 8, k = i; k > compaction_i;) {
2708 this->value.s6_words[--j] = this->value.s6_words[--k];
2710 }
2711 for (; j > compaction_i;) {
2712 this->value.s6_words[--j] = 0;
2713 components[j].start =
2715 }
2716 }
2717 else if (i < 8)
2718 goto error;
2719
2720 if (m_scope_id_separator && m_scope_id_separator->match(text, this->interval.end, end, flags) &&
2721 scope_id && scope_id->match(text, m_scope_id_separator->interval.end, end, flags))
2722 this->interval.end = scope_id->interval.end;
2723 else if (scope_id)
2724 scope_id->invalidate();
2725
2726 this->interval.start = start;
2727 return true;
2728
2729 error:
2730 components[0].start = 1;
2731 components[0].end = 0;
2732 components[1].start = 1;
2733 components[1].end = 0;
2734 components[2].start = 1;
2735 components[2].end = 0;
2736 components[3].start = 1;
2737 components[3].end = 0;
2738 components[4].start = 1;
2739 components[4].end = 0;
2740 components[5].start = 1;
2741 components[5].end = 0;
2742 components[6].start = 1;
2743 components[6].end = 0;
2744 components[7].start = 1;
2745 components[7].end = 0;
2746 memset(&value, 0, sizeof(value));
2747 if (scope_id) scope_id->invalidate();
2748 this->interval.start = (this->interval.end = start) + 1;
2749 return false;
2750 }
2751
2752 virtual void invalidate()
2753 {
2754 components[0].start = 1;
2755 components[0].end = 0;
2756 components[1].start = 1;
2757 components[1].end = 0;
2758 components[2].start = 1;
2759 components[2].end = 0;
2760 components[3].start = 1;
2761 components[3].end = 0;
2762 components[4].start = 1;
2763 components[4].end = 0;
2764 components[5].start = 1;
2765 components[5].end = 0;
2766 components[6].start = 1;
2767 components[6].end = 0;
2768 components[7].start = 1;
2769 components[7].end = 0;
2770 memset(&value, 0, sizeof(value));
2771 if (scope_id) scope_id->invalidate();
2773 }
2774
2775 public:
2778 std::shared_ptr<basic_parser<T>> scope_id;
2779
2780 protected:
2781 std::shared_ptr<basic_parser<T>>
2782 m_digit_0,
2783 m_digit_1,
2784 m_digit_2,
2785 m_digit_3,
2786 m_digit_4,
2787 m_digit_5,
2788 m_digit_6,
2789 m_digit_7,
2790 m_digit_8,
2791 m_digit_9,
2792 m_digit_10,
2793 m_digit_11,
2794 m_digit_12,
2795 m_digit_13,
2796 m_digit_14,
2797 m_digit_15;
2798 std::shared_ptr<basic_parser<T>> m_separator, m_scope_id_separator;
2799 };
2800
2803#ifdef _UNICODE
2805#else
2807#endif
2809
2813 template <class T>
2815 {
2816 public:
2818 _In_ bool allow_idn,
2819 _In_ const std::locale& locale = std::locale()) :
2820 basic_parser<T>(locale),
2821 m_allow_idn(allow_idn),
2822 allow_on_edge(true)
2823 {}
2824
2825 virtual bool match(
2826 _In_reads_or_z_(end) const T* text,
2827 _In_ size_t start = 0,
2828 _In_ size_t end = (size_t)-1,
2829 _In_ int flags = match_default)
2830 {
2831 assert(text || start >= end);
2832 if (start < end && text[start]) {
2833 if (('A' <= text[start] && text[start] <= 'Z') ||
2834 ('a' <= text[start] && text[start] <= 'z') ||
2835 ('0' <= text[start] && text[start] <= '9'))
2836 allow_on_edge = true;
2837 else if (text[start] == '-')
2838 allow_on_edge = false;
2839 else if (m_allow_idn && std::use_facet<std::ctype<T>>(this->m_locale).is(std::ctype_base::alnum, text[start]))
2840 allow_on_edge = true;
2841 else {
2842 this->interval.start = (this->interval.end = start) + 1;
2843 return false;
2844 }
2845 this->interval.end = (this->interval.start = start) + 1;
2846 return true;
2847 }
2848 this->interval.start = (this->interval.end = start) + 1;
2849 return false;
2850 }
2851
2852 public:
2854
2855 protected:
2856 bool m_allow_idn;
2857 };
2858
2861#ifdef _UNICODE
2863#else
2865#endif
2866
2871 {
2872 public:
2874 _In_ bool allow_idn,
2875 _In_ const std::locale& locale = std::locale()) :
2877 {}
2878
2879 virtual bool match(
2880 _In_reads_or_z_(end) const char* text,
2881 _In_ size_t start = 0,
2882 _In_ size_t end = (size_t)-1,
2883 _In_ int flags = match_default)
2884 {
2885 assert(text || start >= end);
2886 if (start < end && text[start]) {
2887 wchar_t buf[3];
2888 const wchar_t* chr = next_sgml_cp(text, start, end, this->interval.end, buf);
2889 const wchar_t* chr_end = chr + stdex::strlen(chr);
2890 if ((('A' <= chr[0] && chr[0] <= 'Z') ||
2891 ('a' <= chr[0] && chr[0] <= 'z') ||
2892 ('0' <= chr[0] && chr[0] <= '9')) && chr[1] == 0)
2893 allow_on_edge = true;
2894 else if (chr[0] == '-' && chr[1] == 0)
2895 allow_on_edge = false;
2896 else if (m_allow_idn && std::use_facet<std::ctype<wchar_t>>(m_locale).scan_not(std::ctype_base::alnum, chr, chr_end) == chr_end)
2897 allow_on_edge = true;
2898 else {
2899 this->interval.start = (this->interval.end = start) + 1;
2900 return false;
2901 }
2902 this->interval.start = start;
2903 return true;
2904 }
2905 this->interval.start = (this->interval.end = start) + 1;
2906 return false;
2907 }
2908 };
2909
2913 template <class T>
2915 {
2916 public:
2918 _In_ bool allow_absolute,
2919 _In_ const std::shared_ptr<basic_dns_domain_char<T>>& domain_char,
2920 _In_ const std::shared_ptr<basic_parser<T>>& separator,
2921 _In_ const std::locale& locale = std::locale()) :
2922 basic_parser<T>(locale),
2924 m_domain_char(domain_char),
2925 m_separator(separator)
2926 {}
2927
2928 virtual bool match(
2929 _In_reads_or_z_(end) const T* text,
2930 _In_ size_t start = 0,
2931 _In_ size_t end = (size_t)-1,
2932 _In_ int flags = match_default)
2933 {
2934 assert(text || start >= end);
2935 size_t i = start, count;
2936 for (count = 0; i < end && text[i] && count < 127; count++) {
2937 if (m_domain_char->match(text, i, end, flags) &&
2938 m_domain_char->allow_on_edge)
2939 {
2940 // Domain start
2941 this->interval.end = i = m_domain_char->interval.end;
2942 while (i < end && text[i]) {
2943 if (m_domain_char->allow_on_edge &&
2944 m_separator->match(text, i, end, flags))
2945 {
2946 // Domain end
2947 if (m_allow_absolute)
2948 this->interval.end = i = m_separator->interval.end;
2949 else {
2950 this->interval.end = i;
2951 i = m_separator->interval.end;
2952 }
2953 break;
2954 }
2955 if (m_domain_char->match(text, i, end, flags)) {
2956 if (m_domain_char->allow_on_edge)
2957 this->interval.end = i = m_domain_char->interval.end;
2958 else
2959 i = m_domain_char->interval.end;
2960 }
2961 else {
2962 this->interval.start = start;
2963 return true;
2964 }
2965 }
2966 }
2967 else
2968 break;
2969 }
2970 if (count) {
2971 this->interval.start = start;
2972 return true;
2973 }
2974 this->interval.start = (this->interval.end = start) + 1;
2975 return false;
2976 }
2977
2978 protected:
2980 std::shared_ptr<basic_dns_domain_char<T>> m_domain_char;
2981 std::shared_ptr<basic_parser<T>> m_separator;
2982 };
2983
2986#ifdef _UNICODE
2987 using tdns_name = wdns_name;
2988#else
2989 using tdns_name = dns_name;
2990#endif
2992
2996 template <class T>
2998 {
2999 public:
3000 basic_url_username_char(_In_ const std::locale& locale = std::locale()) : basic_parser<T>(locale) {}
3001
3002 virtual bool match(
3003 _In_reads_or_z_(end) const T* text,
3004 _In_ size_t start = 0,
3005 _In_ size_t end = (size_t)-1,
3006 _In_ int flags = match_default)
3007 {
3008 assert(text || start >= end);
3009 if (start < end && text[start]) {
3010 if (text[start] == '-' ||
3011 text[start] == '.' ||
3012 text[start] == '_' ||
3013 text[start] == '~' ||
3014 text[start] == '%' ||
3015 text[start] == '!' ||
3016 text[start] == '$' ||
3017 text[start] == '&' ||
3018 text[start] == '\'' ||
3019 //text[start] == '(' ||
3020 //text[start] == ')' ||
3021 text[start] == '*' ||
3022 text[start] == '+' ||
3023 text[start] == ',' ||
3024 text[start] == ';' ||
3025 text[start] == '=' ||
3026 std::use_facet<std::ctype<T>>(this->m_locale).is(std::ctype_base::alnum, text[start]))
3027 {
3028 this->interval.end = (this->interval.start = start) + 1;
3029 return true;
3030 }
3031 }
3032 this->interval.start = (this->interval.end = start) + 1;
3033 return false;
3034 }
3035 };
3036
3039#ifdef _UNICODE
3041#else
3043#endif
3044
3049 {
3050 public:
3051 sgml_url_username_char(_In_ const std::locale& locale = std::locale()) : basic_url_username_char<char>(locale) {}
3052
3053 virtual bool match(
3054 _In_reads_or_z_(end) const char* text,
3055 _In_ size_t start = 0,
3056 _In_ size_t end = (size_t)-1,
3057 _In_ int flags = match_default)
3058 {
3059 assert(text || start >= end);
3060 if (start < end && text[start]) {
3061 wchar_t buf[3];
3062 const wchar_t* chr = next_sgml_cp(text, start, end, this->interval.end, buf);
3063 const wchar_t* chr_end = chr + stdex::strlen(chr);
3064 if (((chr[0] == L'-' ||
3065 chr[0] == L'.' ||
3066 chr[0] == L'_' ||
3067 chr[0] == L'~' ||
3068 chr[0] == L'%' ||
3069 chr[0] == L'!' ||
3070 chr[0] == L'$' ||
3071 chr[0] == L'&' ||
3072 chr[0] == L'\'' ||
3073 //chr[0] == L'(' ||
3074 //chr[0] == L')' ||
3075 chr[0] == L'*' ||
3076 chr[0] == L'+' ||
3077 chr[0] == L',' ||
3078 chr[0] == L';' ||
3079 chr[0] == L'=') && chr[1] == 0) ||
3080 std::use_facet<std::ctype<wchar_t>>(m_locale).scan_not(std::ctype_base::alnum, chr, chr_end) == chr_end)
3081 {
3082 this->interval.start = start;
3083 return true;
3084 }
3085 }
3086
3087 this->interval.start = (this->interval.end = start) + 1;
3088 return false;
3089 }
3090 };
3091
3095 template <class T>
3097 {
3098 public:
3099 basic_url_password_char(_In_ const std::locale& locale = std::locale()) : basic_parser<T>(locale) {}
3100
3101 virtual bool match(
3102 _In_reads_or_z_(end) const T* text,
3103 _In_ size_t start = 0,
3104 _In_ size_t end = (size_t)-1,
3105 _In_ int flags = match_default)
3106 {
3107 assert(text || start >= end);
3108 if (start < end && text[start]) {
3109 if (text[start] == '-' ||
3110 text[start] == '.' ||
3111 text[start] == '_' ||
3112 text[start] == '~' ||
3113 text[start] == '%' ||
3114 text[start] == '!' ||
3115 text[start] == '$' ||
3116 text[start] == '&' ||
3117 text[start] == '\'' ||
3118 text[start] == '(' ||
3119 text[start] == ')' ||
3120 text[start] == '*' ||
3121 text[start] == '+' ||
3122 text[start] == ',' ||
3123 text[start] == ';' ||
3124 text[start] == '=' ||
3125 text[start] == ':' ||
3126 std::use_facet<std::ctype<T>>(this->m_locale).is(std::ctype_base::alnum, text[start]))
3127 {
3128 this->interval.end = (this->interval.start = start) + 1;
3129 return true;
3130 }
3131 }
3132 this->interval.start = (this->interval.end = start) + 1;
3133 return false;
3134 }
3135 };
3136
3139#ifdef _UNICODE
3141#else
3143#endif
3144
3149 {
3150 public:
3151 sgml_url_password_char(_In_ const std::locale& locale = std::locale()) : basic_url_password_char<char>(locale) {}
3152
3153 virtual bool match(
3154 _In_reads_or_z_(end) const char* text,
3155 _In_ size_t start = 0,
3156 _In_ size_t end = (size_t)-1,
3157 _In_ int flags = match_default)
3158 {
3159 assert(text || start >= end);
3160 if (start < end && text[start]) {
3161 wchar_t buf[3];
3162 const wchar_t* chr = next_sgml_cp(text, start, end, this->interval.end, buf);
3163 const wchar_t* chr_end = chr + stdex::strlen(chr);
3164 if (((chr[0] == L'-' ||
3165 chr[0] == L'.' ||
3166 chr[0] == L'_' ||
3167 chr[0] == L'~' ||
3168 chr[0] == L'%' ||
3169 chr[0] == L'!' ||
3170 chr[0] == L'$' ||
3171 chr[0] == L'&' ||
3172 chr[0] == L'\'' ||
3173 chr[0] == L'(' ||
3174 chr[0] == L')' ||
3175 chr[0] == L'*' ||
3176 chr[0] == L'+' ||
3177 chr[0] == L',' ||
3178 chr[0] == L';' ||
3179 chr[0] == L'=' ||
3180 chr[0] == L':') && chr[1] == 0) ||
3181 std::use_facet<std::ctype<wchar_t>>(m_locale).scan_not(std::ctype_base::alnum, chr, chr_end) == chr_end)
3182 {
3183 this->interval.start = start;
3184 return true;
3185 }
3186 }
3187 this->interval.start = (this->interval.end = start) + 1;
3188 return false;
3189 }
3190 };
3191
3195 template <class T>
3197 {
3198 public:
3199 basic_url_path_char(_In_ const std::locale& locale = std::locale()) : basic_parser<T>(locale) {}
3200
3201 virtual bool match(
3202 _In_reads_or_z_(end) const T* text,
3203 _In_ size_t start = 0,
3204 _In_ size_t end = (size_t)-1,
3205 _In_ int flags = match_default)
3206 {
3207 assert(text || start >= end);
3208 if (start < end && text[start]) {
3209 if (text[start] == '/' ||
3210 text[start] == '-' ||
3211 text[start] == '.' ||
3212 text[start] == '_' ||
3213 text[start] == '~' ||
3214 text[start] == '%' ||
3215 text[start] == '!' ||
3216 text[start] == '$' ||
3217 text[start] == '&' ||
3218 text[start] == '\'' ||
3219 text[start] == '(' ||
3220 text[start] == ')' ||
3221 text[start] == '*' ||
3222 text[start] == '+' ||
3223 text[start] == ',' ||
3224 text[start] == ';' ||
3225 text[start] == '=' ||
3226 text[start] == ':' ||
3227 text[start] == '@' ||
3228 text[start] == '?' ||
3229 text[start] == '#' ||
3230 std::use_facet<std::ctype<T>>(this->m_locale).is(std::ctype_base::alnum, text[start]))
3231 {
3232 this->interval.end = (this->interval.start = start) + 1;
3233 return true;
3234 }
3235 }
3236 this->interval.start = (this->interval.end = start) + 1;
3237 return false;
3238 }
3239 };
3240
3243#ifdef _UNICODE
3245#else
3247#endif
3248
3253 {
3254 public:
3255 sgml_url_path_char(_In_ const std::locale& locale = std::locale()) : basic_url_path_char<char>(locale) {}
3256
3257 virtual bool match(
3258 _In_reads_or_z_(end) const char* text,
3259 _In_ size_t start = 0,
3260 _In_ size_t end = (size_t)-1,
3261 _In_ int flags = match_default)
3262 {
3263 assert(text || start >= end);
3264 if (start < end && text[start]) {
3265 wchar_t buf[3];
3266 const wchar_t* chr = next_sgml_cp(text, start, end, this->interval.end, buf);
3267 const wchar_t* chr_end = chr + stdex::strlen(chr);
3268 if (((chr[0] == L'/' ||
3269 chr[0] == L'-' ||
3270 chr[0] == L'.' ||
3271 chr[0] == L'_' ||
3272 chr[0] == L'~' ||
3273 chr[0] == L'%' ||
3274 chr[0] == L'!' ||
3275 chr[0] == L'$' ||
3276 chr[0] == L'&' ||
3277 chr[0] == L'\'' ||
3278 chr[0] == L'(' ||
3279 chr[0] == L')' ||
3280 chr[0] == L'*' ||
3281 chr[0] == L'+' ||
3282 chr[0] == L',' ||
3283 chr[0] == L';' ||
3284 chr[0] == L'=' ||
3285 chr[0] == L':' ||
3286 chr[0] == L'@' ||
3287 chr[0] == L'?' ||
3288 chr[0] == L'#') && chr[1] == 0) ||
3289 std::use_facet<std::ctype<wchar_t>>(m_locale).scan_not(std::ctype_base::alnum, chr, chr_end) == chr_end)
3290 {
3291 this->interval.start = start;
3292 return true;
3293 }
3294 }
3295 this->interval.start = (this->interval.end = start) + 1;
3296 return false;
3297 }
3298 };
3299
3303 template <class T>
3305 {
3306 public:
3308 _In_ const std::shared_ptr<basic_parser<T>>& path_char,
3309 _In_ const std::shared_ptr<basic_parser<T>>& query_start,
3310 _In_ const std::shared_ptr<basic_parser<T>>& bookmark_start,
3311 _In_ const std::locale& locale = std::locale()) :
3312 basic_parser<T>(locale),
3313 m_path_char(path_char),
3314 m_query_start(query_start),
3315 m_bookmark_start(bookmark_start)
3316 {}
3317
3318 virtual bool match(
3319 _In_reads_or_z_(end) const T* text,
3320 _In_ size_t start = 0,
3321 _In_ size_t end = (size_t)-1,
3322 _In_ int flags = match_default)
3323 {
3324 assert(text || start >= end);
3325
3326 this->interval.end = start;
3327 path.start = start;
3328 query.start = 1;
3329 query.end = 0;
3330 bookmark.start = 1;
3331 bookmark.end = 0;
3332
3333 for (;;) {
3334 if (this->interval.end >= end || !text[this->interval.end])
3335 break;
3336 if (m_query_start->match(text, this->interval.end, end, flags)) {
3337 path.end = this->interval.end;
3338 query.start = this->interval.end = m_query_start->interval.end;
3339 for (;;) {
3340 if (this->interval.end >= end || !text[this->interval.end]) {
3341 query.end = this->interval.end;
3342 break;
3343 }
3344 if (m_bookmark_start->match(text, this->interval.end, end, flags)) {
3345 query.end = this->interval.end;
3346 bookmark.start = this->interval.end = m_bookmark_start->interval.end;
3347 for (;;) {
3348 if (this->interval.end >= end || !text[this->interval.end]) {
3349 bookmark.end = this->interval.end;
3350 break;
3351 }
3352 if (m_path_char->match(text, this->interval.end, end, flags))
3353 this->interval.end = m_path_char->interval.end;
3354 else {
3355 bookmark.end = this->interval.end;
3356 break;
3357 }
3358 }
3359 this->interval.start = start;
3360 return true;
3361 }
3362 if (m_path_char->match(text, this->interval.end, end, flags))
3363 this->interval.end = m_path_char->interval.end;
3364 else {
3365 query.end = this->interval.end;
3366 break;
3367 }
3368 }
3369 this->interval.start = start;
3370 return true;
3371 }
3372 if (m_bookmark_start->match(text, this->interval.end, end, flags)) {
3373 path.end = this->interval.end;
3374 bookmark.start = this->interval.end = m_bookmark_start->interval.end;
3375 for (;;) {
3376 if (this->interval.end >= end || !text[this->interval.end]) {
3377 bookmark.end = this->interval.end;
3378 break;
3379 }
3380 if (m_path_char->match(text, this->interval.end, end, flags))
3381 this->interval.end = m_path_char->interval.end;
3382 else {
3383 bookmark.end = this->interval.end;
3384 break;
3385 }
3386 }
3387 this->interval.start = start;
3388 return true;
3389 }
3390 if (m_path_char->match(text, this->interval.end, end, flags))
3391 this->interval.end = m_path_char->interval.end;
3392 else
3393 break;
3394 }
3395
3397 path.end = this->interval.end;
3398 this->interval.start = start;
3399 return true;
3400 }
3401
3402 path.start = 1;
3403 path.end = 0;
3404 bookmark.start = 1;
3405 bookmark.end = 0;
3406 this->interval.start = (this->interval.end = start) + 1;
3407 return false;
3408 }
3409
3410 virtual void invalidate()
3411 {
3412 path.start = 1;
3413 path.end = 0;
3414 query.start = 1;
3415 query.end = 0;
3416 bookmark.start = 1;
3417 bookmark.end = 0;
3419 }
3420
3421 public:
3424 stdex::interval<size_t> bookmark;
3425
3426 protected:
3427 std::shared_ptr<basic_parser<T>> m_path_char;
3428 std::shared_ptr<basic_parser<T>> m_query_start;
3429 std::shared_ptr<basic_parser<T>> m_bookmark_start;
3430 };
3431
3434#ifdef _UNICODE
3435 using turl_path = wurl_path;
3436#else
3437 using turl_path = url_path;
3438#endif
3440
3444 template <class T>
3445 class basic_url : public basic_parser<T>
3446 {
3447 public:
3448 basic_url(
3449 _In_ const std::shared_ptr<basic_parser<T>>& _http_scheme,
3450 _In_ const std::shared_ptr<basic_parser<T>>& _ftp_scheme,
3451 _In_ const std::shared_ptr<basic_parser<T>>& _mailto_scheme,
3452 _In_ const std::shared_ptr<basic_parser<T>>& _file_scheme,
3453 _In_ const std::shared_ptr<basic_parser<T>>& colon,
3454 _In_ const std::shared_ptr<basic_parser<T>>& slash,
3455 _In_ const std::shared_ptr<basic_parser<T>>& _username,
3456 _In_ const std::shared_ptr<basic_parser<T>>& _password,
3457 _In_ const std::shared_ptr<basic_parser<T>>& at,
3458 _In_ const std::shared_ptr<basic_parser<T>>& ip_lbracket,
3459 _In_ const std::shared_ptr<basic_parser<T>>& ip_rbracket,
3460 _In_ const std::shared_ptr<basic_parser<T>>& _ipv4_host,
3461 _In_ const std::shared_ptr<basic_parser<T>>& _ipv6_host,
3462 _In_ const std::shared_ptr<basic_parser<T>>& _dns_host,
3463 _In_ const std::shared_ptr<basic_parser<T>>& _port,
3464 _In_ const std::shared_ptr<basic_parser<T>>& _path,
3465 _In_ const std::locale& locale = std::locale()) :
3466 basic_parser<T>(locale),
3467 http_scheme(_http_scheme),
3468 ftp_scheme(_ftp_scheme),
3469 mailto_scheme(_mailto_scheme),
3470 file_scheme(_file_scheme),
3471 m_colon(colon),
3472 m_slash(slash),
3473 username(_username),
3474 password(_password),
3475 m_at(at),
3476 m_ip_lbracket(ip_lbracket),
3477 m_ip_rbracket(ip_rbracket),
3478 ipv4_host(_ipv4_host),
3479 ipv6_host(_ipv6_host),
3480 dns_host(_dns_host),
3481 port(_port),
3482 path(_path)
3483 {}
3484
3485 virtual bool match(
3486 _In_reads_or_z_(end) const T* text,
3487 _In_ size_t start = 0,
3488 _In_ size_t end = (size_t)-1,
3489 _In_ int flags = match_default)
3490 {
3491 assert(text || start >= end);
3492
3493 this->interval.end = start;
3494
3495 if (http_scheme->match(text, this->interval.end, end, flags) &&
3496 m_colon->match(text, http_scheme->interval.end, end, flags) &&
3497 m_slash->match(text, m_colon->interval.end, end, flags) &&
3498 m_slash->match(text, m_slash->interval.end, end, flags))
3499 {
3500 // http://
3501 this->interval.end = m_slash->interval.end;
3502 ftp_scheme->invalidate();
3503 mailto_scheme->invalidate();
3504 file_scheme->invalidate();
3505 }
3506 else if (ftp_scheme->match(text, this->interval.end, end, flags) &&
3507 m_colon->match(text, ftp_scheme->interval.end, end, flags) &&
3508 m_slash->match(text, m_colon->interval.end, end, flags) &&
3509 m_slash->match(text, m_slash->interval.end, end, flags))
3510 {
3511 // ftp://
3512 this->interval.end = m_slash->interval.end;
3513 http_scheme->invalidate();
3514 mailto_scheme->invalidate();
3515 file_scheme->invalidate();
3516 }
3517 else if (mailto_scheme->match(text, this->interval.end, end, flags) &&
3518 m_colon->match(text, mailto_scheme->interval.end, end, flags))
3519 {
3520 // mailto:
3521 this->interval.end = m_colon->interval.end;
3522 http_scheme->invalidate();
3523 ftp_scheme->invalidate();
3524 file_scheme->invalidate();
3525 }
3526 else if (file_scheme->match(text, this->interval.end, end, flags) &&
3527 m_colon->match(text, file_scheme->interval.end, end, flags) &&
3528 m_slash->match(text, m_colon->interval.end, end, flags) &&
3529 m_slash->match(text, m_slash->interval.end, end, flags))
3530 {
3531 // file://
3532 this->interval.end = m_slash->interval.end;
3533 http_scheme->invalidate();
3534 ftp_scheme->invalidate();
3535 mailto_scheme->invalidate();
3536 }
3537 else {
3538 // Default to http:
3539 http_scheme->invalidate();
3540 ftp_scheme->invalidate();
3541 mailto_scheme->invalidate();
3542 file_scheme->invalidate();
3543 }
3544
3545 if (ftp_scheme->interval) {
3546 if (username->match(text, this->interval.end, end, flags)) {
3547 if (m_colon->match(text, username->interval.end, end, flags) &&
3548 password->match(text, m_colon->interval.end, end, flags) &&
3549 m_at->match(text, password->interval.end, end, flags))
3550 {
3551 // Username and password
3552 this->interval.end = m_at->interval.end;
3553 }
3554 else if (m_at->match(text, this->interval.end, end, flags)) {
3555 // Username only
3556 this->interval.end = m_at->interval.end;
3557 password->invalidate();
3558 }
3559 else {
3560 username->invalidate();
3561 password->invalidate();
3562 }
3563 }
3564 else {
3565 username->invalidate();
3566 password->invalidate();
3567 }
3568
3569 if (ipv4_host->match(text, this->interval.end, end, flags)) {
3570 // Host is IPv4
3571 this->interval.end = ipv4_host->interval.end;
3572 ipv6_host->invalidate();
3573 dns_host->invalidate();
3574 }
3575 else if (
3576 m_ip_lbracket->match(text, this->interval.end, end, flags) &&
3577 ipv6_host->match(text, m_ip_lbracket->interval.end, end, flags) &&
3578 m_ip_rbracket->match(text, ipv6_host->interval.end, end, flags))
3579 {
3580 // Host is IPv6
3581 this->interval.end = m_ip_rbracket->interval.end;
3582 ipv4_host->invalidate();
3583 dns_host->invalidate();
3584 }
3585 else if (dns_host->match(text, this->interval.end, end, flags)) {
3586 // Host is hostname
3587 this->interval.end = dns_host->interval.end;
3588 ipv4_host->invalidate();
3589 ipv6_host->invalidate();
3590 }
3591 else {
3592 invalidate();
3593 return false;
3594 }
3595
3596 if (m_colon->match(text, this->interval.end, end, flags) &&
3597 port->match(text, m_colon->interval.end, end, flags))
3598 {
3599 // Port
3600 this->interval.end = port->interval.end;
3601 }
3602 else
3603 port->invalidate();
3604
3605 if (path->match(text, this->interval.end, end, flags)) {
3606 // Path
3607 this->interval.end = path->interval.end;
3608 }
3609
3610 this->interval.start = start;
3611 return true;
3612 }
3613
3614 if (mailto_scheme->interval) {
3615 if (username->match(text, this->interval.end, end, flags) &&
3616 m_at->match(text, username->interval.end, end, flags))
3617 {
3618 // Username
3619 this->interval.end = m_at->interval.end;
3620 }
3621 else {
3622 invalidate();
3623 return false;
3624 }
3625
3626 if (m_ip_lbracket->match(text, this->interval.end, end, flags) &&
3627 ipv4_host->match(text, m_ip_lbracket->interval.end, end, flags) &&
3628 m_ip_rbracket->match(text, ipv4_host->interval.end, end, flags))
3629 {
3630 // Host is IPv4
3631 this->interval.end = m_ip_rbracket->interval.end;
3632 ipv6_host->invalidate();
3633 dns_host->invalidate();
3634 }
3635 else if (
3636 m_ip_lbracket->match(text, this->interval.end, end, flags) &&
3637 ipv6_host->match(text, m_ip_lbracket->interval.end, end, flags) &&
3638 m_ip_rbracket->match(text, ipv6_host->interval.end, end, flags))
3639 {
3640 // Host is IPv6
3641 this->interval.end = m_ip_rbracket->interval.end;
3642 ipv4_host->invalidate();
3643 dns_host->invalidate();
3644 }
3645 else if (dns_host->match(text, this->interval.end, end, flags)) {
3646 // Host is hostname
3647 this->interval.end = dns_host->interval.end;
3648 ipv4_host->invalidate();
3649 ipv6_host->invalidate();
3650 }
3651 else {
3652 invalidate();
3653 return false;
3654 }
3655
3656 password->invalidate();
3657 port->invalidate();
3658 path->invalidate();
3659 this->interval.start = start;
3660 return true;
3661 }
3662
3663 if (file_scheme->interval) {
3664 if (path->match(text, this->interval.end, end, flags)) {
3665 // Path
3666 this->interval.end = path->interval.end;
3667 }
3668
3669 username->invalidate();
3670 password->invalidate();
3671 ipv4_host->invalidate();
3672 ipv6_host->invalidate();
3673 dns_host->invalidate();
3674 port->invalidate();
3675 this->interval.start = start;
3676 return true;
3677 }
3678
3679 // "http://" found or defaulted to
3680
3681 // If "http://" explicit, test for username&password.
3682 if (http_scheme->interval &&
3683 username->match(text, this->interval.end, end, flags))
3684 {
3685 if (m_colon->match(text, username->interval.end, end, flags) &&
3686 password->match(text, m_colon->interval.end, end, flags) &&
3687 m_at->match(text, password->interval.end, end, flags))
3688 {
3689 // Username and password
3690 this->interval.end = m_at->interval.end;
3691 }
3692 else if (m_at->match(text, username->interval.end, end, flags)) {
3693 // Username only
3694 this->interval.end = m_at->interval.end;
3695 password->invalidate();
3696 }
3697 else {
3698 username->invalidate();
3699 password->invalidate();
3700 }
3701 }
3702 else {
3703 username->invalidate();
3704 password->invalidate();
3705 }
3706
3707 if (ipv4_host->match(text, this->interval.end, end, flags)) {
3708 // Host is IPv4
3709 this->interval.end = ipv4_host->interval.end;
3710 ipv6_host->invalidate();
3711 dns_host->invalidate();
3712 }
3713 else if (
3714 m_ip_lbracket->match(text, this->interval.end, end, flags) &&
3715 ipv6_host->match(text, m_ip_lbracket->interval.end, end, flags) &&
3716 m_ip_rbracket->match(text, ipv6_host->interval.end, end, flags))
3717 {
3718 // Host is IPv6
3719 this->interval.end = m_ip_rbracket->interval.end;
3720 ipv4_host->invalidate();
3721 dns_host->invalidate();
3722 }
3723 else if (dns_host->match(text, this->interval.end, end, flags)) {
3724 // Host is hostname
3725 this->interval.end = dns_host->interval.end;
3726 ipv4_host->invalidate();
3727 ipv6_host->invalidate();
3728 }
3729 else {
3730 invalidate();
3731 return false;
3732 }
3733
3734 if (m_colon->match(text, this->interval.end, end, flags) &&
3735 port->match(text, m_colon->interval.end, end, flags))
3736 {
3737 // Port
3738 this->interval.end = port->interval.end;
3739 }
3740 else
3741 port->invalidate();
3742
3743 if (path->match(text, this->interval.end, end, flags)) {
3744 // Path
3745 this->interval.end = path->interval.end;
3746 }
3747
3748 this->interval.start = start;
3749 return true;
3750 }
3751
3752 virtual void invalidate()
3753 {
3754 http_scheme->invalidate();
3755 ftp_scheme->invalidate();
3756 mailto_scheme->invalidate();
3757 file_scheme->invalidate();
3758 username->invalidate();
3759 password->invalidate();
3760 ipv4_host->invalidate();
3761 ipv6_host->invalidate();
3762 dns_host->invalidate();
3763 port->invalidate();
3764 path->invalidate();
3766 }
3767
3768 public:
3769 std::shared_ptr<basic_parser<T>> http_scheme;
3770 std::shared_ptr<basic_parser<T>> ftp_scheme;
3771 std::shared_ptr<basic_parser<T>> mailto_scheme;
3772 std::shared_ptr<basic_parser<T>> file_scheme;
3773 std::shared_ptr<basic_parser<T>> username;
3774 std::shared_ptr<basic_parser<T>> password;
3775 std::shared_ptr<basic_parser<T>> ipv4_host;
3776 std::shared_ptr<basic_parser<T>> ipv6_host;
3777 std::shared_ptr<basic_parser<T>> dns_host;
3778 std::shared_ptr<basic_parser<T>> port;
3779 std::shared_ptr<basic_parser<T>> path;
3780
3781 protected:
3782 std::shared_ptr<basic_parser<T>> m_colon;
3783 std::shared_ptr<basic_parser<T>> m_slash;
3784 std::shared_ptr<basic_parser<T>> m_at;
3785 std::shared_ptr<basic_parser<T>> m_ip_lbracket;
3786 std::shared_ptr<basic_parser<T>> m_ip_rbracket;
3787 };
3788
3789 using url = basic_url<char>;
3790 using wurl = basic_url<wchar_t>;
3791#ifdef _UNICODE
3792 using turl = wurl;
3793#else
3794 using turl = url;
3795#endif
3796 using sgml_url = basic_url<char>;
3797
3801 template <class T>
3803 {
3804 public:
3806 _In_ const std::shared_ptr<basic_parser<T>>& _username,
3807 _In_ const std::shared_ptr<basic_parser<T>>& at,
3808 _In_ const std::shared_ptr<basic_parser<T>>& ip_lbracket,
3809 _In_ const std::shared_ptr<basic_parser<T>>& ip_rbracket,
3810 _In_ const std::shared_ptr<basic_parser<T>>& _ipv4_host,
3811 _In_ const std::shared_ptr<basic_parser<T>>& _ipv6_host,
3812 _In_ const std::shared_ptr<basic_parser<T>>& _dns_host,
3813 _In_ const std::locale& locale = std::locale()) :
3814 basic_parser<T>(locale),
3815 username(_username),
3816 m_at(at),
3817 m_ip_lbracket(ip_lbracket),
3818 m_ip_rbracket(ip_rbracket),
3819 ipv4_host(_ipv4_host),
3820 ipv6_host(_ipv6_host),
3821 dns_host(_dns_host)
3822 {}
3823
3824 virtual bool match(
3825 _In_reads_or_z_(end) const T* text,
3826 _In_ size_t start = 0,
3827 _In_ size_t end = (size_t)-1,
3828 _In_ int flags = match_default)
3829 {
3830 assert(text || start >= end);
3831
3832 if (username->match(text, start, end, flags) &&
3833 m_at->match(text, username->interval.end, end, flags))
3834 {
3835 // Username@
3836 if (m_ip_lbracket->match(text, m_at->interval.end, end, flags) &&
3837 ipv4_host->match(text, m_ip_lbracket->interval.end, end, flags) &&
3838 m_ip_rbracket->match(text, ipv4_host->interval.end, end, flags))
3839 {
3840 // Host is IPv4
3841 this->interval.end = m_ip_rbracket->interval.end;
3842 ipv6_host->invalidate();
3843 dns_host->invalidate();
3844 }
3845 else if (
3846 m_ip_lbracket->match(text, m_at->interval.end, end, flags) &&
3847 ipv6_host->match(text, m_ip_lbracket->interval.end, end, flags) &&
3848 m_ip_rbracket->match(text, ipv6_host->interval.end, end, flags))
3849 {
3850 // Host is IPv6
3851 this->interval.end = m_ip_rbracket->interval.end;
3852 ipv4_host->invalidate();
3853 dns_host->invalidate();
3854 }
3855 else if (dns_host->match(text, m_at->interval.end, end, flags)) {
3856 // Host is hostname
3857 this->interval.end = dns_host->interval.end;
3858 ipv4_host->invalidate();
3859 ipv6_host->invalidate();
3860 }
3861 else
3862 goto error;
3863 this->interval.start = start;
3864 return true;
3865 }
3866
3867 error:
3868 username->invalidate();
3869 ipv4_host->invalidate();
3870 ipv6_host->invalidate();
3871 dns_host->invalidate();
3872 this->interval.start = (this->interval.end = start) + 1;
3873 return false;
3874 }
3875
3876 virtual void invalidate()
3877 {
3878 username->invalidate();
3879 ipv4_host->invalidate();
3880 ipv6_host->invalidate();
3881 dns_host->invalidate();
3883 }
3884
3885 public:
3886 std::shared_ptr<basic_parser<T>> username;
3887 std::shared_ptr<basic_parser<T>> ipv4_host;
3888 std::shared_ptr<basic_parser<T>> ipv6_host;
3889 std::shared_ptr<basic_parser<T>> dns_host;
3890
3891 protected:
3892 std::shared_ptr<basic_parser<T>> m_at;
3893 std::shared_ptr<basic_parser<T>> m_ip_lbracket;
3894 std::shared_ptr<basic_parser<T>> m_ip_rbracket;
3895 };
3896
3899#ifdef _UNICODE
3901#else
3903#endif
3905
3909 template <class T>
3911 {
3912 public:
3914 _In_ const std::shared_ptr<basic_parser<T>>& _emoticon,
3915 _In_ const std::shared_ptr<basic_parser<T>>& _apex,
3916 _In_ const std::shared_ptr<basic_parser<T>>& _eyes,
3917 _In_ const std::shared_ptr<basic_parser<T>>& _nose,
3918 _In_ const std::shared_ptr<basic_set<T>>& _mouth,
3919 _In_ const std::locale& locale = std::locale()) :
3920 basic_parser<T>(locale),
3922 apex(_apex),
3923 eyes(_eyes),
3924 nose(_nose),
3925 mouth(_mouth)
3926 {}
3927
3928 virtual bool match(
3929 _In_reads_or_z_(end) const T* text,
3930 _In_ size_t start = 0,
3931 _In_ size_t end = (size_t)-1,
3932 _In_ int flags = match_default)
3933 {
3934 assert(text || start >= end);
3935
3936 if (emoticon && emoticon->match(text, start, end, flags)) {
3937 if (apex) apex->invalidate();
3938 eyes->invalidate();
3939 if (nose) nose->invalidate();
3940 mouth->invalidate();
3941 this->interval.start = start;
3942 this->interval.end = emoticon->interval.end;
3943 return true;
3944 }
3945
3946 this->interval.end = start;
3947
3948 if (apex && apex->match(text, this->interval.end, end, flags))
3949 this->interval.end = apex->interval.end;
3950
3951 if (eyes->match(text, this->interval.end, end, flags)) {
3952 if (nose && nose->match(text, eyes->interval.end, end, flags) &&
3953 mouth->match(text, nose->interval.end, end, flags))
3954 {
3955 size_t
3957 hit_offset = mouth->hit_offset;
3958 // Mouth may repeat :-)))))))
3959 for (this->interval.end = mouth->interval.end; mouth->match(text, this->interval.end, end, flags) && mouth->hit_offset == hit_offset; this->interval.end = mouth->interval.end);
3960 mouth->interval.start = start_mouth;
3961 mouth->interval.end = this->interval.end;
3962 this->interval.start = start;
3963 return true;
3964 }
3965 if (mouth->match(text, eyes->interval.end, end, flags)) {
3966 size_t
3968 hit_offset = mouth->hit_offset;
3969 // Mouth may repeat :-)))))))
3970 for (this->interval.end = mouth->interval.end; mouth->match(text, this->interval.end, end, flags) && mouth->hit_offset == hit_offset; this->interval.end = mouth->interval.end);
3971 if (nose) nose->invalidate();
3972 mouth->interval.start = start_mouth;
3973 mouth->interval.end = this->interval.end;
3974 this->interval.start = start;
3975 return true;
3976 }
3977 }
3978
3979 if (emoticon) emoticon->invalidate();
3980 if (apex) apex->invalidate();
3981 eyes->invalidate();
3982 if (nose) nose->invalidate();
3983 mouth->invalidate();
3984 this->interval.start = (this->interval.end = start) + 1;
3985 return false;
3986 }
3987
3988 virtual void invalidate()
3989 {
3990 if (emoticon) emoticon->invalidate();
3991 if (apex) apex->invalidate();
3992 eyes->invalidate();
3993 if (nose) nose->invalidate();
3994 mouth->invalidate();
3996 }
3997
3998 public:
3999 std::shared_ptr<basic_parser<T>> emoticon;
4000 std::shared_ptr<basic_parser<T>> apex;
4001 std::shared_ptr<basic_parser<T>> eyes;
4002 std::shared_ptr<basic_parser<T>> nose;
4003 std::shared_ptr<basic_set<T>> mouth;
4004 };
4005
4008#ifdef _UNICODE
4009 using temoticon = wemoticon;
4010#else
4011 using temoticon = emoticon;
4012#endif
4014
4018 enum date_format_t {
4019 date_format_none = 0,
4020 date_format_dmy = 0x1,
4021 date_format_mdy = 0x2,
4022 date_format_ymd = 0x4,
4023 date_format_ym = 0x8,
4024 date_format_my = 0x10,
4025 date_format_dm = 0x20,
4026 date_format_md = 0x40,
4027 };
4028
4032 template <class T>
4033 class basic_date : public basic_parser<T>
4034 {
4035 public:
4036 basic_date(
4037 _In_ int format_mask,
4038 _In_ const std::shared_ptr<basic_integer<T>>& _day,
4039 _In_ const std::shared_ptr<basic_integer<T>>& _month,
4040 _In_ const std::shared_ptr<basic_integer<T>>& _year,
4041 _In_ const std::shared_ptr<basic_set<T>>& separator,
4042 _In_ const std::shared_ptr<basic_parser<T>>& space,
4043 _In_ const std::locale& locale = std::locale()) :
4044 basic_parser<T>(locale),
4045 format(date_format_none),
4046 m_format_mask(format_mask),
4047 day(_day),
4048 month(_month),
4049 year(_year),
4050 m_separator(separator),
4051 m_space(space)
4052 {}
4053
4054 virtual bool match(
4055 _In_reads_or_z_(end) const T* text,
4056 _In_ size_t start = 0,
4057 _In_ size_t end = (size_t)-1,
4058 _In_ int flags = match_default)
4059 {
4060 assert(text || start >= end);
4061
4062 const int space_match_flags = flags & ~match_multiline; // Spaces in dates must never be broken in new line.
4063 if ((m_format_mask & date_format_dmy) == date_format_dmy) {
4064 if (day->match(text, start, end, flags)) {
4065 for (this->interval.end = day->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4066 if (m_separator->match(text, this->interval.end, end, flags)) {
4067 size_t hit_offset = m_separator->hit_offset;
4068 for (this->interval.end = m_separator->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4069 if (month->match(text, this->interval.end, end, flags)) {
4070 for (this->interval.end = month->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4071 if (m_separator->match(text, this->interval.end, end, flags) &&
4072 m_separator->hit_offset == hit_offset) // Both separators must match.
4073 {
4074 for (this->interval.end = m_separator->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4075 if (year->match(text, this->interval.end, end, flags) &&
4076 is_valid(day->value, month->value))
4077 {
4078 this->interval.start = start;
4079 this->interval.end = year->interval.end;
4080 format = date_format_dmy;
4081 return true;
4082 }
4083 }
4084 }
4085 }
4086 }
4087 }
4088
4089 if ((m_format_mask & date_format_mdy) == date_format_mdy) {
4090 if (month->match(text, start, end, flags)) {
4091 for (this->interval.end = month->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4092 if (m_separator->match(text, this->interval.end, end, flags)) {
4093 size_t hit_offset = m_separator->hit_offset;
4094 for (this->interval.end = m_separator->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4095 if (day->match(text, this->interval.end, end, flags)) {
4096 for (this->interval.end = day->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4097 if (m_separator->match(text, this->interval.end, end, flags) &&
4098 m_separator->hit_offset == hit_offset) // Both separators must match.
4099 {
4100 for (this->interval.end = m_separator->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4101 if (year->match(text, this->interval.end, end, flags) &&
4102 is_valid(day->value, month->value))
4103 {
4104 this->interval.start = start;
4105 this->interval.end = year->interval.end;
4106 format = date_format_mdy;
4107 return true;
4108 }
4109 }
4110 }
4111 }
4112 }
4113 }
4114
4115 if ((m_format_mask & date_format_ymd) == date_format_ymd) {
4116 if (year->match(text, start, end, flags)) {
4117 for (this->interval.end = year->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4118 if (m_separator->match(text, this->interval.end, end, flags)) {
4119 size_t hit_offset = m_separator->hit_offset;
4120 for (this->interval.end = m_separator->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4121 if (month->match(text, this->interval.end, end, flags)) {
4122 for (this->interval.end = month->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4123 if (m_separator->match(text, this->interval.end, end, flags) &&
4124 m_separator->hit_offset == hit_offset) // Both separators must match.
4125 {
4126 for (this->interval.end = m_separator->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4127 if (day->match(text, this->interval.end, end, flags) &&
4128 is_valid(day->value, month->value))
4129 {
4130 this->interval.start = start;
4131 this->interval.end = day->interval.end;
4132 format = date_format_ymd;
4133 return true;
4134 }
4135 }
4136 }
4137 }
4138 }
4139 }
4140
4141 if ((m_format_mask & date_format_ym) == date_format_ym) {
4142 if (year->match(text, start, end, flags)) {
4143 for (this->interval.end = year->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4144 if (m_separator->match(text, this->interval.end, end, flags)) {
4145 for (this->interval.end = m_separator->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4146 if (month->match(text, this->interval.end, end, flags) &&
4147 is_valid((size_t)-1, month->value))
4148 {
4149 if (day) day->invalidate();
4150 this->interval.start = start;
4151 this->interval.end = month->interval.end;
4152 format = date_format_ym;
4153 return true;
4154 }
4155 }
4156 }
4157 }
4158
4159 if ((m_format_mask & date_format_my) == date_format_my) {
4160 if (month->match(text, start, end, flags)) {
4161 for (this->interval.end = month->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4162 if (m_separator->match(text, this->interval.end, end, flags)) {
4163 for (this->interval.end = m_separator->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4164 if (year->match(text, this->interval.end, end, flags) &&
4165 is_valid((size_t)-1, month->value))
4166 {
4167 if (day) day->invalidate();
4168 this->interval.start = start;
4169 this->interval.end = year->interval.end;
4170 format = date_format_my;
4171 return true;
4172 }
4173 }
4174 }
4175 }
4176
4177 if ((m_format_mask & date_format_dm) == date_format_dm) {
4178 if (day->match(text, start, end, flags)) {
4179 for (this->interval.end = day->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4180 if (m_separator->match(text, this->interval.end, end, flags)) {
4181 size_t hit_offset = m_separator->hit_offset;
4182 for (this->interval.end = m_separator->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4183 if (month->match(text, this->interval.end, end, flags) &&
4184 is_valid(day->value, month->value))
4185 {
4186 if (year) year->invalidate();
4187 this->interval.start = start;
4188 for (this->interval.end = month->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4189 if (m_separator->match(text, this->interval.end, end, flags) &&
4190 m_separator->hit_offset == hit_offset) // Both separators must match.
4191 this->interval.end = m_separator->interval.end;
4192 else
4193 this->interval.end = month->interval.end;
4194 format = date_format_dm;
4195 return true;
4196 }
4197 }
4198 }
4199 }
4200
4201 if ((m_format_mask & date_format_md) == date_format_md) {
4202 if (month->match(text, start, end, flags)) {
4203 for (this->interval.end = month->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4204 if (m_separator->match(text, this->interval.end, end, flags)) {
4205 size_t hit_offset = m_separator->hit_offset;
4206 for (this->interval.end = m_separator->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4207 if (day->match(text, this->interval.end, end, flags) &&
4208 is_valid(day->value, month->value))
4209 {
4210 if (year) year->invalidate();
4211 this->interval.start = start;
4212 for (this->interval.end = day->interval.end; m_space->match(text, this->interval.end, end, space_match_flags); this->interval.end = m_space->interval.end);
4213 if (m_separator->match(text, this->interval.end, end, flags) &&
4214 m_separator->hit_offset == hit_offset) // Both separators must match.
4215 this->interval.end = m_separator->interval.end;
4216 else
4217 this->interval.end = day->interval.end;
4218 format = date_format_md;
4219 return true;
4220 }
4221 }
4222 }
4223 }
4224
4225 if (day) day->invalidate();
4226 if (month) month->invalidate();
4227 if (year) year->invalidate();
4228 format = date_format_none;
4229 this->interval.start = (this->interval.end = start) + 1;
4230 return false;
4231 }
4232
4233 virtual void invalidate()
4234 {
4235 if (day) day->invalidate();
4236 if (month) month->invalidate();
4237 if (year) year->invalidate();
4238 format = date_format_none;
4240 }
4241
4242 protected:
4243 static inline bool is_valid(size_t day, size_t month)
4244 {
4245 if (month == (size_t)-1) {
4246 // Default to January. This allows validating day only, as January has all 31 days.
4247 month = 1;
4248 }
4249 if (day == (size_t)-1) {
4250 // Default to 1st day in month. This allows validating month only, as each month has 1st day.
4251 day = 1;
4252 }
4253
4254 switch (month) {
4255 case 1:
4256 case 3:
4257 case 5:
4258 case 7:
4259 case 8:
4260 case 10:
4261 case 12:
4262 return 1 <= day && day <= 31;
4263 case 2:
4264 return 1 <= day && day <= 29;
4265 case 4:
4266 case 6:
4267 case 9:
4268 case 11:
4269 return 1 <= day && day <= 30;
4270 default:
4271 return false;
4272 }
4273 }
4274
4275 public:
4276 date_format_t format;
4277 std::shared_ptr<basic_integer<T>> day;
4278 std::shared_ptr<basic_integer<T>> month;
4279 std::shared_ptr<basic_integer<T>> year;
4280
4281 protected:
4282 int m_format_mask;
4283 std::shared_ptr<basic_set<T>> m_separator;
4284 std::shared_ptr<basic_parser<T>> m_space;
4285 };
4286
4287 using date = basic_date<char>;
4288 using wdate = basic_date<wchar_t>;
4289#ifdef _UNICODE
4290 using tdate = wdate;
4291#else
4292 using tdate = date;
4293#endif
4295
4299 template <class T>
4300 class basic_time : public basic_parser<T>
4301 {
4302 public:
4303 basic_time(
4304 _In_ const std::shared_ptr<basic_integer10<T>>& _hour,
4305 _In_ const std::shared_ptr<basic_integer10<T>>& _minute,
4306 _In_ const std::shared_ptr<basic_integer10<T>>& _second,
4307 _In_ const std::shared_ptr<basic_integer10<T>>& _millisecond,
4308 _In_ const std::shared_ptr<basic_set<T>>& separator,
4309 _In_ const std::shared_ptr<basic_parser<T>>& millisecond_separator,
4310 _In_ const std::locale& locale = std::locale()) :
4311 basic_parser<T>(locale),
4312 hour(_hour),
4313 minute(_minute),
4314 second(_second),
4315 millisecond(_millisecond),
4316 m_separator(separator),
4317 m_millisecond_separator(millisecond_separator)
4318 {}
4319
4320 virtual bool match(
4321 _In_reads_or_z_(end) const T* text,
4322 _In_ size_t start = 0,
4323 _In_ size_t end = (size_t)-1,
4324 _In_ int flags = match_default)
4325 {
4326 assert(text || start >= end);
4327
4328 if (hour->match(text, start, end, flags) &&
4329 m_separator->match(text, hour->interval.end, end, flags) &&
4330 minute->match(text, m_separator->interval.end, end, flags) &&
4331 minute->value < 60)
4332 {
4333 // hh::mm
4334 size_t hit_offset = m_separator->hit_offset;
4335 if (m_separator->match(text, minute->interval.end, end, flags) &&
4336 m_separator->hit_offset == hit_offset && // Both separators must match.
4337 second && second->match(text, m_separator->interval.end, end, flags) &&
4338 second->value < 60)
4339 {
4340 // hh::mm:ss
4341 if (m_millisecond_separator && m_millisecond_separator->match(text, second->interval.end, end, flags) &&
4342 millisecond && millisecond->match(text, m_millisecond_separator->interval.end, end, flags) &&
4343 millisecond->value < 1000)
4344 {
4345 // hh::mm:ss.mmmm
4346 this->interval.end = millisecond->interval.end;
4347 }
4348 else {
4349 if (millisecond) millisecond->invalidate();
4350 this->interval.end = second->interval.end;
4351 }
4352 }
4353 else {
4354 if (second) second->invalidate();
4355 if (millisecond) millisecond->invalidate();
4356 this->interval.end = minute->interval.end;
4357 }
4358 this->interval.start = start;
4359 return true;
4360 }
4361
4362 hour->invalidate();
4363 minute->invalidate();
4364 if (second) second->invalidate();
4365 if (millisecond) millisecond->invalidate();
4366 this->interval.start = (this->interval.end = start) + 1;
4367 return false;
4368 }
4369
4370 virtual void invalidate()
4371 {
4372 hour->invalidate();
4373 minute->invalidate();
4374 if (second) second->invalidate();
4375 if (millisecond) millisecond->invalidate();
4377 }
4378
4379 public:
4380 std::shared_ptr<basic_integer10<T>> hour;
4381 std::shared_ptr<basic_integer10<T>> minute;
4382 std::shared_ptr<basic_integer10<T>> second;
4383 std::shared_ptr<basic_integer10<T>> millisecond;
4384
4385 protected:
4386 std::shared_ptr<basic_set<T>> m_separator;
4387 std::shared_ptr<basic_parser<T>> m_millisecond_separator;
4388 };
4389
4390 using time = basic_time<char>;
4391 using wtime = basic_time<wchar_t>;
4392#ifdef _UNICODE
4393 using ttime = wtime;
4394#else
4395 using ttime = time;
4396#endif
4398
4402 template <class T>
4403 class basic_angle : public basic_parser<T>
4404 {
4405 public:
4407 _In_ const std::shared_ptr<basic_integer10<T>>& _degree,
4408 _In_ const std::shared_ptr<basic_parser<T>>& _degree_separator,
4409 _In_ const std::shared_ptr<basic_integer10<T>>& _minute,
4410 _In_ const std::shared_ptr<basic_parser<T>>& _minute_separator,
4411 _In_ const std::shared_ptr<basic_integer10<T>>& _second,
4412 _In_ const std::shared_ptr<basic_parser<T>>& _second_separator,
4413 _In_ const std::shared_ptr<basic_parser<T>>& _decimal,
4414 _In_ const std::locale& locale = std::locale()) :
4415 basic_parser<T>(locale),
4416 degree(_degree),
4417 degree_separator(_degree_separator),
4418 minute(_minute),
4419 minute_separator(_minute_separator),
4420 second(_second),
4421 second_separator(_second_separator),
4422 decimal(_decimal)
4423 {}
4424
4425 virtual bool match(
4426 _In_reads_or_z_(end) const T* text,
4427 _In_ size_t start = 0,
4428 _In_ size_t end = (size_t)-1,
4429 _In_ int flags = match_default)
4430 {
4431 assert(text || start >= end);
4432
4433 this->interval.end = start;
4434
4435 if (degree->match(text, this->interval.end, end, flags) &&
4436 degree_separator->match(text, degree->interval.end, end, flags))
4437 {
4438 // Degrees
4439 this->interval.end = degree_separator->interval.end;
4440 }
4441 else {
4442 degree->invalidate();
4443 degree_separator->invalidate();
4444 }
4445
4446 if (minute->match(text, this->interval.end, end, flags) &&
4447 minute->value < 60 &&
4448 minute_separator->match(text, minute->interval.end, end, flags))
4449 {
4450 // Minutes
4451 this->interval.end = minute_separator->interval.end;
4452 }
4453 else {
4454 minute->invalidate();
4455 minute_separator->invalidate();
4456 }
4457
4458 if (second && second->match(text, this->interval.end, end, flags) &&
4459 second->value < 60)
4460 {
4461 // Seconds
4462 this->interval.end = second->interval.end;
4463 if (second_separator && second_separator->match(text, this->interval.end, end, flags))
4464 this->interval.end = second_separator->interval.end;
4465 else
4466 if (second_separator) second_separator->invalidate();
4467 }
4468 else {
4469 if (second) second->invalidate();
4470 if (second_separator) second_separator->invalidate();
4471 }
4472
4473 if (degree->interval.start < degree->interval.end ||
4474 minute->interval.start < minute->interval.end ||
4475 (second && second->interval.start < second->interval.end))
4476 {
4477 if (decimal && decimal->match(text, this->interval.end, end, flags)) {
4478 // Decimals
4479 this->interval.end = decimal->interval.end;
4480 }
4481 else if (decimal)
4482 decimal->invalidate();
4483 this->interval.start = start;
4484 return true;
4485 }
4486 if (decimal) decimal->invalidate();
4487 this->interval.start = (this->interval.end = start) + 1;
4488 return false;
4489 }
4490
4491 virtual void invalidate()
4492 {
4493 degree->invalidate();
4494 degree_separator->invalidate();
4495 minute->invalidate();
4496 minute_separator->invalidate();
4497 if (second) second->invalidate();
4498 if (second_separator) second_separator->invalidate();
4499 if (decimal) decimal->invalidate();
4501 }
4502
4503 public:
4504 std::shared_ptr<basic_integer10<T>> degree;
4505 std::shared_ptr<basic_parser<T>> degree_separator;
4506 std::shared_ptr<basic_integer10<T>> minute;
4507 std::shared_ptr<basic_parser<T>> minute_separator;
4508 std::shared_ptr<basic_integer10<T>> second;
4509 std::shared_ptr<basic_parser<T>> second_separator;
4510 std::shared_ptr<basic_parser<T>> decimal;
4511 };
4512
4513 using angle = basic_angle<char>;
4515#ifdef _UNICODE
4516 using RRegElKot = wangle;
4517#else
4518 using RRegElKot = angle;
4519#endif
4521
4525 template <class T>
4527 {
4528 public:
4530 _In_ const std::shared_ptr<basic_parser<T>>& digit,
4531 _In_ const std::shared_ptr<basic_parser<T>>& plus_sign,
4532 _In_ const std::shared_ptr<basic_set<T>>& lparenthesis,
4533 _In_ const std::shared_ptr<basic_set<T>>& rparenthesis,
4534 _In_ const std::shared_ptr<basic_parser<T>>& separator,
4535 _In_ const std::shared_ptr<basic_parser<T>>& space,
4536 _In_ const std::locale& locale = std::locale()) :
4537 basic_parser<T>(locale),
4538 m_digit(digit),
4539 m_plus_sign(plus_sign),
4540 m_lparenthesis(lparenthesis),
4541 m_rparenthesis(rparenthesis),
4542 m_separator(separator),
4543 m_space(space)
4544 {}
4545
4546 virtual bool match(
4547 _In_reads_or_z_(end) const T* text,
4548 _In_ size_t start = 0,
4549 _In_ size_t end = (size_t)-1,
4550 _In_ int flags = match_default)
4551 {
4552 assert(text || start >= end);
4553
4554 size_t safe_digit_end = start, safe_value_size = 0;
4555 bool has_digits = false, after_digit = false, in_parentheses = false, after_parentheses = false;
4556 const int space_match_flags = flags & ~match_multiline; // Spaces in phone numbers must never be broken in new line.
4557
4558 this->interval.end = start;
4559 value.clear();
4560 m_lparenthesis->invalidate();
4561 m_rparenthesis->invalidate();
4562
4563 if (m_plus_sign && m_plus_sign->match(text, this->interval.end, end, flags)) {
4564 value.append(text + m_plus_sign->interval.start, text + m_plus_sign->interval.end);
4565 safe_value_size = value.size();
4566 this->interval.end = m_plus_sign->interval.end;
4567 }
4568
4569 for (;;) {
4570 assert(text || this->interval.end >= end);
4571 if (this->interval.end >= end || !text[this->interval.end])
4572 break;
4573 if (m_digit->match(text, this->interval.end, end, flags)) {
4574 // Digit
4575 value.append(text + m_digit->interval.start, text + m_digit->interval.end);
4576 this->interval.end = m_digit->interval.end;
4577 if (!in_parentheses) {
4578 safe_digit_end = this->interval.end;
4579 safe_value_size = value.size();
4580 has_digits = true;
4581 }
4582 after_digit = true;
4583 after_parentheses = false;
4584 }
4585 else if (
4586 m_lparenthesis && !m_lparenthesis->interval && // No left parenthesis yet
4587 m_rparenthesis && !m_rparenthesis->interval && // Right parenthesis after left
4588 m_lparenthesis->match(text, this->interval.end, end, flags))
4589 {
4590 // Left parenthesis
4591 value.append(text + m_lparenthesis->interval.start, m_lparenthesis->interval.size());
4592 this->interval.end = m_lparenthesis->interval.end;
4593 in_parentheses = true;
4594 after_digit = false;
4595 after_parentheses = false;
4596 }
4597 else if (
4598 in_parentheses && // After left parenthesis
4599 m_rparenthesis && !m_rparenthesis->interval && // No right parenthesis yet
4600 m_rparenthesis->match(text, this->interval.end, end, flags) &&
4601 m_lparenthesis->hit_offset == m_rparenthesis->hit_offset) // Left and right parentheses must match
4602 {
4603 // Right parenthesis
4604 value.append(text + m_rparenthesis->interval.start, text + m_rparenthesis->interval.end);
4605 this->interval.end = m_rparenthesis->interval.end;
4606 safe_digit_end = this->interval.end;
4607 safe_value_size = value.size();
4608 in_parentheses = false;
4609 after_digit = false;
4610 after_parentheses = true;
4611 }
4612 else if (
4613 after_digit &&
4614 !in_parentheses && // No separators inside parentheses
4615 !after_parentheses && // No separators following right parenthesis
4616 m_separator && m_separator->match(text, this->interval.end, end, flags))
4617 {
4618 // Separator
4619 this->interval.end = m_separator->interval.end;
4620 after_digit = false;
4621 after_parentheses = false;
4622 }
4623 else if (
4625 m_space && m_space->match(text, this->interval.end, end, space_match_flags))
4626 {
4627 // Space
4628 this->interval.end = m_space->interval.end;
4629 after_digit = false;
4630 after_parentheses = false;
4631 }
4632 else
4633 break;
4634 }
4635 if (has_digits) {
4636 value.erase(safe_value_size);
4637 this->interval.start = start;
4638 this->interval.end = safe_digit_end;
4639 return true;
4640 }
4641 value.clear();
4642 this->interval.start = (this->interval.end = start) + 1;
4643 return false;
4644 }
4645
4646 virtual void invalidate()
4647 {
4648 value.clear();
4650 }
4651
4652 public:
4653 std::basic_string<T> value;
4654
4655 protected:
4656 std::shared_ptr<basic_parser<T>> m_digit;
4657 std::shared_ptr<basic_parser<T>> m_plus_sign;
4658 std::shared_ptr<basic_set<T>> m_lparenthesis;
4659 std::shared_ptr<basic_set<T>> m_rparenthesis;
4660 std::shared_ptr<basic_parser<T>> m_separator;
4661 std::shared_ptr<basic_parser<T>> m_space;
4662 };
4663
4666#ifdef _UNICODE
4668#else
4670#endif
4672
4678 template <class T>
4679 class basic_iban : public basic_parser<T>
4680 {
4681 public:
4682 basic_iban(
4683 _In_ const std::shared_ptr<basic_parser<T>>& space,
4684 _In_ const std::locale& locale = std::locale()) :
4685 basic_parser<T>(locale),
4686 m_space(space)
4687 {
4688 this->country[0] = 0;
4689 this->check_digits[0] = 0;
4690 this->bban[0] = 0;
4691 this->is_valid = false;
4692 }
4693
4694 virtual bool match(
4695 _In_reads_or_z_(end) const T* text,
4696 _In_ size_t start = 0,
4697 _In_ size_t end = (size_t)-1,
4698 _In_ int flags = match_default)
4699 {
4700 assert(text || start >= end);
4701 const auto& ctype = std::use_facet<std::ctype<T>>(this->m_locale);
4702 const bool case_insensitive = flags & match_case_insensitive ? true : false;
4703 struct country_t {
4704 T country[2];
4705 T check_digits[2];
4706 size_t length;
4707 };
4708 static const country_t s_countries[] = {
4709 { { 'A', 'D' }, {}, 24 }, // Andorra
4710 { { 'A', 'E' }, {}, 23 }, // United Arab Emirates
4711 { { 'A', 'L' }, {}, 28 }, // Albania
4712 { { 'A', 'O' }, {}, 25 }, // Angola
4713 { { 'A', 'T' }, {}, 20 }, // Austria
4714 { { 'A', 'Z' }, {}, 28 }, // Azerbaijan
4715 { { 'B', 'A' }, { '3', '9' }, 20}, // Bosnia and Herzegovina
4716 { { 'B', 'E' }, {}, 16 }, // Belgium
4717 { { 'B', 'F' }, {}, 28 }, // Burkina Faso
4718 { { 'B', 'G' }, {}, 22 }, // Bulgaria
4719 { { 'B', 'H' }, {}, 22 }, // Bahrain
4720 { { 'B', 'I' }, {}, 27 }, // Burundi
4721 { { 'B', 'J' }, {}, 28 }, // Benin
4722 { { 'B', 'R' }, {}, 29 }, // Brazil
4723 { { 'B', 'Y' }, {}, 28 }, // Belarus
4724 { { 'C', 'F' }, {}, 27 }, // Central African Republic
4725 { { 'C', 'G' }, {}, 27 }, // Congo, Republic of the
4726 { { 'C', 'H' }, {}, 21 }, // Switzerland
4727 { { 'C', 'I' }, {}, 28 }, // Côte d'Ivoire
4728 { { 'C', 'M' }, {}, 27 }, // Cameroon
4729 { { 'C', 'R' }, {}, 22 }, // Costa Rica
4730 { { 'C', 'V' }, {}, 25 }, // Cabo Verde
4731 { { 'C', 'Y' }, {}, 28 }, // Cyprus
4732 { { 'C', 'Z' }, {}, 24 }, // Czech Republic
4733 { { 'D', 'E' }, {}, 22 }, // Germany
4734 { { 'D', 'J' }, {}, 27 }, // Djibouti
4735 { { 'D', 'K' }, {}, 18 }, // Denmark
4736 { { 'D', 'O' }, {}, 28 }, // Dominican Republic
4737 { { 'D', 'Z' }, {}, 26 }, // Algeria
4738 { { 'E', 'E' }, {}, 20 }, // Estonia
4739 { { 'E', 'G' }, {}, 29 }, // Egypt
4740 { { 'E', 'S' }, {}, 24 }, // Spain
4741 { { 'F', 'I' }, {}, 18 }, // Finland
4742 { { 'F', 'O' }, {}, 18 }, // Faroe Islands
4743 { { 'F', 'R' }, {}, 27 }, // France
4744 { { 'G', 'A' }, {}, 27 }, // Gabon
4745 { { 'G', 'B' }, {}, 22 }, // United Kingdom
4746 { { 'G', 'E' }, {}, 22 }, // Georgia
4747 { { 'G', 'I' }, {}, 23 }, // Gibraltar
4748 { { 'G', 'L' }, {}, 18 }, // Greenland
4749 { { 'G', 'Q' }, {}, 27 }, // Equatorial Guinea
4750 { { 'G', 'R' }, {}, 27 }, // Greece
4751 { { 'G', 'T' }, {}, 28 }, // Guatemala
4752 { { 'G', 'W' }, {}, 25 }, // Guinea-Bissau
4753 { { 'H', 'N' }, {}, 28 }, // Honduras
4754 { { 'H', 'R' }, {}, 21 }, // Croatia
4755 { { 'H', 'U' }, {}, 28 }, // Hungary
4756 { { 'I', 'E' }, {}, 22 }, // Ireland
4757 { { 'I', 'L' }, {}, 23 }, // Israel
4758 { { 'I', 'Q' }, {}, 23 }, // Iraq
4759 { { 'I', 'R' }, {}, 26 }, // Iran
4760 { { 'I', 'S' }, {}, 26 }, // Iceland
4761 { { 'I', 'T' }, {}, 27 }, // Italy
4762 { { 'J', 'O' }, {}, 30 }, // Jordan
4763 { { 'K', 'M' }, {}, 27 }, // Comoros
4764 { { 'K', 'W' }, {}, 30 }, // Kuwait
4765 { { 'K', 'Z' }, {}, 20 }, // Kazakhstan
4766 { { 'L', 'B' }, {}, 28 }, // Lebanon
4767 { { 'L', 'C' }, {}, 32 }, // Saint Lucia
4768 { { 'L', 'I' }, {}, 21 }, // Liechtenstein
4769 { { 'L', 'T' }, {}, 20 }, // Lithuania
4770 { { 'L', 'U' }, {}, 20 }, // Luxembourg
4771 { { 'L', 'V' }, {}, 21 }, // Latvia
4772 { { 'L', 'Y' }, {}, 25 }, // Libya
4773 { { 'M', 'A' }, {}, 28 }, // Morocco
4774 { { 'M', 'C' }, {}, 27 }, // Monaco
4775 { { 'M', 'D' }, {}, 24 }, // Moldova
4776 { { 'M', 'E' }, { '2', '5' }, 22 }, // Montenegro
4777 { { 'M', 'G' }, {}, 27 }, // Madagascar
4778 { { 'M', 'K' }, { '0', '7' }, 19 }, // North Macedonia
4779 { { 'M', 'L' }, {}, 28 }, // Mali
4780 { { 'M', 'R' }, { '1', '3' }, 27}, // Mauritania
4781 { { 'M', 'T' }, {}, 31 }, // Malta
4782 { { 'M', 'U' }, {}, 30 }, // Mauritius
4783 { { 'M', 'Z' }, {}, 25 }, // Mozambique
4784 { { 'N', 'E' }, {}, 28 }, // Niger
4785 { { 'N', 'I' }, {}, 32 }, // Nicaragua
4786 { { 'N', 'L' }, {}, 18 }, // Netherlands
4787 { { 'N', 'O' }, {}, 15 }, // Norway
4788 { { 'P', 'K' }, {}, 24 }, // Pakistan
4789 { { 'P', 'L' }, {}, 28 }, // Poland
4790 { { 'P', 'S' }, {}, 29 }, // Palestinian territories
4791 { { 'P', 'T' }, { '5', '0' }, 25 }, // Portugal
4792 { { 'Q', 'A' }, {}, 29 }, // Qatar
4793 { { 'R', 'O' }, {}, 24 }, // Romania
4794 { { 'R', 'S' }, { '3', '5' }, 22 }, // Serbia
4795 { { 'R', 'U' }, {}, 33 }, // Russia
4796 { { 'S', 'A' }, {}, 24 }, // Saudi Arabia
4797 { { 'S', 'C' }, {}, 31 }, // Seychelles
4798 { { 'S', 'D' }, {}, 18 }, // Sudan
4799 { { 'S', 'E' }, {}, 24 }, // Sweden
4800 { { 'S', 'I' }, { '5', '6' }, 19 }, // Slovenia
4801 { { 'S', 'K' }, {}, 24 }, // Slovakia
4802 { { 'S', 'M' }, {}, 27 }, // San Marino
4803 { { 'S', 'N' }, {}, 28 }, // Senegal
4804 { { 'S', 'T' }, {}, 25 }, // São Tomé and Príncipe
4805 { { 'S', 'V' }, {}, 28 }, // El Salvador
4806 { { 'T', 'D' }, {}, 27 }, // Chad
4807 { { 'T', 'G' }, {}, 28 }, // Togo
4808 { { 'T', 'L' }, { '3', '8' }, 23}, // East Timor
4809 { { 'T', 'N' }, { '5', '9' }, 24 }, // Tunisia
4810 { { 'T', 'R' }, {}, 26 }, // Turkey
4811 { { 'U', 'A' }, {}, 29 }, // Ukraine
4812 { { 'V', 'A' }, {}, 22 }, // Vatican City
4813 { { 'V', 'G' }, {}, 24 }, // Virgin Islands, British
4814 { { 'X', 'K' }, {}, 20 }, // Kosovo
4815 };
4816 const country_t* country_desc = nullptr;
4817 size_t n, available, next, bban_length;
4819
4820 this->interval.end = start;
4821 for (size_t i = 0; i < 2; ++i, ++this->interval.end) {
4822 if (this->interval.end >= end || !text[this->interval.end])
4823 goto error; // incomplete country code
4824 T chr = case_insensitive ? ctype.toupper(text[this->interval.end]) : text[this->interval.end];
4825 if (chr < 'A' || 'Z' < chr)
4826 goto error; // invalid country code
4827 this->country[i] = chr;
4828 }
4829 for (size_t l = 0, r = _countof(s_countries);;) {
4830 if (l >= r)
4831 goto error; // unknown country
4832 size_t m = (l + r) / 2;
4833 const country_t& c = s_countries[m];
4834 if (c.country[0] < this->country[0] || (c.country[0] == this->country[0] && c.country[1] < this->country[1]))
4835 l = m + 1;
4836 else if (this->country[0] < c.country[0] || (this->country[0] == c.country[0] && this->country[1] < c.country[1]))
4837 r = m;
4838 else {
4839 country_desc = &c;
4840 break;
4841 }
4842 }
4843 this->country[2] = 0;
4844
4845 for (size_t i = 0; i < 2; ++i, ++this->interval.end) {
4846 if (this->interval.end >= end || text[this->interval.end] < '0' || '9' < text[this->interval.end])
4847 goto error; // incomplete or invalid check digits
4848 this->check_digits[i] = text[this->interval.end];
4849 }
4850 this->check_digits[2] = 0;
4851
4852 if ((country_desc->check_digits[0] && this->check_digits[0] != country_desc->check_digits[0]) ||
4853 (country_desc->check_digits[1] && this->check_digits[1] != country_desc->check_digits[1]))
4854 goto error; // unexpected check digits
4855
4856 bban_length = country_desc->length - 4;
4857 for (n = 0; n < bban_length;) {
4858 if (this->interval.end >= end || !text[this->interval.end])
4859 goto error; // bban too short
4860 if (m_space && m_space->match(text, this->interval.end, end, flags)) {
4861 this->interval.end = m_space->interval.end;
4862 continue;
4863 }
4864 T chr = case_insensitive ? ctype.toupper(text[this->interval.end]) : text[this->interval.end];
4865 if (('0' <= chr && chr <= '9') || ('A' <= chr && chr <= 'Z')) {
4866 this->bban[n++] = chr;
4867 this->interval.end++;
4868 }
4869 else
4870 goto error; // invalid bban
4871 }
4872 this->bban[n] = 0;
4873
4874 // Normalize IBAN.
4875 T normalized[69];
4876 available = 0;
4877 for (size_t i = 0; ; ++i) {
4878 if (!this->bban[i]) {
4879 for (i = 0; i < 2; ++i) {
4880 if ('A' <= this->country[i] && this->country[i] <= 'J') {
4881 normalized[available++] = '1';
4882 normalized[available++] = '0' + this->country[i] - 'A';
4883 }
4884 else if ('K' <= this->country[i] && this->country[i] <= 'T') {
4885 normalized[available++] = '2';
4886 normalized[available++] = '0' + this->country[i] - 'K';
4887 }
4888 else if ('U' <= this->country[i] && this->country[i] <= 'Z') {
4889 normalized[available++] = '3';
4890 normalized[available++] = '0' + this->country[i] - 'U';
4891 }
4892 }
4893 normalized[available++] = this->check_digits[0];
4894 normalized[available++] = this->check_digits[1];
4895 normalized[available] = 0;
4896 break;
4897 }
4898 if ('0' <= this->bban[i] && this->bban[i] <= '9')
4899 normalized[available++] = this->bban[i];
4900 else if ('A' <= this->bban[i] && this->bban[i] <= 'J') {
4901 normalized[available++] = '1';
4902 normalized[available++] = '0' + this->bban[i] - 'A';
4903 }
4904 else if ('K' <= this->bban[i] && this->bban[i] <= 'T') {
4905 normalized[available++] = '2';
4906 normalized[available++] = '0' + this->bban[i] - 'K';
4907 }
4908 else if ('U' <= this->bban[i] && this->bban[i] <= 'Z') {
4909 normalized[available++] = '3';
4910 normalized[available++] = '0' + this->bban[i] - 'U';
4911 }
4912 }
4913
4914 // Calculate modulo 97.
4915 nominator = stdex::strtou32(normalized, 9, &next, 10);
4916 for (;;) {
4917 nominator %= 97;
4918 if (!normalized[next]) {
4919 this->is_valid = nominator == 1;
4920 break;
4921 }
4922 size_t digit_count = nominator == 0 ? 0 : nominator < 10 ? 1 : 2;
4923 for (; digit_count < 9 && normalized[next]; ++next, ++digit_count)
4924 nominator = nominator * 10 + (normalized[next] - '0');
4925 }
4926
4927 this->interval.start = start;
4928 return true;
4929
4930 error:
4931 this->country[0] = 0;
4932 this->check_digits[0] = 0;
4933 this->bban[0] = 0;
4934 this->is_valid = false;
4935 this->interval.start = (this->interval.end = start) + 1;
4936 return false;
4937 }
4938
4939 virtual void invalidate()
4940 {
4941 this->country[0] = 0;
4942 this->check_digits[0] = 0;
4943 this->bban[0] = 0;
4944 this->is_valid = false;
4946 }
4947
4948 public:
4949 T country[3];
4951 T bban[31];
4953
4954 protected:
4955 std::shared_ptr<basic_parser<T>> m_space;
4956 };
4957
4958 using iban = basic_iban<char>;
4959 using wiban = basic_iban<wchar_t>;
4960#ifdef _UNICODE
4961 using tiban = wiban;
4962#else
4963 using tiban = iban;
4964#endif
4966
4972 template <class T>
4974 {
4975 public:
4977 _In_ const std::shared_ptr<basic_parser<T>>& space,
4978 _In_ const std::locale& locale = std::locale()) :
4979 basic_parser<T>(locale),
4980 m_space(space)
4981 {
4982 this->check_digits[0] = 0;
4983 this->reference[0] = 0;
4984 this->is_valid = false;
4985 }
4986
4987 virtual bool match(
4988 _In_reads_or_z_(end) const T* text,
4989 _In_ size_t start = 0,
4990 _In_ size_t end = (size_t)-1,
4991 _In_ int flags = match_default)
4992 {
4993 assert(text || start >= end);
4994 const auto& ctype = std::use_facet<std::ctype<T>>(this->m_locale);
4995 const bool case_insensitive = flags & match_case_insensitive ? true : false;
4996 size_t n, available, next;
4998
4999 this->interval.end = start;
5000 if (this->interval.end + 1 >= end ||
5001 (case_insensitive ? ctype.toupper(text[this->interval.end]) : text[this->interval.end]) != 'R' ||
5002 (case_insensitive ? ctype.toupper(text[this->interval.end + 1]) : text[this->interval.end + 1]) != 'F')
5003 goto error; // incomplete or wrong reference ID
5004 this->interval.end += 2;
5005
5006 for (size_t i = 0; i < 2; ++i, ++this->interval.end) {
5007 if (this->interval.end >= end || text[this->interval.end] < '0' || '9' < text[this->interval.end])
5008 goto error; // incomplete or invalid check digits
5009 this->check_digits[i] = text[this->interval.end];
5010 }
5011 this->check_digits[2] = 0;
5012
5013 for (n = 0;;) {
5014 if (m_space && m_space->match(text, this->interval.end, end, flags))
5015 this->interval.end = m_space->interval.end;
5016 for (size_t j = 0; j < 4; ++j) {
5017 if (this->interval.end >= end || !text[this->interval.end])
5018 goto out;
5019 T chr = case_insensitive ? ctype.toupper(text[this->interval.end]) : text[this->interval.end];
5020 if (('0' <= chr && chr <= '9') || ('A' <= chr && chr <= 'Z')) {
5021 if (n >= _countof(reference) - 1)
5022 goto error; // reference overflow
5023 this->reference[n++] = chr;
5024 this->interval.end++;
5025 }
5026 else
5027 goto out;
5028 }
5029 }
5030 out:
5031 if (!n)
5032 goto error; // reference too short
5033 this->reference[_countof(this->reference) - 1] = 0;
5034 for (size_t i = n, j = _countof(this->reference) - 1; i;)
5035 this->reference[--j] = this->reference[--i];
5036 for (size_t j = _countof(this->reference) - 1 - n; j;)
5037 this->reference[--j] = '0';
5038
5039 // Normalize creditor reference.
5040 T normalized[47];
5041 available = 0;
5042 for (size_t i = 0; ; ++i) {
5043 if (!this->reference[i]) {
5044 normalized[available++] = '2'; // R
5045 normalized[available++] = '7';
5046 normalized[available++] = '1'; // F
5047 normalized[available++] = '5';
5048 normalized[available++] = this->check_digits[0];
5049 normalized[available++] = this->check_digits[1];
5050 normalized[available] = 0;
5051 break;
5052 }
5053 if ('0' <= this->reference[i] && this->reference[i] <= '9')
5054 normalized[available++] = this->reference[i];
5055 else if ('A' <= this->reference[i] && this->reference[i] <= 'J') {
5056 normalized[available++] = '1';
5057 normalized[available++] = '0' + this->reference[i] - 'A';
5058 }
5059 else if ('K' <= this->reference[i] && this->reference[i] <= 'T') {
5060 normalized[available++] = '2';
5061 normalized[available++] = '0' + this->reference[i] - 'K';
5062 }
5063 else if ('U' <= this->reference[i] && this->reference[i] <= 'Z') {
5064 normalized[available++] = '3';
5065 normalized[available++] = '0' + this->reference[i] - 'U';
5066 }
5067 }
5068
5069 // Calculate modulo 97.
5070 nominator = stdex::strtou32(normalized, 9, &next, 10);
5071 for (;;) {
5072 nominator %= 97;
5073 if (!normalized[next]) {
5074 this->is_valid = nominator == 1;
5075 break;
5076 }
5077 size_t digit_count = nominator == 0 ? 0 : nominator < 10 ? 1 : 2;
5078 for (; digit_count < 9 && normalized[next]; ++next, ++digit_count)
5079 nominator = nominator * 10 + (normalized[next] - '0');
5080 }
5081
5082 this->interval.start = start;
5083 return true;
5084
5085 error:
5086 this->check_digits[0] = 0;
5087 this->reference[0] = 0;
5088 this->is_valid = false;
5089 this->interval.start = (this->interval.end = start) + 1;
5090 return false;
5091 }
5092
5093 virtual void invalidate()
5094 {
5095 this->check_digits[0] = 0;
5096 this->reference[0] = 0;
5097 this->is_valid = false;
5099 }
5100
5101 public:
5105
5106 protected:
5107 std::shared_ptr<basic_parser<T>> m_space;
5108 };
5109
5112#ifdef _UNICODE
5114#else
5116#endif
5118
5124 template <class T>
5126 {
5127 public:
5128 basic_si_reference_part(_In_ const std::locale& locale = std::locale()) : basic_parser<T>(locale) {}
5129
5130 virtual bool match(
5131 _In_reads_or_z_(end) const T* text,
5132 _In_ size_t start = 0,
5133 _In_ size_t end = (size_t)-1,
5134 _In_ int flags = match_default)
5135 {
5136 assert(text || start >= end);
5137 this->interval.end = start;
5138 for (;;) {
5139 if (this->interval.end >= end || !text[this->interval.end])
5140 break;
5141 if ('0' <= text[this->interval.end] && text[this->interval.end] <= '9')
5142 this->interval.end++;
5143 else
5144 break;
5145 }
5147 this->interval.start = start;
5148 return true;
5149 }
5150 this->interval.start = (this->interval.end = start) + 1;
5151 return false;
5152 }
5153 };
5154
5157#ifdef _UNICODE
5159#else
5161#endif
5163
5169 template <class T>
5171 {
5172 public:
5173 basic_si_reference_delimiter(_In_ const std::locale& locale = std::locale()) : basic_parser<T>(locale) {}
5174
5175 virtual bool match(
5176 _In_reads_or_z_(end) const T* text,
5177 _In_ size_t start = 0,
5178 _In_ size_t end = (size_t)-1,
5179 _In_ int flags = match_default)
5180 {
5181 assert(text || start >= end);
5182 if (start < end && text[start] == '-') {
5183 this->interval.end = (this->interval.start = start) + 1;
5184 return true;
5185 }
5186 this->interval.start = (this->interval.end = start) + 1;
5187 return false;
5188 }
5189 };
5190
5193#ifdef _UNICODE
5195#else
5197#endif
5199
5207 template <class T>
5209 {
5210 public:
5212 _In_ const std::shared_ptr<basic_parser<T>>& space,
5213 _In_ const std::locale& locale = std::locale()) :
5214 basic_parser<T>(locale),
5215 part1(locale),
5216 part2(locale),
5217 part3(locale),
5218 is_valid(false),
5219 m_space(space),
5220 m_delimiter(locale)
5221 {
5222 this->model[0] = 0;
5223 }
5224
5225 virtual bool match(
5226 _In_reads_or_z_(end) const T* text,
5227 _In_ size_t start = 0,
5228 _In_ size_t end = (size_t)-1,
5229 _In_ int flags = match_default)
5230 {
5231 assert(text || start >= end);
5232 const auto& ctype = std::use_facet<std::ctype<T>>(this->m_locale);
5233 const bool case_insensitive = flags & match_case_insensitive ? true : false;
5234
5235 this->interval.end = start;
5236 if (this->interval.end + 1 >= end ||
5237 (case_insensitive ? ctype.toupper(text[this->interval.end]) : text[this->interval.end]) != 'S' ||
5238 (case_insensitive ? ctype.toupper(text[this->interval.end + 1]) : text[this->interval.end + 1]) != 'I')
5239 goto error; // incomplete or wrong reference ID
5240 this->interval.end += 2;
5241
5242 for (size_t i = 0; i < 2; ++i, ++this->interval.end) {
5243 if (this->interval.end >= end || text[this->interval.end] < '0' || '9' < text[this->interval.end])
5244 goto error; // incomplete or invalid model
5245 this->model[i] = text[this->interval.end];
5246 }
5247 this->model[2] = 0;
5248
5249 this->part1.invalidate();
5250 this->part2.invalidate();
5251 this->part3.invalidate();
5252 if (this->model[0] == '9' && this->model[1] == '9') {
5253 is_valid = true;
5254 this->interval.start = start;
5255 return true;
5256 }
5257
5258 if (m_space && m_space->match(text, this->interval.end, end, flags))
5259 this->interval.end = m_space->interval.end;
5260
5261 this->part1.match(text, this->interval.end, end, flags) &&
5262 this->m_delimiter.match(text, this->part1.interval.end, end, flags) &&
5263 this->part2.match(text, this->m_delimiter.interval.end, end, flags) &&
5264 this->m_delimiter.match(text, this->part2.interval.end, end, flags) &&
5265 this->part3.match(text, this->m_delimiter.interval.end, end, flags);
5266
5267 this->interval.start = start;
5268 if (this->part3.interval)
5269 this->interval.end = this->part3.interval.end;
5270 else if (this->part2.interval)
5271 this->interval.end = this->part2.interval.end;
5272 else if (this->part1.interval)
5273 this->interval.end = this->part1.interval.end;
5274 else
5275 this->interval.end = start + 4;
5276
5277 if (this->model[0] == '0' && this->model[1] == '0')
5278 is_valid =
5279 this->part3.interval ?
5280 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5281 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 :
5282 this->part2.interval ?
5283 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 &&
5284 this->part1.interval.size() + this->part2.interval.size() <= 20 :
5285 this->part1.interval ?
5286 this->part1.interval.size() <= 12 :
5287 false;
5288 else if (this->model[0] == '0' && this->model[1] == '1')
5289 is_valid =
5290 this->part3.interval ?
5291 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5292 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 &&
5293 check11(
5294 text + this->part1.interval.start, this->part1.interval.size(),
5295 text + this->part2.interval.start, this->part2.interval.size(),
5296 text + this->part3.interval.start, this->part3.interval.size()) :
5297 this->part2.interval ?
5298 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 &&
5299 this->part1.interval.size() + this->part2.interval.size() <= 20 &&
5300 check11(
5301 text + this->part1.interval.start, this->part1.interval.size(),
5302 text + this->part2.interval.start, this->part2.interval.size()) :
5303 this->part1.interval ?
5304 this->part1.interval.size() <= 12 &&
5305 check11(text + this->part1.interval.start, this->part1.interval.size()) :
5306 false;
5307 else if (this->model[0] == '0' && this->model[1] == '2')
5308 is_valid =
5309 this->part3.interval ?
5310 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5311 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 &&
5312 check11(text + this->part2.interval.start, this->part2.interval.size()) &&
5313 check11(text + this->part3.interval.start, this->part3.interval.size()) :
5314 false;
5315 else if (this->model[0] == '0' && this->model[1] == '3')
5316 is_valid =
5317 this->part3.interval ?
5318 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5319 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 &&
5320 check11(text + this->part1.interval.start, this->part1.interval.size()) &&
5321 check11(text + this->part2.interval.start, this->part2.interval.size()) &&
5322 check11(text + this->part3.interval.start, this->part3.interval.size()) :
5323 false;
5324 else if (this->model[0] == '0' && this->model[1] == '4')
5325 is_valid =
5326 this->part3.interval ?
5327 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5328 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 &&
5329 check11(text + this->part1.interval.start, this->part1.interval.size()) &&
5330 check11(text + this->part3.interval.start, this->part3.interval.size()) :
5331 false;
5332 else if ((this->model[0] == '0' || this->model[0] == '5') && this->model[1] == '5')
5333 is_valid =
5334 this->part3.interval ?
5335 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5336 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 &&
5337 check11(text + this->part1.interval.start, this->part1.interval.size()) :
5338 this->part2.interval ?
5339 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 &&
5340 this->part1.interval.size() + this->part2.interval.size() <= 20 &&
5341 check11(text + this->part1.interval.start, this->part1.interval.size()) :
5342 this->part1.interval ?
5343 this->part1.interval.size() <= 12 &&
5344 check11(text + this->part1.interval.start, this->part1.interval.size()) :
5345 false;
5346 else if (this->model[0] == '0' && this->model[1] == '6')
5347 is_valid =
5348 this->part3.interval ?
5349 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5350 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 &&
5351 check11(
5352 text + this->part2.interval.start, this->part2.interval.size(),
5353 text + this->part3.interval.start, this->part3.interval.size()) :
5354 this->part2.interval ?
5355 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 &&
5356 this->part1.interval.size() + this->part2.interval.size() <= 20 &&
5357 check11(text + this->part2.interval.start, this->part2.interval.size()) :
5358 false;
5359 else if (this->model[0] == '0' && this->model[1] == '7')
5360 is_valid =
5361 this->part3.interval ?
5362 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5363 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 &&
5364 check11(text + this->part2.interval.start, this->part2.interval.size()) :
5365 this->part2.interval ?
5366 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 &&
5367 this->part1.interval.size() + this->part2.interval.size() <= 20 &&
5368 check11(text + this->part2.interval.start, this->part2.interval.size()) :
5369 false;
5370 else if (this->model[0] == '0' && this->model[1] == '8')
5371 is_valid =
5372 this->part3.interval ?
5373 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5374 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 &&
5375 check11(
5376 text + this->part1.interval.start, this->part1.interval.size(),
5377 text + this->part2.interval.start, this->part2.interval.size()) &&
5378 check11(text + this->part3.interval.start, this->part3.interval.size()) :
5379 false;
5380 else if (this->model[0] == '0' && this->model[1] == '9')
5381 is_valid =
5382 this->part3.interval ?
5383 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5384 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 &&
5385 check11(
5386 text + this->part1.interval.start, this->part1.interval.size(),
5387 text + this->part2.interval.start, this->part2.interval.size()) :
5388 this->part2.interval ?
5389 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 &&
5390 this->part1.interval.size() + this->part2.interval.size() <= 20 &&
5391 check11(
5392 text + this->part1.interval.start, this->part1.interval.size(),
5393 text + this->part2.interval.start, this->part2.interval.size()) :
5394 this->part1.interval ?
5395 this->part1.interval.size() <= 12 &&
5396 check11(text + this->part1.interval.start, this->part1.interval.size()) :
5397 false;
5398 else if (this->model[0] == '1' && this->model[1] == '0')
5399 is_valid =
5400 this->part3.interval ?
5401 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5402 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 &&
5403 check11(text + this->part1.interval.start, this->part1.interval.size()) &&
5404 check11(
5405 text + this->part2.interval.start, this->part2.interval.size(),
5406 text + this->part3.interval.start, this->part3.interval.size()) :
5407 this->part2.interval ?
5408 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 &&
5409 this->part1.interval.size() + this->part2.interval.size() <= 20 &&
5410 check11(text + this->part1.interval.start, this->part1.interval.size()) &&
5411 check11(text + this->part2.interval.start, this->part2.interval.size()) :
5412 false;
5413 else if (
5414 (this->model[0] == '1' && (this->model[1] == '1' || this->model[1] == '8' || this->model[1] == '9')) ||
5415 ((this->model[0] == '2' || this->model[0] == '3') && this->model[1] == '8') ||
5416 (this->model[0] == '4' && (this->model[1] == '0' || this->model[1] == '1' || this->model[1] == '8' || this->model[1] == '9')) ||
5417 (this->model[0] == '5' && (this->model[1] == '1' || this->model[1] == '8')))
5418 is_valid =
5419 this->part3.interval ?
5420 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 && this->part3.interval.size() <= 12 &&
5421 this->part1.interval.size() + this->part2.interval.size() + this->part3.interval.size() <= 20 &&
5422 check11(text + this->part1.interval.start, this->part1.interval.size()) &&
5423 check11(text + this->part2.interval.start, this->part2.interval.size()) :
5424 this->part2.interval ?
5425 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 &&
5426 this->part1.interval.size() + this->part2.interval.size() <= 20 &&
5427 check11(text + this->part1.interval.start, this->part1.interval.size()) &&
5428 check11(text + this->part2.interval.start, this->part2.interval.size()) :
5429 false;
5430 else if (this->model[0] == '1' && this->model[1] == '2')
5431 is_valid =
5432 this->part3.interval ? false :
5433 this->part2.interval ? false :
5434 this->part1.interval ?
5435 this->part1.interval.size() <= 13 &&
5436 check11(text + this->part1.interval.start, this->part1.interval.size()) :
5437 false;
5438 else if ((this->model[0] == '2' || this->model[0] == '3') && this->model[1] == '1')
5439 is_valid =
5440 this->part3.interval ? false :
5441 this->part2.interval ?
5442 this->part1.interval.size() <= 12 && this->part2.interval.size() <= 12 &&
5443 this->part1.interval.size() + this->part2.interval.size() <= 20 &&
5444 check11(text + this->part1.interval.start, this->part1.interval.size()) :
5445 false;
5446 else
5447 is_valid = true; // Assume models we don't handle as valid
5448 return true;
5449
5450 error:
5451 this->model[0] = 0;
5452 this->part1.interval.start = (this->part1.interval.end = start) + 1;
5453 this->part2.interval.start = (this->part2.interval.end = start) + 1;
5454 this->part3.interval.start = (this->part3.interval.end = start) + 1;
5455 this->is_valid = false;
5456 this->interval.start = (this->interval.end = start) + 1;
5457 return false;
5458 }
5459
5460 virtual void invalidate()
5461 {
5462 this->model[0] = 0;
5463 this->part1.invalidate();
5464 this->part2.invalidate();
5465 this->part3.invalidate();
5466 this->is_valid = false;
5468 }
5469
5470 protected:
5471 static bool check11(
5472 _In_count_(num_part1) const T* part1, _In_ size_t num_part1)
5473 {
5474 assert(part1 && num_part1 >= 1);
5475 uint32_t nominator = 0, ponder = 2;
5476 for (size_t i = num_part1 - 1; i--; ++ponder)
5477 nominator += (part1[i] - '0') * ponder;
5478 uint8_t control = 11 - static_cast<uint8_t>(nominator % 11);
5479 if (control >= 10)
5480 control = 0;
5481 return control == part1[num_part1 - 1] - '0';
5482 }
5483
5484 static bool check11(
5485 _In_count_(num_part1) const T* part1, _In_ size_t num_part1,
5486 _In_count_(num_part2) const T* part2, _In_ size_t num_part2)
5487 {
5488 assert(part1 || !num_part1);
5489 assert(part2 && num_part2 >= 1);
5490 uint32_t nominator = 0, ponder = 2;
5491 for (size_t i = num_part2 - 1; i--; ++ponder)
5492 nominator += (part2[i] - '0') * ponder;
5493 for (size_t i = num_part1; i--; ++ponder)
5494 nominator += (part1[i] - '0') * ponder;
5495 uint8_t control = 11 - static_cast<uint8_t>(nominator % 11);
5496 if (control == 10)
5497 control = 0;
5498 return control == part2[num_part2 - 1] - '0';
5499 }
5500
5501 static bool check11(
5502 _In_count_(num_part1) const T* part1, _In_ size_t num_part1,
5503 _In_count_(num_part2) const T* part2, _In_ size_t num_part2,
5504 _In_count_(num_part3) const T* part3, _In_ size_t num_part3)
5505 {
5506 assert(part1 || !num_part1);
5507 assert(part2 || !num_part2);
5508 assert(part3 && num_part3 >= 1);
5509 uint32_t nominator = 0, ponder = 2;
5510 for (size_t i = num_part3 - 1; i--; ++ponder)
5511 nominator += (part3[i] - '0') * ponder;
5512 for (size_t i = num_part2; i--; ++ponder)
5513 nominator += (part2[i] - '0') * ponder;
5514 for (size_t i = num_part1; i--; ++ponder)
5515 nominator += (part1[i] - '0') * ponder;
5516 uint8_t control = 11 - static_cast<uint8_t>(nominator % 11);
5517 if (control == 10)
5518 control = 0;
5519 return control == part2[num_part3 - 1] - '0';
5520 }
5521
5522 public:
5523 T model[3];
5528
5529 protected:
5530 std::shared_ptr<basic_parser<T>> m_space;
5532 };
5533
5536#ifdef _UNICODE
5538#else
5540#endif
5542
5546 template <class T>
5548 {
5549 public:
5551 _In_ const std::shared_ptr<basic_parser<T>>& element,
5552 _In_ const std::shared_ptr<basic_parser<T>>& digit,
5553 _In_ const std::shared_ptr<basic_parser<T>>& sign,
5554 _In_ const std::locale& locale = std::locale()) :
5555 basic_parser<T>(locale),
5556 m_element(element),
5557 m_digit(digit),
5558 m_sign(sign),
5559 has_digits(false),
5560 has_charge(false)
5561 {}
5562
5563 virtual bool match(
5564 _In_reads_or_z_(end) const T* text,
5565 _In_ size_t start = 0,
5566 _In_ size_t end = (size_t)-1,
5567 _In_ int flags = match_default)
5568 {
5569 assert(text || start >= end);
5570
5571 has_digits = false;
5572 has_charge = false;
5573 this->interval.end = start;
5574
5575 const int element_match_flags = flags & ~match_case_insensitive; // Chemical elements are always case-sensitive.
5576 for (;;) {
5577 if (m_element->match(text, this->interval.end, end, element_match_flags)) {
5578 this->interval.end = m_element->interval.end;
5579 while (m_digit->match(text, this->interval.end, end, flags)) {
5580 this->interval.end = m_digit->interval.end;
5581 has_digits = true;
5582 }
5583 }
5584 else if (start < this->interval.end) {
5585 if (m_sign->match(text, this->interval.end, end, flags)) {
5586 this->interval.end = m_sign->interval.end;
5587 has_charge = true;
5588 }
5589 this->interval.start = start;
5590 return true;
5591 }
5592 else {
5593 this->interval.start = (this->interval.end = start) + 1;
5594 return false;
5595 }
5596 }
5597 }
5598
5599 virtual void invalidate()
5600 {
5601 has_digits = false;
5602 has_charge = false;
5604 }
5605
5606 public:
5607 bool has_digits;
5608 bool has_charge;
5609
5610 protected:
5611 std::shared_ptr<basic_parser<T>> m_element;
5612 std::shared_ptr<basic_parser<T>> m_digit;
5613 std::shared_ptr<basic_parser<T>> m_sign;
5614 };
5615
5618#ifdef _UNICODE
5620#else
5622#endif
5624
5629 {
5630 public:
5631 virtual bool match(
5632 _In_reads_or_z_(end) const char* text,
5633 _In_ size_t start = 0,
5634 _In_ size_t end = (size_t)-1,
5635 _In_ int flags = match_default)
5636 {
5637 assert(text || start >= end);
5638 this->interval.end = start;
5639
5640 assert(text || this->interval.end >= end);
5641 if (this->interval.end < end && text[this->interval.end]) {
5642 if (text[this->interval.end] == '\r') {
5643 this->interval.end++;
5644 if (this->interval.end < end && text[this->interval.end] == '\n') {
5645 this->interval.start = start;
5646 this->interval.end++;
5647 return true;
5648 }
5649 }
5650 else if (text[this->interval.end] == '\n') {
5651 this->interval.start = start;
5652 this->interval.end++;
5653 return true;
5654 }
5655 }
5656 this->interval.start = (this->interval.end = start) + 1;
5657 return false;
5658 }
5659 };
5660
5664 class http_space : public parser
5665 {
5666 public:
5667 virtual bool match(
5668 _In_reads_or_z_(end) const char* text,
5669 _In_ size_t start = 0,
5670 _In_ size_t end = (size_t)-1,
5671 _In_ int flags = match_default)
5672 {
5673 assert(text || start >= end);
5674 this->interval.end = start;
5675 if (m_line_break.match(text, this->interval.end, end, flags)) {
5676 this->interval.end = m_line_break.interval.end;
5677 if (this->interval.end < end && text[this->interval.end] && isspace(text[this->interval.end])) {
5678 this->interval.start = start;
5679 this->interval.end++;
5680 while (this->interval.end < end && text[this->interval.end] && isspace(text[this->interval.end])) this->interval.end++;
5681 return true;
5682 }
5683 }
5684 else if (this->interval.end < end && text[this->interval.end] && isspace(text[this->interval.end])) {
5685 this->interval.start = start;
5686 this->interval.end++;
5687 while (this->interval.end < end && text[this->interval.end] && isspace(text[this->interval.end])) this->interval.end++;
5688 return true;
5689 }
5690 this->interval.start = (this->interval.end = start) + 1;
5691 return false;
5692 }
5693
5694 protected:
5695 http_line_break m_line_break;
5696 };
5697
5701 class http_text_char : public parser
5702 {
5703 public:
5704 virtual bool match(
5705 _In_reads_or_z_(end) const char* text,
5706 _In_ size_t start = 0,
5707 _In_ size_t end = (size_t)-1,
5708 _In_ int flags = match_default)
5709 {
5710 assert(text || start >= end);
5711 this->interval.end = start;
5712
5713 assert(text || this->interval.end >= end);
5714 if (m_space.match(text, this->interval.end, end, flags)) {
5715 this->interval.start = start;
5716 this->interval.end = m_space.interval.end;
5717 return true;
5718 }
5719 else if (this->interval.end < end && text[this->interval.end] && text[this->interval.end] >= 0x20) {
5720 this->interval.start = start;
5721 this->interval.end++;
5722 return true;
5723 }
5724 this->interval.start = (this->interval.end = start) + 1;
5725 return false;
5726 }
5727
5728 protected:
5729 http_space m_space;
5730 };
5731
5735 class http_token : public parser
5736 {
5737 public:
5738 virtual bool match(
5739 _In_reads_or_z_(end) const char* text,
5740 _In_ size_t start = 0,
5741 _In_ size_t end = (size_t)-1,
5742 _In_ int flags = match_default)
5743 {
5744 assert(text || start >= end);
5745 this->interval.end = start;
5746 for (;;) {
5747 if (this->interval.end < end && text[this->interval.end]) {
5748 if ((unsigned int)text[this->interval.end] < 0x20 ||
5749 (unsigned int)text[this->interval.end] == 0x7f ||
5750 text[this->interval.end] == '(' ||
5751 text[this->interval.end] == ')' ||
5752 text[this->interval.end] == '<' ||
5753 text[this->interval.end] == '>' ||
5754 text[this->interval.end] == '@' ||
5755 text[this->interval.end] == ',' ||
5756 text[this->interval.end] == ';' ||
5757 text[this->interval.end] == ':' ||
5758 text[this->interval.end] == '\\' ||
5759 text[this->interval.end] == '\"' ||
5760 text[this->interval.end] == '/' ||
5761 text[this->interval.end] == '[' ||
5762 text[this->interval.end] == ']' ||
5763 text[this->interval.end] == '?' ||
5764 text[this->interval.end] == '=' ||
5765 text[this->interval.end] == '{' ||
5766 text[this->interval.end] == '}' ||
5767 isspace(text[this->interval.end]))
5768 break;
5769 else
5770 this->interval.end++;
5771 }
5772 else
5773 break;
5774 }
5776 this->interval.start = start;
5777 return true;
5778 }
5779 else {
5780 this->interval.start = (this->interval.end = start) + 1;
5781 return false;
5782 }
5783 }
5784 };
5785
5790 {
5791 public:
5792 virtual bool match(
5793 _In_reads_or_z_(end) const char* text,
5794 _In_ size_t start = 0,
5795 _In_ size_t end = (size_t)-1,
5796 _In_ int flags = match_default)
5797 {
5798 assert(text || start >= end);
5799 this->interval.end = start;
5800 if (this->interval.end < end && text[this->interval.end] != '"')
5801 goto error;
5802 this->interval.end++;
5803 content.start = this->interval.end;
5804 for (;;) {
5805 assert(text || this->interval.end >= end);
5806 if (this->interval.end < end && text[this->interval.end]) {
5807 if (text[this->interval.end] == '"') {
5808 content.end = this->interval.end;
5809 this->interval.end++;
5810 break;
5811 }
5812 else if (text[this->interval.end] == '\\') {
5813 this->interval.end++;
5814 if (this->interval.end < end && text[this->interval.end]) {
5815 this->interval.end++;
5816 }
5817 else
5818 goto error;
5819 }
5820 else if (m_chr.match(text, this->interval.end, end, flags))
5821 this->interval.end++;
5822 else
5823 goto error;
5824 }
5825 else
5826 goto error;
5827 }
5828 this->interval.start = start;
5829 return true;
5830
5831 error:
5832 content.start = 1;
5833 content.end = 0;
5834 this->interval.start = (this->interval.end = start) + 1;
5835 return false;
5836 }
5837
5838 virtual void invalidate()
5839 {
5840 content.start = 1;
5841 content.end = 0;
5842 parser::invalidate();
5843 }
5844
5845 public:
5847
5848 protected:
5849 http_text_char m_chr;
5850 };
5851
5855 class http_value : public parser
5856 {
5857 public:
5858 virtual bool match(
5859 _In_reads_or_z_(end) const char* text,
5860 _In_ size_t start = 0,
5861 _In_ size_t end = (size_t)-1,
5862 _In_ int flags = match_default)
5863 {
5864 assert(text || start >= end);
5865 this->interval.end = start;
5866 if (string.match(text, this->interval.end, end, flags)) {
5867 token.invalidate();
5868 this->interval.end = string.interval.end;
5869 this->interval.start = start;
5870 return true;
5871 }
5872 else if (token.match(text, this->interval.end, end, flags)) {
5873 string.invalidate();
5874 this->interval.end = token.interval.end;
5875 this->interval.start = start;
5876 return true;
5877 }
5878 else {
5879 this->interval.start = (this->interval.end = start) + 1;
5880 return false;
5881 }
5882 }
5883
5884 virtual void invalidate()
5885 {
5886 string.invalidate();
5887 token.invalidate();
5888 parser::invalidate();
5889 }
5890
5891 public:
5894 };
5895
5899 class http_parameter : public parser
5900 {
5901 public:
5902 virtual bool match(
5903 _In_reads_or_z_(end) const char* text,
5904 _In_ size_t start = 0,
5905 _In_ size_t end = (size_t)-1,
5906 _In_ int flags = match_default)
5907 {
5908 assert(text || start >= end);
5909 this->interval.end = start;
5910 if (name.match(text, this->interval.end, end, flags))
5911 this->interval.end = name.interval.end;
5912 else
5913 goto error;
5914 while (m_space.match(text, this->interval.end, end, flags))
5915 this->interval.end = m_space.interval.end;
5916 assert(text || this->interval.end >= end);
5917 if (this->interval.end < end && text[this->interval.end] == '=')
5918 this->interval.end++;
5919 else
5920 while (m_space.match(text, this->interval.end, end, flags))
5921 this->interval.end = m_space.interval.end;
5922 if (value.match(text, this->interval.end, end, flags))
5923 this->interval.end = value.interval.end;
5924 else
5925 goto error;
5926 this->interval.start = start;
5927 return true;
5928
5929 error:
5930 name.invalidate();
5931 value.invalidate();
5932 this->interval.start = (this->interval.end = start) + 1;
5933 return false;
5934 }
5935
5936 virtual void invalidate()
5937 {
5938 name.invalidate();
5939 value.invalidate();
5940 parser::invalidate();
5941 }
5942
5943 public:
5946
5947 protected:
5948 http_space m_space;
5949 };
5950
5954 class http_any_type : public parser
5955 {
5956 public:
5957 virtual bool match(
5958 _In_reads_or_z_(end) const char* text,
5959 _In_ size_t start = 0,
5960 _In_ size_t end = (size_t)-1,
5961 _In_ int flags = match_default)
5962 {
5963 assert(text || start >= end);
5964 if (start + 2 < end &&
5965 text[start] == '*' &&
5966 text[start + 1] == '/' &&
5967 text[start + 2] == '*')
5968 {
5969 this->interval.end = (this->interval.start = start) + 3;
5970 return true;
5971 }
5972 else if (start < end && text[start] == '*') {
5973 this->interval.end = (this->interval.start = start) + 1;
5974 return true;
5975 }
5976 else {
5977 this->interval.start = (this->interval.end = start) + 1;
5978 return false;
5979 }
5980 }
5981 };
5982
5987 {
5988 public:
5989 virtual bool match(
5990 _In_reads_or_z_(end) const char* text,
5991 _In_ size_t start = 0,
5992 _In_ size_t end = (size_t)-1,
5993 _In_ int flags = match_default)
5994 {
5995 assert(text || start >= end);
5996 this->interval.end = start;
5997 if (type.match(text, this->interval.end, end, flags))
5998 this->interval.end = type.interval.end;
5999 else
6000 goto error;
6001 while (m_space.match(text, this->interval.end, end, flags))
6002 this->interval.end = m_space.interval.end;
6003 if (this->interval.end < end && text[this->interval.end] == '/')
6004 this->interval.end++;
6005 else
6006 goto error;
6007 while (m_space.match(text, this->interval.end, end, flags))
6008 this->interval.end = m_space.interval.end;
6009 if (subtype.match(text, this->interval.end, end, flags))
6010 this->interval.end = subtype.interval.end;
6011 else
6012 goto error;
6013 this->interval.start = start;
6014 return true;
6015
6016 error:
6017 type.invalidate();
6018 subtype.invalidate();
6019 this->interval.start = (this->interval.end = start) + 1;
6020 return false;
6021 }
6022
6023 virtual void invalidate()
6024 {
6025 type.invalidate();
6026 subtype.invalidate();
6027 parser::invalidate();
6028 }
6029
6030 public:
6031 http_token type;
6032 http_token subtype;
6033
6034 protected:
6035 http_space m_space;
6036 };
6037
6042 {
6043 public:
6044 virtual bool match(
6045 _In_reads_or_z_(end) const char* text,
6046 _In_ size_t start = 0,
6047 _In_ size_t end = (size_t)-1,
6048 _In_ int flags = match_default)
6049 {
6050 assert(text || start >= end);
6051 if (!http_media_range::match(text, start, end, flags))
6052 goto error;
6053 params.clear();
6054 for (;;) {
6055 if (this->interval.end < end && text[this->interval.end]) {
6056 if (m_space.match(text, this->interval.end, end, flags))
6057 this->interval.end = m_space.interval.end;
6058 else if (text[this->interval.end] == ';') {
6059 this->interval.end++;
6060 while (m_space.match(text, this->interval.end, end, flags))
6061 this->interval.end = m_space.interval.end;
6063 if (param.match(text, this->interval.end, end, flags)) {
6064 this->interval.end = param.interval.end;
6065 params.push_back(std::move(param));
6066 }
6067 else
6068 break;
6069 }
6070 else
6071 break;
6072 }
6073 else
6074 break;
6075 }
6076 this->interval.end = params.empty() ? subtype.interval.end : params.back().interval.end;
6077 return true;
6078
6079 error:
6080 http_media_range::invalidate();
6081 params.clear();
6082 this->interval.start = (this->interval.end = start) + 1;
6083 return false;
6084 }
6085
6086 virtual void invalidate()
6087 {
6088 params.clear();
6089 http_media_range::invalidate();
6090 }
6091
6092 public:
6093 std::list<http_parameter> params;
6094 };
6095
6100 {
6101 public:
6102 virtual bool match(
6103 _In_reads_or_z_(end) const char* text,
6104 _In_ size_t start = 0,
6105 _In_ size_t end = (size_t)-1,
6106 _In_ int flags = match_default)
6107 {
6108 assert(text || start >= end);
6109 this->interval.end = start;
6110 for (;;) {
6111 if (this->interval.end < end && text[this->interval.end]) {
6112 if ((unsigned int)text[this->interval.end] < 0x20 ||
6113 (unsigned int)text[this->interval.end] == 0x7f ||
6114 text[this->interval.end] == ':' ||
6115 text[this->interval.end] == '/' ||
6116 isspace(text[this->interval.end]))
6117 break;
6118 else
6119 this->interval.end++;
6120 }
6121 else
6122 break;
6123 }
6125 this->interval.start = start;
6126 return true;
6127 }
6128 this->interval.start = (this->interval.end = start) + 1;
6129 return false;
6130 }
6131 };
6132
6136 class http_url_port : public parser
6137 {
6138 public:
6139 http_url_port(_In_ const std::locale& locale = std::locale()) :
6140 parser(locale),
6141 value(0)
6142 {}
6143
6144 virtual bool match(
6145 _In_reads_or_z_(end) const char* text,
6146 _In_ size_t start = 0,
6147 _In_ size_t end = (size_t)-1,
6148 _In_ int flags = match_default)
6149 {
6150 assert(text || start >= end);
6151 value = 0;
6152 this->interval.end = start;
6153 for (;;) {
6154 if (this->interval.end < end && text[this->interval.end]) {
6155 if ('0' <= text[this->interval.end] && text[this->interval.end] <= '9') {
6156 size_t _value = (size_t)value * 10 + text[this->interval.end] - '0';
6157 if (_value > (uint16_t)-1) {
6158 value = 0;
6159 this->interval.start = (this->interval.end = start) + 1;
6160 return false;
6161 }
6162 value = (uint16_t)_value;
6163 this->interval.end++;
6164 }
6165 else
6166 break;
6167 }
6168 else
6169 break;
6170 }
6172 this->interval.start = start;
6173 return true;
6174 }
6175 this->interval.start = (this->interval.end = start) + 1;
6176 return false;
6177 }
6178
6179 virtual void invalidate()
6180 {
6181 value = 0;
6182 parser::invalidate();
6183 }
6184
6185 public:
6186 uint16_t value;
6187 };
6188
6193 {
6194 public:
6195 virtual bool match(
6196 _In_reads_or_z_(end) const char* text,
6197 _In_ size_t start = 0,
6198 _In_ size_t end = (size_t)-1,
6199 _In_ int flags = match_default)
6200 {
6201 assert(text || start >= end);
6202 this->interval.end = start;
6203 for (;;) {
6204 if (this->interval.end < end && text[this->interval.end]) {
6205 if ((unsigned int)text[this->interval.end] < 0x20 ||
6206 (unsigned int)text[this->interval.end] == 0x7f ||
6207 text[this->interval.end] == '?' ||
6208 text[this->interval.end] == '/' ||
6209 isspace(text[this->interval.end]))
6210 break;
6211 else
6212 this->interval.end++;
6213 }
6214 else
6215 break;
6216 }
6217 this->interval.start = start;
6218 return true;
6219 }
6220 };
6221
6225 class http_url_path : public parser
6226 {
6227 public:
6228 virtual bool match(
6229 _In_reads_or_z_(end) const char* text,
6230 _In_ size_t start = 0,
6231 _In_ size_t end = (size_t)-1,
6232 _In_ int flags = match_default)
6233 {
6234 assert(text || start >= end);
6236 this->interval.end = start;
6237 segments.clear();
6238 assert(text || this->interval.end >= end);
6239 if (this->interval.end < end && text[this->interval.end] != '/')
6240 goto error;
6241 this->interval.end++;
6242 s.match(text, this->interval.end, end, flags);
6243 segments.push_back(s);
6244 this->interval.end = s.interval.end;
6245 for (;;) {
6246 if (this->interval.end < end && text[this->interval.end]) {
6247 if (text[this->interval.end] == '/') {
6248 this->interval.end++;
6249 s.match(text, this->interval.end, end, flags);
6250 segments.push_back(s);
6251 this->interval.end = s.interval.end;
6252 }
6253 else
6254 break;
6255 }
6256 else
6257 break;
6258 }
6259 this->interval.start = start;
6260 return true;
6261
6262 error:
6263 segments.clear();
6264 this->interval.start = (this->interval.end = start) + 1;
6265 return false;
6266 }
6267
6268 virtual void invalidate()
6269 {
6270 segments.clear();
6271 parser::invalidate();
6272 }
6273
6274 public:
6275 std::vector<http_url_path_segment> segments;
6276 };
6277
6282 {
6283 public:
6284 virtual bool match(
6285 _In_reads_or_z_(end) const char* text,
6286 _In_ size_t start = 0,
6287 _In_ size_t end = (size_t)-1,
6288 _In_ int flags = match_default)
6289 {
6290 assert(text || start >= end);
6291 this->interval.end = start;
6292 name.start = this->interval.end;
6293 for (;;) {
6294 if (this->interval.end < end && text[this->interval.end]) {
6295 if ((unsigned int)text[this->interval.end] < 0x20 ||
6296 (unsigned int)text[this->interval.end] == 0x7f ||
6297 text[this->interval.end] == '&' ||
6298 text[this->interval.end] == '=' ||
6299 isspace(text[this->interval.end]))
6300 break;
6301 else
6302 this->interval.end++;
6303 }
6304 else
6305 break;
6306 }
6308 name.end = this->interval.end;
6309 else
6310 goto error;
6311 if (text[this->interval.end] == '=') {
6312 this->interval.end++;
6313 value.start = this->interval.end;
6314 for (;;) {
6315 if (this->interval.end < end && text[this->interval.end]) {
6316 if ((unsigned int)text[this->interval.end] < 0x20 ||
6317 (unsigned int)text[this->interval.end] == 0x7f ||
6318 text[this->interval.end] == '&' ||
6319 isspace(text[this->interval.end]))
6320 break;
6321 else
6322 this->interval.end++;
6323 }
6324 else
6325 break;
6326 }
6327 value.end = this->interval.end;
6328 }
6329 else {
6330 value.start = 1;
6331 value.end = 0;
6332 }
6333 this->interval.start = start;
6334 return true;
6335
6336 error:
6337 name.start = 1;
6338 name.end = 0;
6339 value.start = 1;
6340 value.end = 0;
6341 this->interval.start = (this->interval.end = start) + 1;
6342 return false;
6343 }
6344
6345 virtual void invalidate()
6346 {
6347 name.start = 1;
6348 name.end = 0;
6349 value.start = 1;
6350 value.end = 0;
6351 parser::invalidate();
6352 }
6353
6354 public:
6357 };
6358
6362 class http_url : public parser
6363 {
6364 public:
6365 http_url(_In_ const std::locale& locale = std::locale()) :
6366 parser(locale),
6367 port(locale)
6368 {}
6369
6370 virtual bool match(
6371 _In_reads_or_z_(end) const char* text,
6372 _In_ size_t start = 0,
6373 _In_ size_t end = (size_t)-1,
6374 _In_ int flags = match_default)
6375 {
6376 assert(text || start >= end);
6377 this->interval.end = start;
6378
6379 if (this->interval.end + 7 <= end && stdex::strnicmp(text + this->interval.end, 7, "http://", (size_t)-1, m_locale) == 0) {
6380 this->interval.end += 7;
6381 if (server.match(text, this->interval.end, end, flags))
6382 this->interval.end = server.interval.end;
6383 else
6384 goto error;
6385 if (this->interval.end < end && text[this->interval.end] == ':') {
6386 this->interval.end++;
6387 if (port.match(text, this->interval.end, end, flags))
6388 this->interval.end = port.interval.end;
6389 }
6390 else {
6391 port.invalidate();
6392 port.value = 80;
6393 }
6394 }
6395 else {
6396 server.invalidate();
6397 port.invalidate();
6398 port.value = 80;
6399 }
6400
6401 if (path.match(text, this->interval.end, end, flags))
6402 this->interval.end = path.interval.end;
6403 else
6404 goto error;
6405
6406 params.clear();
6407
6408 if (this->interval.end < end && text[this->interval.end] == '?') {
6409 this->interval.end++;
6410 for (;;) {
6411 if (this->interval.end < end && text[this->interval.end]) {
6412 if ((unsigned int)text[this->interval.end] < 0x20 ||
6413 (unsigned int)text[this->interval.end] == 0x7f ||
6414 isspace(text[this->interval.end]))
6415 break;
6416 else if (text[this->interval.end] == '&')
6417 this->interval.end++;
6418 else {
6420 if (param.match(text, this->interval.end, end, flags)) {
6421 this->interval.end = param.interval.end;
6422 params.push_back(std::move(param));
6423 }
6424 else
6425 break;
6426 }
6427 }
6428 else
6429 break;
6430 }
6431 }
6432
6433 this->interval.start = start;
6434 return true;
6435
6436 error:
6437 server.invalidate();
6438 port.invalidate();
6439 path.invalidate();
6440 params.clear();
6441 this->interval.start = (this->interval.end = start) + 1;
6442 return false;
6443 }
6444
6445 virtual void invalidate()
6446 {
6447 server.invalidate();
6448 port.invalidate();
6449 path.invalidate();
6450 params.clear();
6451 parser::invalidate();
6452 }
6453
6454 public:
6455 http_url_server server;
6456 http_url_port port;
6457 http_url_path path;
6458 std::list<http_url_parameter> params;
6459 };
6460
6464 class http_language : public parser
6465 {
6466 public:
6467 virtual bool match(
6468 _In_reads_or_z_(end) const char* text,
6469 _In_ size_t start = 0,
6470 _In_ size_t end = (size_t)-1,
6471 _In_ int flags = match_default)
6472 {
6473 assert(text || start >= end);
6474 this->interval.end = start;
6475 components.clear();
6476 for (;;) {
6477 if (this->interval.end < end && text[this->interval.end]) {
6479 k.end = this->interval.end;
6480 for (;;) {
6481 if (k.end < end && text[k.end]) {
6482 if (isalpha(text[k.end]))
6483 k.end++;
6484 else
6485 break;
6486 }
6487 else
6488 break;
6489 }
6490 if (this->interval.end < k.end) {
6491 k.start = this->interval.end;
6492 this->interval.end = k.end;
6493 components.push_back(k);
6494 }
6495 else
6496 break;
6497 if (this->interval.end < end && text[this->interval.end] == '-')
6498 this->interval.end++;
6499 else
6500 break;
6501 }
6502 else
6503 break;
6504 }
6505 if (!components.empty()) {
6506 this->interval.start = start;
6507 this->interval.end = components.back().end;
6508 return true;
6509 }
6510 this->interval.start = (this->interval.end = start) + 1;
6511 return false;
6512 }
6513
6514 virtual void invalidate()
6515 {
6516 components.clear();
6517 parser::invalidate();
6518 }
6519
6520 public:
6521 std::vector<stdex::interval<size_t>> components;
6522 };
6523
6527 class http_weight : public parser
6528 {
6529 public:
6530 http_weight(_In_ const std::locale& locale = std::locale()) :
6531 parser(locale),
6532 value(1.0f)
6533 {}
6534
6535 virtual bool match(
6536 _In_reads_or_z_(end) const char* text,
6537 _In_ size_t start = 0,
6538 _In_ size_t end = (size_t)-1,
6539 _In_ int flags = match_default)
6540 {
6541 assert(text || start >= end);
6542 size_t celi_del = 0, decimalni_del = 0, decimalni_del_n = 1;
6543 this->interval.end = start;
6544 for (;;) {
6545 if (this->interval.end < end && text[this->interval.end]) {
6546 if ('0' <= text[this->interval.end] && text[this->interval.end] <= '9') {
6547 celi_del = celi_del * 10 + text[this->interval.end] - '0';
6548 this->interval.end++;
6549 }
6550 else if (text[this->interval.end] == '.') {
6551 this->interval.end++;
6552 for (;;) {
6553 if (this->interval.end < end && text[this->interval.end]) {
6554 if ('0' <= text[this->interval.end] && text[this->interval.end] <= '9') {
6555 decimalni_del = decimalni_del * 10 + text[this->interval.end] - '0';
6556 decimalni_del_n *= 10;
6557 this->interval.end++;
6558 }
6559 else
6560 break;
6561 }
6562 else
6563 break;
6564 }
6565 break;
6566 }
6567 else
6568 break;
6569 }
6570 else
6571 break;
6572 }
6575 this->interval.start = start;
6576 return true;
6577 }
6578 value = 1.0f;
6579 this->interval.start = (this->interval.end = start) + 1;
6580 return false;
6581 }
6582
6583 virtual void invalidate()
6584 {
6585 value = 1.0f;
6586 parser::invalidate();
6587 }
6588
6589 public:
6590 float value;
6591 };
6592
6596 class http_asterisk : public parser
6597 {
6598 public:
6599 virtual bool match(
6600 _In_reads_or_z_(end) const char* text,
6601 _In_ size_t start = 0,
6602 _In_ size_t end = (size_t)-1,
6603 _In_ int flags = match_default)
6604 {
6605 assert(text || end <= start);
6606 if (start < end && text[start] == '*') {
6607 this->interval.end = (this->interval.start = start) + 1;
6608 return true;
6609 }
6610 this->interval.start = (this->interval.end = start) + 1;
6611 return false;
6612 }
6613 };
6614
6618 template <class T, class T_asterisk = http_asterisk>
6620 {
6621 public:
6622 http_weighted_value(_In_ const std::locale& locale = std::locale()) :
6623 parser(locale),
6624 factor(locale)
6625 {}
6626
6627 virtual bool match(
6628 _In_reads_or_z_(end) const char* text,
6629 _In_ size_t start = 0,
6630 _In_ size_t end = (size_t)-1,
6631 _In_ int flags = match_default)
6632 {
6633 assert(text || start >= end);
6634 size_t konec_vrednosti;
6635 this->interval.end = start;
6636 if (asterisk.match(text, this->interval.end, end, flags)) {
6637 this->interval.end = konec_vrednosti = asterisk.interval.end;
6638 value.invalidate();
6639 }
6640 else if (value.match(text, this->interval.end, end, flags)) {
6641 this->interval.end = konec_vrednosti = value.interval.end;
6642 asterisk.invalidate();
6643 }
6644 else {
6645 asterisk.invalidate();
6646 value.invalidate();
6647 this->interval.start = (this->interval.end = start) + 1;
6648 return false;
6649 }
6650
6651 while (this->interval.end < end && text[this->interval.end] && isspace(text[this->interval.end])) this->interval.end++;
6652 if (this->interval.end < end && text[this->interval.end] == ';') {
6653 this->interval.end++;
6654 while (this->interval.end < end && text[this->interval.end] && isspace(text[this->interval.end])) this->interval.end++;
6655 if (this->interval.end < end && (text[this->interval.end] == 'q' || text[this->interval.end] == 'Q')) {
6656 this->interval.end++;
6657 while (this->interval.end < end && text[this->interval.end] && isspace(text[this->interval.end])) this->interval.end++;
6658 if (this->interval.end < end && text[this->interval.end] == '=') {
6659 this->interval.end++;
6660 while (this->interval.end < end && text[this->interval.end] && isspace(text[this->interval.end])) this->interval.end++;
6661 if (factor.match(text, this->interval.end, end, flags))
6662 this->interval.end = factor.interval.end;
6663 }
6664 }
6665 }
6666 if (!factor.interval) {
6667 factor.invalidate();
6669 }
6670 this->interval.start = start;
6671 return true;
6672 }
6673
6674 virtual void invalidate()
6675 {
6676 asterisk.invalidate();
6677 value.invalidate();
6678 factor.invalidate();
6679 parser::invalidate();
6680 }
6681
6682 public:
6683 T_asterisk asterisk;
6684 T value;
6685 http_weight factor;
6686 };
6687
6692 {
6693 public:
6694 virtual bool match(
6695 _In_reads_or_z_(end) const char* text,
6696 _In_ size_t start = 0,
6697 _In_ size_t end = (size_t)-1,
6698 _In_ int flags = match_default)
6699 {
6700 assert(text || start >= end);
6701 this->interval.end = start;
6702 if (this->interval.end < end && text[this->interval.end] == '$')
6703 this->interval.end++;
6704 else
6705 goto error;
6706 if (name.match(text, this->interval.end, end, flags))
6707 this->interval.end = name.interval.end;
6708 else
6709 goto error;
6710 while (m_space.match(text, this->interval.end, end, flags))
6711 this->interval.end = m_space.interval.end;
6712 if (this->interval.end < end && text[this->interval.end] == '=')
6713 this->interval.end++;
6714 else
6715 goto error;
6716 while (m_space.match(text, this->interval.end, end, flags))
6717 this->interval.end = m_space.interval.end;
6718 if (value.match(text, this->interval.end, end, flags))
6719 this->interval.end = value.interval.end;
6720 else
6721 goto error;
6722 this->interval.start = start;
6723 return true;
6724
6725 error:
6726 name.invalidate();
6727 value.invalidate();
6728 this->interval.start = (this->interval.end = start) + 1;
6729 return false;
6730 }
6731
6732 virtual void invalidate()
6733 {
6734 name.invalidate();
6735 value.invalidate();
6736 parser::invalidate();
6737 }
6738
6739 public:
6740 http_token name;
6741 http_value value;
6742
6743 protected:
6744 http_space m_space;
6745 };
6746
6750 class http_cookie : public parser
6751 {
6752 public:
6753 virtual bool match(
6754 _In_reads_or_z_(end) const char* text,
6755 _In_ size_t start = 0,
6756 _In_ size_t end = (size_t)-1,
6757 _In_ int flags = match_default)
6758 {
6759 assert(text || start >= end);
6760 this->interval.end = start;
6761 if (name.match(text, this->interval.end, end, flags))
6762 this->interval.end = name.interval.end;
6763 else
6764 goto error;
6765 while (m_space.match(text, this->interval.end, end, flags))
6766 this->interval.end = m_space.interval.end;
6767 if (this->interval.end < end && text[this->interval.end] == '=')
6768 this->interval.end++;
6769 else
6770 goto error;
6771 while (m_space.match(text, this->interval.end, end, flags))
6772 this->interval.end = m_space.interval.end;
6773 if (value.match(text, this->interval.end, end, flags))
6774 this->interval.end = value.interval.end;
6775 else
6776 goto error;
6777 params.clear();
6778 for (;;) {
6779 if (this->interval.end < end && text[this->interval.end]) {
6780 if (m_space.match(text, this->interval.end, end, flags))
6781 this->interval.end = m_space.interval.end;
6782 else if (text[this->interval.end] == ';') {
6783 this->interval.end++;
6784 while (m_space.match(text, this->interval.end, end, flags))
6785 this->interval.end = m_space.interval.end;
6787 if (param.match(text, this->interval.end, end, flags)) {
6788 this->interval.end = param.interval.end;
6789 params.push_back(std::move(param));
6790 }
6791 else
6792 break;
6793 }
6794 else
6795 break;
6796 }
6797 else
6798 break;
6799 }
6800 this->interval.start = start;
6801 this->interval.end = params.empty() ? value.interval.end : params.back().interval.end;
6802 return true;
6803
6804 error:
6805 name.invalidate();
6806 value.invalidate();
6807 params.clear();
6808 this->interval.start = (this->interval.end = start) + 1;
6809 return false;
6810 }
6811
6812 virtual void invalidate()
6813 {
6814 name.invalidate();
6815 value.invalidate();
6816 params.clear();
6817 parser::invalidate();
6818 }
6819
6820 public:
6823 std::list<http_cookie_parameter> params;
6824
6825 protected:
6826 http_space m_space;
6827 };
6828
6832 class http_agent : public parser
6833 {
6834 public:
6835 virtual bool match(
6836 _In_reads_or_z_(end) const char* text,
6837 _In_ size_t start = 0,
6838 _In_ size_t end = (size_t)-1,
6839 _In_ int flags = match_default)
6840 {
6841 assert(text || start >= end);
6842 this->interval.end = start;
6843 type.start = this->interval.end;
6844 for (;;) {
6845 if (this->interval.end < end && text[this->interval.end]) {
6846 if (text[this->interval.end] == '/') {
6847 type.end = this->interval.end;
6848 this->interval.end++;
6849 version.start = this->interval.end;
6850 for (;;) {
6851 if (this->interval.end < end && text[this->interval.end]) {
6852 if (isspace(text[this->interval.end])) {
6853 version.end = this->interval.end;
6854 break;
6855 }
6856 else
6857 this->interval.end++;
6858 }
6859 else {
6860 version.end = this->interval.end;
6861 break;
6862 }
6863 }
6864 break;
6865 }
6866 else if (isspace(text[this->interval.end])) {
6867 type.end = this->interval.end;
6868 break;
6869 }
6870 else
6871 this->interval.end++;
6872 }
6873 else {
6874 type.end = this->interval.end;
6875 break;
6876 }
6877 }
6879 this->interval.start = start;
6880 return true;
6881 }
6882 type.start = 1;
6883 type.end = 0;
6884 version.start = 1;
6885 version.end = 0;
6886 this->interval.start = 1;
6887 this->interval.end = 0;
6888 return false;
6889 }
6890
6891 virtual void invalidate()
6892 {
6893 type.start = 1;
6894 type.end = 0;
6895 version.start = 1;
6896 version.end = 0;
6897 parser::invalidate();
6898 }
6899
6900 public:
6903 };
6904
6908 class http_protocol : public parser
6909 {
6910 public:
6911 http_protocol(_In_ const std::locale& locale = std::locale()) :
6912 parser(locale),
6913 version(0x009)
6914 {}
6915
6916 virtual bool match(
6917 _In_reads_or_z_(end) const char* text,
6918 _In_ size_t start = 0,
6919 _In_ size_t end = (size_t)-1,
6920 _In_ int flags = match_default)
6921 {
6922 assert(text || start >= end);
6923 this->interval.end = start;
6924 type.start = this->interval.end;
6925 for (;;) {
6926 if (this->interval.end < end && text[this->interval.end]) {
6927 if (text[this->interval.end] == '/') {
6928 type.end = this->interval.end;
6929 this->interval.end++;
6930 break;
6931 }
6932 else if (isspace(text[this->interval.end]))
6933 goto error;
6934 else
6935 this->interval.end++;
6936 }
6937 else {
6938 type.end = this->interval.end;
6939 goto error;
6940 }
6941 }
6942 version_maj.start = this->interval.end;
6943 for (;;) {
6944 if (this->interval.end < end && text[this->interval.end]) {
6945 if (text[this->interval.end] == '.') {
6946 version_maj.end = this->interval.end;
6947 this->interval.end++;
6948 version_min.start = this->interval.end;
6949 for (;;) {
6950 if (this->interval.end < end && text[this->interval.end]) {
6951 if (isspace(text[this->interval.end])) {
6952 version_min.end = this->interval.end;
6953 version =
6954 (uint16_t)strtoui(text + version_maj.start, version_maj.size(), nullptr, 10) * 0x100 +
6955 (uint16_t)strtoui(text + version_min.start, version_min.size(), nullptr, 10);
6956 break;
6957 }
6958 else
6959 this->interval.end++;
6960 }
6961 else
6962 goto error;
6963 }
6964 break;
6965 }
6966 else if (isspace(text[this->interval.end])) {
6967 version_maj.end = this->interval.end;
6968 version_min.start = 1;
6969 version_min.end = 0;
6970 version = (uint16_t)strtoui(text + version_maj.start, version_maj.size(), nullptr, 10) * 0x100;
6971 break;
6972 }
6973 else
6974 this->interval.end++;
6975 }
6976 else
6977 goto error;
6978 }
6979 this->interval.start = start;
6980 return true;
6981
6982 error:
6983 type.start = 1;
6984 type.end = 0;
6985 version_maj.start = 1;
6986 version_maj.end = 0;
6987 version_min.start = 1;
6988 version_min.end = 0;
6989 version = 0x009;
6990 this->interval.start = 1;
6991 this->interval.end = 0;
6992 return false;
6993 }
6994
6995 virtual void invalidate()
6996 {
6997 type.start = 1;
6998 type.end = 0;
6999 version_maj.start = 1;
7000 version_maj.end = 0;
7001 version_min.start = 1;
7002 version_min.end = 0;
7003 version = 0x009;
7004 parser::invalidate();
7005 }
7006
7007 public:
7009 stdex::interval<size_t> version_maj;
7010 stdex::interval<size_t> version_min;
7012 };
7013
7017 class http_request : public parser
7018 {
7019 public:
7020 http_request(_In_ const std::locale& locale = std::locale()) :
7021 parser(locale),
7022 url(locale),
7023 protocol(locale)
7024 {}
7025
7026 virtual bool match(
7027 _In_reads_or_z_(end) const char* text,
7028 _In_ size_t start = 0,
7029 _In_ size_t end = (size_t)-1,
7030 _In_ int flags = match_default)
7031 {
7032 assert(text || start >= end);
7033 this->interval.end = start;
7034
7035 for (;;) {
7036 if (m_line_break.match(text, this->interval.end, end, flags))
7037 goto error;
7038 else if (this->interval.end < end && text[this->interval.end]) {
7039 if (isspace(text[this->interval.end]))
7040 this->interval.end++;
7041 else
7042 break;
7043 }
7044 else
7045 goto error;
7046 }
7047 verb.start = this->interval.end;
7048 for (;;) {
7049 if (m_line_break.match(text, this->interval.end, end, flags))
7050 goto error;
7051 else if (this->interval.end < end && text[this->interval.end]) {
7052 if (isspace(text[this->interval.end])) {
7053 verb.end = this->interval.end;
7054 this->interval.end++;
7055 break;
7056 }
7057 else
7058 this->interval.end++;
7059 }
7060 else
7061 goto error;
7062 }
7063
7064 for (;;) {
7065 if (m_line_break.match(text, this->interval.end, end, flags))
7066 goto error;
7067 else if (this->interval.end < end && text[this->interval.end]) {
7068 if (isspace(text[this->interval.end]))
7069 this->interval.end++;
7070 else
7071 break;
7072 }
7073 else
7074 goto error;
7075 }
7076 if (url.match(text, this->interval.end, end, flags))
7077 this->interval.end = url.interval.end;
7078 else
7079 goto error;
7080
7081 protocol.invalidate();
7082 for (;;) {
7083 if (m_line_break.match(text, this->interval.end, end, flags)) {
7084 this->interval.end = m_line_break.interval.end;
7085 goto end;
7086 }
7087 else if (this->interval.end < end && text[this->interval.end]) {
7088 if (isspace(text[this->interval.end]))
7089 this->interval.end++;
7090 else
7091 break;
7092 }
7093 else
7094 goto end;
7095 }
7096 for (;;) {
7097 if (m_line_break.match(text, this->interval.end, end, flags)) {
7098 this->interval.end = m_line_break.interval.end;
7099 goto end;
7100 }
7101 else if (protocol.match(text, this->interval.end, end, flags)) {
7102 this->interval.end = protocol.interval.end;
7103 break;
7104 }
7105 else
7106 goto end;
7107 }
7108
7109 for (;;) {
7110 if (m_line_break.match(text, this->interval.end, end, flags)) {
7111 this->interval.end = m_line_break.interval.end;
7112 break;
7113 }
7114 else if (this->interval.end < end && text[this->interval.end])
7115 this->interval.end++;
7116 else
7117 goto end;
7118 }
7119
7120 end:
7121 this->interval.start = start;
7122 return true;
7123
7124 error:
7125 verb.start = 1;
7126 verb.end = 0;
7127 url.invalidate();
7128 protocol.invalidate();
7129 this->interval.start = 1;
7130 this->interval.end = 0;
7131 return false;
7132 }
7133
7134 virtual void invalidate()
7135 {
7136 verb.start = 1;
7137 verb.end = 0;
7138 url.invalidate();
7139 protocol.invalidate();
7140 parser::invalidate();
7141 }
7142
7143 public:
7145 http_url url;
7146 http_protocol protocol;
7147
7148 protected:
7149 http_line_break m_line_break;
7150 };
7151
7155 class http_header : public parser
7156 {
7157 public:
7158 virtual bool match(
7159 _In_reads_or_z_(end) const char* text,
7160 _In_ size_t start = 0,
7161 _In_ size_t end = (size_t)-1,
7162 _In_ int flags = match_default)
7163 {
7164 assert(text || start >= end);
7165 this->interval.end = start;
7166
7167 if (m_line_break.match(text, this->interval.end, end, flags) ||
7168 (this->interval.end < end && text[this->interval.end] && isspace(text[this->interval.end])))
7169 goto error;
7170 name.start = this->interval.end;
7171 for (;;) {
7172 if (m_line_break.match(text, this->interval.end, end, flags))
7173 goto error;
7174 else if (this->interval.end < end && text[this->interval.end]) {
7175 if (isspace(text[this->interval.end])) {
7176 name.end = this->interval.end;
7177 this->interval.end++;
7178 for (;;) {
7179 if (m_line_break.match(text, this->interval.end, end, flags))
7180 goto error;
7181 else if (this->interval.end < end && text[this->interval.end]) {
7182 if (isspace(text[this->interval.end]))
7183 this->interval.end++;
7184 else
7185 break;
7186 }
7187 else
7188 goto error;
7189 }
7190 if (this->interval.end < end && text[this->interval.end] == ':') {
7191 this->interval.end++;
7192 break;
7193 }
7194 else
7195 goto error;
7196 break;
7197 }
7198 else if (text[this->interval.end] == ':') {
7199 name.end = this->interval.end;
7200 this->interval.end++;
7201 break;
7202 }
7203 else
7204 this->interval.end++;
7205 }
7206 else
7207 goto error;
7208 }
7209 value.start = (size_t)-1;
7210 value.end = 0;
7211 for (;;) {
7212 if (m_line_break.match(text, this->interval.end, end, flags)) {
7213 this->interval.end = m_line_break.interval.end;
7214 if (!m_line_break.match(text, this->interval.end, end, flags) &&
7215 this->interval.end < end && text[this->interval.end] && isspace(text[this->interval.end]))
7216 this->interval.end++;
7217 else
7218 break;
7219 }
7220 else if (this->interval.end < end && text[this->interval.end]) {
7221 if (isspace(text[this->interval.end]))
7222 this->interval.end++;
7223 else {
7224 if (value.start == (size_t)-1) value.start = this->interval.end;
7225 value.end = ++this->interval.end;
7226 }
7227 }
7228 else
7229 break;
7230 }
7231 this->interval.start = start;
7232 return true;
7233
7234 error:
7235 name.start = 1;
7236 name.end = 0;
7237 value.start = 1;
7238 value.end = 0;
7239 this->interval.start = 1;
7240 this->interval.end = 0;
7241 return false;
7242 }
7243
7244 virtual void invalidate()
7245 {
7246 name.start = 1;
7247 name.end = 0;
7248 value.start = 1;
7249 value.end = 0;
7250 parser::invalidate();
7251 }
7252
7253 public:
7256
7257 protected:
7258 http_line_break m_line_break;
7259 };
7260
7264 template <class _Key, class T>
7265 class http_value_collection : public T
7266 {
7267 public:
7268 void insert(
7269 _In_reads_or_z_(end) const char* text,
7270 _In_ size_t start = 0,
7271 _In_ size_t end = (size_t)-1,
7272 _In_ int flags = match_default)
7273 {
7274 while (start < end) {
7275 while (start < end && text[start] && isspace(text[start])) start++;
7276 if (start < end && text[start] == ',') {
7277 start++;
7278 while (start < end&& text[start] && isspace(text[start])) start++;
7279 }
7280 _Key el;
7281 if (el.match(text, start, end, flags)) {
7282 start = el.interval.end;
7283 T::insert(std::move(el));
7284 }
7285 else
7286 break;
7287 }
7288 }
7289 };
7290
7291 template <class T>
7293 constexpr bool operator()(const T& a, const T& b) const noexcept
7294 {
7295 return a.factor.value > b.factor.value;
7296 }
7297 };
7298
7302 template <class T, class _Alloc = std::allocator<T>>
7304
7308 template <class T>
7310 {
7311 public:
7313 _In_ const std::shared_ptr<basic_parser<T>>& quote,
7314 _In_ const std::shared_ptr<basic_parser<T>>& chr,
7315 _In_ const std::shared_ptr<basic_parser<T>>& escape,
7316 _In_ const std::shared_ptr<basic_parser<T>>& sol,
7317 _In_ const std::shared_ptr<basic_parser<T>>& bs,
7318 _In_ const std::shared_ptr<basic_parser<T>>& ff,
7319 _In_ const std::shared_ptr<basic_parser<T>>& lf,
7320 _In_ const std::shared_ptr<basic_parser<T>>& cr,
7321 _In_ const std::shared_ptr<basic_parser<T>>& htab,
7322 _In_ const std::shared_ptr<basic_parser<T>>& uni,
7323 _In_ const std::shared_ptr<basic_integer16<T>>& hex,
7324 _In_ const std::locale& locale = std::locale()) :
7325 basic_parser<T>(locale),
7326 m_quote(quote),
7327 m_chr(chr),
7328 m_escape(escape),
7329 m_sol(sol),
7330 m_bs(bs),
7331 m_ff(ff),
7332 m_lf(lf),
7333 m_cr(cr),
7334 m_htab(htab),
7335 m_uni(uni),
7336 m_hex(hex)
7337 {}
7338
7339 virtual bool match(
7340 _In_reads_or_z_(end) const T* text,
7341 _In_ size_t start = 0,
7342 _In_ size_t end = (size_t)-1,
7343 _In_ int flags = match_default)
7344 {
7345 assert(text || start >= end);
7346 this->interval.end = start;
7347 if (m_quote->match(text, this->interval.end, end, flags)) {
7348 this->interval.end = m_quote->interval.end;
7349 value.clear();
7350 for (;;) {
7351 if (m_quote->match(text, this->interval.end, end, flags)) {
7352 this->interval.start = start;
7353 this->interval.end = m_quote->interval.end;
7354 return true;
7355 }
7356 if (m_escape->match(text, this->interval.end, end, flags)) {
7357 if (m_quote->match(text, m_escape->interval.end, end, flags)) {
7358 value += '"'; this->interval.end = m_quote->interval.end;
7359 continue;
7360 }
7361 if (m_sol->match(text, m_escape->interval.end, end, flags)) {
7362 value += '/'; this->interval.end = m_sol->interval.end;
7363 continue;
7364 }
7365 if (m_bs->match(text, m_escape->interval.end, end, flags)) {
7366 value += '\b'; this->interval.end = m_bs->interval.end;
7367 continue;
7368 }
7369 if (m_ff->match(text, m_escape->interval.end, end, flags)) {
7370 value += '\f'; this->interval.end = m_ff->interval.end;
7371 continue;
7372 }
7373 if (m_lf->match(text, m_escape->interval.end, end, flags)) {
7374 value += '\n'; this->interval.end = m_lf->interval.end;
7375 continue;
7376 }
7377 if (m_cr->match(text, m_escape->interval.end, end, flags)) {
7378 value += '\r'; this->interval.end = m_cr->interval.end;
7379 continue;
7380 }
7381 if (m_htab->match(text, m_escape->interval.end, end, flags)) {
7382 value += '\t'; this->interval.end = m_htab->interval.end;
7383 continue;
7384 }
7385 if (
7386 m_uni->match(text, m_escape->interval.end, end, flags) &&
7387 m_hex->match(text, m_uni->interval.end, std::min(m_uni->interval.end + 4, end), flags | match_case_insensitive) &&
7388 m_hex->interval.size() == 4 /* JSON requests 4-digit Unicode sequneces: \u.... */)
7389 {
7390 assert(m_hex->value <= 0xffff);
7391 if (sizeof(T) == 1) {
7392 if (m_hex->value > 0x7ff) {
7393 value += (T)(0xe0 | ((m_hex->value >> 12) & 0x0f));
7394 value += (T)(0x80 | ((m_hex->value >> 6) & 0x3f));
7395 value += (T)(0x80 | (m_hex->value & 0x3f));
7396 }
7397 else if (m_hex->value > 0x7f) {
7398 value += (T)(0xc0 | ((m_hex->value >> 6) & 0x1f));
7399 value += (T)(0x80 | (m_hex->value & 0x3f));
7400 }
7401 else
7402 value += (T)(m_hex->value & 0x7f);
7403 }
7404 else
7405 value += (T)m_hex->value;
7406 this->interval.end = m_hex->interval.end;
7407 continue;
7408 }
7409 if (m_escape->match(text, m_escape->interval.end, end, flags)) {
7410 value += '\\'; this->interval.end = m_escape->interval.end;
7411 continue;
7412 }
7413 }
7414 if (m_chr->match(text, this->interval.end, end, flags)) {
7415 value.Prilepi(text + m_chr->interval.start, m_chr->interval.size());
7416 this->interval.end = m_chr->interval.end;
7417 continue;
7418 }
7419 break;
7420 }
7421 }
7422 value.clear();
7423 this->interval.start = (this->interval.end = start) + 1;
7424 return false;
7425 }
7426
7427 virtual void invalidate()
7428 {
7429 value.clear();
7431 }
7432
7433 public:
7434 std::basic_string<T> value;
7435
7436 protected:
7437 std::shared_ptr<basic_parser<T>> m_quote;
7438 std::shared_ptr<basic_parser<T>> m_chr;
7439 std::shared_ptr<basic_parser<T>> m_escape;
7440 std::shared_ptr<basic_parser<T>> m_sol;
7441 std::shared_ptr<basic_parser<T>> m_bs;
7442 std::shared_ptr<basic_parser<T>> m_ff;
7443 std::shared_ptr<basic_parser<T>> m_lf;
7444 std::shared_ptr<basic_parser<T>> m_cr;
7445 std::shared_ptr<basic_parser<T>> m_htab;
7446 std::shared_ptr<basic_parser<T>> m_uni;
7447 std::shared_ptr<basic_integer16<T>> m_hex;
7448 };
7449
7452#ifdef _UNICODE
7453 using tjson_string = wjson_string;
7454#else
7455 using tjson_string = json_string;
7456#endif
7457 }
7458}
7459
7460#undef ENUM_FLAG_OPERATOR
7461#undef ENUM_FLAGS
7462
7463#ifdef _MSC_VER
7464#pragma warning(pop)
7465#endif
Test for angle in d°mm'ss.dddd form.
Definition parser.hpp:4404
Test for any code unit.
Definition parser.hpp:230
Test for beginning of line.
Definition parser.hpp:624
Test for any.
Definition parser.hpp:1066
Test for chemical formula.
Definition parser.hpp:5548
Test for Creditor Reference.
Definition parser.hpp:4974
T reference[22]
Normalized national reference number.
Definition parser.hpp:5103
T check_digits[3]
Two check digits.
Definition parser.hpp:5102
bool is_valid
Is reference valid per ISO 7064.
Definition parser.hpp:5104
Test for any code unit from a given string of code units.
Definition parser.hpp:729
Test for specific code unit.
Definition parser.hpp:300
Test for date.
Definition parser.hpp:4034
Test for valid DNS domain character.
Definition parser.hpp:2815
bool allow_on_edge
Is character allowed at the beginning or an end of a DNS domain?
Definition parser.hpp:2853
Test for DNS domain/hostname.
Definition parser.hpp:2915
bool m_allow_absolute
May DNS names end with a dot (absolute name)?
Definition parser.hpp:2979
Test for e-mail address.
Definition parser.hpp:3803
Test for emoticon.
Definition parser.hpp:3911
std::shared_ptr< basic_parser< T > > apex
apex/eyebrows/halo (e.g. O, 0)
Definition parser.hpp:4000
std::shared_ptr< basic_parser< T > > eyes
eyes (e.g. :, ;, >, |, B)
Definition parser.hpp:4001
std::shared_ptr< basic_set< T > > mouth
mouth (e.g. ), ), (, (, |, P, D, p, d)
Definition parser.hpp:4003
std::shared_ptr< basic_parser< T > > nose
nose (e.g. -, o)
Definition parser.hpp:4002
std::shared_ptr< basic_parser< T > > emoticon
emoticon as a whole (e.g. 😀, 🤔, 😶)
Definition parser.hpp:3999
Test for end of line.
Definition parser.hpp:662
Test for fraction.
Definition parser.hpp:1695
Test for International Bank Account Number.
Definition parser.hpp:4680
T bban[31]
Normalized Basic Bank Account Number.
Definition parser.hpp:4951
T country[3]
ISO 3166-1 alpha-2 country code.
Definition parser.hpp:4949
T check_digits[3]
Two check digits.
Definition parser.hpp:4950
bool is_valid
Is IBAN valid per ISO 7064.
Definition parser.hpp:4952
Test for decimal integer.
Definition parser.hpp:1304
Test for decimal integer possibly containing thousand separators.
Definition parser.hpp:1389
bool has_separators
Did integer have any separators?
Definition parser.hpp:1449
size_t digit_count
Total number of digits in integer.
Definition parser.hpp:1448
Test for hexadecimal integer.
Definition parser.hpp:1470
Base class for integer testing.
Definition parser.hpp:1282
size_t value
Calculated value of the numeral.
Definition parser.hpp:1296
Test for IPv4 address.
Definition parser.hpp:2355
stdex::interval< size_t > components[4]
Individual component intervals.
Definition parser.hpp:2470
struct in_addr value
IPv4 address value.
Definition parser.hpp:2471
Test for IPv6 address.
Definition parser.hpp:2574
std::shared_ptr< basic_parser< T > > scope_id
Scope ID (e.g. NIC index with link-local addresses)
Definition parser.hpp:2778
stdex::interval< size_t > components[8]
Individual component intervals.
Definition parser.hpp:2776
struct in6_addr value
IPv6 address value.
Definition parser.hpp:2777
Test for valid IPv6 address scope ID character.
Definition parser.hpp:2502
Test for repeating.
Definition parser.hpp:919
bool m_greedy
try to match as long sequence as possible
Definition parser.hpp:958
std::shared_ptr< basic_parser< T > > m_el
repeating element
Definition parser.hpp:955
size_t m_min_iterations
minimum number of iterations
Definition parser.hpp:956
size_t m_max_iterations
maximum number of iterations
Definition parser.hpp:957
Test for JSON string.
Definition parser.hpp:7310
Test for mixed numeral.
Definition parser.hpp:1931
std::shared_ptr< basic_parser< T > > fraction
fraction
Definition parser.hpp:2037
std::shared_ptr< basic_parser< T > > special_sign
Special sign (e.g. plus-minus '±')
Definition parser.hpp:2035
std::shared_ptr< basic_parser< T > > negative_sign
Negative sign.
Definition parser.hpp:2034
std::shared_ptr< basic_parser< T > > positive_sign
Positive sign.
Definition parser.hpp:2033
std::shared_ptr< basic_parser< T > > integer
Integer part.
Definition parser.hpp:2036
Test for monetary numeral.
Definition parser.hpp:2226
std::shared_ptr< basic_parser< T > > positive_sign
Positive sign.
Definition parser.hpp:2332
std::shared_ptr< basic_parser< T > > decimal_separator
Decimal separator.
Definition parser.hpp:2337
std::shared_ptr< basic_parser< T > > currency
Currency part.
Definition parser.hpp:2335
std::shared_ptr< basic_parser< T > > decimal
Decimal part.
Definition parser.hpp:2338
std::shared_ptr< basic_parser< T > > integer
Integer part.
Definition parser.hpp:2336
std::shared_ptr< basic_parser< T > > negative_sign
Negative sign.
Definition parser.hpp:2333
std::shared_ptr< basic_parser< T > > special_sign
Special sign (e.g. plus-minus '±')
Definition parser.hpp:2334
"No-op" match
Definition parser.hpp:198
Base template for all parsers.
Definition parser.hpp:79
interval< size_t > interval
Region of the last match.
Definition parser.hpp:178
Test for permutation.
Definition parser.hpp:1206
Test for phone number.
Definition parser.hpp:4527
std::basic_string< T > value
Normalized phone number.
Definition parser.hpp:4653
Test for any punctuation code unit.
Definition parser.hpp:472
Test for Roman numeral.
Definition parser.hpp:1579
Test for scientific numeral.
Definition parser.hpp:2057
std::shared_ptr< basic_parser< T > > special_sign
Special sign (e.g. plus-minus '±')
Definition parser.hpp:2201
std::shared_ptr< basic_parser< T > > exponent_symbol
Exponent symbol (e.g. 'e')
Definition parser.hpp:2205
std::shared_ptr< basic_parser< T > > positive_sign
Positive sign.
Definition parser.hpp:2199
std::shared_ptr< basic_parser< T > > negative_sign
Negative sign.
Definition parser.hpp:2200
double value
Calculated value of the numeral.
Definition parser.hpp:2209
std::shared_ptr< basic_parser< T > > negative_exp_sign
Negative exponent sign (e.g. '-')
Definition parser.hpp:2207
std::shared_ptr< basic_integer< T > > decimal
Decimal part.
Definition parser.hpp:2204
std::shared_ptr< basic_parser< T > > positive_exp_sign
Positive exponent sign (e.g. '+')
Definition parser.hpp:2206
std::shared_ptr< basic_integer< T > > exponent
Exponent part.
Definition parser.hpp:2208
std::shared_ptr< basic_parser< T > > decimal_separator
Decimal separator.
Definition parser.hpp:2203
std::shared_ptr< basic_integer< T > > integer
Integer part.
Definition parser.hpp:2202
Test for match score.
Definition parser.hpp:1758
Test for sequence.
Definition parser.hpp:1015
Definition parser.hpp:697
Test for SI Reference delimiter.
Definition parser.hpp:5171
Test for SI Reference part.
Definition parser.hpp:5126
Test for SI Reference.
Definition parser.hpp:5209
basic_si_reference_part< T > part3
Reference data part 3 (P3)
Definition parser.hpp:5526
basic_si_reference_part< T > part1
Reference data part 1 (P1)
Definition parser.hpp:5524
bool is_valid
Is reference valid.
Definition parser.hpp:5527
T model[3]
Reference model.
Definition parser.hpp:5523
basic_si_reference_part< T > part2
Reference data part 2 (P2)
Definition parser.hpp:5525
Test for signed numeral.
Definition parser.hpp:1845
std::shared_ptr< basic_parser< T > > special_sign
Special sign (e.g. plus-minus '±')
Definition parser.hpp:1913
std::shared_ptr< basic_parser< T > > negative_sign
Negative sign.
Definition parser.hpp:1912
std::shared_ptr< basic_parser< T > > positive_sign
Positive sign.
Definition parser.hpp:1911
std::shared_ptr< basic_parser< T > > number
Number.
Definition parser.hpp:1914
Test for any space code unit.
Definition parser.hpp:393
Test for any space or punctuation code unit.
Definition parser.hpp:546
Test for any string.
Definition parser.hpp:1134
Test for given string.
Definition parser.hpp:824
Test for time.
Definition parser.hpp:4301
Test for valid URL password character.
Definition parser.hpp:3097
Test for valid URL path character.
Definition parser.hpp:3197
Test for URL path.
Definition parser.hpp:3305
Test for valid URL username character.
Definition parser.hpp:2998
Test for URL.
Definition parser.hpp:3446
Test for HTTP agent.
Definition parser.hpp:6833
Test for HTTP any type.
Definition parser.hpp:5955
Test for HTTP asterisk.
Definition parser.hpp:6597
Test for HTTP header.
Definition parser.hpp:7156
Test for HTTP language (RFC1766)
Definition parser.hpp:6465
Test for HTTP line break (RFC2616: CRLF | LF)
Definition parser.hpp:5629
Test for HTTP media range (RFC2616: media-range)
Definition parser.hpp:5987
Test for HTTP media type (RFC2616: media-type)
Definition parser.hpp:6042
Test for HTTP parameter (RFC2616: parameter)
Definition parser.hpp:5900
http_token name
Parameter name.
Definition parser.hpp:5944
http_value value
Parameter value.
Definition parser.hpp:5945
Test for HTTP protocol.
Definition parser.hpp:6909
uint16_t version
HTTP protocol version: 0x100 = 1.0, 0x101 = 1.1...
Definition parser.hpp:7011
Test for HTTP quoted string (RFC2616: quoted-string)
Definition parser.hpp:5790
stdex::interval< size_t > content
String content (without quotes)
Definition parser.hpp:5846
Test for HTTP request.
Definition parser.hpp:7018
Test for HTTP space (RFC2616: LWS)
Definition parser.hpp:5665
Test for HTTP text character (RFC2616: TEXT)
Definition parser.hpp:5702
Test for HTTP token (RFC2616: token - tolerates non-ASCII)
Definition parser.hpp:5736
Test for HTTP URL parameter.
Definition parser.hpp:6282
Test for HTTP URL path segment.
Definition parser.hpp:6193
Test for HTTP URL path segment.
Definition parser.hpp:6226
std::vector< http_url_path_segment > segments
Path segments.
Definition parser.hpp:6275
Test for HTTP URL port.
Definition parser.hpp:6137
Test for HTTP URL server.
Definition parser.hpp:6100
Test for HTTP URL.
Definition parser.hpp:6363
Collection of HTTP values.
Definition parser.hpp:7266
Test for HTTP value (RFC2616: value)
Definition parser.hpp:5856
http_quoted_string string
Value when matched as quoted string.
Definition parser.hpp:5892
http_token token
Value when matched as token.
Definition parser.hpp:5893
Test for HTTP weight factor.
Definition parser.hpp:6528
float value
Calculated value of the weight factor.
Definition parser.hpp:6590
Test for HTTP weighted value.
Definition parser.hpp:6620
Base template for collection-holding parsers.
Definition parser.hpp:975
Test for any SGML code point.
Definition parser.hpp:262
Test for any SGML code point from a given string of SGML code points.
Definition parser.hpp:781
Test for specific SGML code point.
Definition parser.hpp:349
Test for valid DNS domain SGML character.
Definition parser.hpp:2871
Test for valid IPv6 address scope ID SGML character.
Definition parser.hpp:2540
Test for any SGML punctuation code point.
Definition parser.hpp:513
Test for any SGML space code point.
Definition parser.hpp:436
Test for any SGML space or punctuation code point.
Definition parser.hpp:589
Test for SGML given string.
Definition parser.hpp:871
Test for valid URL password SGML character.
Definition parser.hpp:3149
Test for valid URL path SGML character.
Definition parser.hpp:3253
Test for valid URL username SGML character.
Definition parser.hpp:3049
Numerical interval.
Definition interval.hpp:18
T size() const
Returns interval size.
Definition interval.hpp:47
T end
interval end
Definition interval.hpp:20
interval() noexcept
Constructs an invalid interval.
Definition interval.hpp:25
T start
interval start
Definition interval.hpp:19
Definition parser.hpp:7292