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