/* $Id: stringalloc.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */ /** @file * IPRT - String Manipulation. */ /* * Copyright (C) 2006-2023 Oracle and/or its affiliates. * * This file is part of VirtualBox base platform packages, as * available from https://www.virtualbox.org. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, in version 3 of the * License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * The contents of this file may alternatively be used under the terms * of the Common Development and Distribution License Version 1.0 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included * in the VirtualBox distribution, in which case the provisions of the * CDDL are applicable instead of those of the GPL. * * You may elect to license modified versions of this file under the * terms and conditions of either the GPL or the CDDL or both. * * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include #include "internal/iprt.h" #ifndef IN_RING0 # include #endif #include #include #include #include "internal/string.h" RTDECL(char *) RTStrAllocTag(size_t cb, const char *pszTag) { char *psz = (char *)RTMemAllocTag(RT_MAX(cb, 1), pszTag); if (psz) *psz = '\0'; return psz; } RT_EXPORT_SYMBOL(RTStrAllocTag); RTDECL(int) RTStrAllocExTag(char **ppsz, size_t cb, const char *pszTag) { char *psz = *ppsz = (char *)RTMemAllocTag(RT_MAX(cb, 1), pszTag); if (psz) { *psz = '\0'; return VINF_SUCCESS; } return VERR_NO_STR_MEMORY; } RT_EXPORT_SYMBOL(RTStrAllocExTag); RTDECL(int) RTStrReallocTag(char **ppsz, size_t cbNew, const char *pszTag) { char *pszOld = *ppsz; if (!cbNew) { RTMemFree(pszOld); *ppsz = NULL; } else if (pszOld) { char *pszNew = (char *)RTMemReallocTag(pszOld, cbNew, pszTag); if (!pszNew) return VERR_NO_STR_MEMORY; pszNew[cbNew - 1] = '\0'; *ppsz = pszNew; } else { char *pszNew = (char *)RTMemAllocTag(cbNew, pszTag); if (!pszNew) return VERR_NO_STR_MEMORY; pszNew[0] = '\0'; pszNew[cbNew - 1] = '\0'; *ppsz = pszNew; } return VINF_SUCCESS; } RT_EXPORT_SYMBOL(RTStrReallocTag); RTDECL(void) RTStrFree(char *pszString) { if (pszString) RTMemTmpFree(pszString); } RT_EXPORT_SYMBOL(RTStrFree); RTDECL(char *) RTStrDupTag(const char *pszString, const char *pszTag) { #if defined(__cplusplus) AssertPtr(pszString); #endif size_t cch = strlen(pszString) + 1; char *psz = (char *)RTMemAllocTag(cch, pszTag); if (psz) memcpy(psz, pszString, cch); return psz; } RT_EXPORT_SYMBOL(RTStrDupTag); RTDECL(int) RTStrDupExTag(char **ppszCopy, const char *pszString, const char *pszTag) { #if defined(__cplusplus) AssertPtr(ppszCopy); AssertPtr(pszString); #endif size_t cch = strlen(pszString); char *pszDst = (char *)RTMemAllocTag(cch + 1, pszTag); if (pszDst) { memcpy(pszDst, pszString, cch); pszDst[cch] = '\0'; *ppszCopy = pszDst; return VINF_SUCCESS; } *ppszCopy = NULL; return VERR_NO_STR_MEMORY; } RT_EXPORT_SYMBOL(RTStrDupExTag); RTDECL(char *) RTStrDupNTag(const char *pszString, size_t cchMax, const char *pszTag) { #if defined(__cplusplus) AssertPtr(pszString); #endif char const *pszEnd = RTStrEnd(pszString, cchMax); size_t cch = pszEnd ? (uintptr_t)pszEnd - (uintptr_t)pszString : cchMax; char *pszDst = (char *)RTMemAllocTag(cch + 1, pszTag); if (pszDst) { memcpy(pszDst, pszString, cch); pszDst[cch] = '\0'; } return pszDst; } RT_EXPORT_SYMBOL(RTStrDupNTag); RTDECL(int) RTStrDupNExTag(char **ppszCopy, const char *pszString, size_t cchMax, const char *pszTag) { #if defined(__cplusplus) AssertPtr(pszString); #endif char const *pszEnd = RTStrEnd(pszString, cchMax); size_t cch = pszEnd ? (uintptr_t)pszEnd - (uintptr_t)pszString : cchMax; char *pszDst = (char *)RTMemAllocTag(cch + 1, pszTag); if (pszDst) { memcpy(pszDst, pszString, cch); pszDst[cch] = '\0'; *ppszCopy = pszDst; return VINF_SUCCESS; } *ppszCopy = NULL; return VERR_NO_STR_MEMORY; } RT_EXPORT_SYMBOL(RTStrDupNExTag); RTDECL(int) RTStrAAppendTag(char **ppsz, const char *pszAppend, const char *pszTag) { if (!pszAppend) return VINF_SUCCESS; return RTStrAAppendNTag(ppsz, pszAppend, RTSTR_MAX, pszTag); } RTDECL(int) RTStrAAppendNTag(char **ppsz, const char *pszAppend, size_t cchAppend, const char *pszTag) { size_t cchOrg; char *pszNew; if (!cchAppend) return VINF_SUCCESS; if (cchAppend == RTSTR_MAX) cchAppend = strlen(pszAppend); else Assert(cchAppend == RTStrNLen(pszAppend, cchAppend)); cchOrg = *ppsz ? strlen(*ppsz) : 0; pszNew = (char *)RTMemReallocTag(*ppsz, cchOrg + cchAppend + 1, pszTag); if (!pszNew) return VERR_NO_STR_MEMORY; memcpy(&pszNew[cchOrg], pszAppend, cchAppend); pszNew[cchOrg + cchAppend] = '\0'; *ppsz = pszNew; return VINF_SUCCESS; } #if !defined(IN_RING0) && !defined(IPRT_NO_ALLOCA_TROUBLE) /* XXX Currently not needed anywhere. alloca() induces some linker problems for ring 0 code * with newer versions of VCC */ RTDECL(int) RTStrAAppendExNVTag(char **ppsz, size_t cPairs, va_list va, const char *pszTag) { AssertPtr(ppsz); if (!cPairs) return VINF_SUCCESS; /* * Determine the length of each string and calc the new total. */ struct RTStrAAppendExNVStruct { const char *psz; size_t cch; } *paPairs = (struct RTStrAAppendExNVStruct *)alloca(cPairs * sizeof(*paPairs)); AssertReturn(paPairs, VERR_NO_STR_MEMORY); size_t cchOrg = *ppsz ? strlen(*ppsz) : 0; size_t cchNewTotal = cchOrg; for (size_t i = 0; i < cPairs; i++) { const char *psz = va_arg(va, const char *); size_t cch = va_arg(va, size_t); AssertPtrNull(psz); Assert(cch == RTSTR_MAX || cch == RTStrNLen(psz, cch)); if (cch == RTSTR_MAX) cch = psz ? strlen(psz) : 0; cchNewTotal += cch; paPairs[i].cch = cch; paPairs[i].psz = psz; } cchNewTotal++; /* '\0' */ /* * Try reallocate the string. */ char *pszNew = (char *)RTMemReallocTag(*ppsz, cchNewTotal, pszTag); if (!pszNew) return VERR_NO_STR_MEMORY; /* * Do the appending. */ size_t off = cchOrg; for (size_t i = 0; i < cPairs; i++) { memcpy(&pszNew[off], paPairs[i].psz, paPairs[i].cch); off += paPairs[i].cch; } Assert(off + 1 == cchNewTotal); pszNew[off] = '\0'; /* done */ *ppsz = pszNew; return VINF_SUCCESS; } RT_EXPORT_SYMBOL(RTStrAAppendExNVTag); #endif RTDECL(int) RTStrATruncateTag(char **ppsz, size_t cchNew, const char *pszTag) { char *pszNew; char *pszOld = *ppsz; if (!cchNew) { if (pszOld && *pszOld) { *pszOld = '\0'; pszNew = (char *)RTMemReallocTag(pszOld, 1, pszTag); if (pszNew) *ppsz = pszNew; } } else { char *pszZero; AssertPtrReturn(pszOld, VERR_OUT_OF_RANGE); AssertReturn(cchNew < ~(size_t)64, VERR_OUT_OF_RANGE); pszZero = RTStrEnd(pszOld, cchNew + 63); AssertReturn(!pszZero || (size_t)(pszZero - pszOld) >= cchNew, VERR_OUT_OF_RANGE); pszOld[cchNew] = '\0'; if (!pszZero) { pszNew = (char *)RTMemReallocTag(pszOld, cchNew + 1, pszTag); if (pszNew) *ppsz = pszNew; } } return VINF_SUCCESS; } RT_EXPORT_SYMBOL(RTStrATruncateTag);