VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/uri.cpp@ 57720

最後變更 在這個檔案從57720是 57720,由 vboxsync 提交於 10 年 前

RTUri: Preps for parsing the authority bits into smaller pieces for cURL proxy config.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 24.0 KB
 
1/* $Id: uri.cpp 57720 2015-09-11 14:49:21Z vboxsync $ */
2/** @file
3 * IPRT - Uniform Resource Identifier handling.
4 */
5
6/*
7 * Copyright (C) 2011-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/uri.h>
32
33#include <iprt/assert.h>
34#include <iprt/ctype.h>
35#include <iprt/path.h>
36#include <iprt/string.h>
37
38/* General URI format:
39
40 foo://example.com:8042/over/there?name=ferret#nose
41 \_/ \______________/\_________/ \_________/ \__/
42 | | | | |
43 scheme authority path query fragment
44 | _____________________|__
45 / \ / \
46 urn:example:animal:ferret:nose
47*/
48
49/**
50 * Parsed URI.
51 */
52typedef struct RTURIPARSED
53{
54 /** RTURIPARSED_F_XXX. */
55 uint32_t fFlags;
56
57 /** The length of the scheme. */
58 size_t cchScheme;
59
60 /** The offset into the string of the authority. */
61 size_t offAuthority;
62 /** The authority length.
63 * @remarks The authority component can be zero length, so to check whether
64 * it's there or not consult RTURIPARSED_F_HAVE_AUTHORITY. */
65 size_t cchAuthority;
66
67 /** The offset into the string of the path. */
68 size_t offPath;
69 /** The length of the path. */
70 size_t cchPath;
71
72 /** The offset into the string of the query. */
73 size_t offQuery;
74 /** The length of the query. */
75 size_t cchQuery;
76
77 /** The offset into the string of the fragment. */
78 size_t offFragment;
79 /** The length of the fragment. */
80 size_t cchFragment;
81
82 /** @name Authority subdivisions
83 * @{ */
84 /** If there is a userinfo part, this is the start of it. Otherwise it's the
85 * same as offAuthorityHost. */
86 size_t offAuthorityUsername;
87 /** The length of the username (zero if not present). */
88 size_t cchAuthorityUsername;
89 /** If there is a userinfo part containing a password, this is the start of it.
90 * Otherwise it's the same as offAuthorityHost. */
91 size_t offAuthorityPassword;
92 /** The length of the password (zero if not present). */
93 size_t cchAuthorityPassword;
94 /** The offset of the host part of the authority. */
95 size_t offAuthorityHost;
96 /** The length of the host part of the authority. */
97 size_t cchAuthorityHost;
98 /** The authority port number, UINT32_MAX if not present. */
99 uint32_t uAuthorityPort;
100 /** @} */
101} RTURIPARSED;
102/** Pointer to a parsed URI. */
103typedef RTURIPARSED *PRTURIPARSED;
104/** Set if the URI contains escaped characters. */
105#define RTURIPARSED_F_CONTAINS_ESCAPED_CHARS UINT32_C(0x00000001)
106/** Set if the URI have an authority component. Necessary since the authority
107 * component can have a zero length. */
108#define RTURIPARSED_F_HAVE_AUTHORITY UINT32_C(0x00000002)
109
110
111
112/*********************************************************************************************************************************
113* Internal Functions *
114*********************************************************************************************************************************/
115
116/**
117 * The following defines characters which have to be % escaped:
118 * control = 00-1F
119 * space = ' '
120 * delims = '<' , '>' , '#' , '%' , '"'
121 * unwise = '{' , '}' , '|' , '\' , '^' , '[' , ']' , '`'
122 */
123#define URI_EXCLUDED(a) \
124 ( ((a) >= 0x0 && (a) <= 0x20) \
125 || ((a) >= 0x5B && (a) <= 0x5E) \
126 || ((a) >= 0x7B && (a) <= 0x7D) \
127 || (a) == '<' || (a) == '>' || (a) == '#' \
128 || (a) == '%' || (a) == '"' || (a) == '`' )
129
130static char *rtUriPercentEncodeN(const char *pszString, size_t cchMax)
131{
132 if (!pszString)
133 return NULL;
134
135 int rc = VINF_SUCCESS;
136
137 size_t cbLen = RT_MIN(strlen(pszString), cchMax);
138 /* The new string can be max 3 times in size of the original string. */
139 char *pszNew = RTStrAlloc(cbLen * 3 + 1);
140 if (!pszNew)
141 return NULL;
142
143 char *pszRes = NULL;
144 size_t iIn = 0;
145 size_t iOut = 0;
146 while (iIn < cbLen)
147 {
148 if (URI_EXCLUDED(pszString[iIn]))
149 {
150 char szNum[3] = { 0, 0, 0 };
151 RTStrFormatU8(&szNum[0], 3, pszString[iIn++], 16, 2, 2, RTSTR_F_CAPITAL | RTSTR_F_ZEROPAD);
152 pszNew[iOut++] = '%';
153 pszNew[iOut++] = szNum[0];
154 pszNew[iOut++] = szNum[1];
155 }
156 else
157 pszNew[iOut++] = pszString[iIn++];
158 }
159 if (RT_SUCCESS(rc))
160 {
161 pszNew[iOut] = '\0';
162 if (iOut != iIn)
163 {
164 /* If the source and target strings have different size, recreate
165 * the target string with the correct size. */
166 pszRes = RTStrDupN(pszNew, iOut);
167 RTStrFree(pszNew);
168 }
169 else
170 pszRes = pszNew;
171 }
172 else
173 RTStrFree(pszNew);
174
175 return pszRes;
176}
177
178static char *rtUriPercentDecodeN(const char *pszString, size_t cchMax)
179{
180 if (!pszString)
181 return NULL;
182
183 /* The new string can only get smaller. */
184 size_t cchLen = strlen(pszString);
185 cchLen = RT_MIN(cchLen, cchMax);
186 char *pszNew = RTStrAlloc(cchLen + 1);
187 if (!pszNew)
188 return NULL;
189
190 int rc = VINF_SUCCESS;
191 char *pszRes = NULL;
192 size_t iIn = 0;
193 size_t iOut = 0;
194 while (iIn < cchLen)
195 {
196 if (pszString[iIn] == '%')
197 {
198 /* % encoding means the percent sign and exactly 2 hexadecimal
199 * digits describing the ASCII number of the character. */
200 ++iIn;
201 char szNum[3];
202 szNum[0] = pszString[iIn++];
203 szNum[1] = pszString[iIn++];
204 szNum[2] = '\0';
205
206 uint8_t u8;
207 rc = RTStrToUInt8Ex(szNum, NULL, 16, &u8);
208 if (RT_FAILURE(rc))
209 break;
210 pszNew[iOut] = u8;
211 }
212 else
213 pszNew[iOut] = pszString[iIn++];
214 ++iOut;
215 }
216 if (RT_SUCCESS(rc))
217 {
218 pszNew[iOut] = '\0';
219 if (iOut != iIn)
220 {
221 /* If the source and target strings have different size, recreate
222 * the target string with the correct size. */
223 pszRes = RTStrDupN(pszNew, iOut);
224 RTStrFree(pszNew);
225 }
226 else
227 pszRes = pszNew;
228 }
229 else
230 RTStrFree(pszNew);
231
232 return pszRes;
233}
234
235static bool rtUriFindSchemeEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
236{
237 /* The scheme has to end with ':'. */
238 size_t i = iStart;
239 while (i < iStart + cbLen)
240 {
241 if (pszUri[i] == ':')
242 {
243 *piEnd = i;
244 return true;
245 }
246 ++i;
247 }
248 return false;
249}
250
251static bool rtUriCheckAuthorityStart(const char *pszUri, size_t iStart, size_t cbLen, size_t *piStart)
252{
253 /* The authority have to start with '//' */
254 if ( cbLen >= 2
255 && pszUri[iStart ] == '/'
256 && pszUri[iStart + 1] == '/')
257 {
258 *piStart = iStart + 2;
259 return true;
260 }
261
262 return false;
263}
264
265static bool rtUriFindAuthorityEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
266{
267 /* The authority can end with '/' || '?' || '#'. */
268 size_t i = iStart;
269 while (i < iStart + cbLen)
270 {
271 if ( pszUri[i] == '/'
272 || pszUri[i] == '?'
273 || pszUri[i] == '#')
274 {
275 *piEnd = i;
276 return true;
277 }
278 ++i;
279 }
280 return false;
281}
282
283static bool rtUriCheckPathStart(const char *pszUri, size_t iStart, size_t cbLen, size_t *piStart)
284{
285 /* The path could start with a '/'. */
286 if ( cbLen >= 1
287 && pszUri[iStart] == '/')
288 {
289 *piStart = iStart; /* Including '/' */
290 return true;
291 }
292
293 /* '?' || '#' means there is no path. */
294 if ( cbLen >= 1
295 && ( pszUri[iStart] == '?'
296 || pszUri[iStart] == '#'))
297 return false;
298
299 /* All other values are allowed. */
300 *piStart = iStart;
301 return true;
302}
303
304static bool rtUriFindPathEnd(const char *pszUri, size_t iStart, size_t cbLen, size_t *piEnd)
305{
306 /* The path can end with '?' || '#'. */
307 size_t i = iStart;
308 while (i < iStart + cbLen)
309 {
310 if ( pszUri[i] == '?'
311 || pszUri[i] == '#')
312 {
313 *piEnd = i;
314 return true;
315 }
316 ++i;
317 }
318 return false;
319}
320
321static int rtUriParse(const char *pszUri, PRTURIPARSED pParsed)
322{
323 /*
324 * Validate the input and clear the output.
325 */
326 AssertPtrReturn(pParsed, VERR_INVALID_POINTER);
327 RT_ZERO(*pParsed);
328 pParsed->uAuthorityPort = UINT32_MAX;
329
330 AssertPtrReturn(pszUri, VERR_INVALID_POINTER);
331 size_t const cchUri = strlen(pszUri);
332 if (RT_LIKELY(cchUri >= 3)) { /* likely */ }
333 else return cchUri ? VERR_URI_TOO_SHORT : VERR_URI_EMPTY;
334
335 /*
336 * RFC-3986, section 3.1:
337 * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
338 *
339 * The scheme ends with a ':', which we also skip here.
340 */
341 size_t off = 0;
342 char ch = pszUri[off++];
343 if (RT_LIKELY(RT_C_IS_ALPHA(ch))) { /* likely */ }
344 else return VERR_URI_INVALID_SCHEME;
345 for (;;)
346 {
347 ch = pszUri[off];
348 if (ch == ':')
349 break;
350 if (RT_LIKELY(RT_C_IS_ALNUM(ch) || ch == '.' || ch == '-' || ch == '+')) { /* likely */ }
351 else return VERR_URI_INVALID_SCHEME;
352 off++;
353 }
354 pParsed->cchScheme = off;
355
356 /* Require the scheme length to be at least two chars so we won't confuse
357 it with a path starting with a DOS drive letter specification. */
358 if (RT_LIKELY(off >= 2)) { /* likely */ }
359 else return VERR_URI_INVALID_SCHEME;
360
361 off++; /* (skip colon) */
362
363 /*
364 * Find the end of the path, we'll need this several times.
365 * Also, while we're potentially scanning the whole thing, check for '%'.
366 */
367 size_t const offHash = RTStrOffCharOrTerm(&pszUri[off], '#') + off;
368 size_t const offQuestionMark = RTStrOffCharOrTerm(&pszUri[off], '?') + off;
369
370 if (memchr(pszUri, '%', cchUri) != NULL)
371 pParsed->fFlags |= RTURIPARSED_F_CONTAINS_ESCAPED_CHARS;
372
373 /*
374 * RFC-3986, section 3.2:
375 * The authority component is preceeded by a double slash ("//")...
376 */
377 if ( pszUri[off] == '/'
378 && pszUri[off + 1] == '/')
379 {
380 off += 2;
381 pParsed->offAuthority = pParsed->offAuthorityUsername = pParsed->offAuthorityPassword = pParsed->offAuthorityHost = off;
382 pParsed->fFlags |= RTURIPARSED_F_HAVE_AUTHORITY;
383
384 /*
385 * RFC-3986, section 3.2:
386 * ...and is terminated by the next slash ("/"), question mark ("?"),
387 * or number sign ("#") character, or by the end of the URI.
388 */
389 const char *pszAuthority = &pszUri[off];
390 size_t cchAuthority = RTStrOffCharOrTerm(pszAuthority, '/');
391 cchAuthority = RT_MIN(cchAuthority, offHash - off);
392 cchAuthority = RT_MIN(cchAuthority, offQuestionMark - off);
393 pParsed->cchAuthority = cchAuthority;
394
395 /* The Authority can be empty, like for: file:///usr/bin/grep */
396 if (cchAuthority > 0)
397 {
398 pParsed->cchAuthorityHost = cchAuthority;
399
400 /*
401 * If there is a userinfo part, it is ended by a '@'.
402 */
403 const char *pszAt = (const char *)memchr(pszAuthority, '@', cchAuthority);
404 if (pszAt)
405 {
406 size_t cchTmp = pszAt - pszAuthority;
407 pParsed->offAuthorityHost += cchTmp + 1;
408 pParsed->cchAuthorityHost -= cchTmp + 1;
409
410 /* If there is a password part, it's separated from the username with a colon. */
411 const char *pszColon = (const char *)memchr(pszAuthority, ':', cchTmp);
412 if (pszColon)
413 {
414 pParsed->cchAuthorityUsername = pszColon - pszAuthority;
415 pParsed->offAuthorityPassword = &pszColon[1] - pszUri;
416 pParsed->cchAuthorityPassword = pszAt - &pszColon[1];
417 }
418 else
419 {
420 pParsed->cchAuthorityUsername = cchTmp;
421 pParsed->offAuthorityPassword = off + cchTmp;
422 }
423 }
424
425 /*
426 * If there is a port part, its after the last colon in the host part.
427 */
428 const char *pszColon = (const char *)memrchr(&pszUri[pParsed->offAuthorityHost], ':', pParsed->cchAuthorityHost);
429 if (pszColon)
430 {
431 size_t cchTmp = &pszUri[pParsed->offAuthorityHost + pParsed->cchAuthorityHost] - &pszColon[1];
432 pParsed->cchAuthorityHost -= cchTmp + 1;
433
434 pParsed->uAuthorityPort = 0;
435 while (cchTmp-- > 0)
436 {
437 ch = *++pszColon;
438 if ( RT_C_IS_DIGIT(ch)
439 && pParsed->uAuthorityPort < UINT32_MAX / UINT32_C(10))
440 {
441 pParsed->uAuthorityPort *= 10;
442 pParsed->uAuthorityPort += ch - '0';
443 }
444 else
445 return VERR_URI_INVALID_PORT_NUMBER;
446 }
447 }
448 }
449
450 /* Skip past the authority. */
451 off += cchAuthority;
452 }
453 else
454 pParsed->offAuthority = pParsed->offAuthorityUsername = pParsed->offAuthorityPassword = pParsed->offAuthorityHost = off;
455
456 /*
457 * RFC-3986, section 3.3: Path
458 * The path is terminated by the first question mark ("?")
459 * or number sign ("#") character, or by the end of the URI.
460 */
461 pParsed->offPath = off;
462 pParsed->cchPath = RT_MIN(offHash, offQuestionMark) - off;
463 off += pParsed->cchPath;
464
465 /*
466 * RFC-3986, section 3.4: Query
467 * The query component is indicated by the first question mark ("?")
468 * character and terminated by a number sign ("#") character or by the
469 * end of the URI.
470 */
471 if ( off == offQuestionMark
472 && off < cchUri)
473 {
474 Assert(pszUri[offQuestionMark] == '?');
475 pParsed->offQuery = ++off;
476 pParsed->cchQuery = offHash - off;
477 off = offHash;
478 }
479 else
480 {
481 Assert(!pszUri[offQuestionMark]);
482 pParsed->offQuery = off;
483 }
484
485 /*
486 * RFC-3986, section 3.5: Fragment
487 * A fragment identifier component is indicated by the presence of a
488 * number sign ("#") character and terminated by the end of the URI.
489 */
490 if ( off == offHash
491 && off < cchUri)
492 {
493 pParsed->offFragment = ++off;
494 pParsed->cchFragment = cchUri - off;
495 }
496 else
497 {
498 Assert(!pszUri[offHash]);
499 pParsed->offFragment = off;
500 }
501
502 return VINF_SUCCESS;
503}
504
505
506/*********************************************************************************************************************************
507* Generic URI APIs *
508*********************************************************************************************************************************/
509
510RTR3DECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery,
511 const char *pszFragment)
512{
513 if (!pszScheme) /* Scheme is minimum requirement */
514 return NULL;
515
516 char *pszResult = 0;
517 char *pszAuthority1 = 0;
518 char *pszPath1 = 0;
519 char *pszQuery1 = 0;
520 char *pszFragment1 = 0;
521
522 do
523 {
524 /* Create the percent encoded strings and calculate the necessary uri
525 * length. */
526 size_t cbSize = strlen(pszScheme) + 1 + 1; /* plus zero byte */
527 if (pszAuthority)
528 {
529 pszAuthority1 = rtUriPercentEncodeN(pszAuthority, RTSTR_MAX);
530 if (!pszAuthority1)
531 break;
532 cbSize += strlen(pszAuthority1) + 2;
533 }
534 if (pszPath)
535 {
536 pszPath1 = rtUriPercentEncodeN(pszPath, RTSTR_MAX);
537 if (!pszPath1)
538 break;
539 cbSize += strlen(pszPath1);
540 }
541 if (pszQuery)
542 {
543 pszQuery1 = rtUriPercentEncodeN(pszQuery, RTSTR_MAX);
544 if (!pszQuery1)
545 break;
546 cbSize += strlen(pszQuery1) + 1;
547 }
548 if (pszFragment)
549 {
550 pszFragment1 = rtUriPercentEncodeN(pszFragment, RTSTR_MAX);
551 if (!pszFragment1)
552 break;
553 cbSize += strlen(pszFragment1) + 1;
554 }
555
556 char *pszTmp = pszResult = (char *)RTStrAlloc(cbSize);
557 if (!pszResult)
558 break;
559 RT_BZERO(pszTmp, cbSize);
560
561 /* Compose the target uri string. */
562 RTStrCatP(&pszTmp, &cbSize, pszScheme);
563 RTStrCatP(&pszTmp, &cbSize, ":");
564 if (pszAuthority1)
565 {
566 RTStrCatP(&pszTmp, &cbSize, "//");
567 RTStrCatP(&pszTmp, &cbSize, pszAuthority1);
568 }
569 if (pszPath1)
570 {
571 RTStrCatP(&pszTmp, &cbSize, pszPath1);
572 }
573 if (pszQuery1)
574 {
575 RTStrCatP(&pszTmp, &cbSize, "?");
576 RTStrCatP(&pszTmp, &cbSize, pszQuery1);
577 }
578 if (pszFragment1)
579 {
580 RTStrCatP(&pszTmp, &cbSize, "#");
581 RTStrCatP(&pszTmp, &cbSize, pszFragment1);
582 }
583 } while (0);
584
585 /* Cleanup */
586 if (pszAuthority1)
587 RTStrFree(pszAuthority1);
588 if (pszPath1)
589 RTStrFree(pszPath1);
590 if (pszQuery1)
591 RTStrFree(pszQuery1);
592 if (pszFragment1)
593 RTStrFree(pszFragment1);
594
595 return pszResult;
596}
597
598RTR3DECL(bool) RTUriHasScheme(const char *pszUri, const char *pszScheme)
599{
600 bool fRes = false;
601 char *pszTmp = RTUriScheme(pszUri);
602 if (pszTmp)
603 {
604 fRes = RTStrNICmp(pszScheme, pszTmp, strlen(pszTmp)) == 0;
605 RTStrFree(pszTmp);
606 }
607 return fRes;
608}
609
610RTR3DECL(char *) RTUriScheme(const char *pszUri)
611{
612 AssertPtrReturn(pszUri, NULL);
613
614 size_t iPos1;
615 size_t cbLen = strlen(pszUri);
616 if (rtUriFindSchemeEnd(pszUri, 0, cbLen, &iPos1))
617 return rtUriPercentDecodeN(pszUri, iPos1);
618 return NULL;
619}
620
621RTR3DECL(char *) RTUriAuthority(const char *pszUri)
622{
623 RTURIPARSED Parsed;
624 int rc = rtUriParse(pszUri, &Parsed);
625 if (RT_SUCCESS(rc))
626 if (Parsed.cchAuthority || (Parsed.fFlags & RTURIPARSED_F_HAVE_AUTHORITY))
627 return rtUriPercentDecodeN(&pszUri[Parsed.offAuthority], Parsed.cchAuthority);
628 return NULL;
629}
630
631RTR3DECL(char *) RTUriAuthorityUsername(const char *pszUri)
632{
633 RTURIPARSED Parsed;
634 int rc = rtUriParse(pszUri, &Parsed);
635 if (RT_SUCCESS(rc))
636 if (Parsed.cchAuthorityUsername)
637 return rtUriPercentDecodeN(&pszUri[Parsed.offAuthorityUsername], Parsed.cchAuthorityUsername);
638 return NULL;
639}
640
641RTR3DECL(char *) RTUriAuthorityPassword(const char *pszUri)
642{
643 RTURIPARSED Parsed;
644 int rc = rtUriParse(pszUri, &Parsed);
645 if (RT_SUCCESS(rc))
646 if (Parsed.cchAuthorityPassword)
647 return rtUriPercentDecodeN(&pszUri[Parsed.offAuthorityPassword], Parsed.cchAuthorityPassword);
648 return NULL;
649}
650
651RTR3DECL(uint32_t) RTUriAuthorityPort(const char *pszUri)
652{
653 RTURIPARSED Parsed;
654 int rc = rtUriParse(pszUri, &Parsed);
655 if (RT_SUCCESS(rc))
656 return Parsed.uAuthorityPort;
657 return UINT32_MAX;
658}
659
660RTR3DECL(char *) RTUriPath(const char *pszUri)
661{
662 RTURIPARSED Parsed;
663 int rc = rtUriParse(pszUri, &Parsed);
664 if (RT_SUCCESS(rc))
665 if (Parsed.cchPath)
666 return rtUriPercentDecodeN(&pszUri[Parsed.offPath], Parsed.cchPath);
667 return NULL;
668}
669
670RTR3DECL(char *) RTUriQuery(const char *pszUri)
671{
672 RTURIPARSED Parsed;
673 int rc = rtUriParse(pszUri, &Parsed);
674 if (RT_SUCCESS(rc))
675 if (Parsed.cchQuery)
676 return rtUriPercentDecodeN(&pszUri[Parsed.offQuery], Parsed.cchQuery);
677 return NULL;
678}
679
680RTR3DECL(char *) RTUriFragment(const char *pszUri)
681{
682 RTURIPARSED Parsed;
683 int rc = rtUriParse(pszUri, &Parsed);
684 if (RT_SUCCESS(rc))
685 if (Parsed.cchFragment)
686 return rtUriPercentDecodeN(&pszUri[Parsed.offFragment], Parsed.cchFragment);
687 return NULL;
688}
689
690
691/*********************************************************************************************************************************
692* File URI APIs *
693*********************************************************************************************************************************/
694
695RTR3DECL(char *) RTUriFileCreate(const char *pszPath)
696{
697 char *pszResult = NULL;
698 if (pszPath)
699 {
700 /* Create the percent encoded strings and calculate the necessary uri length. */
701 char *pszPath1 = rtUriPercentEncodeN(pszPath, RTSTR_MAX);
702 if (pszPath1)
703 {
704 size_t cbSize = 7 /* file:// */ + strlen(pszPath1) + 1; /* plus zero byte */
705 if (pszPath1[0] != '/')
706 ++cbSize;
707 char *pszTmp = pszResult = RTStrAlloc(cbSize);
708 if (pszResult)
709 {
710 /* Compose the target uri string. */
711 *pszTmp = '\0';
712 RTStrCatP(&pszTmp, &cbSize, "file://");
713 if (pszPath1[0] != '/')
714 RTStrCatP(&pszTmp, &cbSize, "/");
715 RTStrCatP(&pszTmp, &cbSize, pszPath1);
716 }
717 RTStrFree(pszPath1);
718 }
719 }
720 return pszResult;
721}
722
723RTR3DECL(char *) RTUriFilePath(const char *pszUri, uint32_t uFormat)
724{
725 return RTUriFileNPath(pszUri, uFormat, RTSTR_MAX);
726}
727
728RTR3DECL(char *) RTUriFileNPath(const char *pszUri, uint32_t uFormat, size_t cchMax)
729{
730 AssertPtrReturn(pszUri, NULL);
731 AssertReturn(uFormat == URI_FILE_FORMAT_AUTO || uFormat == URI_FILE_FORMAT_UNIX || uFormat == URI_FILE_FORMAT_WIN, NULL);
732
733 /* Auto is based on the current OS. */
734 if (uFormat == URI_FILE_FORMAT_AUTO)
735#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
736 uFormat = URI_FILE_FORMAT_WIN;
737#else
738 uFormat = URI_FILE_FORMAT_UNIX;
739#endif
740
741 /* Check that this is a file Uri */
742 if (RTStrNICmp(pszUri, RT_STR_TUPLE("file:")) != 0)
743 return NULL;
744
745 RTURIPARSED Parsed;
746 int rc = rtUriParse(pszUri, &Parsed);
747 if (RT_SUCCESS(rc) && Parsed.cchPath)
748 {
749 /* Special hack for DOS path like file:///c:/WINDOWS/clock.avi where we
750 have to drop the leading slash that was used to separate the authority
751 from the path. */
752 if ( uFormat == URI_FILE_FORMAT_WIN
753 && Parsed.cchPath >= 3
754 && pszUri[Parsed.offPath] == '/'
755 && pszUri[Parsed.offPath + 2] == ':'
756 && RT_C_IS_ALPHA(pszUri[Parsed.offPath + 1]) )
757 {
758 Parsed.offPath++;
759 Parsed.cchPath--;
760 }
761
762 char *pszPath = rtUriPercentDecodeN(&pszUri[Parsed.offPath], Parsed.cchPath);
763 if (uFormat == URI_FILE_FORMAT_UNIX)
764 return RTPathChangeToUnixSlashes(pszPath, true);
765 Assert(uFormat == URI_FILE_FORMAT_WIN);
766 return RTPathChangeToDosSlashes(pszPath, true);
767 }
768 return NULL;
769}
770
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette