UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
urlparser.cpp
Go to the documentation of this file.
1// Copyright (C) 2022+ GPL 3 and higher by Ingo Höft, <Ingo@Hoeft-online.de>
2// Redistribution only with this Copyright remark. Last modified: 2024-08-18
10
11#include <string> // needed for MSC_VER
12#include <iostream>
13
15namespace UPnPsdk {
16
18// ======================
19std::array<unsigned short, 8> ipv6_parser(std::string_view a_input) {
20 std::array<unsigned short, 8> address{0, 0, 0, 0, 0, 0, 0, 0};
21
22 unsigned short pieceIndex{0};
23 int compress{-1};
24 std::string_view::const_iterator pointer{a_input.begin()};
25 int failure_line{0};
26
27 unsigned char c = pointer < a_input.end() ? (unsigned char)*pointer : '\0';
28
29 if (c == ':') {
30 if (pointer + 1 >= a_input.end() ||
31 *(pointer + 1) != (unsigned char)':') {
32 failure_line = __LINE__;
33 goto throw_failure;
34 }
35
36 pointer = pointer + 2;
37 pieceIndex++;
38 compress = pieceIndex;
39 }
40
41 while (pointer < a_input.end()) {
42 if (pieceIndex >= 8) {
43 failure_line = __LINE__;
44 goto throw_failure;
45 }
46
47 if (*pointer == (unsigned char)':') {
48 if (compress >= 0) {
49 failure_line = __LINE__;
50 goto throw_failure;
51 }
52
53 pointer++;
54 pieceIndex++;
55 compress = pieceIndex;
56
57 continue;
58 }
59
60 unsigned short value{};
61 int length{};
62 while (length < 4 && pointer < a_input.end() &&
63 std::isxdigit((unsigned char)*pointer)) {
64 unsigned char hx = (unsigned char)*pointer;
65 // hx interpreted as hexadecimal number
66 unsigned short v =
67 (hx >= 'A') ? (hx >= 'a') ? (hx - 'a' + 10) : (hx - 'A' + 10)
68 : (hx - '0');
69 // Arithmetic with implicit type cast to int, type cast is checked
70 value = (unsigned short)(value * 0x10 + v);
71 pointer++;
72 length++;
73 }
74
75 if (pointer < a_input.end() && *pointer == (unsigned char)'.') {
76 if (length == 0) {
77 failure_line = __LINE__;
78 goto throw_failure;
79 }
80
81 pointer = pointer - length;
82
83 if (pieceIndex > 6) {
84 failure_line = __LINE__;
85 goto throw_failure;
86 }
87
88 int numbersSeen{};
89 while (pointer < a_input.end()) {
90
91 // Valid values for ipv4Piece are 0 - 255
92 // 65535 (signed -1) means uninitialized (NULL)
93 unsigned short ipv4Piece{65535};
94 if (numbersSeen > 0) {
95 if (*pointer == (unsigned char)'.' && numbersSeen < 4) {
96 pointer++;
97 } else {
98 failure_line = __LINE__;
99 goto throw_failure;
100 }
101 }
102
103 if (pointer < a_input.end() &&
104 !std::isdigit((unsigned char)*pointer)) {
105 failure_line = __LINE__;
106 goto throw_failure;
107 }
108
109 while (pointer < a_input.end() &&
110 std::isdigit((unsigned char)*pointer)) {
111 // interpreted as decimal number, type cast is checked
112 unsigned short number = (unsigned short)(*pointer - '0');
113 switch (ipv4Piece) {
114 case 65535: // means uninitialized (NULL)
115 ipv4Piece = number;
116 break;
117 case 0:
118 failure_line = __LINE__;
119 goto throw_failure;
120 default:
121 // Arithmetic with implicit type cast to int, type cast
122 // is checked
123 ipv4Piece = (unsigned short)(ipv4Piece * 10 + number);
124 }
125
126 if (ipv4Piece > 255) {
127 failure_line = __LINE__;
128 goto throw_failure;
129 }
130
131 pointer++;
132 }
133
134 // Arithmetic with implicit type cast to int
135 address[pieceIndex] =
136 (unsigned short)(address[pieceIndex] * 0x100 + ipv4Piece);
137 numbersSeen++;
138 if (numbersSeen == 2 || numbersSeen == 4)
139 pieceIndex++;
140 }
141
142 if (numbersSeen != 4) {
143 failure_line = __LINE__;
144 goto throw_failure;
145 }
146
147 break;
148
149 } else if (pointer < a_input.end() && *pointer == (unsigned char)':') {
150 pointer++;
151 if (pointer >= a_input.end()) {
152 failure_line = __LINE__;
153 goto throw_failure;
154 }
155
156 } else if (pointer < a_input.end()) {
157 failure_line = __LINE__;
158 goto throw_failure;
159 }
160
161 address[pieceIndex] = value;
162 pieceIndex++;
163 }
164
165 if (compress >= 0) {
166 int swaps{pieceIndex - compress};
167 pieceIndex = 7;
168
169 while (pieceIndex != 0 && swaps > 0) {
170 // swap address[pieceIndex] with address[compress + swaps - 1]
171 unsigned short swapIndex = (unsigned short)(compress + swaps - 1);
172 unsigned short piece = address[pieceIndex];
173 address[pieceIndex] = address[swapIndex];
174 address[swapIndex] = piece;
175 pieceIndex--;
176 swaps--;
177 }
178
179 } else if (compress < 0 && pieceIndex != 8) {
180 failure_line = __LINE__;
181 goto throw_failure;
182 }
183
184 return address;
185
186throw_failure:
187 std::string errormsg =
188 "Error: " + (std::string) __func__ + "(\"" + (std::string)a_input +
189 "\"):" + std::to_string(failure_line) + " - Invalid IPv6 address.";
190 std::clog << errormsg << std::endl;
191 throw std::invalid_argument(errormsg);
192}
193
194
196// ======================
197std::string host_parser(std::string_view a_input,
198 bool a_isNotSpecial = false) //
199{
200 if (!a_input.empty() && a_input.front() == '[') {
201 if (a_input.back() != ']') {
202 std::clog << "Error: missing closing ']'." << std::endl;
203 throw std::invalid_argument("Missing closing ']': '" +
204 (std::string)a_input + "'");
205 }
206 // Return the result of IPv6 parsing a_input with its leading U+005B ([)
207 // and trailing U+005D (]) removed.
208 return "2001:DB8:1234:5678:9ABC:DEF0:1234:5678";
209 }
210
211 if (a_isNotSpecial) {
212 // If isNotSpecial is true, then return the result of opaque-host
213 // parsing a_input.
214 return "";
215 }
216
217 if (a_input.empty())
218 throw std::invalid_argument("Host string must not be empty.");
219
220 return "dummy.final.parsed.host";
221}
222
223} // namespace UPnPsdk
Reengineered Object Oriented UPnP+ program code.
Free functions to parse IPv6 and host URLs. Not usable, work in progess.