/** * Reads from a pipe. * * @returns @a rc or other status code. * @param rc The current status of the operation. Error status * are preserved and returned. * @param phPipeR Pointer to the pipe handle. * @param pcbAllocated Pointer to the buffer size variable. * @param poffCur Pointer to the buffer offset variable. * @param ppszBuffer Pointer to the buffer pointer variable. */ static int rtProcProcessOutput(int rc, PRTPIPE phPipeR, size_t *pcbAllocated, size_t *poffCur, char **ppszBuffer, RTPOLLSET hPollSet, uint32_t idPollSet) { size_t cbRead; char szTmp[_4K - 1]; for (;;) { int rc2 = RTPipeRead(*phPipeR, szTmp, sizeof(szTmp), &cbRead); if (RT_SUCCESS(rc2) && cbRead) { /* Resize the buffer. */ if (*poffCur + cbRead >= *pcbAllocated) { if (*pcbAllocated >= _1G) { RTPollSetRemove(hPollSet, idPollSet); rc2 = RTPipeClose(*phPipeR); AssertRC(rc2); *phPipeR = NIL_RTPIPE; return RT_SUCCESS(rc) ? VERR_TOO_MUCH_DATA : rc; } size_t cbNew = *pcbAllocated ? *pcbAllocated * 2 : sizeof(szTmp) + 1; Assert(*poffCur + cbRead < cbNew); rc2 = RTStrRealloc(ppszBuffer, cbNew); if (RT_FAILURE(rc2)) { RTPollSetRemove(hPollSet, idPollSet); rc2 = RTPipeClose(*phPipeR); AssertRC(rc2); *phPipeR = NIL_RTPIPE; return RT_SUCCESS(rc) ? rc2 : rc; } *pcbAllocated = cbNew; } /* Append the new data, terminating it. */ memcpy(*ppszBuffer + *poffCur, szTmp, cbRead); *poffCur += cbRead; (*ppszBuffer)[*poffCur] = '\0'; /* Check for null terminators in the string. */ if (RT_SUCCESS(rc) && memchr(szTmp, '\0', cbRead)) rc = VERR_NO_TRANSLATION; /* If we read a full buffer, try read some more. */ if (RT_SUCCESS(rc) && cbRead == sizeof(szTmp)) continue; } else if (rc2 != VINF_TRY_AGAIN) { if (RT_FAILURE(rc) && rc2 != VERR_BROKEN_PIPE) rc = rc2; RTPollSetRemove(hPollSet, idPollSet); rc2 = RTPipeClose(*phPipeR); AssertRC(rc2); *phPipeR = NIL_RTPIPE; } return rc; } }
/** * Grows the command line string buffer. * * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. * @param ppszCmdLine Pointer to the command line string pointer. * @param pcbCmdLineAlloc Pointer to the allocation length variable. * @param cchMin The minimum size to grow with, kind of. */ static int rtGetOptArgvToStringGrow(char **ppszCmdLine, size_t *pcbCmdLineAlloc, size_t cchMin) { size_t cb = *pcbCmdLineAlloc; while (cb < cchMin) cb *= 2; cb *= 2; *pcbCmdLineAlloc = cb; return RTStrRealloc(ppszCmdLine, cb); }
/** * 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); }
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; }