VirtualBox

source: vbox/trunk/src/VBox/Main/glue/string.cpp@ 80114

Last change on this file since 80114 was 78417, checked in by vboxsync, 6 years ago

Utf8Str,RTCString: Assert that C-string pointer parameters in assignment type operations don't point into the object they're being assigned to, as that will lead to use-afer-free situations. bugref:9448

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1/* $Id: string.cpp 78417 2019-05-06 23:24:31Z vboxsync $ */
2/** @file
3 * MS COM / XPCOM Abstraction Layer - UTF-8 and UTF-16 string classes.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.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
18#include "VBox/com/string.h"
19
20#include <iprt/err.h>
21#include <iprt/path.h>
22#include <iprt/log.h>
23#include <iprt/string.h>
24#include <iprt/uni.h>
25
26namespace com
27{
28
29// BSTR representing a null wide char with 32 bits of length prefix (0);
30// this will work on Windows as well as other platforms where BSTR does
31// not use length prefixes
32const OLECHAR g_achEmptyBstr[3] = { 0, 0, 0 };
33const BSTR g_bstrEmpty = (BSTR)&g_achEmptyBstr[2];
34
35/* static */
36const Bstr Bstr::Empty; /* default ctor is OK */
37
38void Bstr::copyFromN(const char *a_pszSrc, size_t a_cchMax)
39{
40 /*
41 * Initialize m_bstr first in case of throws further down in the code, then
42 * check for empty input (m_bstr == NULL means empty, there are no NULL
43 * strings).
44 */
45 m_bstr = NULL;
46 if (!a_cchMax || !a_pszSrc || !*a_pszSrc)
47 return;
48
49 /*
50 * Calculate the length and allocate a BSTR string buffer of the right
51 * size, i.e. optimize heap usage.
52 */
53 size_t cwc;
54 int vrc = ::RTStrCalcUtf16LenEx(a_pszSrc, a_cchMax, &cwc);
55 if (RT_SUCCESS(vrc))
56 {
57 m_bstr = ::SysAllocStringByteLen(NULL, (unsigned)(cwc * sizeof(OLECHAR)));
58 if (RT_LIKELY(m_bstr))
59 {
60 PRTUTF16 pwsz = (PRTUTF16)m_bstr;
61 vrc = ::RTStrToUtf16Ex(a_pszSrc, a_cchMax, &pwsz, cwc + 1, NULL);
62 if (RT_SUCCESS(vrc))
63 return;
64
65 /* This should not happen! */
66 AssertRC(vrc);
67 cleanup();
68 }
69 }
70 else /* ASSUME: input is valid Utf-8. Fake out of memory error. */
71 AssertLogRelMsgFailed(("%Rrc %.*Rhxs\n", vrc, RTStrNLen(a_pszSrc, a_cchMax), a_pszSrc));
72 throw std::bad_alloc();
73}
74
75int Bstr::compareUtf8(const char *a_pszRight, CaseSensitivity a_enmCase /*= CaseSensitive*/) const
76{
77 PCRTUTF16 pwszLeft = m_bstr;
78
79 /*
80 * Special case for null/empty strings. Unlike RTUtf16Cmp we
81 * treat null and empty equally.
82 */
83 if (!pwszLeft)
84 return !a_pszRight || *a_pszRight == '\0' ? 0 : -1;
85 if (!a_pszRight)
86 return *pwszLeft == '\0' ? 0 : 1;
87
88 /*
89 * Compare with a UTF-8 string by enumerating them char by char.
90 */
91 for (;;)
92 {
93 RTUNICP ucLeft;
94 int rc = RTUtf16GetCpEx(&pwszLeft, &ucLeft);
95 AssertRCReturn(rc, 1);
96
97 RTUNICP ucRight;
98 rc = RTStrGetCpEx(&a_pszRight, &ucRight);
99 AssertRCReturn(rc, -1);
100 if (ucLeft == ucRight)
101 {
102 if (ucLeft)
103 continue;
104 return 0;
105 }
106
107 if (a_enmCase == CaseInsensitive)
108 {
109 if (RTUniCpToUpper(ucLeft) == RTUniCpToUpper(ucRight))
110 continue;
111 if (RTUniCpToLower(ucLeft) == RTUniCpToLower(ucRight))
112 continue;
113 }
114
115 return ucLeft < ucRight ? -1 : 1;
116 }
117}
118
119
120/* static */
121const Utf8Str Utf8Str::Empty; /* default ctor is OK */
122
123#if defined(VBOX_WITH_XPCOM)
124void Utf8Str::cloneTo(char **pstr) const
125{
126 size_t cb = length() + 1;
127 *pstr = (char *)nsMemory::Alloc(cb);
128 if (RT_LIKELY(*pstr))
129 memcpy(*pstr, c_str(), cb);
130 else
131 throw std::bad_alloc();
132}
133
134HRESULT Utf8Str::cloneToEx(char **pstr) const
135{
136 size_t cb = length() + 1;
137 *pstr = (char *)nsMemory::Alloc(cb);
138 if (RT_LIKELY(*pstr))
139 {
140 memcpy(*pstr, c_str(), cb);
141 return S_OK;
142 }
143 return E_OUTOFMEMORY;
144}
145#endif
146
147Utf8Str& Utf8Str::stripTrailingSlash()
148{
149 if (length())
150 {
151 ::RTPathStripTrailingSlash(m_psz);
152 jolt();
153 }
154 return *this;
155}
156
157Utf8Str& Utf8Str::stripFilename()
158{
159 if (length())
160 {
161 RTPathStripFilename(m_psz);
162 jolt();
163 }
164 return *this;
165}
166
167Utf8Str& Utf8Str::stripPath()
168{
169 if (length())
170 {
171 char *pszName = ::RTPathFilename(m_psz);
172 if (pszName)
173 {
174 size_t cchName = length() - (pszName - m_psz);
175 memmove(m_psz, pszName, cchName + 1);
176 jolt();
177 }
178 else
179 cleanup();
180 }
181 return *this;
182}
183
184Utf8Str& Utf8Str::stripSuffix()
185{
186 if (length())
187 {
188 RTPathStripSuffix(m_psz);
189 jolt();
190 }
191 return *this;
192}
193
194size_t Utf8Str::parseKeyValue(Utf8Str &a_rKey, Utf8Str &a_rValue, size_t a_offStart /* = 0*/,
195 const Utf8Str &a_rPairSeparator /*= ","*/, const Utf8Str &a_rKeyValueSeparator /*= "="*/) const
196{
197 /* Find the end of the next pair, skipping empty pairs.
198 Note! The skipping allows us to pass the return value of a parseKeyValue()
199 call as offStart to the next call. */
200 size_t offEnd;
201 while ( a_offStart == (offEnd = find(&a_rPairSeparator, a_offStart))
202 && offEnd != npos)
203 a_offStart++;
204
205 /* Look for a key/value separator before the end of the pair.
206 ASSUMES npos value returned by find when the substring is not found is
207 really high. */
208 size_t offKeyValueSep = find(&a_rKeyValueSeparator, a_offStart);
209 if (offKeyValueSep < offEnd)
210 {
211 a_rKey = substr(a_offStart, offKeyValueSep - a_offStart);
212 if (offEnd == npos)
213 offEnd = m_cch; /* No confusing npos when returning strings. */
214 a_rValue = substr(offKeyValueSep + 1, offEnd - offKeyValueSep - 1);
215 }
216 else
217 {
218 a_rKey.setNull();
219 a_rValue.setNull();
220 }
221
222 return offEnd;
223}
224
225/**
226 * Internal function used in Utf8Str copy constructors and assignment when
227 * copying from a UTF-16 string.
228 *
229 * As with the RTCString::copyFrom() variants, this unconditionally sets the
230 * members to a copy of the given other strings and makes no assumptions about
231 * previous contents. This can therefore be used both in copy constructors,
232 * when member variables have no defined value, and in assignments after having
233 * called cleanup().
234 *
235 * This variant converts from a UTF-16 string, most probably from
236 * a Bstr assignment.
237 *
238 * @param a_pbstr The source string. The caller guarantees that this
239 * is valid UTF-16.
240 * @param a_cwcMax The number of characters to be copied. If set to RTSTR_MAX,
241 * the entire string will be copied.
242 *
243 * @sa RTCString::copyFromN
244 */
245void Utf8Str::copyFrom(CBSTR a_pbstr, size_t a_cwcMax)
246{
247 if (a_pbstr && *a_pbstr)
248 {
249 int vrc = RTUtf16ToUtf8Ex((PCRTUTF16)a_pbstr,
250 a_cwcMax, // size_t cwcString: translate entire string
251 &m_psz, // char **ppsz: output buffer
252 0, // size_t cch: if 0, func allocates buffer in *ppsz
253 &m_cch); // size_t *pcch: receives the size of the output string, excluding the terminator.
254 if (RT_SUCCESS(vrc))
255 m_cbAllocated = m_cch + 1;
256 else
257 {
258 if ( vrc != VERR_NO_STR_MEMORY
259 && vrc != VERR_NO_MEMORY)
260 {
261 /* ASSUME: input is valid Utf-16. Fake out of memory error. */
262 AssertLogRelMsgFailed(("%Rrc %.*Rhxs\n", vrc, RTUtf16Len(a_pbstr) * sizeof(RTUTF16), a_pbstr));
263 }
264
265 m_cch = 0;
266 m_cbAllocated = 0;
267 m_psz = NULL;
268
269 throw std::bad_alloc();
270 }
271 }
272 else
273 {
274 m_cch = 0;
275 m_cbAllocated = 0;
276 m_psz = NULL;
277 }
278}
279
280/**
281 * A variant of Utf8Str::copyFrom that does not throw any exceptions but returns
282 * E_OUTOFMEMORY instead.
283 *
284 * @param a_pbstr The source string.
285 * @returns S_OK or E_OUTOFMEMORY.
286 */
287HRESULT Utf8Str::copyFromEx(CBSTR a_pbstr)
288{
289 if (a_pbstr && *a_pbstr)
290 {
291 int vrc = RTUtf16ToUtf8Ex((PCRTUTF16)a_pbstr,
292 RTSTR_MAX, // size_t cwcString: translate entire string
293 &m_psz, // char **ppsz: output buffer
294 0, // size_t cch: if 0, func allocates buffer in *ppsz
295 &m_cch); // size_t *pcch: receives the size of the output string, excluding the terminator.
296 if (RT_SUCCESS(vrc))
297 m_cbAllocated = m_cch + 1;
298 else
299 {
300 if ( vrc != VERR_NO_STR_MEMORY
301 && vrc != VERR_NO_MEMORY)
302 {
303 /* ASSUME: input is valid Utf-16. Fake out of memory error. */
304 AssertLogRelMsgFailed(("%Rrc %.*Rhxs\n", vrc, RTUtf16Len(a_pbstr) * sizeof(RTUTF16), a_pbstr));
305 }
306
307 m_cch = 0;
308 m_cbAllocated = 0;
309 m_psz = NULL;
310
311 return E_OUTOFMEMORY;
312 }
313 }
314 else
315 {
316 m_cch = 0;
317 m_cbAllocated = 0;
318 m_psz = NULL;
319 }
320 return S_OK;
321}
322
323
324/**
325 * A variant of Utf8Str::copyFromN that does not throw any exceptions but
326 * returns E_OUTOFMEMORY instead.
327 *
328 * @param a_pcszSrc The source string.
329 * @param a_offSrc Start offset to copy from.
330 * @param a_cchSrc How much to copy
331 * @returns S_OK or E_OUTOFMEMORY.
332 *
333 * @remarks This calls cleanup() first, so the caller doesn't have to. (Saves
334 * code space.)
335 */
336HRESULT Utf8Str::copyFromExNComRC(const char *a_pcszSrc, size_t a_offSrc, size_t a_cchSrc)
337{
338 Assert(!a_cchSrc || !m_psz || (uintptr_t)&a_pcszSrc[a_offSrc] - (uintptr_t)m_psz >= (uintptr_t)m_cbAllocated);
339 cleanup();
340 if (a_cchSrc)
341 {
342 m_psz = RTStrAlloc(a_cchSrc + 1);
343 if (RT_LIKELY(m_psz))
344 {
345 m_cch = a_cchSrc;
346 m_cbAllocated = a_cchSrc + 1;
347 memcpy(m_psz, a_pcszSrc + a_offSrc, a_cchSrc);
348 m_psz[a_cchSrc] = '\0';
349 }
350 else
351 {
352 m_cch = 0;
353 m_cbAllocated = 0;
354 return E_OUTOFMEMORY;
355 }
356 }
357 else
358 {
359 m_cch = 0;
360 m_cbAllocated = 0;
361 m_psz = NULL;
362 }
363 return S_OK;
364}
365
366} /* namespace com */
Note: See TracBrowser for help on using the repository browser.

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