OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
StdBuf.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 #include "C4Include.h"
17 #include "lib/StdBuf.h"
18 #include "lib/StdCompiler.h"
19 #include "lib/StdAdaptors.h"
20 #include "platform/StdFile.h"
21 
22 #include <stdarg.h>
23 #include <stdio.h>
24 #ifdef _WIN32
25 #include <io.h>
27 #else
28 #define O_BINARY 0
29 #define O_SEQUENTIAL 0
30 #include <unistd.h>
31 #include <stdlib.h>
32 #endif
33 #include <ctype.h>
34 #include <fcntl.h>
35 #include <sys/stat.h>
36 
37 // *** StdBuf
38 
39 bool StdBuf::LoadFromFile(const char *szFile)
40 {
41  // Open file
42 #ifdef _WIN32
43  int fh = _wopen(::GetWideChar(szFile), O_BINARY | O_RDONLY | O_SEQUENTIAL, S_IREAD | S_IWRITE);
44 #else
45  int fh = open(szFile, O_BINARY | O_CLOEXEC | O_RDONLY | O_SEQUENTIAL, S_IREAD | S_IWRITE);
46 #endif
47  if (fh < 0) return false;
48  // Create buf
49  New(FileSize(fh));
50  // Read
51  if (read(fh, getMData(), getSize()) != (signed int) getSize())
52  {
53  close(fh);
54  return false;
55  }
56  close(fh);
57  // Ok
58  return true;
59 }
60 bool StdBuf::SaveToFile(const char *szFile) const
61 {
62  // Open file
63 #ifdef _WIN32
64  int fh = _wopen(::GetWideChar(szFile), O_BINARY | O_CREAT | O_WRONLY | O_SEQUENTIAL | O_TRUNC, S_IREAD | S_IWRITE);
65 #else
66  int fh = open(szFile, O_BINARY | O_CLOEXEC | O_CREAT | O_WRONLY | O_SEQUENTIAL | O_TRUNC, S_IREAD | S_IWRITE);
67 #endif
68  if (fh < 0) return false;
69  // Write data
70  if (write(fh, getData(), getSize()) != (signed int) getSize())
71  {
72  close(fh);
73  return false;
74  }
75  close(fh);
76  // Ok
77  return true;
78 }
79 
80 bool StdStrBuf::LoadFromFile(const char *szFile)
81 {
82  // Open file
83 #ifdef _WIN32
84  int fh = _wopen(::GetWideChar(szFile), O_BINARY | O_RDONLY | O_SEQUENTIAL, S_IREAD | S_IWRITE);
85 #else
86  int fh = open(szFile, O_BINARY | O_CLOEXEC | O_RDONLY | O_SEQUENTIAL, S_IREAD | S_IWRITE);
87 #endif
88  if (fh < 0) return false;
89  // Create buf
90  SetLength(FileSize(fh));
91  // Read
92  if (read(fh, getMData(), getLength()) != (ssize_t) getLength())
93  {
94  close(fh);
95  return false;
96  }
97  close(fh);
98  // Ok
99  return true;
100 }
101 bool StdStrBuf::SaveToFile(const char *szFile) const
102 {
103  // Open file
104 #ifdef _WIN32
105  int fh = _wopen(::GetWideChar(szFile), O_BINARY | O_CREAT | O_WRONLY | O_SEQUENTIAL | O_TRUNC, S_IREAD | S_IWRITE);
106 #else
107  int fh = open(szFile, O_BINARY | O_CLOEXEC | O_CREAT | O_WRONLY | O_SEQUENTIAL | O_TRUNC, S_IREAD | S_IWRITE);
108 #endif
109  if (fh < 0) return false;
110  // Write data
111  if (write(fh, getData(), getLength()) != (ssize_t) getLength())
112  {
113  close(fh);
114  return false;
115  }
116  close(fh);
117  // Ok
118  return true;
119 }
120 
121 void StdBuf::CompileFunc(StdCompiler *pComp, int iType)
122 {
123  // Size (guess it is a small value most of the time - if it's big, an extra byte won't hurt anyway)
124  uint32_t tmp = iSize; pComp->Value(mkIntPackAdapt(tmp)); iSize = tmp;
126  // Read/write data
127  if (pComp->isDeserializer())
128  {
129  New(iSize);
130  pComp->Raw(getMData(), iSize, StdCompiler::RawCompileType(iType));
131  }
132  else
133  {
134  pComp->Raw(const_cast<void *>(getData()), iSize, StdCompiler::RawCompileType(iType));
135  }
136 }
137 
138 // *** StdStringBuf
139 
140 #ifdef _WIN32
141 StdStrBuf::StdStrBuf(const wchar_t * utf16)
142 {
143  int len = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, nullptr, 0, 0, 0);
144  SetSize(len);
145  WideCharToMultiByte(CP_UTF8, 0, utf16, -1, getMData(), getSize(), 0, 0);
146 }
147 StdStrBuf::wchar_t_holder StdStrBuf::GetWideChar() const
148 {
149  if (!getSize()) return StdStrBuf::wchar_t_holder(nullptr);
150 
151  int len = MultiByteToWideChar(CP_UTF8, 0, getData(), getSize(), nullptr, 0);
152  wchar_t * p = new wchar_t[len];
153  MultiByteToWideChar(CP_UTF8, 0, getData(), getSize(), p, len);
154  return StdStrBuf::wchar_t_holder(p);
155 }
157 {
158  int len = MultiByteToWideChar(CP_UTF8, 0, getData(), getSize(), nullptr, 0);
159  StdBuf r; r.SetSize(len * sizeof(wchar_t));
160  MultiByteToWideChar(CP_UTF8, 0, getData(), getSize(), getMBufPtr<wchar_t>(r), len);
161  return r;
162 }
163 StdStrBuf::wchar_t_holder GetWideChar(const char * utf8, bool double_null_terminate)
164 {
165  int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, nullptr, 0);
166  if (double_null_terminate) ++len;
167  wchar_t * p = new wchar_t[len];
168  MultiByteToWideChar(CP_UTF8, 0, utf8, -1, p, len);
169  if (double_null_terminate) p[len - 1] = wchar_t(0);
170  return StdStrBuf::wchar_t_holder(p);
171 }
172 StdBuf GetWideCharBuf(const char * utf8)
173 {
174  int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, nullptr, 0);
175  StdBuf r; r.SetSize(len * sizeof(wchar_t));
176  MultiByteToWideChar(CP_UTF8, 0, utf8, -1, getMBufPtr<wchar_t>(r), len);
177  return r;
178 }
179 #endif
180 
181 void StdStrBuf::Format(const char *szFmt, ...)
182 {
183  // Create argument list
184  va_list args; va_start(args, szFmt);
185  // Format
186  FormatV(szFmt, args);
187 }
188 
189 void StdStrBuf::FormatV(const char *szFmt, va_list args)
190 {
191  // Clear previous contents
192  Clear();
193  // Format
194  AppendFormatV(szFmt, args);
195 }
196 
197 void StdStrBuf::AppendFormat(const char *szFmt, ...)
198 {
199  // Create argument list
200  va_list args; va_start(args, szFmt);
201  // Format
202  AppendFormatV(szFmt, args);
203 }
204 
205 void StdStrBuf::AppendFormatV(const char *szFmt, va_list args)
206 {
207 #ifdef HAVE_VASPRINTF
208  // Format
209  char *pStr; int iBytes = vasprintf(&pStr, szFmt, args);
210  if (iBytes < 0 || !pStr) return;
211  // Append
212  if (isNull())
213  Take(pStr, iBytes);
214  else
215  {
216  Append(pStr, iBytes);
217  free(pStr);
218  }
219 #elif defined(HAVE_VSCPRINTF)
220  // Save append start
221  int iStart = getLength();
222  // Calculate size, allocate
223  int iLength = vscprintf(szFmt, args);
224  Grow(iLength);
225  // Format
226  char *pPos = getMElem<char>(*this, iSize - iLength - 1);
227  vsprintf(getMPtr(iStart), szFmt, args);
228 #else
229  // Save append start
230  int iStart = getLength(), iBytes;
231  do
232  {
233  // Grow
234  Grow(512);
235  // Try output
236  va_list args_copy;
237  #ifdef va_copy
238  va_copy(args_copy, args);
239  #else
240  args_copy = args;
241  #endif
242  iBytes = vsnprintf(getMPtr(iStart), getLength() - iStart, szFmt, args_copy);
243  #ifdef va_copy
244  va_end(args_copy);
245  #endif
246  }
247  while (iBytes < 0 || (unsigned int)(iBytes) >= getLength() - iStart);
248  // Calculate real length, if vsnprintf didn't return anything of value
249  iBytes = strlen(getMPtr(iStart));
250  // Shrink to fit
251  SetSize(iStart + iBytes + 1);
252 #endif
253 }
254 
256 {
257  if(getLength() && *getPtr(getLength() - 1) == DirectorySeparator) return;
259 }
260 
261 void StdStrBuf::CompileFunc(StdCompiler *pComp, int iRawType)
262 {
263  if (pComp->isDeserializer())
264  {
265  char *pnData;
266  pComp->String(&pnData, StdCompiler::RawCompileType(iRawType));
267  Take(pnData);
268  }
269  else
270  {
271  char *pData = const_cast<char *>(getData());
272  if (!pData) pData = const_cast<char *>("");
273  pComp->String(&pData, StdCompiler::RawCompileType(iRawType));
274  }
275 }
276 
277 StdStrBuf FormatString(const char *szFmt, ...)
278 {
279  va_list args; va_start(args, szFmt);
280  return FormatStringV(szFmt, args);
281 }
282 
283 StdStrBuf FormatStringV(const char *szFmt, va_list args)
284 {
285  StdStrBuf Buf;
286  Buf.FormatV(szFmt, args);
287  return Buf;
288 }
289 
290 // replace all occurences of one string with another. Return number of replacements.
291 int StdStrBuf::Replace(const char *szOld, const char *szNew, size_t iStartSearch)
292 {
293  if (!getPtr(0) || !szOld) return 0;
294  if (!szNew) szNew = "";
295  int cnt=0;
296  size_t iOldLen = strlen(szOld), iNewLen = strlen(szNew);
297  if (iOldLen != iNewLen)
298  {
299  // count number of occurences to calculate new string length
300  size_t iResultLen = getLength();
301  const char *szPos = getPtr(iStartSearch);
302  while ((szPos = SSearch(szPos, szOld)))
303  {
304  iResultLen += iNewLen - iOldLen;
305  ++cnt;
306  }
307  if (!cnt) return 0;
308  // now construct new string by replacement
309  StdStrBuf sResult;
310  sResult.New(iResultLen+1);
311  const char *szRPos = getPtr(0), *szRNextPos;
312  char *szWrite = sResult.getMPtr(0);
313  if (iStartSearch)
314  {
315  memcpy(szWrite, szRPos, iStartSearch * sizeof(char));
316  szRPos += iStartSearch;
317  szWrite += iStartSearch;
318  }
319  while ((szRNextPos = SSearch(szRPos, szOld)))
320  {
321  memcpy(szWrite, szRPos, (szRNextPos - szRPos - iOldLen) * sizeof(char));
322  szWrite += (szRNextPos - szRPos - iOldLen);
323  memcpy(szWrite, szNew, iNewLen * sizeof(char));
324  szWrite += iNewLen;
325  szRPos = szRNextPos;
326  }
327  strcpy(szWrite, szRPos);
328  Take(std::move(sResult));
329  }
330  else
331  {
332  // replace directly in this string
333  char *szRPos = getMPtr(iStartSearch);
334  while ((szRPos = const_cast<char *>(SSearch(szRPos, szOld))))
335  {
336  memcpy(szRPos - iOldLen, szNew, iOldLen * sizeof(char));
337  ++cnt;
338  }
339  }
340  return cnt;
341 }
342 
343 int StdStrBuf::ReplaceChar(char cOld, char cNew)
344 {
345  if (isNull()) return 0;
346  char *szPos = getMPtr(0);
347  if (!cOld) return 0;
348  if (!cNew) cNew = '_';
349  int cnt=0;
350  while ((szPos = strchr(szPos, cOld)))
351  {
352  *szPos++ = cNew;
353  ++cnt;
354  }
355  return cnt;
356 }
357 
358 void StdStrBuf::ReplaceEnd(size_t iPos, const char *szNewEnd)
359 {
360  size_t iLen = getLength();
361  assert(iPos <= iLen); if (iPos > iLen) return;
362  size_t iEndLen = strlen(szNewEnd);
363  if (iLen - iPos != iEndLen) SetLength(iPos + iEndLen);
364  memcpy(getMPtr(iPos), szNewEnd, iEndLen * sizeof(char));
365 }
366 
367 bool StdStrBuf::ValidateChars(const char *szInitialChars, const char *szMidChars)
368 {
369  // only given chars may be in string
370  for (size_t i=0; i<getLength(); ++i)
371  if (!strchr(i ? szMidChars : szInitialChars, getData()[i]))
372  return false;
373  return true;
374 }
375 
376 bool StdStrBuf::GetSection(size_t idx, StdStrBuf *psOutSection, char cSeparator) const
377 {
378  assert(psOutSection);
379  psOutSection->Clear();
380  const char *szStr = getData(), *szSepPos;
381  if (!szStr) return false; // invaid argument
382  while ((szSepPos = strchr(szStr, cSeparator)) && idx) { szStr = szSepPos+1; --idx; }
383  if (idx) return false; // indexed section not found
384  // fill output buffer with section, if not empty
385  if (!szSepPos) szSepPos = getData() + getLength();
386  if (szSepPos != szStr) psOutSection->Copy(szStr, szSepPos - szStr);
387  // return true even if section is empty, because the section obviously exists
388  // (to enable loops like while (buf.GetSection(i++, &sect)) if (sect) ...)
389  return true;
390 }
391 
393 {
394  if (!isNull())
395  for (char *szPos = getMPtr(0); *szPos; ++szPos)
396  *szPos = tolower(*szPos);
397 }
398 
399 void StdStrBuf::AppendCharacter(uint32_t unicodechar)
400 {
401  if (unicodechar < 0x80)
402  AppendChar(unicodechar);
403  else if (unicodechar < 0x800)
404  {
405  Grow(2);
406  *getMPtr(getLength() - 2) = (0xC0 | (unicodechar >> 6));
407  *getMPtr(getLength() - 1) = (0x80 | (unicodechar & 0x3F));
408  }
409  else if (unicodechar < 0x10000)
410  {
411  Grow(3);
412  *getMPtr(getLength() - 3) = (0xE0 | (unicodechar >> 12));
413  *getMPtr(getLength() - 2) = (0x80 | ((unicodechar >> 6) & 0x3F));
414  *getMPtr(getLength() - 1) = (0x80 | (unicodechar & 0x3F));
415  }
416  else if (unicodechar < 0x110000)
417  {
418  Grow(4);
419  *getMPtr(getLength() - 4) = (0xF0 | (unicodechar >> 18));
420  *getMPtr(getLength() - 3) = (0x80 | ((unicodechar >> 12) & 0x3F));
421  *getMPtr(getLength() - 2) = (0x80 | ((unicodechar >> 6) & 0x3F));
422  *getMPtr(getLength() - 1) = (0x80 | (unicodechar & 0x3F));
423  }
424  else /* not an unicode code point, ignore */ {}
425 }
426 
427 // Returns true if charset was converted.
429 {
430  // assume that it's windows-1252 and convert to utf-8
431  if (!IsValidUtf8(getData(), getLength()))
432  {
433  size_t j = 0;
434  StdStrBuf buf;
435  buf.Grow(getLength());
436  // totally unfounded statistic: most texts have less than 20 umlauts.
437  enum { GROWSIZE = 20 };
438  for (size_t i = 0; i < getSize(); ++i)
439  {
440  unsigned char c = *getPtr(i);
441  // ASCII
442  if (c < 0x80)
443  {
444  if (j >= buf.getLength())
445  buf.Grow(GROWSIZE);
446  *buf.getMPtr(j++) = c;
447  continue;
448  }
449  // Is c one of the control characters only in ISO/IEC_8859-1 or part of the common subset with windows-1252?
450  if (c == 0x81 || c == 0x8D || c == 0x8F || c == 0x90 || c == 0x9D || c >= 0xA0)
451  {
452  if (j + 1 >= buf.getLength())
453  buf.Grow(GROWSIZE);
454  *buf.getMPtr(j++) = (0xC0 | (c >> 6));
455  *buf.getMPtr(j++) = (0x80 | (c & 0x3F));
456  continue;
457  }
458  // Extra windows-1252-characters
459  buf.SetLength(j);
460  static const char * extra_chars [] =
461  {
462  //"€", 0, "‚", "ƒ", "„", "…", "†", "‡", "ˆ", "‰", "Š", "‹", "Œ", 0, "Ž", 0,
463  // 0, "‘", "’", "“", "”", "•", "–", "—", "˜", "™", "š", "›", "œ", 0, "ž", "Ÿ" };
464  "\xe2\x82\xac", 0, "\xe2\x80\x9a", "\xc6\x92", "\xe2\x80\x9e", "\xe2\x80\xa6", "\xe2\x80\xa0", "\xe2\x80\xa1", "\xcb\x86", "\xe2\x80\xb0", "\xc5\xa0", "\xe2\x80\xb9", "\xc5\x92", 0, "\xc5\xbd", 0,
465  0, "\xe2\x80\x98", "\xe2\x80\x99", "\xe2\x80\x9c", "\xe2\x80\x9d", "\xe2\x80\xa2", "\xe2\x80\x93", "\xe2\x80\x94", "\xcb\x9c", "\xe2\x84\xa2", "\xc5\xa1", "\xe2\x80\xba", "\xc5\x93", 0, "\xc5\xbe", "\xc5\xb8"
466  };
467  buf.Append(extra_chars[c - 0x80]);
468  j += strlen(extra_chars[c - 0x80]);
469  }
470  buf.SetLength(j);
471  Take(std::move(buf));
472  return true;
473  }
474  return false;
475 }
476 
478 {
479  // get left trim
480  int32_t iSpaceLeftCount = 0, iLength = getLength();
481  if (!iLength) return false;
482  const char *szStr = getData();
483  while (iSpaceLeftCount < iLength)
484  if (isspace((unsigned char)(unsigned char) szStr[iSpaceLeftCount]))
485  ++iSpaceLeftCount;
486  else
487  break;
488  // only spaces? Clear!
489  if (iSpaceLeftCount == iLength)
490  {
491  Clear();
492  return true;
493  }
494  // get right trim
495  int32_t iSpaceRightCount = 0;
496  while (isspace((unsigned char)szStr[iLength - 1 - iSpaceRightCount])) ++iSpaceRightCount;
497  // anything to trim?
498  if (!iSpaceLeftCount && !iSpaceRightCount) return false;
499  // only right trim? Can do this by shortening
500  if (!iSpaceLeftCount)
501  {
502  SetLength(iLength - iSpaceRightCount);
503  return true;
504  }
505  // left trim involved - move text and shorten
506  memmove(getMPtr(0), szStr+iSpaceLeftCount, iLength - iSpaceLeftCount - iSpaceRightCount);
507  SetLength(iLength - iSpaceLeftCount - iSpaceRightCount);
508  return true;
509 }
510 
511 #ifdef _WIN32
512 std::string WStrToString(wchar_t *ws)
513 {
514  int len = WideCharToMultiByte(CP_UTF8, 0, ws, -1, nullptr, 0, 0, 0);
515  assert(len >= 0);
516  if (len <= 0) return std::string{};
517 
518  std::string s(static_cast<size_t>(len), '\0');
519  s.resize(WideCharToMultiByte(CP_UTF8, 0, ws, -1, &s[0], s.size(), 0, 0) - 1);
520  return s;
521 }
522 #endif
const char * getData() const
Definition: StdBuf.h:450
virtual bool Separator(Sep eSep=SEP_SEP)
Definition: StdCompiler.h:129
bool GetSection(size_t idx, StdStrBuf *psOutSection, char cSeparator=';') const
Definition: StdBuf.cpp:376
const void * getData() const
Definition: StdBuf.h:107
Definition: StdBuf.h:37
int Replace(const char *szOld, const char *szNew, size_t iStartSearch=0)
Definition: StdBuf.cpp:291
void Clear()
Definition: StdBuf.h:474
StdStrBuf::wchar_t_holder GetWideChar(const char *utf8, bool double_null_terminate=false)
const char * SSearch(const char *szString, const char *szIndex)
Definition: Standard.cpp:333
bool LoadFromFile(const char *szFile)
Definition: StdBuf.cpp:39
bool ValidateChars(const char *szInitialChars, const char *szMidChars)
Definition: StdBuf.cpp:367
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:181
virtual void Raw(void *pData, size_t iSize, RawCompileType eType=RCT_Escaped)=0
void CompileFunc(class StdCompiler *pComp, int iType=0)
Definition: StdBuf.cpp:121
#define O_BINARY
Definition: StdBuf.cpp:28
#define O_CLOEXEC
size_t getSize() const
Definition: StdBuf.h:109
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType=RCT_Escaped)=0
void SetSize(size_t inSize)
Definition: StdBuf.h:212
void AppendFormat(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:197
char * getMData()
Definition: StdBuf.h:451
void AppendChar(char cChar)
Definition: StdBuf.h:596
void ToLowerCase()
Definition: StdBuf.cpp:392
bool LoadFromFile(const char *szFile)
Definition: StdBuf.cpp:80
void AppendBackslash()
Definition: StdBuf.cpp:255
bool SaveToFile(const char *szFile) const
Definition: StdBuf.cpp:101
ptrdiff_t ssize_t
void AppendCharacter(uint32_t unicodechar)
Definition: StdBuf.cpp:399
void Take(char *pnData)
Definition: StdBuf.h:465
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:527
void ReplaceEnd(size_t iPos, const char *szNewEnd)
Definition: StdBuf.cpp:358
StdStrBuf FormatStringV(const char *szFmt, va_list args)
Definition: StdBuf.cpp:283
bool IsValidUtf8(const char *text, int length)
Definition: Standard.cpp:666
void Value(const T &rStruct)
Definition: StdCompiler.h:171
int ReplaceChar(char cOld, char cNew)
Definition: StdBuf.cpp:343
void New(size_t inSize)
Definition: StdBuf.h:154
bool SaveToFile(const char *szFile) const
Definition: StdBuf.cpp:60
void AppendFormatV(const char *szFmt, va_list args)
Definition: StdBuf.cpp:205
virtual bool isDeserializer()
Definition: StdCompiler.h:63
StdIntPackAdapt< T > mkIntPackAdapt(T &rVal)
Definition: StdAdaptors.h:757
void Grow(size_t iGrow)
Definition: StdBuf.h:506
size_t FileSize(const char *szFilename)
Definition: StdFile.cpp:448
StdBuf GetWideCharBuf(const char *utf8)
size_t getSize() const
Definition: StdBuf.h:452
bool EnsureUnicode()
Definition: StdBuf.cpp:428
bool isNull() const
Definition: StdBuf.h:449
void FormatV(const char *szFmt, va_list args)
Definition: StdBuf.cpp:189
unsigned int iSize
Definition: StdBuf.h:100
const char * getPtr(size_t i) const
Definition: StdBuf.h:456
size_t getLength() const
Definition: StdBuf.h:453
bool TrimSpaces()
Definition: StdBuf.cpp:477
void SetLength(size_t iLength)
Definition: StdBuf.h:517
char * getMPtr(size_t i)
Definition: StdBuf.h:457
#define DirectorySeparator
#define O_SEQUENTIAL
Definition: StdBuf.cpp:29
void Copy()
Definition: StdBuf.h:475
#define s
void CompileFunc(class StdCompiler *pComp, int iRawType=0)
Definition: StdBuf.cpp:261
void * getMData()
Definition: StdBuf.h:108
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:277
StdStrBuf()=default