int rtPathFromNative(const char **ppszPath, const char *pszNativePath, const char *pszBasePath) { *ppszPath = NULL; int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL); if (RT_SUCCESS(rc)) { if (g_fPassthruUtf8 || !*pszNativePath) { size_t cCpsIgnored; size_t cchNativePath; rc = rtUtf8Length(pszNativePath, RTSTR_MAX, &cCpsIgnored, &cchNativePath); if (RT_SUCCESS(rc)) { char *pszPath; *ppszPath = pszPath = RTStrAlloc(cchNativePath + 1); if (pszPath) memcpy(pszPath, pszNativePath, cchNativePath + 1); else rc = VERR_NO_STR_MEMORY; } } else rc = rtStrConvert(pszNativePath, strlen(pszNativePath), g_szFsCodeset, (char **)ppszPath, 0, "UTF-8", 2, g_enmFsToUtf8Idx); } NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */ return rc; }
RTR3DECL(int) RTManifestWriteFilesBuf(void **ppvBuf, size_t *pcbSize, RTDIGESTTYPE enmDigestType, PRTMANIFESTTEST paFiles, size_t cFiles) { /* Validate input */ AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER); AssertPtrReturn(pcbSize, VERR_INVALID_POINTER); AssertPtrReturn(paFiles, VERR_INVALID_POINTER); AssertReturn(cFiles > 0, VERR_INVALID_PARAMETER); const char *pcszDigestType; switch (enmDigestType) { case RTDIGESTTYPE_CRC32: pcszDigestType = "CRC32"; break; case RTDIGESTTYPE_CRC64: pcszDigestType = "CRC64"; break; case RTDIGESTTYPE_MD5: pcszDigestType = "MD5"; break; case RTDIGESTTYPE_SHA1: pcszDigestType = "SHA1"; break; case RTDIGESTTYPE_SHA256: pcszDigestType = "SHA256"; break; default: return VERR_INVALID_PARAMETER; } /* Calculate the size necessary for the memory buffer. */ size_t cbSize = 0; size_t cbMaxSize = 0; for (size_t i = 0; i < cFiles; ++i) { size_t cbTmp = strlen(RTPathFilename(paFiles[i].pszTestFile)) + strlen(paFiles[i].pszTestDigest) + strlen(pcszDigestType) + 6; cbMaxSize = RT_MAX(cbMaxSize, cbTmp); cbSize += cbTmp; } /* Create the memory buffer */ void *pvBuf = RTMemAlloc(cbSize); if (!pvBuf) return VERR_NO_MEMORY; /* Allocate a temporary string buffer. */ char *pszTmp = RTStrAlloc(cbMaxSize + 1); if (!pszTmp) { RTMemFree(pvBuf); return VERR_NO_MEMORY; } size_t cbPos = 0; for (size_t i = 0; i < cFiles; ++i) { size_t cch = RTStrPrintf(pszTmp, cbMaxSize + 1, "%s (%s)= %s\n", pcszDigestType, RTPathFilename(paFiles[i].pszTestFile), paFiles[i].pszTestDigest); memcpy(&((char*)pvBuf)[cbPos], pszTmp, cch); cbPos += cch; } RTStrFree(pszTmp); /* Results */ *ppvBuf = pvBuf; *pcbSize = cbSize; return VINF_SUCCESS; }
RTR3DECL(int) RTProcQueryUsernameA(RTPROCESS hProcess, char **ppszUser) { /* * Validation. */ AssertPtrReturn(ppszUser, VERR_INVALID_POINTER); int rc = VINF_SUCCESS; size_t cbUser = 0; rc = RTProcQueryUsername(hProcess, NULL, cbUser, &cbUser); if (rc == VERR_BUFFER_OVERFLOW) { char *pszUser = (char *)RTStrAlloc(cbUser); if (pszUser) { rc = RTProcQueryUsername(hProcess, pszUser, cbUser, NULL); Assert(rc != VERR_BUFFER_OVERFLOW); if (RT_SUCCESS(rc)) *ppszUser = pszUser; else RTStrFree(pszUser); } else rc = VERR_NO_STR_MEMORY; } return rc; }
/** * A variant of Utf8Str::copyFromN that does not throw any exceptions but * returns E_OUTOFMEMORY instead. * * @param a_pcszSrc The source string. * @param a_offSrc Start offset to copy from. * @param a_cchSrc The source string. * @returns S_OK or E_OUTOFMEMORY. * * @remarks This calls cleanup() first, so the caller doesn't have to. (Saves * code space.) */ HRESULT Utf8Str::copyFromExNComRC(const char *a_pcszSrc, size_t a_offSrc, size_t a_cchSrc) { cleanup(); if (a_cchSrc) { m_psz = RTStrAlloc(a_cchSrc + 1); if (RT_LIKELY(m_psz)) { m_cch = a_cchSrc; m_cbAllocated = a_cchSrc + 1; memcpy(m_psz, a_pcszSrc + a_offSrc, a_cchSrc); m_psz[a_cchSrc] = '\0'; } else { m_cch = 0; m_cbAllocated = 0; return E_OUTOFMEMORY; } } else { m_cch = 0; m_cbAllocated = 0; m_psz = NULL; } return S_OK; }
static char *rtUriPercentEncodeN(const char *pszString, size_t cchMax) { if (!pszString) return NULL; int rc = VINF_SUCCESS; size_t cbLen = RT_MIN(strlen(pszString), cchMax); /* The new string can be max 3 times in size of the original string. */ char *pszNew = RTStrAlloc(cbLen * 3 + 1); if (!pszNew) return NULL; char *pszRes = NULL; size_t iIn = 0; size_t iOut = 0; while (iIn < cbLen) { if (URI_EXCLUDED(pszString[iIn])) { char szNum[3] = { 0, 0, 0 }; RTStrFormatU8(&szNum[0], 3, pszString[iIn++], 16, 2, 2, RTSTR_F_CAPITAL | RTSTR_F_ZEROPAD); pszNew[iOut++] = '%'; pszNew[iOut++] = szNum[0]; pszNew[iOut++] = szNum[1]; } else pszNew[iOut++] = pszString[iIn++]; } if (RT_SUCCESS(rc)) { pszNew[iOut] = '\0'; if (iOut != iIn) { /* If the source and target strings have different size, recreate * the target string with the correct size. */ pszRes = RTStrDupN(pszNew, iOut); RTStrFree(pszNew); } else pszRes = pszNew; } else RTStrFree(pszNew); return pszRes; }
RTR3DECL(int) RTManifestWriteFilesBuf(void **ppvBuf, size_t *pcbSize, PRTMANIFESTTEST paFiles, size_t cFiles) { /* Validate input */ AssertPtrReturn(ppvBuf, VERR_INVALID_POINTER); AssertPtrReturn(pcbSize, VERR_INVALID_POINTER); AssertPtrReturn(paFiles, VERR_INVALID_POINTER); AssertReturn(cFiles > 0, VERR_INVALID_PARAMETER); /* Calculate the size necessary for the memory buffer. */ size_t cbSize = 0; size_t cbMaxSize = 0; for (size_t i = 0; i < cFiles; ++i) { size_t cbTmp = strlen(RTPathFilename(paFiles[i].pszTestFile)) + strlen(paFiles[i].pszTestDigest) + 10; cbMaxSize = RT_MAX(cbMaxSize, cbTmp); cbSize += cbTmp; } /* Create the memory buffer */ void *pvBuf = RTMemAlloc(cbSize); if (!pvBuf) return VERR_NO_MEMORY; /* Allocate a temporary string buffer. */ char * pszTmp = RTStrAlloc(cbMaxSize + 1); size_t cbPos = 0; for (size_t i = 0; i < cFiles; ++i) { size_t cch = RTStrPrintf(pszTmp, cbMaxSize + 1, "SHA1 (%s)= %s\n", RTPathFilename(paFiles[i].pszTestFile), paFiles[i].pszTestDigest); memcpy(&((char*)pvBuf)[cbPos], pszTmp, cch); cbPos += cch; } RTStrFree(pszTmp); /* Results */ *ppvBuf = pvBuf; *pcbSize = cbSize; return VINF_SUCCESS; }
/** * Basic API checks. * We'll return if any of these fails. */ static void tst1(void) { RTTestISub("Basics"); char *psz; int rc = VINF_SUCCESS; /* RTStrAlloc */ RTTESTI_CHECK(psz = RTStrAlloc(0)); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrAlloc(1)); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrAlloc(128)); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); /* RTStrAllocEx */ psz = (char*)"asdfasdf"; RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 1), VINF_SUCCESS); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 128), VINF_SUCCESS); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); /* RTStrRealloc */ psz = NULL; RTTESTI_CHECK_RC(RTStrRealloc(&psz, 10), VINF_SUCCESS); RTTESTI_CHECK(psz && !psz[0]); RTTESTI_CHECK(psz && !psz[9]); RTStrFree(psz); psz = NULL; RTTESTI_CHECK_RC(RTStrRealloc(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!psz); psz = NULL; RTTESTI_CHECK_RC(RTStrRealloc(&psz, 128), VINF_SUCCESS); RTTESTI_CHECK(psz && !psz[0]); RTTESTI_CHECK(psz && !psz[127]); if (psz) { memset(psz, 'a', 127); RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 160), VINF_SUCCESS); if (RT_SUCCESS(rc) && psz) { RTTESTI_CHECK(!psz[127]); RTTESTI_CHECK(!psz[159]); RTTESTI_CHECK(ASMMemIsAll8(psz, 127, 'a') == NULL); memset(psz, 'b', 159); RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 79), VINF_SUCCESS); if (RT_SUCCESS(rc)) { RTTESTI_CHECK(!psz[78]); RTTESTI_CHECK(ASMMemIsAll8(psz, 78, 'b') == NULL); RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!psz); } } } RTStrFree(psz); /* RTStrDup */ RTTESTI_CHECK(psz = RTStrDup("")); RTTESTI_CHECK(psz && *psz == '\0'); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("abcdefghijklmnop")); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnop")); RTStrFree(psz); /* RTStrDupEx */ psz = NULL; RTTESTI_CHECK_RC(RTStrDupEx(&psz, ""), VINF_SUCCESS); RTTESTI_CHECK(RT_FAILURE(rc) || *psz == '\0'); if (RT_SUCCESS(rc)) RTStrFree(psz); psz = (char*)"asdfasdfasdfasdf"; RTTESTI_CHECK_RC(rc = RTStrDupEx(&psz, "abcdefghijklmnop"), VINF_SUCCESS); RTTESTI_CHECK(RT_FAILURE(rc) || !RTStrCmp(psz, "abcdefghijklmnop")); if (RT_SUCCESS(rc)) RTStrFree(psz); /* RTStrDupN */ RTTESTI_CHECK(psz = RTStrDupN("abcdefg", 3)); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDupN("abc", 100000)); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDupN("abc", 0)); RTTESTI_CHECK(psz && *psz == '\0'); RTStrFree(psz); /* RTStrAAppend */ RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppend(&psz, "def"), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdef")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppend(&psz, ""), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppend(&psz, NULL), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); psz = NULL; RTTESTI_CHECK_RC(RTStrAAppend(&psz, "xyz"), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "xyz")); RTStrFree(psz); /* RTStrAAppendN */ RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "def", 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcd")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "", 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "", RTSTR_MAX), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, NULL, 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); psz = NULL; RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "abc", 2), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "ab")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "cdefghijklm", 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "defghijklm", RTSTR_MAX), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklm")); RTStrFree(psz); /* RTStrAAppendExN / RTStrAAppendExNV */ psz = NULL; RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 5, "a", (size_t)1, "bc", (size_t)1, "cdefg", RTSTR_MAX, "hijkl", (size_t)2, "jklmnopqrstuvwxyz", RTSTR_MAX), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 2, NULL, (size_t)0, "", (size_t)0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 1, "-", (size_t)1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz-")); RTStrFree(psz); /* RTStrATruncate */ psz = NULL; RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!psz); RTTESTI_CHECK(psz = RTStrDup("")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("1234567890")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 5), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "12345")); RTStrFree(psz); psz = NULL; for (uint32_t i = 0; i < 128; i++) RTTESTI_CHECK_RC_RETV(RTStrAAppend(&psz, "abcdefghijklmnopqrstuvwxyz"), VINF_SUCCESS); RTTESTI_CHECK_RC(RTStrATruncate(&psz, sizeof("abcdefghijklmnopqrstuvwxyz") - 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 6), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdef")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "a")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "")); RTStrFree(psz); }
RTDECL(int) RTGetOptArgvToString(char **ppszCmdLine, const char * const *papszArgv, uint32_t fFlags) { AssertReturn(!(fFlags & ~RTGETOPTARGV_CNV_QUOTE_MASK), VERR_INVALID_PARAMETER); #define PUT_CH(ch) \ if (RT_UNLIKELY(off + 1 >= cbCmdLineAlloc)) { \ rc = rtGetOptArgvToStringGrow(&pszCmdLine, &cbCmdLineAlloc, 1); \ if (RT_FAILURE(rc)) \ break; \ } \ pszCmdLine[off++] = (ch) #define PUT_PSZ(psz, cch) \ if (RT_UNLIKELY(off + (cch) >= cbCmdLineAlloc)) { \ rc = rtGetOptArgvToStringGrow(&pszCmdLine, &cbCmdLineAlloc, (cch)); \ if (RT_FAILURE(rc)) \ break; \ } \ memcpy(&pszCmdLine[off], (psz), (cch)); \ off += (cch); #define PUT_SZ(sz) PUT_PSZ(sz, sizeof(sz) - 1) /* * Take the realloc approach, it requires less code and is probably more * efficient than figuring out the size first. */ int rc = VINF_SUCCESS; size_t off = 0; size_t cbCmdLineAlloc = 256; char *pszCmdLine = RTStrAlloc(256); if (!pszCmdLine) return VERR_NO_STR_MEMORY; for (size_t i = 0; papszArgv[i]; i++) { if (i > 0) { PUT_CH(' '); } /* does it need quoting? */ const char *pszArg = papszArgv[i]; size_t cchArg; if (!rtGetOpArgvRequiresQuoting(pszArg, fFlags, &cchArg)) { /* No quoting needed, just append the argument. */ PUT_PSZ(pszArg, cchArg); } else if ((fFlags & RTGETOPTARGV_CNV_QUOTE_MASK) == RTGETOPTARGV_CNV_QUOTE_MS_CRT) { /* * Microsoft CRT quoting. Quote the whole argument in double * quotes to make it easier to read and code. */ PUT_CH('"'); char ch; while ((ch = *pszArg++)) { if ( ch == '\\' && rtGetOptArgvMsCrtIsSlashQuote(pszArg)) { PUT_SZ("\\\\"); } else if (ch == '"') { PUT_SZ("\\\""); } else { PUT_CH(ch); } } PUT_CH('"'); } else { /* * Bourne Shell quoting. Quote the whole thing in single quotes * and use double quotes for any single quote chars. */ PUT_CH('\''); char ch; while ((ch = *pszArg++)) { if (ch == '\'') { PUT_SZ("'\"'\"'"); } else { PUT_CH(ch); } } PUT_CH('\''); } } /* Set return value / cleanup. */ if (RT_SUCCESS(rc)) { pszCmdLine[off] = '\0'; *ppszCmdLine = pszCmdLine; } else RTStrFree(pszCmdLine); #undef PUT_SZ #undef PUT_PSZ #undef PUT_CH return rc; }
RTDECL(int) RTUriFilePathEx(const char *pszUri, uint32_t fPathStyle, char **ppszPath, size_t cbPath, size_t *pcchPath) { /* * Validate and adjust input. */ if (pcchPath) { AssertPtrReturn(pcchPath, VERR_INVALID_POINTER); *pcchPath = ~(size_t)0; } AssertPtrReturn(ppszPath, VERR_INVALID_POINTER); AssertReturn(!(fPathStyle & ~RTPATH_STR_F_STYLE_MASK) && fPathStyle != RTPATH_STR_F_STYLE_RESERVED, VERR_INVALID_FLAGS); if (fPathStyle == RTPATH_STR_F_STYLE_HOST) fPathStyle = RTPATH_STYLE; AssertPtrReturn(pszUri, VERR_INVALID_POINTER); /* * Check that this is a file URI. */ if (RTStrNICmp(pszUri, RT_STR_TUPLE("file:")) == 0) { /* likely */ } else return VERR_URI_NOT_FILE_SCHEME; /* * We may have a number of variations here, mostly thanks to * various windows software. First the canonical variations: * - file:///C:/Windows/System32/kernel32.dll * - file:///C|/Windows/System32/kernel32.dll * - file:///C:%5CWindows%5CSystem32%5Ckernel32.dll * - file://localhost/C:%5CWindows%5CSystem32%5Ckernel32.dll * - file://cifsserver.dev/systemshare%5CWindows%5CSystem32%5Ckernel32.dll * - file://cifsserver.dev:139/systemshare%5CWindows%5CSystem32%5Ckernel32.dll (not quite sure here, but whatever) * * Legacy variant without any slashes after the schema: * - file:C:/Windows/System32/kernel32.dll * - file:C|/Windows/System32%5Ckernel32.dll * - file:~/.bashrc * \--path-/ * * Legacy variant with exactly one slashes after the schema: * - file:/C:/Windows/System32%5Ckernel32.dll * - file:/C|/Windows/System32/kernel32.dll * - file:/usr/bin/env * \---path---/ * * Legacy variant with two slashes after the schema and an unescaped DOS path: * - file://C:/Windows/System32\kernel32.dll (**) * - file://C|/Windows/System32\kernel32.dll * \---path---------------------/ * -- authority, with ':' as non-working port separator * * Legacy variant with exactly four slashes after the schema and an unescaped DOS path. * - file:////C:/Windows\System32\user32.dll * * Legacy variant with four or more slashes after the schema and an unescaped UNC path: * - file:////cifsserver.dev/systemshare/System32%\kernel32.dll * - file://///cifsserver.dev/systemshare/System32\kernel32.dll * \---path--------------------------------------------/ * * The the two unescaped variants shouldn't be handed to rtUriParse, which * is good as we cannot actually handle the one marked by (**). So, handle * those two special when parsing. */ RTURIPARSED Parsed; int rc; size_t cSlashes = 0; while (pszUri[5 + cSlashes] == '/') cSlashes++; if ( (cSlashes == 2 || cSlashes == 4) && RT_C_IS_ALPHA(pszUri[5 + cSlashes]) && (pszUri[5 + cSlashes + 1] == ':' || pszUri[5 + cSlashes + 1] == '|')) { RT_ZERO(Parsed); /* RTURIPARSED_F_CONTAINS_ESCAPED_CHARS is now clear. */ Parsed.offPath = 5 + cSlashes; Parsed.cchPath = strlen(&pszUri[Parsed.offPath]); rc = RTStrValidateEncoding(&pszUri[Parsed.offPath]); } else if (cSlashes >= 4) { RT_ZERO(Parsed); Parsed.fFlags = cSlashes > 4 ? RTURIPARSED_F_CONTAINS_ESCAPED_CHARS : 0; Parsed.offPath = 5 + cSlashes - 2; Parsed.cchPath = strlen(&pszUri[Parsed.offPath]); rc = RTStrValidateEncoding(&pszUri[Parsed.offPath]); } else rc = rtUriParse(pszUri, &Parsed); if (RT_SUCCESS(rc)) { /* * Ignore localhost as hostname (it's implicit). */ static char const s_szLocalhost[] = "localhost"; if ( Parsed.cchAuthorityHost == sizeof(s_szLocalhost) - 1U && RTStrNICmp(&pszUri[Parsed.offAuthorityHost], RT_STR_TUPLE(s_szLocalhost)) == 0) { Parsed.cchAuthorityHost = 0; Parsed.cchAuthority = 0; } /* * Ignore leading path slash/separator if we detect a DOS drive letter * and we don't have a host name. */ if ( Parsed.cchPath >= 3 && Parsed.cchAuthorityHost == 0 && pszUri[Parsed.offPath] == '/' /* Leading path slash/separator. */ && ( pszUri[Parsed.offPath + 2] == ':' /* Colon after drive letter. */ || pszUri[Parsed.offPath + 2] == '|') /* Colon alternative. */ && RT_C_IS_ALPHA(pszUri[Parsed.offPath + 1]) ) /* Drive letter. */ { Parsed.offPath++; Parsed.cchPath--; } /* * Calculate the size of the encoded result. * * Since we're happily returning "C:/Windows/System32/kernel.dll" * style paths when the caller requested UNIX style paths, we will * return straight UNC paths too ("//cifsserver/share/dir/file"). */ size_t cchDecodedHost = 0; size_t cbResult; if (Parsed.fFlags & RTURIPARSED_F_CONTAINS_ESCAPED_CHARS) { cchDecodedHost = rtUriCalcDecodedLength(&pszUri[Parsed.offAuthorityHost], Parsed.cchAuthorityHost); cbResult = cchDecodedHost + rtUriCalcDecodedLength(&pszUri[Parsed.offPath], Parsed.cchPath) + 1; } else { cchDecodedHost = 0; cbResult = Parsed.cchAuthorityHost + Parsed.cchPath + 1; } if (pcchPath) *pcchPath = cbResult - 1; if (cbResult > 1) { /* * Prepare the necessary buffer space for the result. */ char *pszDst; char *pszFreeMe = NULL; if (!cbPath || *ppszPath == NULL) { cbPath = RT_MAX(cbPath, cbResult); *ppszPath = pszFreeMe = pszDst = RTStrAlloc(cbPath); AssertReturn(pszDst, VERR_NO_STR_MEMORY); } else if (cbResult <= cbPath) pszDst = *ppszPath; else return VERR_BUFFER_OVERFLOW; /* * Compose the result. */ if (Parsed.fFlags & RTURIPARSED_F_CONTAINS_ESCAPED_CHARS) { rc = rtUriDecodeIntoBuffer(&pszUri[Parsed.offAuthorityHost],Parsed.cchAuthorityHost, pszDst, cchDecodedHost + 1); Assert(RT_SUCCESS(rc) && strlen(pszDst) == cchDecodedHost); if (RT_SUCCESS(rc)) rc = rtUriDecodeIntoBuffer(&pszUri[Parsed.offPath], Parsed.cchPath, &pszDst[cchDecodedHost], cbResult - cchDecodedHost); Assert(RT_SUCCESS(rc) && strlen(pszDst) == cbResult - 1); } else { memcpy(pszDst, &pszUri[Parsed.offAuthorityHost], Parsed.cchAuthorityHost); memcpy(&pszDst[Parsed.cchAuthorityHost], &pszUri[Parsed.offPath], Parsed.cchPath); pszDst[cbResult - 1] = '\0'; } if (RT_SUCCESS(rc)) { /* * Convert colon DOS driver letter colon alternative. * We do this regardless of the desired path style. */ if ( RT_C_IS_ALPHA(pszDst[0]) && pszDst[1] == '|') pszDst[1] = ':'; /* * Fix slashes. */ if (fPathStyle == RTPATH_STR_F_STYLE_DOS) RTPathChangeToDosSlashes(pszDst, true); else if (fPathStyle == RTPATH_STR_F_STYLE_UNIX) RTPathChangeToUnixSlashes(pszDst, true); /** @todo not quite sure how this actually makes sense... */ else AssertFailed(); return rc; } /* bail out */ RTStrFree(pszFreeMe); } else rc = VERR_PATH_ZERO_LENGTH; } return rc; }
RTDECL(int) RTUriFileCreateEx(const char *pszPath, uint32_t fPathStyle, char **ppszUri, size_t cbUri, size_t *pcchUri) { /* * Validate and adjust input. (RTPathParse check pszPath out for us) */ if (pcchUri) { AssertPtrReturn(pcchUri, VERR_INVALID_POINTER); *pcchUri = ~(size_t)0; } AssertPtrReturn(ppszUri, VERR_INVALID_POINTER); AssertReturn(!(fPathStyle & ~RTPATH_STR_F_STYLE_MASK) && fPathStyle != RTPATH_STR_F_STYLE_RESERVED, VERR_INVALID_FLAGS); if (fPathStyle == RTPATH_STR_F_STYLE_HOST) fPathStyle = RTPATH_STYLE; /* * Let the RTPath code parse the stuff (no reason to duplicate path parsing * and get it slightly wrong here). */ RTPATHPARSED ParsedPath; int rc = RTPathParse(pszPath, &ParsedPath, sizeof(ParsedPath), fPathStyle); if (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW) { /* Skip leading slashes. */ if (ParsedPath.fProps & RTPATH_PROP_ROOT_SLASH) { if (fPathStyle == RTPATH_STR_F_STYLE_DOS) while (pszPath[0] == '/' || pszPath[0] == '\\') pszPath++; else while (pszPath[0] == '/') pszPath++; } const size_t cchPath = strlen(pszPath); /* * Calculate the encoded length and figure destination buffering. */ static const char s_szPrefix[] = "file:///"; size_t const cchPrefix = sizeof(s_szPrefix) - (ParsedPath.fProps & RTPATH_PROP_UNC ? 2 : 1); size_t cchEncoded = rtUriCalcEncodedLength(pszPath, cchPath, fPathStyle != RTPATH_STR_F_STYLE_DOS); if (pcchUri) *pcchUri = cchEncoded; char *pszDst; char *pszFreeMe = NULL; if (!cbUri || *ppszUri == NULL) { cbUri = RT_MAX(cbUri, cchPrefix + cchEncoded + 1); *ppszUri = pszFreeMe = pszDst = RTStrAlloc(cbUri); AssertReturn(pszDst, VERR_NO_STR_MEMORY); } else if (cchEncoded < cbUri) pszDst = *ppszUri; else return VERR_BUFFER_OVERFLOW; /* * Construct the URI. */ memcpy(pszDst, s_szPrefix, cchPrefix); pszDst[cchPrefix] = '\0'; rc = rtUriEncodeIntoBuffer(pszPath, cchPath, fPathStyle != RTPATH_STR_F_STYLE_DOS, &pszDst[cchPrefix], cbUri - cchPrefix); if (RT_SUCCESS(rc)) { Assert(strlen(pszDst) == cbUri - 1); if (fPathStyle == RTPATH_STR_F_STYLE_DOS) RTPathChangeToUnixSlashes(pszDst, true /*fForce*/); return VINF_SUCCESS; } AssertRC(rc); /* Impossible! rtUriCalcEncodedLength or something above is busted! */ if (pszFreeMe) RTStrFree(pszFreeMe); } return rc; }
RTDECL(char *) RTUriCreate(const char *pszScheme, const char *pszAuthority, const char *pszPath, const char *pszQuery, const char *pszFragment) { if (!pszScheme) /* Scheme is minimum requirement */ return NULL; char *pszResult = 0; char *pszAuthority1 = 0; char *pszPath1 = 0; char *pszQuery1 = 0; char *pszFragment1 = 0; do { /* Create the percent encoded strings and calculate the necessary uri * length. */ size_t cbSize = strlen(pszScheme) + 1 + 1; /* plus zero byte */ if (pszAuthority) { pszAuthority1 = rtUriPercentEncodeN(pszAuthority, RTSTR_MAX); if (!pszAuthority1) break; cbSize += strlen(pszAuthority1) + 2; } if (pszPath) { pszPath1 = rtUriPercentEncodeN(pszPath, RTSTR_MAX); if (!pszPath1) break; cbSize += strlen(pszPath1); } if (pszQuery) { pszQuery1 = rtUriPercentEncodeN(pszQuery, RTSTR_MAX); if (!pszQuery1) break; cbSize += strlen(pszQuery1) + 1; } if (pszFragment) { pszFragment1 = rtUriPercentEncodeN(pszFragment, RTSTR_MAX); if (!pszFragment1) break; cbSize += strlen(pszFragment1) + 1; } char *pszTmp = pszResult = (char *)RTStrAlloc(cbSize); if (!pszResult) break; RT_BZERO(pszTmp, cbSize); /* Compose the target uri string. */ RTStrCatP(&pszTmp, &cbSize, pszScheme); RTStrCatP(&pszTmp, &cbSize, ":"); if (pszAuthority1) { RTStrCatP(&pszTmp, &cbSize, "//"); RTStrCatP(&pszTmp, &cbSize, pszAuthority1); } if (pszPath1) { RTStrCatP(&pszTmp, &cbSize, pszPath1); } if (pszQuery1) { RTStrCatP(&pszTmp, &cbSize, "?"); RTStrCatP(&pszTmp, &cbSize, pszQuery1); } if (pszFragment1) { RTStrCatP(&pszTmp, &cbSize, "#"); RTStrCatP(&pszTmp, &cbSize, pszFragment1); } } while (0); /* Cleanup */ if (pszAuthority1) RTStrFree(pszAuthority1); if (pszPath1) RTStrFree(pszPath1); if (pszQuery1) RTStrFree(pszQuery1); if (pszFragment1) RTStrFree(pszFragment1); return pszResult; }
static char *rtUriPercentDecodeN(const char *pszString, size_t cchString) { AssertPtrReturn(pszString, NULL); AssertReturn(memchr(pszString, '\0', cchString) == NULL, NULL); /* * The new string can only get smaller, so use the input length as a * staring buffer size. */ char *pszDecoded = RTStrAlloc(cchString + 1); if (pszDecoded) { /* * Knowing that the pszString itself is valid UTF-8, we only have to * validate the escape sequences. */ size_t cchLeft = cchString; char const *pchSrc = pszString; char *pchDst = pszDecoded; while (cchLeft > 0) { const char *pchPct = (const char *)memchr(pchSrc, '%', cchLeft); if (pchPct) { size_t cchBefore = pchPct - pchSrc; if (cchBefore) { memcpy(pchDst, pchSrc, cchBefore); pchDst += cchBefore; pchSrc += cchBefore; cchLeft -= cchBefore; } char chHigh, chLow; if ( cchLeft >= 3 && RT_C_IS_XDIGIT(chHigh = pchSrc[1]) && RT_C_IS_XDIGIT(chLow = pchSrc[2])) { uint8_t b = RT_C_IS_DIGIT(chHigh) ? chHigh - '0' : (chHigh & ~0x20) - 'A' + 10; b <<= 4; b |= RT_C_IS_DIGIT(chLow) ? chLow - '0' : (chLow & ~0x20) - 'A' + 10; *pchDst++ = (char)b; pchSrc += 3; cchLeft -= 3; } else { AssertFailed(); *pchDst++ = *pchSrc++; cchLeft--; } } else { memcpy(pchDst, pchSrc, cchLeft); pchDst += cchLeft; pchSrc += cchLeft; cchLeft = 0; break; } } *pchDst = '\0'; /* * If we've got lof space room in the result string, reallocate it. */ size_t cchDecoded = pchDst - pszDecoded; Assert(cchDecoded <= cchString); if (cchString - cchDecoded > 64) RTStrRealloc(&pszDecoded, cchDecoded + 1); } return pszDecoded; }