Line data Source code
1 : /**
2 : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "SPIdn.h"
25 :
26 : #ifdef WIN32
27 : #include "SPPlatformUnistd.h"
28 : #include "SPString.h"
29 : #include "winnls.h"
30 : #else
31 : #include "unicode/uidna.h"
32 : #endif
33 :
34 : namespace STAPPLER_VERSIONIZED stappler::idn {
35 :
36 : using HostUnicodeChars = chars::Compose<char, chars::CharGroup<char, CharGroupId::Alphanumeric>,
37 : chars::Chars<char, '.', '-'>, chars::Range<char, char(128), char(255)>>;
38 :
39 : using HostAsciiChars = chars::Compose<char, chars::CharGroup<char, CharGroupId::Alphanumeric>,
40 : chars::Chars<char, '.', '-'>>;
41 :
42 : template <typename Interface>
43 1875 : auto _idnToAscii(StringView source, bool validate) -> typename Interface::StringType {
44 1875 : if (source.empty()) {
45 0 : return typename Interface::StringType();
46 : }
47 :
48 1875 : if (validate) {
49 1000 : StringView r(source);
50 1000 : r.skipChars<HostUnicodeChars>();
51 1000 : if (!r.empty()) {
52 0 : return typename Interface::StringType();
53 : }
54 : }
55 :
56 : #ifdef WIN32
57 : auto in_w = string::toUtf16<memory::StandartInterface>(source);
58 : wchar_t punycode[256] = { 0 };
59 : int chars = IdnToAscii(0, (const wchar_t *)in_w.data(), -1, punycode, 255);
60 : if (chars) {
61 : return string::toUtf8<Interface>((char16_t *)punycode);
62 : }
63 : #else
64 1875 : char buf[1_KiB] = { 0 };
65 1875 : UErrorCode code = U_ZERO_ERROR;
66 1875 : auto retLen = u_nameToASCII_UTF8(UIDNA_NONTRANSITIONAL_TO_ASCII, source.data(), source.size(), buf, 1_KiB, nullptr, &code);
67 1875 : if (retLen > 0 && code == U_ZERO_ERROR) {
68 1875 : typename Interface::StringType ret(buf, retLen);
69 1875 : return ret;
70 1875 : }
71 :
72 : /*char *out = nullptr;
73 : auto err = idn2_to_ascii_8z(source.data(), &out, IDN2_NFC_INPUT|IDN2_NONTRANSITIONAL);
74 : if (err == IDN2_OK) {
75 : typename Interface::StringType ret(out);
76 : free(out);
77 : return ret;
78 : }*/
79 : #endif
80 0 : return typename Interface::StringType();
81 : }
82 :
83 : template <typename Interface>
84 0 : auto _idnToUnicode(StringView source, bool validate) -> typename Interface::StringType {
85 0 : if (source.empty()) {
86 0 : return typename Interface::StringType();
87 : }
88 :
89 0 : if (validate) {
90 0 : StringView r(source);
91 0 : r.skipChars<HostAsciiChars>();
92 0 : if (!r.empty()) {
93 0 : return typename Interface::StringType();
94 : }
95 : }
96 :
97 : #ifdef WIN32
98 : auto in_w = string::toUtf16<memory::StandartInterface>(source);
99 : wchar_t unicode[256] = { 0 };
100 : int chars = IdnToUnicode(0, (const wchar_t *)in_w.data(), int(in_w.size()), unicode, 255);
101 : if (chars) {
102 : return string::toUtf8<Interface>((char16_t *)unicode);
103 : }
104 : #else
105 0 : char buf[1_KiB] = { 0 };
106 0 : UErrorCode code = U_ZERO_ERROR;
107 0 : auto retLen = u_nameToUnicodeUTF8(0, source.data(), source.size(), buf, 1_KiB, nullptr, &code);
108 0 : if (retLen > 0 && code == U_ZERO_ERROR) {
109 0 : typename Interface::StringType ret(buf, retLen);
110 0 : return ret;
111 0 : }
112 :
113 : /*char *out = nullptr;
114 : auto err = idn2_to_unicode_8z8z(source.data(), &out, 0);
115 : if (err == IDN2_OK) {
116 : typename Interface::StringType ret(out);
117 : free(out);
118 : return ret;
119 : }*/
120 : #endif
121 0 : return typename Interface::StringType();
122 : }
123 :
124 :
125 : template <>
126 1675 : auto toAscii<memory::PoolInterface>(StringView source, bool validate) -> memory::PoolInterface::StringType {
127 1675 : return _idnToAscii<memory::PoolInterface>(source, validate);
128 : }
129 :
130 : template <>
131 200 : auto toAscii<memory::StandartInterface>(StringView source, bool validate) -> memory::StandartInterface::StringType {
132 200 : return _idnToAscii<memory::StandartInterface>(source, validate);
133 : }
134 :
135 : template <>
136 0 : auto toUnicode<memory::PoolInterface>(StringView source, bool validate) -> memory::PoolInterface::StringType {
137 0 : return _idnToUnicode<memory::PoolInterface>(source, validate);
138 : }
139 :
140 : template <>
141 0 : auto toUnicode<memory::StandartInterface>(StringView source, bool validate) -> memory::StandartInterface::StringType {
142 0 : return _idnToUnicode<memory::StandartInterface>(source, validate);
143 : }
144 :
145 : }
|