dc313bf22ad4191e5b146fa5ee019c087c2bb05a
[public/netxms.git] / src / libnetxms / string.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003-2013 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published
8 ** by the Free Software Foundation; either version 3 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: string.cpp
21 **
22 **/
23
24 #include "libnetxms.h"
25
26 /**
27 * Static members
28 */
29 const int String::npos = -1;
30
31
32 //
33 // Constructors
34 //
35
36 String::String()
37 {
38 m_dwBufSize = 1;
39 m_pszBuffer = NULL;
40 }
41
42 String::String(const String &src)
43 {
44 m_dwBufSize = src.m_dwBufSize;
45 m_pszBuffer = (src.m_pszBuffer != NULL) ? (TCHAR *)nx_memdup(src.m_pszBuffer, src.m_dwBufSize * sizeof(TCHAR)) : NULL;
46 }
47
48 String::String(const TCHAR *init)
49 {
50 m_dwBufSize = (UINT32)_tcslen(init) + 1;
51 m_pszBuffer = _tcsdup(init);
52 }
53
54 /**
55 * Destructor
56 */
57 String::~String()
58 {
59 safe_free(m_pszBuffer);
60 }
61
62 /**
63 * Operator =
64 */
65 const String& String::operator =(const TCHAR *pszStr)
66 {
67 safe_free(m_pszBuffer);
68 m_pszBuffer = _tcsdup(CHECK_NULL_EX(pszStr));
69 m_dwBufSize = (UINT32)_tcslen(CHECK_NULL_EX(pszStr)) + 1;
70 return *this;
71 }
72
73 /**
74 * Operator =
75 */
76 const String& String::operator =(const String &src)
77 {
78 if (&src == this)
79 return *this;
80 safe_free(m_pszBuffer);
81 m_dwBufSize = src.m_dwBufSize;
82 m_pszBuffer = (src.m_pszBuffer != NULL) ? (TCHAR *)nx_memdup(src.m_pszBuffer, src.m_dwBufSize * sizeof(TCHAR)) : NULL;
83 return *this;
84 }
85
86 /**
87 * Append given string to the end
88 */
89 const String& String::operator +=(const TCHAR *str)
90 {
91 if (str != NULL)
92 {
93 UINT32 dwLen = (UINT32)_tcslen(str);
94 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, (m_dwBufSize + dwLen) * sizeof(TCHAR));
95 _tcscpy(&m_pszBuffer[m_dwBufSize - 1], str);
96 m_dwBufSize += dwLen;
97 }
98 return *this;
99 }
100
101 /**
102 * Append given string to the end
103 */
104 const String& String::operator +=(const String &str)
105 {
106 UINT32 dwLen = str.m_dwBufSize;
107 if (dwLen > 1)
108 {
109 dwLen--;
110 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, (m_dwBufSize + dwLen) * sizeof(TCHAR));
111 _tcscpy(&m_pszBuffer[m_dwBufSize - 1], str.m_pszBuffer);
112 m_dwBufSize += dwLen;
113 }
114 return *this;
115 }
116
117 /**
118 * Add formatted string to the end of buffer
119 */
120 void String::addFormattedString(const TCHAR *format, ...)
121 {
122 va_list args;
123
124 va_start(args, format);
125 addFormattedStringV(format, args);
126 va_end(args);
127 }
128
129 void String::addFormattedStringV(const TCHAR *format, va_list args)
130 {
131 int len;
132 TCHAR *buffer;
133
134 #ifdef UNICODE
135
136 #if HAVE_VASWPRINTF
137 vaswprintf(&buffer, format, args);
138 #elif HAVE_VSCWPRINTF && HAVE_DECL_VA_COPY
139 va_list argsCopy;
140 va_copy(argsCopy, args);
141
142 len = (int)vscwprintf(format, args) + 1;
143 buffer = (WCHAR *)malloc(len * sizeof(WCHAR));
144
145 vsnwprintf(buffer, len, format, argsCopy);
146 va_end(argsCopy);
147 #else
148 // No way to determine required buffer size, guess
149 len = wcslen(format) + NumCharsW(format, L'%') * 1000 + 1;
150 buffer = (WCHAR *)malloc(len * sizeof(WCHAR));
151
152 nx_vswprintf(buffer, len, format, args);
153 #endif
154
155 #else /* UNICODE */
156
157 #if HAVE_VASPRINTF && !defined(_IPSO)
158 if (vasprintf(&buffer, format, args) == -1)
159 {
160 buffer = (char *)malloc(1);
161 *buffer = 0;
162 }
163 #elif HAVE_VSCPRINTF && HAVE_DECL_VA_COPY
164 va_list argsCopy;
165 va_copy(argsCopy, args);
166
167 len = (int)vscprintf(format, args) + 1;
168 buffer = (char *)malloc(len);
169
170 vsnprintf(buffer, len, format, argsCopy);
171 va_end(argsCopy);
172 #elif SNPRINTF_RETURNS_REQUIRED_SIZE && HAVE_DECL_VA_COPY
173 va_list argsCopy;
174 va_copy(argsCopy, args);
175
176 len = (int)vsnprintf(NULL, 0, format, args) + 1;
177 buffer = (char *)malloc(len);
178
179 vsnprintf(buffer, len, format, argsCopy);
180 va_end(argsCopy);
181 #else
182 // No way to determine required buffer size, guess
183 len = strlen(format) + NumChars(format, '%') * 1000 + 1;
184 buffer = (char *)malloc(len);
185
186 vsnprintf(buffer, len, format, args);
187 #endif
188
189 #endif /* UNICODE */
190
191 *this += buffer;
192 free(buffer);
193 }
194
195 /**
196 * Add string to the end of buffer
197 */
198 void String::addString(const TCHAR *pStr, UINT32 dwSize)
199 {
200 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, (m_dwBufSize + dwSize) * sizeof(TCHAR));
201 memcpy(&m_pszBuffer[m_dwBufSize - 1], pStr, dwSize * sizeof(TCHAR));
202 m_dwBufSize += dwSize;
203 m_pszBuffer[m_dwBufSize - 1] = 0;
204 }
205
206 /**
207 * Add multibyte string to the end of buffer
208 */
209 void String::addMultiByteString(const char *pStr, UINT32 dwSize, int nCodePage)
210 {
211 #ifdef UNICODE
212 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, (m_dwBufSize + dwSize) * sizeof(TCHAR));
213 m_dwBufSize += MultiByteToWideChar(nCodePage, (nCodePage == CP_UTF8) ? 0 : MB_PRECOMPOSED, pStr, dwSize, &m_pszBuffer[m_dwBufSize - 1], dwSize);
214 m_pszBuffer[m_dwBufSize - 1] = 0;
215 #else
216 addString(pStr, dwSize);
217 #endif
218 }
219
220 /**
221 * Add widechar string to the end of buffer
222 */
223 void String::addWideCharString(const WCHAR *pStr, UINT32 dwSize)
224 {
225 #ifdef UNICODE
226 addString(pStr, dwSize);
227 #else
228 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, (m_dwBufSize + dwSize) * sizeof(TCHAR));
229 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pStr, dwSize, &m_pszBuffer[m_dwBufSize - 1], dwSize, NULL, NULL);
230 m_dwBufSize += dwSize;
231 m_pszBuffer[m_dwBufSize - 1] = 0;
232 #endif
233 }
234
235 /**
236 * Escape given character
237 */
238 void String::escapeCharacter(int ch, int esc)
239 {
240 int nCount;
241 UINT32 i;
242
243 if (m_pszBuffer == NULL)
244 return;
245
246 nCount = NumChars(m_pszBuffer, ch);
247 if (nCount == 0)
248 return;
249
250 m_dwBufSize += nCount;
251 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, m_dwBufSize * sizeof(TCHAR));
252 for(i = 0; m_pszBuffer[i] != 0; i++)
253 {
254 if (m_pszBuffer[i] == ch)
255 {
256 memmove(&m_pszBuffer[i + 1], &m_pszBuffer[i], (m_dwBufSize - i - 1) * sizeof(TCHAR));
257 m_pszBuffer[i] = esc;
258 i++;
259 }
260 }
261 }
262
263 /**
264 * Set dynamically allocated string as a new buffer
265 */
266 void String::setBuffer(TCHAR *pszBuffer)
267 {
268 safe_free(m_pszBuffer);
269 m_pszBuffer = pszBuffer;
270 m_dwBufSize = (m_pszBuffer != NULL) ? (UINT32)_tcslen(m_pszBuffer) + 1 : 1;
271 }
272
273 /**
274 * Replace all occurences of source substring with destination substring
275 */
276 void String::replace(const TCHAR *pszSrc, const TCHAR *pszDst)
277 {
278 if (m_pszBuffer == NULL)
279 return;
280
281 int lenSrc = (int)_tcslen(pszSrc);
282 int lenDst = (int)_tcslen(pszDst);
283
284 for(int i = 0; ((int)m_dwBufSize > lenSrc) && (i < (int)m_dwBufSize - lenSrc); i++)
285 {
286 if (!memcmp(pszSrc, &m_pszBuffer[i], lenSrc * sizeof(TCHAR)))
287 {
288 if (lenSrc == lenDst)
289 {
290 memcpy(&m_pszBuffer[i], pszDst, lenDst * sizeof(TCHAR));
291 i += lenDst - 1;
292 }
293 else if (lenSrc > lenDst)
294 {
295 memcpy(&m_pszBuffer[i], pszDst, lenDst * sizeof(TCHAR));
296 i += lenDst;
297 int delta = lenSrc - lenDst;
298 m_dwBufSize -= (UINT32)delta;
299 memmove(&m_pszBuffer[i], &m_pszBuffer[i + delta], (m_dwBufSize - (UINT32)i) * sizeof(TCHAR));
300 i--;
301 }
302 else
303 {
304 int delta = lenDst - lenSrc;
305 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, (m_dwBufSize + (UINT32)delta) * sizeof(TCHAR));
306 memmove(&m_pszBuffer[i + lenDst], &m_pszBuffer[i + lenSrc], ((int)m_dwBufSize - i - lenSrc) * sizeof(TCHAR));
307 m_dwBufSize += (UINT32)delta;
308 memcpy(&m_pszBuffer[i], pszDst, lenDst * sizeof(TCHAR));
309 i += lenDst - 1;
310 }
311 }
312 }
313 }
314
315 /**
316 * Extract substring into buffer
317 */
318 TCHAR *String::subStr(int nStart, int nLen, TCHAR *pszBuffer)
319 {
320 int nCount;
321 TCHAR *pszOut;
322
323 if ((nStart < (int)m_dwBufSize - 1) && (nStart >= 0))
324 {
325 if (nLen == -1)
326 {
327 nCount = (int)m_dwBufSize - nStart - 1;
328 }
329 else
330 {
331 nCount = min(nLen, (int)m_dwBufSize - nStart - 1);
332 }
333 pszOut = (pszBuffer != NULL) ? pszBuffer : (TCHAR *)malloc((nCount + 1) * sizeof(TCHAR));
334 memcpy(pszOut, &m_pszBuffer[nStart], nCount * sizeof(TCHAR));
335 pszOut[nCount] = 0;
336 }
337 else
338 {
339 pszOut = (pszBuffer != NULL) ? pszBuffer : (TCHAR *)malloc(sizeof(TCHAR));
340 *pszOut = 0;
341 }
342 return pszOut;
343 }
344
345 /**
346 * Find substring in a string
347 */
348 int String::find(const TCHAR *pszStr, int nStart)
349 {
350 TCHAR *p;
351
352 if ((nStart >= (int)m_dwBufSize - 1) || (nStart < 0))
353 return npos;
354
355 p = _tcsstr(&m_pszBuffer[nStart], pszStr);
356 return (p != NULL) ? (int)(((char *)p - (char *)m_pszBuffer) / sizeof(TCHAR)) : npos;
357 }
358
359 /**
360 * Strip leading and trailing spaces, tabs, newlines
361 */
362 void String::trim()
363 {
364 if (m_pszBuffer != NULL)
365 {
366 Trim(m_pszBuffer);
367 m_dwBufSize = (UINT32)_tcslen(m_pszBuffer) + 1;
368 }
369 }
370
371 /**
372 * Shring string by removing trailing characters
373 */
374 void String::shrink(int chars)
375 {
376 if (m_dwBufSize > 1)
377 {
378 m_dwBufSize -= min(m_dwBufSize - 1, (UINT32)chars);
379 if (m_pszBuffer != NULL)
380 m_pszBuffer[m_dwBufSize - 1] = 0;
381 }
382 }
383
384 /**
385 * Get content as dynamically allocated UTF-8 string
386 */
387 char *String::getUTF8String()
388 {
389 #ifdef UNICODE
390 return UTF8StringFromWideString(m_pszBuffer);
391 #else
392 return strdup(m_pszBuffer);
393 #endif
394 }