VirtualBox

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

Last change on this file since 67641 was 67640, checked in by vboxsync, 8 years ago

Utf8Str::parseKeyValue: Docs and style.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.1 KB
Line 
1/* $Id: string.cpp 67640 2017-06-27 15:23:45Z vboxsync $ */
2/** @file
3 * MS COM / XPCOM Abstraction Layer - UTF-8 and UTF-16 string classes.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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.c_str(), 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.c_str(), a_offStart);
209 if (offKeyValueSep < offEnd)
210 {
211 a_rKey = substr(a_offStart, offKeyValueSep - a_offStart);
212 a_rValue = substr(offKeyValueSep + 1, offEnd - offKeyValueSep - 1);
213 }
214 else
215 {
216 a_rKey.setNull();
217 a_rValue.setNull();
218 }
219
220 return offEnd;
221}
222
223/**
224 * Internal function used in Utf8Str copy constructors and assignment when
225 * copying from a UTF-16 string.
226 *
227 * As with the RTCString::copyFrom() variants, this unconditionally sets the
228 * members to a copy of the given other strings and makes no assumptions about
229 * previous contents. This can therefore be used both in copy constructors,
230 * when member variables have no defined value, and in assignments after having
231 * called cleanup().
232 *
233 * This variant converts from a UTF-16 string, most probably from
234 * a Bstr assignment.
235 *
236 * @param a_pbstr The source string. The caller guarantees that this
237 * is valid UTF-16.
238 * @param a_cwcMax The number of characters to be copied. If set to RTSTR_MAX,
239 * the entire string will be copied.
240 *
241 * @sa RTCString::copyFromN
242 */
243void Utf8Str::copyFrom(CBSTR a_pbstr, size_t a_cwcMax)
244{
245 if (a_pbstr && *a_pbstr)
246 {
247 int vrc = RTUtf16ToUtf8Ex((PCRTUTF16)a_pbstr,
248 a_cwcMax, // size_t cwcString: translate entire string
249 &m_psz, // char **ppsz: output buffer
250 0, // size_t cch: if 0, func allocates buffer in *ppsz
251 &m_cch); // size_t *pcch: receives the size of the output string, excluding the terminator.
252 if (RT_SUCCESS(vrc))
253 m_cbAllocated = m_cch + 1;
254 else
255 {
256 if ( vrc != VERR_NO_STR_MEMORY
257 && vrc != VERR_NO_MEMORY)
258 {
259 /* ASSUME: input is valid Utf-16. Fake out of memory error. */
260 AssertLogRelMsgFailed(("%Rrc %.*Rhxs\n", vrc, RTUtf16Len(a_pbstr) * sizeof(RTUTF16), a_pbstr));
261 }
262
263 m_cch = 0;
264 m_cbAllocated = 0;
265 m_psz = NULL;
266
267 throw std::bad_alloc();
268 }
269 }
270 else
271 {
272 m_cch = 0;
273 m_cbAllocated = 0;
274 m_psz = NULL;
275 }
276}
277
278/**
279 * A variant of Utf8Str::copyFrom that does not throw any exceptions but returns
280 * E_OUTOFMEMORY instead.
281 *
282 * @param a_pbstr The source string.
283 * @returns S_OK or E_OUTOFMEMORY.
284 */
285HRESULT Utf8Str::copyFromEx(CBSTR a_pbstr)
286{
287 if (a_pbstr && *a_pbstr)
288 {
289 int vrc = RTUtf16ToUtf8Ex((PCRTUTF16)a_pbstr,
290 RTSTR_MAX, // size_t cwcString: translate entire string
291 &m_psz, // char **ppsz: output buffer
292 0, // size_t cch: if 0, func allocates buffer in *ppsz
293 &m_cch); // size_t *pcch: receives the size of the output string, excluding the terminator.
294 if (RT_SUCCESS(vrc))
295 m_cbAllocated = m_cch + 1;
296 else
297 {
298 if ( vrc != VERR_NO_STR_MEMORY
299 && vrc != VERR_NO_MEMORY)
300 {
301 /* ASSUME: input is valid Utf-16. Fake out of memory error. */
302 AssertLogRelMsgFailed(("%Rrc %.*Rhxs\n", vrc, RTUtf16Len(a_pbstr) * sizeof(RTUTF16), a_pbstr));
303 }
304
305 m_cch = 0;
306 m_cbAllocated = 0;
307 m_psz = NULL;
308
309 return E_OUTOFMEMORY;
310 }
311 }
312 else
313 {
314 m_cch = 0;
315 m_cbAllocated = 0;
316 m_psz = NULL;
317 }
318 return S_OK;
319}
320
321
322/**
323 * A variant of Utf8Str::copyFromN that does not throw any exceptions but
324 * returns E_OUTOFMEMORY instead.
325 *
326 * @param a_pcszSrc The source string.
327 * @param a_offSrc Start offset to copy from.
328 * @param a_cchSrc The source string.
329 * @returns S_OK or E_OUTOFMEMORY.
330 *
331 * @remarks This calls cleanup() first, so the caller doesn't have to. (Saves
332 * code space.)
333 */
334HRESULT Utf8Str::copyFromExNComRC(const char *a_pcszSrc, size_t a_offSrc, size_t a_cchSrc)
335{
336 cleanup();
337 if (a_cchSrc)
338 {
339 m_psz = RTStrAlloc(a_cchSrc + 1);
340 if (RT_LIKELY(m_psz))
341 {
342 m_cch = a_cchSrc;
343 m_cbAllocated = a_cchSrc + 1;
344 memcpy(m_psz, a_pcszSrc + a_offSrc, a_cchSrc);
345 m_psz[a_cchSrc] = '\0';
346 }
347 else
348 {
349 m_cch = 0;
350 m_cbAllocated = 0;
351 return E_OUTOFMEMORY;
352 }
353 }
354 else
355 {
356 m_cch = 0;
357 m_cbAllocated = 0;
358 m_psz = NULL;
359 }
360 return S_OK;
361}
362
363} /* namespace com */
Note: See TracBrowser for help on using the repository browser.

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