Md4qt

traits.h
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2022-2024 Igor Mironchik <igor.mironchik@gmail.com>
3 SPDX-License-Identifier: MIT
4*/
5
6#ifndef MD4QT_MD_TRAITS_HPP_INCLUDED
7#define MD4QT_MD_TRAITS_HPP_INCLUDED
8
9#ifdef MD4QT_ICU_STL_SUPPORT
10
11// C++ include.
12#include <algorithm>
13#include <cctype>
14#include <filesystem>
15#include <map>
16#include <memory>
17#include <string>
18#include <utility>
19#include <vector>
20
21// ICU include.
22#include <unicode/uchar.h>
23#include <unicode/unistr.h>
24
25// uriparser include.
26#include <uriparser/Uri.h>
27
28#endif // MD4QT_ICU_STL_SUPPORT
29
30#ifdef MD4QT_QT_SUPPORT
31
32#ifndef MD4QT_ICU_STL_SUPPORT
33
34// C++ include.
35#include <map>
36#include <memory>
37
38#endif // MD4QT_ICU_STL_SUPPORT
39
40// Qt include.
41#include <QFileInfo>
42#include <QString>
43#include <QStringList>
44#include <QTextStream>
45#include <QUrl>
46#include <QVector>
47
48#endif // MD4QT_QT_SUPPORT
49
50namespace MD
51{
52
53//! Internal string, used to get virgin (original) string from transformed string.
54template<class String, class Char, class Latin1Char>
56{
57public:
59 {
60 }
61 InternalStringT(const String &s)
62 : m_str(s)
63 , m_virginStr(s)
64 {
65 }
66
67 //! \return Reference to string.
68 String &asString()
69 {
70 return m_str;
71 }
72
73 //! \return Reference to string.
74 const String &asString() const
75 {
76 return m_str;
77 }
78
79 //! \return Full virgin string.
80 const String & fullVirginString() const
81 {
82 return m_virginStr;
83 }
84
85 //! \return Virgin sub-string with position and length in the transformed string.
86 String virginSubString(long long int pos = 0, long long int len = -1) const
87 {
88 if (pos < 0) {
89 pos = 0;
90 }
91
92 if (pos + len > m_str.length() || len < 0) {
93 len = m_str.length() - pos;
94 }
95
96 if (len == 0) {
97 return (m_str.isEmpty() ? m_virginStr : String());
98 }
99
100 auto virginStartPos = virginPos(pos);
101 String startStr, endStr;
102
103 if (m_virginStr[virginStartPos] == Latin1Char('\t')) {
104 const auto spaces = countOfSpacesForTab(virginStartPos);
105
106 for (long long int i = 1; i < spaces; ++i) {
107 if (virginPos(pos + i) != virginStartPos) {
108 startStr = String(i, Latin1Char(' '));
109 ++virginStartPos;
110 break;
111 }
112 }
113 }
114
115 auto virginEndPos = virginPos(pos + len - 1, true);
116
117 if (m_virginStr[virginEndPos] == Latin1Char('\t')) {
118 const auto spaces = countOfSpacesForTab(virginEndPos);
119
120 for (long long int i = 1; i < spaces; ++i) {
121 if (virginPos(pos + len - 1 - i) != virginEndPos) {
122 endStr = String(i, Latin1Char(' '));
123 --virginEndPos;
124 break;
125 }
126 }
127 }
128
129 return startStr + m_virginStr.sliced(virginStartPos, virginEndPos - virginStartPos + 1) + endStr;
130 }
131
132 //! \return Virgin position from transformed.
133 long long int virginPos(
134 //! Transformed position.
135 long long int pos,
136 //! If true will be return last virgin position before transformation.
137 //! For example if in virgin string 2 characters were replaced with 1,
138 //! we will receive position of second character if \p end is true.
139 bool end = false) const
140 {
141 for (auto it = m_changedPos.crbegin(), last = m_changedPos.crend(); it != last; ++it) {
142 pos = virginPosImpl(pos, *it, end);
143 }
144
145 return pos;
146 }
147
148 Char operator[](long long int position) const
149 {
150 return m_str[position];
151 }
152
153 //! Replace substring.
154 InternalStringT &replaceOne(long long int pos, long long int size, const String &with)
155 {
156 const auto len = m_str.length();
157
158 m_str.remove(pos, size);
159 m_str.insert(pos, with);
160
161 if (with.length() != size) {
162 m_changedPos.push_back({{0, len}, {}});
163 m_changedPos.back().second.push_back({pos, size, with.size()});
164 }
165
166 return *this;
167 }
168
169 //! Replace string.
170 InternalStringT &replace(const String &what, const String &with)
171 {
172 String tmp;
173 bool init = false;
174 const auto len = m_str.length();
175
176 for (long long int i = 0; i < m_str.size();) {
177 long long int p = m_str.indexOf(what, i);
178
179 if (p != -1) {
180 tmp.push_back(m_str.sliced(i, p - i));
181 tmp.push_back(with);
182
183 i = p + what.size();
184
185 if (what.size() != with.size()) {
186 if (!init) {
187 m_changedPos.push_back({{0, len}, {}});
188 init = true;
189 }
190
191 m_changedPos.back().second.push_back({p, what.size(), with.size()});
192 }
193 } else {
194 tmp.push_back(m_str.sliced(i));
195
196 i = m_str.size();
197 }
198 }
199
200 std::swap(m_str, tmp);
201
202 return *this;
203 }
204
205 //! Remove sub-string.
206 InternalStringT &remove(long long int pos, long long int size)
207 {
208 const auto len = m_str.length();
209
210 m_str.remove(pos, size);
211
212 m_changedPos.push_back({{0, len}, {}});
213 m_changedPos.back().second.push_back({pos, size, 0});
214
215 return *this;
216 }
217
218 //! \return Is this string empty?
219 bool isEmpty() const
220 {
221 return m_str.isEmpty();
222 }
223
224 //! \return Length of the string.
225 long long int length() const
226 {
227 return m_str.length();
228 }
229
230 //! \return Simplified string.
232 {
233 if (isEmpty()) {
234 return *this;
235 }
236
237 const auto len = m_str.length();
238
239 InternalStringT result = *this;
240 result.m_str.clear();
241 long long int i = 0;
242 bool init = false;
243 bool first = true;
244 long long int spaces = 0;
245
246 while (true) {
247 long long tmp = i;
248
249 while (i < length() && m_str[i].isSpace()) {
250 ++i;
251 }
252
253 spaces = i - tmp;
254
255 if (i != tmp) {
256 if (!init) {
257 result.m_changedPos.push_back({{0, len}, {}});
258 init = true;
259 }
260
261 if (i - tmp > 1 || first) {
262 result.m_changedPos.back().second.push_back({tmp, i - tmp, (first ? 0 : 1)});
263 }
264 }
265
266 first = false;
267
268 while (i != length() && !m_str[i].isSpace()) {
269 result.m_str.push_back(m_str[i]);
270 ++i;
271 }
272
273 if (i == length()) {
274 break;
275 }
276
277 result.m_str.push_back(Latin1Char(' '));
278 }
279
280 if (!result.isEmpty() && result.m_str[result.length() - 1] == Latin1Char(' ')) {
281 result.m_str.remove(result.length() - 1, 1);
282
283 if (spaces > 1) {
284 result.m_changedPos.back().second.back().m_len = 0;
285 } else if (spaces == 1) {
286 result.m_changedPos.back().second.push_back({m_str.length() - spaces, spaces, 0});
287 }
288 }
289
290 return result;
291 }
292
293 //! Split string.
294 std::vector<InternalStringT> split(const InternalStringT &sep) const
295 {
296 std::vector<InternalStringT> result;
297 const auto len = m_str.length();
298
299 if (sep.isEmpty()) {
300 for (long long int i = 0; i < m_str.length(); ++i) {
301 auto is = *this;
302 is.m_str = m_str[i];
303 is.m_changedPos.push_back({{i, len}, {}});
304
305 result.push_back(is);
306 }
307
308 return result;
309 }
310
311 long long int pos = 0;
312 long long int fpos = 0;
313
314 while ((fpos = m_str.indexOf(sep.asString(), pos)) != -1 && fpos < length()) {
315 if (fpos - pos > 0) {
316 auto is = *this;
317 is.m_str = m_str.sliced(pos, fpos - pos);
318 is.m_changedPos.push_back({{pos, len}, {}});
319
320 result.push_back(is);
321 }
322
323 pos = fpos + sep.length();
324 }
325
326 if (pos < m_str.length()) {
327 auto is = *this;
328 is.m_str = m_str.sliced(pos, m_str.length() - pos);
329 is.m_changedPos.push_back({{pos, len}, {}});
330
331 result.push_back(is);
332 }
333
334 return result;
335 }
336
337 //! \return Sliced sub-string.
338 InternalStringT sliced(long long int pos, long long int len = -1) const
339 {
340 InternalStringT tmp = *this;
341 const auto oldLen = m_str.length();
342 tmp.m_str = tmp.m_str.sliced(pos, (len == -1 ? tmp.m_str.length() - pos : len));
343 tmp.m_changedPos.push_back({{pos, oldLen}, {}});
344 if (len != -1 && len < length() - pos) {
345 tmp.m_changedPos.back().second.push_back({pos + len, length() - pos - len, 0});
346 }
347
348 return tmp;
349 }
350
351 //! \return Right sub-string.
352 InternalStringT right(long long int n) const
353 {
354 InternalStringT tmp = *this;
355 const auto len = m_str.length();
356 tmp.m_str = tmp.m_str.right(n);
357 tmp.m_changedPos.push_back({{length() - n, len}, {}});
358
359 return tmp;
360 }
361
362 //! Insert one character.
363 InternalStringT &insert(long long int pos, Char ch)
364 {
365 return insert(pos, String(1, ch));
366 }
367
368 //! Insert string.
369 InternalStringT &insert(long long int pos, const String &s)
370 {
371 const auto len = m_str.length();
372 const auto ilen = s.length();
373
374 m_str.insert(pos, s);
375
376 m_changedPos.push_back({{0, len}, {}});
377 m_changedPos.back().second.push_back({pos, 1, ilen + 1});
378
379 return *this;
380 }
381
382private:
383 //! Transformed string.
384 String m_str;
385 //! Virgin (original) string.
386 String m_virginStr;
387
388 //! Auxiliary struct to store information about transformation.
389 struct ChangedPos {
390 long long int m_pos = -1;
391 long long int m_oldLen = -1;
392 long long int m_len = -1;
393 };
394
395 //! Auxiliary struct to store information about transformation.
396 struct LengthAndStartPos {
397 long long int m_firstPos = 0;
398 long long int m_length = 0;
399 };
400
401 //! Information about transformations.
402 std::vector<std::pair<LengthAndStartPos, std::vector<ChangedPos>>> m_changedPos;
403
404private:
405 long long int virginPosImpl(long long int pos,
406 const std::pair<LengthAndStartPos, std::vector<ChangedPos>> &changed,
407 bool end) const
408 {
409 for (const auto &c : changed.second) {
410 const auto startPos = c.m_pos;
411 const auto endPos = startPos + c.m_len - 1;
412
413 if (pos >= startPos && pos <= endPos) {
414 const auto oldEndPos = startPos + c.m_oldLen - 1;
415
416 if (pos > oldEndPos || end) {
417 return oldEndPos + changed.first.m_firstPos;
418 } else {
419 return pos + changed.first.m_firstPos;
420 }
421 } else if (pos > endPos) {
422 pos += c.m_oldLen - c.m_len;
423 } else {
424 break;
425 }
426 }
427
428 pos += changed.first.m_firstPos;
429
430 return (pos > changed.first.m_length ? changed.first.m_length : pos);
431 }
432
433 long long int countOfSpacesForTab(long long int virginPos) const
434 {
435 long long int p = 0;
436
437 for (const auto &v : std::as_const(m_changedPos)) {
438 p += v.first.m_firstPos;
439
440 if (virginPos < p) {
441 break;
442 }
443
444 for (const auto &c : std::as_const(v.second)) {
445 if (c.m_pos + p == virginPos) {
446 return c.m_len;
447 }
448
449 virginPos += (virginPos > c.m_pos ? c.m_len - c.m_oldLen : 0);
450 }
451 }
452
453 return -1;
454 }
455}; // class InternalString
456
457#ifdef MD4QT_ICU_STL_SUPPORT
458
459//
460// UnicodeChar
461//
462
463//! Wrapper for UChar32 to be used with MD::Parser.
464class UnicodeChar
465{
466public:
467 UnicodeChar()
468 : m_ch(0)
469 {
470 }
471
472 UnicodeChar(UChar32 ch)
473 : m_ch(ch)
474 {
475 }
476
477 operator UChar32() const
478 {
479 return m_ch;
480 }
481
482 inline bool isSpace() const
483 {
484 bool unicodeSpace = false;
485
486 const auto type = u_charType(m_ch);
487
488 switch (type) {
489 case U_SPACE_SEPARATOR:
490 case U_LINE_SEPARATOR:
491 case U_PARAGRAPH_SEPARATOR:
492 unicodeSpace = true;
493 break;
494
495 default:
496 break;
497 }
498
499 return m_ch == 0x20 || (m_ch <= 0x0D && m_ch >= 0x09) ||
500 (m_ch > 127 && (m_ch == 0x85 || m_ch == 0xA0 || unicodeSpace));
501 }
502
503 inline bool isDigit() const
504 {
505 return (u_charType(m_ch) == U_DECIMAL_DIGIT_NUMBER);
506 }
507
508 inline bool isNull() const
509 {
510 return m_ch == 0;
511 }
512
513 inline UChar32 unicode() const
514 {
515 return m_ch;
516 }
517
518 inline bool isLetter() const
519 {
520 const auto type = u_charType(m_ch);
521
522 switch (type) {
523 case U_UPPERCASE_LETTER:
524 case U_LOWERCASE_LETTER:
525 case U_TITLECASE_LETTER:
526 case U_MODIFIER_LETTER:
527 case U_OTHER_LETTER:
528 return true;
529
530 default:
531 return false;
532 }
533 }
534
535 inline bool isLetterOrNumber() const
536 {
537 return isLetter() || isDigit();
538 }
539
540 inline bool isPunct() const
541 {
542 const auto type = u_charType(m_ch);
543
544 switch (type) {
545 case U_DASH_PUNCTUATION:
546 case U_START_PUNCTUATION:
547 case U_END_PUNCTUATION:
548 case U_CONNECTOR_PUNCTUATION:
549 case U_OTHER_PUNCTUATION:
550 case U_INITIAL_PUNCTUATION:
551 case U_FINAL_PUNCTUATION:
552 return true;
553
554 default:
555 return false;
556 }
557 }
558
559 inline bool isSymbol() const
560 {
561 const auto type = u_charType(m_ch);
562
563 switch (type) {
564 case U_MATH_SYMBOL:
565 case U_CURRENCY_SYMBOL:
566 case U_MODIFIER_SYMBOL:
567 case U_OTHER_SYMBOL:
568 return true;
569
570 default:
571 return false;
572 }
573 }
574
575 UnicodeChar toLower() const
576 {
577 return icu::UnicodeString(1, m_ch, 1).toLower().char32At(0);
578 }
579
580 bool operator==(const UnicodeChar &other) const
581 {
582 return m_ch == other.m_ch;
583 }
584
585 bool operator!=(const UnicodeChar &other) const
586 {
587 return m_ch != other.m_ch;
588 }
589
590private:
591 UChar32 m_ch;
592}; // class UnicodeChar
593
594//
595// UnicodeString
596//
597
598//! Wrapper for icu::UnicodeString to be used with MD::Parser.
599class UnicodeString final : public icu::UnicodeString
600{
601public:
602 UnicodeString()
603 {
604 }
605
606 UnicodeString(const icu::UnicodeString &str)
607 : icu::UnicodeString(str)
608 {
609 }
610
611 UnicodeString(char ch)
612 : icu::UnicodeString((char16_t)ch)
613 {
614 }
615
616 UnicodeString(const char16_t *str)
617 : icu::UnicodeString(str)
618 {
619 }
620
621 UnicodeString(const UnicodeChar &ch)
622 : icu::UnicodeString(1, (UChar32)ch, 1)
623 {
624 }
625
626 UnicodeString(const char *str)
627 : icu::UnicodeString(icu::UnicodeString::fromUTF8(str))
628 {
629 }
630
631 UnicodeString(const std::string &str)
632 : icu::UnicodeString(icu::UnicodeString::fromUTF8(str))
633 {
634 }
635
636 UnicodeString(long long int count, char ch)
637 : icu::UnicodeString((int32_t)count, (UChar32)ch, (int32_t)count)
638 {
639 }
640
641 ~UnicodeString() override = default;
642
643 UnicodeChar operator[](long long int position) const
644 {
645 return UnicodeChar(char32At((int32_t)position));
646 }
647
648 void push_back(const UnicodeChar &ch)
649 {
650 icu::UnicodeString::append((UChar32)ch);
651 }
652
653 void push_back(const UnicodeString &str)
654 {
655 icu::UnicodeString::append(str);
656 }
657
658 int32_t size() const
659 {
660 return length();
661 }
662
663 int toInt(bool *ok = nullptr, int base = 10) const
664 {
665 try {
666 std::string tmp;
667 toUTF8String(tmp);
668 const auto result = std::stoi(tmp, nullptr, base);
669 if (ok) {
670 *ok = true;
671 }
672 return result;
673 } catch (const std::invalid_argument &) {
674 if (ok) {
675 *ok = false;
676 }
677 } catch (const std::out_of_range &) {
678 if (ok) {
679 *ok = false;
680 }
681 }
682
683 return 0;
684 }
685
686 bool contains(const UnicodeChar &ch) const
687 {
688 return (icu::UnicodeString::indexOf((UChar32)ch) != -1);
689 }
690
691 bool contains(const UnicodeString &str) const
692 {
693 return (icu::UnicodeString::indexOf(str) != -1);
694 }
695
696 UnicodeString simplified() const
697 {
698 if (isEmpty()) {
699 return *this;
700 }
701
702 UnicodeString result;
703 int32_t i = 0;
704
705 while (true) {
706 while (i < length() && UnicodeChar(char32At(i)).isSpace()) {
707 ++i;
708 }
709
710 while (i != length() && !UnicodeChar(char32At(i)).isSpace()) {
711 result.append(UnicodeChar(char32At(i)));
712 ++i;
713 }
714
715 if (i == length()) {
716 break;
717 }
718
719 result.append(UnicodeChar(' '));
720 }
721
722 if (!result.isEmpty() && result[result.size() - 1] == UnicodeChar(' ')) {
723 result.remove(result.size() - 1, 1);
724 }
725
726 return result;
727 }
728
729 std::vector<UnicodeString> split(const UnicodeChar &ch) const
730 {
731 std::vector<UnicodeString> result;
732
733 int32_t pos = 0;
734 int32_t fpos = 0;
735
736 while ((fpos = indexOf(ch, pos)) != -1 && fpos < length()) {
737 if (fpos - pos > 0) {
738 icu::UnicodeString tmp;
739 extract(pos, fpos - pos, tmp);
740 result.push_back(tmp);
741 }
742
743 pos = fpos + 1;
744 }
745
746 if (pos < length()) {
747 icu::UnicodeString tmp;
748 extract(pos, length() - pos, tmp);
749 result.push_back(tmp);
750 }
751
752 return result;
753 }
754
755 std::vector<UnicodeString> split(char ch) const
756 {
757 return split(UnicodeChar(ch));
758 }
759
760 UnicodeString &replace(const UnicodeChar &before, const UnicodeString &after)
761 {
762 for (int32_t pos = 0; (pos = indexOf(before, pos)) != -1; pos += after.size()) {
763 icu::UnicodeString::replace(pos, 1, after);
764 }
765
766 return *this;
767 }
768
769 UnicodeString &replace(const UnicodeString &before, const UnicodeString &after)
770 {
771 for (int32_t pos = 0; (pos = indexOf(before, pos)) != -1; pos += after.size()) {
772 icu::UnicodeString::replace(pos, before.length(), after);
773 }
774
775 return *this;
776 }
777
778 UnicodeString sliced(long long int pos, long long int len = -1) const
779 {
780 icu::UnicodeString tmp;
781 extract((int32_t)pos, (int32_t)(len == -1 ? length() - pos : len), tmp);
782
783 return tmp;
784 }
785
786 UnicodeString right(long long int n) const
787 {
788 icu::UnicodeString tmp;
789 extract(length() - (int32_t)n, (int32_t)n, tmp);
790
791 return tmp;
792 }
793
794 UnicodeString toCaseFolded() const
795 {
796 icu::UnicodeString tmp = *this;
797 tmp.foldCase();
798
799 return tmp;
800 }
801
802 UnicodeString toUpper() const
803 {
804 icu::UnicodeString tmp = *this;
805 tmp.toUpper();
806
807 return tmp;
808 }
809
810 UnicodeString toLower() const
811 {
812 icu::UnicodeString tmp = *this;
813 tmp.toLower();
814
815 return tmp;
816 }
817
818 void clear()
819 {
820 icu::UnicodeString::remove();
821 }
822}; // class UnicodeString
823
824//
825// UrlUri
826//
827
828class UrlUri
829{
830public:
831 explicit UrlUri(const UnicodeString &uriStr)
832 : m_valid(false)
833 , m_relative(false)
834 {
835 UriUriA uri;
836 std::string uriString;
837 uriStr.toUTF8String(uriString);
838
839 if (uriParseSingleUriA(&uri, uriString.c_str(), NULL) == URI_SUCCESS) {
840 m_valid = true;
841 m_relative = !(uri.scheme.first && uri.scheme.afterLast);
842
843 if (!m_relative) {
844 m_scheme = UnicodeString(std::string(uri.scheme.first,
845 uri.scheme.afterLast - uri.scheme.first).c_str());
846 }
847
848 if (uri.hostText.first && uri.hostText.afterLast) {
849 m_host = UnicodeString(std::string(uri.hostText.first,
850 uri.hostText.afterLast - uri.hostText.first).c_str());
851 }
852
853 uriFreeUriMembersA(&uri);
854 }
855 }
856
857 ~UrlUri()
858 {
859 }
860
861 bool isValid() const
862 {
863 return m_valid;
864 }
865
866 bool isRelative() const
867 {
868 return m_relative;
869 }
870
871 UnicodeString scheme() const
872 {
873 return m_scheme;
874 }
875
876 UnicodeString host() const
877 {
878 return m_host;
879 }
880
881private:
882 bool m_valid;
883 bool m_relative;
884 UnicodeString m_scheme;
885 UnicodeString m_host;
886}; // class UrlUri
887
888//
889// UnicodeStringTrait
890//
891
892//! Trait to use this library with std::string.
893struct UnicodeStringTrait {
894 template<class T>
895 using Vector = std::vector<T>;
896
897 template<class T, class U>
898 using Map = std::map<T, U>;
899
900 using String = UnicodeString;
901
902 using Char = UnicodeChar;
903
904 using InternalString = InternalStringT<String, Char, Char>;
905
906 using TextStream = std::istream;
907
908 using StringList = std::vector<String>;
909
910 using InternalStringList = std::vector<InternalString>;
911
912 using Url = UrlUri;
913
914 //! \return Is Unicode whitespace?
915 static bool isUnicodeWhitespace(const UnicodeChar &ch)
916 {
917 const auto c = ch.unicode();
918
919 if (u_charType(c) == U_SPACE_SEPARATOR) {
920 return true;
921 } else if (c == 0x09 || c == 0x0A || c == 0x0C || c == 0x0D) {
922 return true;
923 } else {
924 return false;
925 }
926 }
927
928 //! Convert UTF-16 into trait's string.
929 static String utf16ToString(const char16_t *u16)
930 {
931 return UnicodeString(u16);
932 }
933
934 //! Convert Latin1 into trait's string.
935 static String latin1ToString(const char *latin1)
936 {
937 return UnicodeString(latin1);
938 }
939
940 //! Convert Latin1 char into trait's char.
941 static Char latin1ToChar(char latin1)
942 {
943 return UnicodeChar(latin1);
944 }
945
946 //! Convert UTF8 into trait's string.
947 static String utf8ToString(const char *utf8)
948 {
949 return UnicodeString(utf8);
950 }
951
952 //! \return Does file exist.
953 static bool fileExists(const String &fileName, const String &workingPath)
954 {
955 std::string path;
956 (workingPath.isEmpty() ? fileName : String(workingPath + "/" + fileName)).toUTF8String(path);
957
958 std::error_code er;
959
960 const auto result = std::filesystem::exists(path, er);
961
962 return (er ? false : result);
963 }
964
965 //! \return Does file exist.
966 static bool fileExists(const String &fileName)
967 {
968 std::string path;
969 fileName.toUTF8String(path);
970
971 std::error_code er;
972
973 const auto result = std::filesystem::exists(path, er);
974
975 return (er ? false : result);
976 }
977
978 //! \return Absolute file path.
979 static String absoluteFilePath(const String &path)
980 {
981 std::string tmp;
982 path.toUTF8String(tmp);
983 std::error_code er;
984 auto p = std::filesystem::canonical(tmp, er).u8string();
985
986 std::replace(p.begin(), p.end(), '\\', '/');
987
988 return (er ? "" : UnicodeString::fromUTF8(p));
989 }
990
991 //! Add UCS4 to string.
992 static void appendUcs4(String &str, char32_t ch)
993 {
994 str.push_back(Char(ch));
995 }
996}; // struct UnicodeStringTrait
997
998#endif // MD4QT_ICU_STL_SUPPORT
999
1000#ifdef MD4QT_QT_SUPPORT
1001
1002//
1003// QStringTrait
1004//
1005
1006//! Trait to use this library with QString.
1007struct QStringTrait {
1008 template<class T>
1009 using Vector = QVector<T>;
1010
1011 template<class T, class U>
1012 using Map = std::map<T, U>;
1013
1014 using String = QString;
1015
1016 using Char = QChar;
1017
1018 using InternalString = InternalStringT<String, Char, QLatin1Char>;
1019
1020 using InternalStringList = std::vector<InternalString>;
1021
1022 using TextStream = QTextStream;
1023
1024 using StringList = QStringList;
1025
1026 using Url = QUrl;
1027
1028 //! \return Is Unicode whitespace?
1029 static bool isUnicodeWhitespace(const QChar &ch)
1030 {
1031 const auto c = ch.unicode();
1032
1033 if (ch.category() == QChar::Separator_Space) {
1034 return true;
1035 } else if (c == 0x09 || c == 0x0A || c == 0x0C || c == 0x0D) {
1036 return true;
1037 } else {
1038 return false;
1039 }
1040 }
1041
1042 //! Convert UTF-16 into trait's string.
1043 static String utf16ToString(const char16_t *u16)
1044 {
1045 return QString::fromUtf16(u16);
1046 }
1047
1048 //! Convert Latin1 into trait's string.
1049 static String latin1ToString(const char *latin1)
1050 {
1051 return QLatin1String(latin1);
1052 }
1053
1054 //! Convert Latin1 char into trait's char.
1055 static Char latin1ToChar(char latin1)
1056 {
1057 return QLatin1Char(latin1);
1058 }
1059
1060 //! Convert UTF8 into trait's string.
1061 static String utf8ToString(const char *utf8)
1062 {
1063 return QString::fromUtf8(utf8, -1);
1064 }
1065
1066 //! \return Does file exist.
1067 static bool fileExists(const String &fileName, const String &workingPath)
1068 {
1069 return QFileInfo::exists((workingPath.isEmpty() ?
1070 QString() : workingPath + latin1ToString("/")) + fileName);
1071 }
1072
1073 //! \return Does file exist.
1074 static bool fileExists(const String &fileName)
1075 {
1076 return QFileInfo::exists(fileName);
1077 }
1078
1079 //! \return Absolute file path.
1080 static String absoluteFilePath(const String &path)
1081 {
1082 return QFileInfo(path).absoluteFilePath();
1083 }
1084
1085 //! Add UCS4 to string.
1086 static void appendUcs4(String &str, char32_t ch)
1087 {
1088 str += QChar::fromUcs4(ch);
1089 }
1090}; // struct QStringTrait
1091
1092#endif // MD4QT_QT_SUPPORT
1093
1094} /* namespace MD */
1095
1096#endif // MD4QT_MD_TRAITS_HPP_INCLUDED
Internal string, used to get virgin (original) string from transformed string.
Definition traits.h:56
Char operator[](long long int position) const
Definition traits.h:148
long long int virginPos(long long int pos, bool end=false) const
Definition traits.h:133
const String & asString() const
Definition traits.h:74
InternalStringT(const String &s)
Definition traits.h:61
long long int length() const
Definition traits.h:225
bool isEmpty() const
Definition traits.h:219
std::vector< InternalStringT > split(const InternalStringT &sep) const
Split string.
Definition traits.h:294
InternalStringT simplified() const
Definition traits.h:231
InternalStringT & insert(long long int pos, const String &s)
Insert string.
Definition traits.h:369
String virginSubString(long long int pos=0, long long int len=-1) const
Definition traits.h:86
InternalStringT & replace(const String &what, const String &with)
Replace string.
Definition traits.h:170
InternalStringT & remove(long long int pos, long long int size)
Remove sub-string.
Definition traits.h:206
InternalStringT sliced(long long int pos, long long int len=-1) const
Definition traits.h:338
InternalStringT & replaceOne(long long int pos, long long int size, const String &with)
Replace substring.
Definition traits.h:154
const String & fullVirginString() const
Definition traits.h:80
String & asString()
Definition traits.h:68
InternalStringT right(long long int n) const
Definition traits.h:352
InternalStringT & insert(long long int pos, Char ch)
Insert one character.
Definition traits.h:363
bool fileExists(const QUrl &path)
KIOCORE_EXPORT bool operator!=(const UDSEntry &entry, const UDSEntry &other)
KIOCORE_EXPORT bool operator==(const UDSEntry &entry, const UDSEntry &other)
QString path(const QString &relativePath)
bool isValid(QStringView ifopt)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
QAction * replace(const QObject *recvr, const char *slot, QObject *parent)
KGuiItem clear()
Definition algo.h:17
Separator_Space
Category category(char32_t ucs4)
R fromUcs4(char32_t c)
char16_t & unicode()
QString absoluteFilePath() const const
bool exists() const const
QString fromUtf16(const char16_t *unicode, qsizetype size)
QString fromUtf8(QByteArrayView str)
QTextStream & right(QTextStream &stream)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Wed Nov 6 2024 12:12:28 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.