VirtualBox

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

Last change on this file since 60409 was 60409, checked in by vboxsync, 9 years ago

com::Bstr: Added compareUtf8() for optimal comparsions with UTF-8 strings. Also added a few equals() and equalsIgnoreCase() method for convenience.

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