1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "uri_ext.h"
17 #include <iostream>
18 #include <vector>
19 #include <regex>
20 #include "hilog/log.h"
21 #include "string_ex.h"
22
23 using std::string;
24 using std::regex;
25 using OHOS::HiviewDFX::HiLog;
26
27 namespace OHOS {
28 namespace FileAccessFwk {
29 // 默认构造函数实现
Urie()30 Urie::Urie() : OHOS::Uri("")
31 {
32 cachedSsi_ = NOT_FOUND;
33 cachedFsi_ = NOT_FOUND;
34 port_ = NOT_CALCULATED;
35 }
36
37 // 接受字符串参数的构造函数实现
Urie(const std::string & uriString)38 Urie::Urie(const std::string& uriString) : OHOS::Uri(uriString)
39 {
40 cachedSsi_ = NOT_FOUND;
41 cachedFsi_ = NOT_FOUND;
42 port_ = NOT_CALCULATED;
43
44 if (uriString.empty()) {
45 return;
46 }
47
48 uriString_ = uriString;
49 scheme_ = NOT_CACHED;
50 ssp_ = NOT_CACHED;
51 authority_ = NOT_CACHED;
52 host_ = NOT_CACHED;
53 userInfo_ = NOT_CACHED;
54 query_ = NOT_CACHED;
55 path_ = NOT_CACHED;
56 fragment_ = NOT_CACHED;
57
58 if (!CheckScheme()) {
59 uriString_ = EMPTY;
60 std::cerr << "URI Scheme wrong" << std::endl; // 简单的错误输出,可替换为合适的日志记录方式
61 }
62 }
63
64 // 析构函数实现
~Urie()65 Urie::~Urie() {
66 }
67
CheckScheme()68 bool Urie::CheckScheme()
69 {
70 scheme_ = ParseScheme();
71 if (scheme_.empty()) {
72 return true;
73 }
74 regex schemeRegex("[a-zA-Z][a-zA-Z|\\d|\\+|\\-|.]*$");
75 if (!regex_match(scheme_, schemeRegex)) {
76 return false;
77 }
78 return true;
79 }
80
GetScheme()81 string Urie::GetScheme()
82 {
83 if (uriString_.empty()) {
84 return EMPTY;
85 }
86
87 if (scheme_ == NOT_CACHED) {
88 scheme_ = ParseScheme();
89 }
90 return scheme_;
91 }
92
ParseScheme()93 string Urie::ParseScheme()
94 {
95 size_t ssi = FindSchemeSeparator();
96 return (ssi == NOT_FOUND) ? EMPTY : uriString_.substr(0, ssi);
97 }
98
GetSchemeSpecificPart()99 string Urie::GetSchemeSpecificPart()
100 {
101 if (uriString_.empty()) {
102 return EMPTY;
103 }
104
105 return (ssp_ == NOT_CACHED) ? (ssp_ = ParseSsp()) : ssp_;
106 }
107
ParseSsp()108 string Urie::ParseSsp()
109 {
110 size_t ssi = FindSchemeSeparator();
111 size_t fsi = FindFragmentSeparator();
112
113 size_t start = (ssi == NOT_FOUND) ? 0 : (ssi + 1);
114 size_t end = (fsi == NOT_FOUND) ? uriString_.size() : fsi;
115
116 // Return everything between ssi and fsi.
117 string ssp = EMPTY;
118 if (end > start) {
119 ssp = uriString_.substr(start, end - start);
120 }
121
122 return ssp;
123 }
124
GetAuthority()125 string Urie::GetAuthority()
126 {
127 if (uriString_.empty()) {
128 return EMPTY;
129 }
130
131 if (authority_ == NOT_CACHED) {
132 authority_ = ParseAuthority();
133 }
134 return authority_;
135 }
136
ParseAuthority()137 string Urie::ParseAuthority()
138 {
139 size_t ssi = FindSchemeSeparator();
140 if (ssi == NOT_FOUND) {
141 return EMPTY;
142 }
143
144 size_t length = uriString_.length();
145 // If "//" follows the scheme separator, we have an authority.
146 if ((length > (ssi + POS_INC_MORE)) && (uriString_.at(ssi + POS_INC) == LEFT_SEPARATOR) &&
147 (uriString_.at(ssi + POS_INC_MORE) == LEFT_SEPARATOR)) {
148 // Look for the start of the path, query, or fragment, or the end of the string.
149 size_t start = ssi + POS_INC_AGAIN;
150 size_t end = start;
151
152 while (end < length) {
153 char ch = uriString_.at(end);
154 if ((ch == LEFT_SEPARATOR) || (ch == RIGHT_SEPARATOR) || (ch == QUERY_FLAG) ||
155 (ch == SCHEME_FRAGMENT)) {
156 break;
157 }
158
159 end++;
160 }
161
162 return uriString_.substr(start, end - start);
163 } else {
164 return EMPTY;
165 }
166 }
167
GetUserInfo()168 string Urie::GetUserInfo()
169 {
170 if (uriString_.empty()) {
171 return EMPTY;
172 }
173
174 if (userInfo_ == NOT_CACHED) {
175 userInfo_ = ParseUserInfo();
176 }
177 return userInfo_;
178 }
179
ParseUserInfo()180 string Urie::ParseUserInfo()
181 {
182 string authority = GetAuthority();
183 if (authority.empty()) {
184 return EMPTY;
185 }
186
187 size_t end = authority.find_last_of(USER_HOST_SEPARATOR);
188 return (end == NOT_FOUND) ? EMPTY : authority.substr(0, end);
189 }
190
GetHost()191 string Urie::GetHost()
192 {
193 if (uriString_.empty()) {
194 return EMPTY;
195 }
196
197 if (host_ == NOT_CACHED) {
198 host_ = ParseHost();
199 }
200 return host_;
201 }
202
ParseHost()203 string Urie::ParseHost()
204 {
205 string authority = GetAuthority();
206 if (authority.empty()) {
207 return EMPTY;
208 }
209
210 // Parse out user info and then port.
211 size_t userInfoSeparator = authority.find_last_of(USER_HOST_SEPARATOR);
212 size_t start = (userInfoSeparator == NOT_FOUND) ? 0 : (userInfoSeparator + 1);
213 size_t portSeparator = authority.find_first_of(PORT_SEPARATOR, start);
214 size_t end = (portSeparator == NOT_FOUND) ? authority.size() : portSeparator;
215
216 string host = EMPTY;
217 if (start < end) {
218 host = authority.substr(start, end - start);
219 }
220
221 return host;
222 }
223
GetPort()224 int Urie::GetPort()
225 {
226 if (uriString_.empty()) {
227 return PORT_NONE;
228 }
229
230 if (port_ == NOT_CALCULATED) {
231 port_ = ParsePort();
232 }
233 return port_;
234 }
235
ParsePort()236 int Urie::ParsePort()
237 {
238 string authority = GetAuthority();
239 if (authority.empty()) {
240 return PORT_NONE;
241 }
242
243 // Make sure we look for the port separtor *after* the user info separator.
244 size_t userInfoSeparator = authority.find_last_of(USER_HOST_SEPARATOR);
245 size_t start = (userInfoSeparator == NOT_FOUND) ? 0 : (userInfoSeparator + 1);
246 size_t portSeparator = authority.find_first_of(PORT_SEPARATOR, start);
247 if (portSeparator == NOT_FOUND) {
248 return PORT_NONE;
249 }
250
251 start = portSeparator + 1;
252 string portString = authority.substr(start);
253
254 int value = PORT_NONE;
255 return StrToInt(portString, value) ? value : PORT_NONE;
256 }
257
GetQuery()258 string Urie::GetQuery()
259 {
260 if (uriString_.empty()) {
261 return EMPTY;
262 }
263
264 if (query_ == NOT_CACHED) {
265 query_ = ParseQuery();
266 }
267 return query_;
268 }
269
ParseQuery()270 string Urie::ParseQuery()
271 {
272 size_t ssi = FindSchemeSeparator();
273 if (ssi == NOT_FOUND) {
274 ssi = 0;
275 }
276 size_t qsi = uriString_.find_first_of(QUERY_FLAG, ssi);
277 if (qsi == NOT_FOUND) {
278 return EMPTY;
279 }
280
281 size_t start = qsi + 1;
282 size_t fsi = FindFragmentSeparator();
283 if (fsi == NOT_FOUND) {
284 return uriString_.substr(start);
285 }
286
287 if (fsi < qsi) {
288 // Invalid.
289 return EMPTY;
290 }
291
292 return uriString_.substr(start, fsi - start);
293 }
294
GetPath()295 string Urie::GetPath()
296 {
297 if (uriString_.empty()) {
298 return EMPTY;
299 }
300
301 if (path_ == NOT_CACHED) {
302 path_ = ParsePath();
303 }
304 return path_;
305 }
306
GetPathSegments(std::vector<std::string> & segments)307 void Urie::GetPathSegments(std::vector<std::string>& segments)
308 {
309 if (uriString_.empty()) {
310 return;
311 }
312 if (path_ == NOT_CACHED) {
313 path_ = ParsePath();
314 }
315
316 size_t previous = 0;
317 size_t current;
318 while ((current = path_.find(LEFT_SEPARATOR, previous)) != std::string::npos) {
319 if (previous < current) {
320 segments.emplace_back(path_.substr(previous, current - previous));
321 }
322 previous = current + POS_INC;
323 }
324 // Add in the final path segment.
325 if (previous < path_.length()) {
326 segments.emplace_back(path_.substr(previous));
327 }
328 }
329
ParsePath()330 string Urie::ParsePath()
331 {
332 size_t ssi = FindSchemeSeparator();
333 // If the URI is absolute.
334 if (ssi != NOT_FOUND) {
335 // Is there anything after the ':'?
336 if ((ssi + 1) == uriString_.length()) {
337 // Opaque URI.
338 return EMPTY;
339 }
340
341 // A '/' after the ':' means this is hierarchical.
342 if (uriString_.at(ssi + 1) != LEFT_SEPARATOR) {
343 // Opaque URI.
344 return EMPTY;
345 }
346 } else {
347 // All relative URIs are hierarchical.
348 }
349
350 return ParsePath(ssi);
351 }
352
ParsePath(size_t ssi)353 string Urie::ParsePath(size_t ssi)
354 {
355 size_t length = uriString_.length();
356
357 // Find start of path.
358 size_t pathStart = (ssi == NOT_FOUND) ? 0 : (ssi + POS_INC);
359 if ((length > (pathStart + POS_INC)) && (uriString_.at(pathStart) == LEFT_SEPARATOR) &&
360 (uriString_.at(pathStart + POS_INC) == LEFT_SEPARATOR)) {
361 // Skip over authority to path.
362 pathStart += POS_INC_MORE;
363
364 while (pathStart < length) {
365 char ch = uriString_.at(pathStart);
366 if ((ch == QUERY_FLAG) || (ch == SCHEME_FRAGMENT)) {
367 return EMPTY;
368 }
369
370 if ((ch == LEFT_SEPARATOR) || (ch == RIGHT_SEPARATOR)) {
371 break;
372 }
373
374 pathStart++;
375 }
376 }
377
378 // Find end of path.
379 size_t pathEnd = pathStart;
380 while (pathEnd < length) {
381 char ch = uriString_.at(pathEnd);
382 if ((ch == QUERY_FLAG) || (ch == SCHEME_FRAGMENT)) {
383 break;
384 }
385
386 pathEnd++;
387 }
388
389 return uriString_.substr(pathStart, pathEnd - pathStart);
390 }
391
GetFragment()392 string Urie::GetFragment()
393 {
394 if (uriString_.empty()) {
395 return EMPTY;
396 }
397
398 if (fragment_ == NOT_CACHED) {
399 fragment_ = ParseFragment();
400 }
401 return fragment_;
402 }
403
ParseFragment()404 string Urie::ParseFragment()
405 {
406 size_t fsi = FindFragmentSeparator();
407 return (fsi == NOT_FOUND) ? EMPTY : uriString_.substr(fsi + 1);
408 }
409
FindSchemeSeparator()410 size_t Urie::FindSchemeSeparator()
411 {
412 if (cachedSsi_ == NOT_FOUND) {
413 cachedSsi_ = uriString_.find_first_of(SCHEME_SEPARATOR);
414 }
415 return cachedSsi_;
416 }
417
FindFragmentSeparator()418 size_t Urie::FindFragmentSeparator()
419 {
420 if (cachedFsi_ == NOT_FOUND) {
421 cachedFsi_ = uriString_.find_first_of(SCHEME_FRAGMENT, FindSchemeSeparator());
422 }
423 return cachedFsi_;
424 }
425
IsHierarchical()426 bool Urie::IsHierarchical()
427 {
428 if (uriString_.empty()) {
429 return false;
430 }
431
432 size_t ssi = FindSchemeSeparator();
433 if (ssi == NOT_FOUND) {
434 // All relative URIs are hierarchical.
435 return true;
436 }
437
438 if (uriString_.length() == (ssi + 1)) {
439 // No ssp.
440 return false;
441 }
442
443 // If the ssp starts with a '/', this is hierarchical.
444 return (uriString_.at(ssi + 1) == LEFT_SEPARATOR);
445 }
446
IsAbsolute()447 bool Urie::IsAbsolute()
448 {
449 if (uriString_.empty()) {
450 return false;
451 }
452
453 return !IsRelative();
454 }
455
IsRelative()456 bool Urie::IsRelative()
457 {
458 if (uriString_.empty()) {
459 return false;
460 }
461
462 // Note: We return true if the index is 0
463 return FindSchemeSeparator() == NOT_FOUND;
464 }
465
Equals(const Urie & other) const466 bool Urie::Equals(const Urie& other) const
467 {
468 return uriString_ == other.ToString();
469 }
470
CompareTo(const Urie & other) const471 int Urie::CompareTo(const Urie& other) const
472 {
473 return uriString_.compare(other.ToString());
474 }
475
ToString() const476 string Urie::ToString() const
477 {
478 return uriString_;
479 }
480
operator ==(const Urie & other) const481 bool Urie::operator==(const Urie& other) const
482 {
483 return uriString_ == other.ToString();
484 }
485
Marshalling(Parcel & parcel) const486 bool Urie::Marshalling(Parcel& parcel) const
487 {
488 if (IsAsciiString(uriString_)) {
489 return parcel.WriteString16(Str8ToStr16(uriString_));
490 }
491
492 HILOG_IMPL(LOG_CORE, LOG_ERROR, 0xD001305, "URIe", "uriString_ is not ascii string");
493 return false;
494 }
495
Unmarshalling(Parcel & parcel)496 Urie* Urie::Unmarshalling(Parcel& parcel)
497 {
498 return new Urie(Str16ToStr8(parcel.ReadString16()));
499 }
500 }
501 }