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