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 // Standard buffer classes
17 
18 #ifndef STDBUF_H
19 #define STDBUF_H
20 
21 #include <zlib.h>
22 
23 // debug memory management
24 #if defined(_DEBUG) && defined(_MSC_VER)
25 #include <crtdbg.h>
26 #endif
27 
28 // Base buffer class. Either references or holds data.
29 class StdBuf
30 {
31 public:
32 
33 	// *** Construction
34 	// Standard constructor
35 	StdBuf() = default;
36 
37 	// Constructor from other buffer (copy construction):
38 	// Will take over buffer ownership. Copies data if specified.
39 	// Note: Construct with Buf2.getRef() to construct a reference (This will work for a constant Buf2, too)
40 	StdBuf(StdBuf & Buf2, bool fCopy = false)
pData(nullptr)41 			: pData(nullptr)
42 	{
43 		if (fCopy)
44 			Copy(Buf2);
45 		else if (!Buf2.isRef())
46 			Take(std::move(Buf2));
47 		else
48 			Ref(Buf2);
49 	}
50 	StdBuf(const StdBuf & Buf2, bool fCopy = true)
pData(nullptr)51 			: pData(nullptr)
52 	{
53 		if (fCopy)
54 			Copy(Buf2);
55 		else
56 			Ref(Buf2);
57 	}
StdBuf(StdBuf && Buf2)58 	StdBuf(StdBuf && Buf2) noexcept
59 			: pData(nullptr)
60 	{
61 		if (!Buf2.isRef())
62 			Take(std::move(Buf2));
63 		else
64 			Ref(Buf2);
65 	}
66 
67 	// Set by constant data. Copies data if desired.
68 	StdBuf(const void *pData, size_t iSize, bool fCopy = false)
pData(pData)69 			: pData(pData), iSize(iSize)
70 	{
71 		if (fCopy) Copy();
72 	}
73 
~StdBuf()74 	~StdBuf()
75 	{
76 		Clear();
77 	}
78 
79 protected:
80 
81 	// Reference? Otherwise, this object holds the data.
82 	bool fRef = true;
83 	// Data
84 	union
85 	{
86 		const void *pData = nullptr;
87 		void *pMData;
88 #if defined(_DEBUG)
89 		char *szString; // for debugger preview
90 #endif
91 	};
92 	unsigned int iSize = 0;
93 
94 public:
95 
96 	// *** Getters
97 
isNull()98 	bool        isNull()  const { return ! getData(); }
getData()99 	const void *getData() const { return fRef ? pData : pMData; }
getMData()100 	void       *getMData()      { assert(!fRef); return pMData; }
getSize()101 	size_t      getSize() const { return iSize; }
isRef()102 	bool        isRef()   const { return fRef; }
103 
getPtr(size_t i)104 	const void *getPtr(size_t i) const { return reinterpret_cast<const char*>(getData()) + i; }
getMPtr(size_t i)105 	void       *getMPtr(size_t i)      { return reinterpret_cast<char*>(getMData()) + i; }
106 
getPart(size_t iStart,size_t inSize)107 	StdBuf getPart(size_t iStart, size_t inSize) const
108 	{
109 		assert(iStart + inSize <= iSize);
110 		return StdBuf(getPtr(iStart), inSize);
111 	}
112 
113 	// *** Setters
114 
115 	// * Direct setters
116 
117 	// Reference given data
Ref(const void * pnData,size_t inSize)118 	void Ref(const void *pnData, size_t inSize)
119 	{
120 		Clear();
121 		fRef = true; pData = pnData; iSize = inSize;
122 	}
123 	// Take over data (hold it)
Take(void * pnData,size_t inSize)124 	void Take(void *pnData, size_t inSize)
125 	{
126 		Clear();
127 		if (pnData)
128 		{
129 			fRef = false; pMData = pnData; iSize = inSize;
130 		}
131 	}
132 	// Transfer puffer ownership to the caller
GrabPointer()133 	void *GrabPointer()
134 	{
135 		if (isNull()) return nullptr;
136 		// Do not give out a buffer which someone else will free
137 		if (fRef) Copy();
138 		void *pMData = getMData();
139 		pData = pMData; fRef = true;
140 		return pMData;
141 	}
142 
143 	// * Buffer data operations
144 
145 	// Create new buffer with given size
New(size_t inSize)146 	void New(size_t inSize)
147 	{
148 		Clear();
149 		pMData = malloc(iSize = inSize);
150 		fRef = false;
151 	}
152 	// Write data into the buffer
153 	void Write(const void *pnData, size_t inSize, size_t iAt = 0)
154 	{
155 		assert(iAt + inSize <= iSize);
156 		if (pnData && inSize) std::memcpy(getMPtr(iAt), pnData, inSize);
157 	}
158 	// Move data around inside the buffer (checks overlap)
159 	void Move(size_t iFrom, size_t inSize, size_t iTo = 0)
160 	{
161 		assert(iFrom + inSize <= iSize); assert(iTo + inSize <= iSize);
162 		std::memmove(getMPtr(iTo), getPtr(iFrom), inSize);
163 	}
164 	// Compare to memory
165 	int Compare(const void *pCData, size_t iCSize, size_t iAt = 0) const
166 	{
167 		assert(iAt + iCSize <= getSize());
168 		return std::memcmp(getPtr(iAt), pCData, iCSize);
169 	}
170 	// Grow the buffer
Grow(size_t iGrow)171 	void Grow(size_t iGrow)
172 	{
173 		// Grow dereferences
174 		if (fRef) { Copy(iSize + iGrow); return; }
175 		if (!iGrow) return;
176 		// Realloc
177 		pMData = realloc(pMData, iSize += iGrow);
178 	}
179 	// Shrink the buffer
Shrink(size_t iShrink)180 	void Shrink(size_t iShrink)
181 	{
182 		assert(iSize >= iShrink);
183 		// Shrink dereferences
184 		if (fRef) { Copy(iSize - iShrink); return; }
185 		if (!iShrink) return;
186 		// Realloc
187 		pMData = realloc(pMData, iSize -= iShrink);
188 	}
189 	// Clear buffer
Clear()190 	void Clear()
191 	{
192 		if (!fRef) free(pMData);
193 		pMData = nullptr; fRef = true; iSize = 0;
194 	}
195 	// Free buffer that had been grabbed
DeletePointer(void * data)196 	static void DeletePointer(void *data)
197 	{
198 		free(data);
199 	}
200 
201 	// * Composed actions
202 
203 	// Set buffer size (dereferences)
SetSize(size_t inSize)204 	void SetSize(size_t inSize)
205 	{
206 		if (inSize > iSize)
207 			Grow(inSize - iSize);
208 		else
209 			Shrink(iSize - inSize);
210 	}
211 
212 	// Write buffer contents into the buffer
213 	void Write(const StdBuf &Buf2, size_t iAt = 0)
214 	{
215 		Write(Buf2.getData(), Buf2.getSize(), iAt);
216 	}
217 
218 	// Compare (a part of) this buffer's contents to another's
219 	int Compare(const StdBuf &Buf2, size_t iAt = 0) const
220 	{
221 		return Compare(Buf2.getData(), Buf2.getSize(), iAt);
222 	}
223 
224 	// Create a copy of the data (dereferences, obviously)
Copy(size_t inSize)225 	void Copy(size_t inSize)
226 	{
227 		if (isNull() && !inSize) return;
228 		const void *pOldData = getData();
229 		size_t iOldSize = iSize;
230 		New(inSize);
231 		Write(pOldData, std::min(iOldSize, inSize));
232 	}
Copy()233 	void Copy()
234 	{
235 		Copy(iSize);
236 	}
237 	// Copy data from address
Copy(const void * pnData,size_t inSize)238 	void Copy(const void *pnData, size_t inSize)
239 	{
240 		Ref(pnData, inSize); Copy();
241 	}
242 	// Copy from another buffer
Copy(const StdBuf & Buf2)243 	void Copy(const StdBuf &Buf2)
244 	{
245 		Copy(Buf2.getData(), Buf2.getSize());
246 	}
247 	// Create a copy and return it
Duplicate()248 	StdBuf Duplicate() const
249 	{
250 		StdBuf Buf; Buf.Copy(*this); return Buf;
251 	}
252 
253 	// Append data from address
Append(const void * pnData,size_t inSize)254 	void Append(const void *pnData, size_t inSize)
255 	{
256 		Grow(inSize);
257 		Write(pnData, inSize, iSize - inSize);
258 	}
259 	// Append data from another buffer
Append(const StdBuf & Buf2)260 	void Append(const StdBuf &Buf2)
261 	{
262 		Append(Buf2.getData(), Buf2.getSize());
263 	}
264 
265 	// Reference another buffer's contents
Ref(const StdBuf & Buf2)266 	void Ref(const StdBuf &Buf2)
267 	{
268 		Ref(Buf2.getData(), Buf2.getSize());
269 	}
270 	// Create a reference to this buffer's contents
getRef()271 	StdBuf getRef() const
272 	{
273 		return StdBuf(getData(), getSize());
274 	}
275 	// take over another buffer's contents
Take(StdBuf & Buf2)276 	void Take(StdBuf & Buf2)
277 	{
278 		Take(Buf2.GrabPointer(), Buf2.getSize());
279 	}
Take(StdBuf && Buf2)280 	void Take(StdBuf &&Buf2)
281 	{
282 		Take(Buf2.GrabPointer(), Buf2.getSize());
283 	}
284 
285 	// * File support
286 	bool LoadFromFile(const char *szFile);
287 	bool SaveToFile(const char *szFile) const;
288 
289 	// *** Operators
290 
291 	// Null check
292 	bool operator ! () const { return isNull(); }
293 
294 	// Appending
295 	StdBuf operator += (const StdBuf &Buf2)
296 	{
297 		Append(Buf2);
298 		return *this;
299 	}
300 	StdBuf operator + (const StdBuf &Buf2) const
301 	{
302 		StdBuf Buf(getRef());
303 		Buf.Append(Buf2);
304 		return Buf;
305 	}
306 
307 	// Compare
308 	bool operator == (const StdBuf &Buf2) const
309 	{
310 		return getSize() == Buf2.getSize() && !Compare(Buf2);
311 	}
312 	bool operator != (const StdBuf &Buf2) const { return ! operator == (Buf2); }
313 
314 	// Set (as constructor: take if possible)
315 	StdBuf &operator = (StdBuf &&Buf2)
316 	{
317 		if (Buf2.isRef()) Ref(Buf2); else Take(std::move(Buf2));
318 		return *this;
319 	}
320 
321 	// build a simple hash
GetHash()322 	int GetHash() const
323 	{
324 		if (isNull()) return 0;
325 		return crc32(0, reinterpret_cast<const Bytef *>(getData()), getSize());
326 	}
327 
328 	// *** Compiling
329 
330 	void CompileFunc(class StdCompiler *pComp, int iType = 0);
331 
332 };
333 
334 // Cast Hide Helpers - MSVC doesn't allow this as member template
335 template <class elem_t>
336 const elem_t *getBufPtr(const StdBuf &Buf, size_t iPos = 0)
337 {
338 	// assert(iPos + sizeof(elem_t) <= Buf.getSize());
339 	const void *pPos = reinterpret_cast<const char *>(Buf.getData()) + iPos;
340 	return reinterpret_cast<const elem_t *>(pPos);
341 }
342 template <class elem_t>
343 elem_t *getMBufPtr(StdBuf &Buf, size_t iPos = 0)
344 {
345 	// assert(iPos + sizeof(elem_t) <= Buf.getSize());
346 	void *pPos = reinterpret_cast<char *>(Buf.getMData()) + iPos;
347 	return reinterpret_cast<elem_t *>(pPos);
348 }
349 
350 // Copy-Buffer - Just copies data in the copy constructor.
351 class StdCopyBuf : public StdBuf
352 {
353 public:
354 
355 	StdCopyBuf() = default;
356 
357 	// Set by buffer. Copies data by default.
358 	StdCopyBuf(const StdBuf &Buf2, bool fCopy = true)
359 			: StdBuf(Buf2.getRef(), fCopy)
360 	{ }
361 
362 	// Set by buffer. Copies data by default.
363 	StdCopyBuf(const StdCopyBuf &Buf2, bool fCopy = true)
364 			: StdBuf(Buf2.getRef(), fCopy)
365 	{ }
StdCopyBuf(StdBuf & Buf2)366 	StdCopyBuf(StdBuf & Buf2) noexcept
367 			: StdBuf(std::move(Buf2))
368 	{ }
StdCopyBuf(StdCopyBuf && Buf2)369 	StdCopyBuf(StdCopyBuf &&Buf2) noexcept
370 			: StdBuf(std::move(Buf2))
371 	{ }
372 
373 	// Set by constant data. Copies data by default.
374 	StdCopyBuf(const void *pData, size_t iSize, bool fCopy = true)
StdBuf(pData,iSize,fCopy)375 			: StdBuf(pData, iSize, fCopy)
376 	{ }
377 
378 	StdCopyBuf &operator = (const StdBuf &Buf2) { Copy(Buf2); return *this; }
379 	StdCopyBuf &operator = (const StdCopyBuf &Buf2) { Copy(Buf2); return *this; }
380 
381 };
382 
383 // Stringbuffer (operates on null-terminated character buffers)
384 class StdStrBuf : protected StdBuf
385 {
386 public:
387 
388 	// *** Construction
389 
390 	StdStrBuf() = default;
391 
392 	// See StdBuf::StdBuf. Will take data if possible.
393 	// The static_cast is necessary to pass a rvalue reference to
394 	// the StdBuf constructor. Without it, the const lvalue
395 	// StdBuf constructor will be used, which will ref the contents
396 	// instead of moving them.
397 	StdStrBuf(StdStrBuf & Buf2, bool fCopy = false)
398 //			: StdBuf(static_cast<StdStrBuf &>(Buf2), fCopy)
StdBuf(Buf2,fCopy)399 			: StdBuf(Buf2, fCopy)
400 	{ }
401 
402 	// This constructor is important, because the compiler will create one
403 	// otherwise, despite having two other constructors to choose from
404 	StdStrBuf(const StdStrBuf & Buf2, bool fCopy = true)
StdBuf(Buf2,fCopy)405 			: StdBuf(Buf2, fCopy)
406 	{ }
StdStrBuf(StdStrBuf && Buf2)407 	StdStrBuf(StdStrBuf && Buf2) noexcept
408 			: StdBuf(std::move(Buf2))
409 	{ }
410 
411 	// Set by constant data. References data by default, copies if specified.
412 	explicit StdStrBuf(const char *pData, bool fCopy = false)
413 			: StdBuf(pData, pData ? strlen(pData) + 1 : 0, fCopy)
414 	{ }
415 
416 #ifdef _WIN32
417 	explicit StdStrBuf(const wchar_t * utf16);
418 	struct wchar_t_holder {
419 		wchar_t * p;
wchar_t_holderwchar_t_holder420 		wchar_t_holder(wchar_t * p): p(p) { }
421 		wchar_t_holder(const wchar_t_holder &);
~wchar_t_holderwchar_t_holder422 		~wchar_t_holder() { delete[] p; }
423 		operator wchar_t * () { return p; }
424 	};
425 	wchar_t_holder GetWideChar() const;
426 	StdBuf GetWideCharBuf();
427 #endif
428 
429 	// As previous constructor, but set length manually.
StdStrBuf(const char * pData,long int iLength)430 	StdStrBuf(const char *pData, long int iLength)
431 			: StdBuf(pData, pData ? iLength + 1 : 0, false)
432 	{ }
433 	StdStrBuf(const char *pData, size_t iLength, bool fCopy = false)
434 			: StdBuf(pData, pData ? iLength + 1 : 0, fCopy)
435 	{ }
436 
437 public:
438 
439 	// *** Getters
440 
isNull()441 	bool        isNull()  const { return StdBuf::isNull(); }
getData()442 	const char *getData() const { return getBufPtr<char>(*this); }
getMData()443 	char       *getMData()      { return getMBufPtr<char>(*this); }
getSize()444 	size_t      getSize() const { return StdBuf::getSize(); }
getLength()445 	size_t      getLength() const { return getSize() ? getSize() - 1 : 0; }
isRef()446 	bool        isRef()   const { return StdBuf::isRef(); }
447 
getPtr(size_t i)448 	const char *getPtr(size_t i) const { return getBufPtr<char>(*this, i); }
getMPtr(size_t i)449 	char       *getMPtr(size_t i)      { return getMBufPtr<char>(*this, i); }
450 
451 	// For convenience. Note that writing can't be allowed.
452 	char operator [] (size_t i) const { return *getPtr(i); }
453 
454 	// Analogous to StdBuf
Ref(const char * pnData)455 	void Ref(const char *pnData) { StdBuf::Ref(pnData, pnData ? std::strlen(pnData) + 1 : 0); }
Ref(const char * pnData,size_t iLength)456 	void Ref(const char *pnData, size_t iLength) { assert((!pnData && !iLength) || std::strlen(pnData) == iLength); StdBuf::Ref(pnData, iLength + 1); }
Take(char * pnData)457 	void Take(char *pnData) { StdBuf::Take(pnData, pnData ? std::strlen(pnData) + 1 : 0); }
Take(char * pnData,size_t iLength)458 	void Take(char *pnData, size_t iLength) { assert((!pnData && !iLength) || std::strlen(pnData) == iLength); StdBuf::Take(pnData, iLength + 1); }
GrabPointer()459 	char *GrabPointer() { return reinterpret_cast<char *>(StdBuf::GrabPointer()); }
460 
Ref(const StdStrBuf & Buf2)461 	void Ref(const StdStrBuf &Buf2) { StdBuf::Ref(Buf2.getData(), Buf2.getSize()); }
getRef()462 	StdStrBuf getRef() const { return StdStrBuf(getData(), getLength()); }
Take(StdStrBuf & Buf2)463 	void Take(StdStrBuf & Buf2) { StdBuf::Take(Buf2); }
Take(StdStrBuf && Buf2)464 	void Take(StdStrBuf &&Buf2) { StdBuf::Take(std::move(Buf2)); }
465 
Clear()466 	void Clear() { StdBuf::Clear(); }
Copy()467 	void Copy() { StdBuf::Copy(); }
Copy(const char * pnData)468 	void Copy(const char *pnData) { StdBuf::Copy(pnData, pnData ? std::strlen(pnData) + 1 : 0); }
Copy(const StdStrBuf & Buf2)469 	void Copy(const StdStrBuf &Buf2) { StdBuf::Copy(Buf2); }
Duplicate()470 	StdStrBuf Duplicate() const { StdStrBuf Buf; Buf.Copy(*this); return Buf; }
471 	void Move(size_t iFrom, size_t inSize, size_t iTo = 0) { StdBuf::Move(iFrom, inSize, iTo); }
472 
473 	// Byte-wise compare (will compare this string from iAt to the full string in Buf2)
474 	int Compare(const StdStrBuf &Buf2, size_t iAt = 0) const
475 	{
476 		assert(iAt <= getLength());
477 		const int result = StdBuf::Compare(Buf2.getData(), std::min(getLength() - iAt, Buf2.getLength()), iAt);
478 		if (result) return result;
479 
480 		if (getLength() < Buf2.getLength() + iAt) return -1;
481 		else if (getLength() > Buf2.getLength() + iAt) return 1;
482 		return 0;
483 	}
484 	int Compare_(const char *pCData, size_t iAt = 0) const
485 	{
486 		StdStrBuf str(pCData); // GCC needs this, for some obscure reason
487 		return Compare(str, iAt);
488 	}
BeginsWith(const char * beginning)489 	bool BeginsWith(const char *beginning) const
490 	{
491 		// Return whether string starts with beginning
492 		return strncmp((const char
493 			*)pData, beginning, strlen(beginning)) == 0;
494 	}
495 
496 	// Grows the string to contain the specified number more/less characters.
497 	// Note: Will set the terminator, but won't initialize - use Append* instead.
Grow(size_t iGrow)498 	void Grow(size_t iGrow)
499 	{
500 		StdBuf::Grow(getSize() ? iGrow : iGrow + 1);
501 		*getMPtr(getLength()) = '\0';
502 	}
Shrink(size_t iShrink)503 	void Shrink(size_t iShrink)
504 	{
505 		assert(iShrink <= getLength());
506 		StdBuf::Shrink(iShrink);
507 		*getMPtr(getLength()) = '\0';
508 	}
SetLength(size_t iLength)509 	void SetLength(size_t iLength)
510 	{
511 		if (iLength == getLength() && !isNull()) return;
512 		if (iLength >= getLength())
513 			Grow(iLength - getLength());
514 		else
515 			Shrink(getLength() - iLength);
516 	}
517 
518 	// Append string
Append(const char * pnData,size_t iChars)519 	void Append(const char *pnData, size_t iChars)
520 	{
521 		Grow(iChars);
522 		Write(pnData, iChars, iSize - iChars - 1);
523 	}
Append(const char * pnData)524 	void Append(const char *pnData)
525 	{
526 		Append(pnData, std::strlen(pnData));
527 	}
Append(const StdStrBuf & Buf2)528 	void Append(const StdStrBuf &Buf2)
529 	{
530 		Append(Buf2.getData(), Buf2.getLength());
531 	}
532 
533 	// Copy string
Copy(const char * pnData,size_t iChars)534 	void Copy(const char *pnData, size_t iChars)
535 	{
536 		Clear();
537 		Append(pnData, iChars);
538 	}
539 
540 	// * File support
541 	bool LoadFromFile(const char *szFile);
542 	bool SaveToFile(const char *szFile) const;
543 
544 	// * Operators
545 
546 	bool operator ! () const { return isNull(); }
547 
548 	StdStrBuf &operator += (const StdStrBuf &Buf2) { Append(Buf2); return *this; }
549 	StdStrBuf &operator += (const char *szString) { Append(szString); return *this; }
550 	StdStrBuf operator + (const StdStrBuf &Buf2) const { StdStrBuf Buf = getRef(); Buf.Append(Buf2); return Buf; }
551 	StdStrBuf operator + (const char *szString) const { StdStrBuf Buf = getRef(); Buf.Append(szString); return Buf; }
552 	StdStrBuf operator + (char c) const { StdStrBuf Buf = getRef(); Buf.AppendChar(c); return Buf; }
553 
554 	bool operator == (const StdStrBuf &Buf2) const
555 	{
556 		return getLength() == Buf2.getLength() && !Compare(Buf2);
557 	}
558 	bool operator != (const StdStrBuf &Buf2) const { return !operator == (Buf2); }
559 
560 	bool operator == (const char *szString) const { return StdStrBuf(szString) == *this; }
561 	bool operator != (const char *szString) const { return ! operator == (szString); }
562 
563 	// Note this references the data.
564 	StdStrBuf &operator = (const StdStrBuf &Buf2) { Ref(Buf2); return *this; }
565 	StdStrBuf &operator = (const char *szString) { Ref(szString); return *this; }
566 
567 	// conversion to "bool"
568 	operator const void *() const { return getData(); }
569 
570 	// less-than operation for map
571 	inline bool operator <(const StdStrBuf &v2) const
572 	{
573 		size_t iLen = getLength(), iLen2 = v2.getLength();
574 		if (iLen == iLen2)
575 			return iLen ? (std::strcmp(getData(), v2.getData())<0) : false;
576 		else
577 			return iLen < iLen2;
578 	}
579 
580 	// * String specific
581 
AppendChars(char cChar,size_t iCnt)582 	void AppendChars(char cChar, size_t iCnt)
583 	{
584 		Grow(iCnt);
585 		for (size_t i = getLength() - iCnt; i < getLength(); i++)
586 			*getMPtr(i) = cChar;
587 	}
AppendChar(char cChar)588 	void AppendChar(char cChar)
589 	{
590 		AppendChars(cChar, 1);
591 	}
592 	void AppendCharacter(uint32_t unicodechar);
593 	void AppendBackslash();
InsertChar(char cChar,size_t insert_before)594 	void InsertChar(char cChar, size_t insert_before)
595 	{
596 		assert(insert_before <= getLength());
597 		Grow(1);
598 		for (size_t i = getLength()-1; i > insert_before; --i)
599 			*getMPtr(i) = *getPtr(i-1);
600 		*getMPtr(insert_before) = cChar;
601 	}
602 
603 	// Append data until given character (or string end) occurs.
AppendUntil(const char * szString,char cUntil)604 	void AppendUntil(const char *szString, char cUntil)
605 	{
606 		const char *pPos = std::strchr(szString, cUntil);
607 		if (pPos)
608 			Append(szString, pPos - szString);
609 		else
610 			Append(szString);
611 	}
612 	// See above
CopyUntil(const char * szString,char cUntil)613 	void CopyUntil(const char *szString, char cUntil)
614 	{
615 		Clear();
616 		AppendUntil(szString, cUntil);
617 	}
618 	// cut end after given char into another string. Return whether char was found at all
SplitAtChar(char cSplit,StdStrBuf * psSplit)619 	bool SplitAtChar(char cSplit, StdStrBuf *psSplit)
620 	{
621 		if (!getData()) return false;
622 		const char *pPos = std::strchr(getData(), cSplit);
623 		if (!pPos) return false;
624 		size_t iPos = pPos - getData();
625 		if (psSplit) psSplit->Take(copyPart(iPos + 1, getLength() - iPos - 1));
626 		Shrink(getLength() - iPos);
627 		return true;
628 	}
629 
630 	void Format(const char *szFmt, ...) GNUC_FORMAT_ATTRIBUTE_O;
631 	void FormatV(const char *szFmt, va_list args);
632 	void AppendFormat(const char *szFmt, ...) GNUC_FORMAT_ATTRIBUTE_O;
633 	void AppendFormatV(const char *szFmt, va_list args);
634 
copyPart(size_t iStart,size_t inSize)635 	StdStrBuf copyPart(size_t iStart, size_t inSize) const
636 	{
637 		assert(iStart + inSize <= iSize);
638 		if (!inSize) return StdStrBuf();
639 		StdStrBuf sResult;
640 		sResult.Copy(getPtr(iStart), inSize);
641 		return sResult;
642 	}
643 
644 	// replace all occurences of one string with another. Return number of replacements.
645 	int Replace(const char *szOld, const char *szNew, size_t iStartSearch=0);
646 	int ReplaceChar(char cOld, char cNew);
647 
648 	// replace the trailing part of a string with something else
649 	void ReplaceEnd(size_t iPos, const char *szNewEnd);
650 
651 	// get an indexed section from the string like Section1;Section2;Section3
652 	bool GetSection(size_t idx, StdStrBuf *psOutSection, char cSeparator=';') const;
653 
654 	// Checks whether the content is valid UTF-8, and if not, convert it from windows-1252 to UTF-8 and return true.
655 	bool EnsureUnicode();
656 
657 	// convert to lower case
658 	void ToLowerCase();
659 
660 	// check if a string consists only of the given chars
661 	bool ValidateChars(const char *szInitialChars, const char *szMidChars);
662 
663 	// build a simple hash
GetHash()664 	int GetHash() const
665 	{
666 		return StdBuf::GetHash();
667 	}
668 
EscapeString()669 	void EscapeString()
670 	{
671 		Replace(R"(\)", R"(\\)");
672 		Replace(R"(")", R"(\")");
673 	}
674 
675 	bool TrimSpaces(); // kill spaces at beginning and end. Return if changed.
676 
677 	// * Compiling
678 
679 	void CompileFunc(class StdCompiler *pComp, int iRawType = 0);
680 
681 };
682 
683 // Copy-Stringbuffer - Just copies data in the copy constructor.
684 class StdCopyStrBuf : public StdStrBuf
685 {
686 public:
687 
688 	StdCopyStrBuf() = default;
689 
690 	explicit StdCopyStrBuf(const StdStrBuf &Buf2, bool fCopy = true)
691 			: StdStrBuf(Buf2.getRef(), fCopy)
692 	{ }
693 
694 	StdCopyStrBuf(const StdCopyStrBuf &Buf2, bool fCopy = true)
695 			: StdStrBuf(Buf2.getRef(), fCopy)
696 	{ }
697 	StdCopyStrBuf(StdStrBuf && Buf2) noexcept
698 			: StdStrBuf(std::move(Buf2))
699 	{ }
700 	StdCopyStrBuf(StdCopyStrBuf && Buf2) noexcept
701 			: StdStrBuf(std::move(Buf2))
702 	{ }
703 
704 	// Set by constant data. Copies data if desired.
705 	explicit StdCopyStrBuf(const char *pData, bool fCopy = true)
706 			: StdStrBuf(pData, fCopy)
707 	{ }
708 
709 #ifdef _WIN32
710 	explicit StdCopyStrBuf(const wchar_t * utf16): StdStrBuf(utf16) {}
711 #endif
712 
713 	StdCopyStrBuf(const std::string &s) noexcept
714 		: StdStrBuf(s.c_str(), s.size(), true)
715 	{ }
716 
717 	StdCopyStrBuf &operator = (const StdStrBuf &Buf2) { Copy(Buf2); return *this; }
718 	StdCopyStrBuf &operator = (const StdCopyStrBuf &Buf2) { Copy(Buf2); return *this; }
719 	StdCopyStrBuf &operator = (const char *szString) { Copy(szString); return *this; }
720 	StdCopyStrBuf &operator = (const std::string &s) { Copy(s.c_str(), s.size()); return *this; }
721 
722 	operator std::string() const
723 	{
724 		return std::string(getData(), getLength());
725 	}
726 };
727 
728 // Wrappers
729 extern StdStrBuf FormatString(const char *szFmt, ...) GNUC_FORMAT_ATTRIBUTE;
730 extern StdStrBuf FormatStringV(const char *szFmt, va_list args);
731 
732 #ifdef _WIN32
733 // Converts a wide char string to UTF-8 std::string
734 std::string WStrToString(wchar_t *s);
735 #endif
736 
737 #endif
738