1 //=============================================================================
2 //
3 //   File : KviCString.cpp
4 //   Creation date : Fri Mar 19 1999 03:20:45 by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 1999-2008 Szymon Stefanek (pragma at kvirc dot net)
8 //
9 //   This program is FREE software. You can redistribute it and/or
10 //   modify it under the terms of the GNU General Public License
11 //   as published by the Free Software Foundation; either version 2
12 //   of the License, or (at your option) any later version.
13 //
14 //   This program is distributed in the HOPE that it will be USEFUL,
15 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 //   See the GNU General Public License for more details.
18 //
19 //   You should have received a copy of the GNU General Public License
20 //   along with this program. If not, write to the Free Software Foundation,
21 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24 
25 #include "kvi_debug.h"
26 
27 #define _KVI_STRING_CPP_
28 
29 #include "KviCString.h"
30 #include "KviMemory.h"
31 
32 #include <QString>
33 
34 static char hexdigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
35 
kvi_wstrlen(const kvi_wchar_t * str)36 kvi_wslen_t kvi_wstrlen(const kvi_wchar_t * str)
37 {
38 	const kvi_wchar_t * ptr = str;
39 	while(*ptr)
40 		ptr++;
41 	return (ptr - str);
42 }
43 
kvi_qstringEqualCI(const QString & s1,const QString & s2)44 bool kvi_qstringEqualCI(const QString & s1, const QString & s2)
45 {
46 	const QChar * p1 = s1.unicode();
47 	const QChar * p2 = s2.unicode();
48 	int l = s1.length() < s2.length() ? s1.length() : s2.length();
49 
50 	while(l-- && (p1->toLower() == p2->toLower()))
51 		p1++, p2++;
52 
53 	if(l == -1)
54 		return true;
55 	return false;
56 }
57 
kvi_matchStringCI(const char * exp,const char * str)58 bool kvi_matchStringCI(const char * exp, const char * str)
59 {
60 	//               a
61 	//               .
62 	// exp = a*x?mem*a
63 	// str = arexoxmexamemizazv
64 	//                         .
65 	//                         n
66 	const char * afterWild = nullptr;
67 	const char * nextStrToCheck = nullptr;
68 
69 	while(*exp)
70 	{
71 		if(*exp == '*')
72 		{
73 			// exp is a wildcard...
74 			afterWild = ++exp;
75 			nextStrToCheck = str + 1;
76 			if(!(*exp))
77 				return true; // and it's the last char in the string: matches everything ahead
78 			continue;
79 		}
80 
81 		if(!(*str))
82 			return false; // str finished but we had something to match :(
83 
84 		if(tolower(*exp) == tolower(*str))
85 		{
86 			// chars matched
87 			++exp;
88 			++str;
89 			if((!(*exp)) && *str)
90 				goto check_recovery;
91 			continue;
92 		}
93 
94 		if(*exp == '?')
95 		{
96 			// any-char wildcard
97 			++exp;
98 			++str;
99 			continue;
100 		}
101 
102 	check_recovery:
103 		// chars unmatched!!!
104 		if(afterWild)
105 		{
106 			// we had a wildcard in exp...
107 			// let's use this jolly then
108 			exp = afterWild;
109 			str = nextStrToCheck;
110 			nextStrToCheck++;
111 			// and try to compare now
112 			continue;
113 		}
114 
115 		return false; // no match :(
116 	}
117 	return (!(*str));
118 }
119 
kvi_matchStringCS(const char * exp,const char * str)120 bool kvi_matchStringCS(const char * exp, const char * str)
121 {
122 	//               a
123 	//               .
124 	// exp = a*x?mem*a
125 	// str = arexoxmexamemizazv
126 	//                         .
127 	//                         n
128 	const char * afterWild = nullptr;
129 	const char * nextStrToCheck = nullptr;
130 
131 	while(*exp)
132 	{
133 		if(*exp == '*')
134 		{
135 			// exp is a wildcard...
136 			afterWild = ++exp;
137 			nextStrToCheck = str + 1;
138 			if(!(*exp))
139 				return true; // and it's the last char in the string: matches everything ahead
140 			continue;
141 		}
142 
143 		if(!(*str))
144 			return false; // str finished but we had something to match :(
145 
146 		if(*exp == *str)
147 		{
148 			// chars matched
149 			++exp;
150 			++str;
151 			if((!(*exp)) && *str)
152 				goto check_recovery;
153 			continue;
154 		}
155 
156 		if(*exp == '?')
157 		{
158 			// any-char wildcard
159 			++exp;
160 			++str;
161 			continue;
162 		}
163 
164 	check_recovery:
165 		// chars unmatched!!!
166 		if(afterWild)
167 		{
168 			// we had a wildcard in exp...
169 			// let's use this jolly then
170 			exp = afterWild;
171 			str = nextStrToCheck;
172 			nextStrToCheck++;
173 			// and try to compare now
174 			continue;
175 		}
176 
177 		return false; // no match :(
178 	}
179 	return (!(*str));
180 }
181 
kvi_matchStringWithTerminator(const char * exp,const char * str,char terminator,const char ** r1,const char ** r2)182 bool kvi_matchStringWithTerminator(const char * exp, const char * str, char terminator, const char ** r1, const char ** r2)
183 {
184 #define NOT_AT_END(__str) (*__str && (*__str != terminator))
185 
186 	//               a
187 	//               .
188 	// exp = a*x?mem*a
189 	// str = arexoxmexamemizazv
190 	//                         .
191 	//                         n
192 	const char * afterWild = nullptr;
193 	const char * nextStrToCheck = nullptr;
194 
195 	while(NOT_AT_END(exp))
196 	{
197 		if(*exp == '*')
198 		{
199 			// exp is a wildcard...
200 			afterWild = ++exp;
201 			nextStrToCheck = str + 1;
202 			if(!(NOT_AT_END(exp)))
203 			{
204 				while(NOT_AT_END(str))
205 					str++;
206 				*r1 = exp;
207 				*r2 = str;
208 				return true; // and it's the last char in the string: matches everything ahead
209 			}
210 			continue;
211 		}
212 
213 		if(!(*str))
214 			return false; // str finished but we had something to match :(
215 
216 		if(tolower(*exp) == tolower(*str))
217 		{
218 			// chars matched
219 			++exp;
220 			++str;
221 			if((!(NOT_AT_END(exp))) && NOT_AT_END(str))
222 				goto check_recovery;
223 			continue;
224 		}
225 
226 		if(*exp == '?')
227 		{
228 			// any-char wildcard
229 			++exp;
230 			++str;
231 			continue;
232 		}
233 
234 	check_recovery:
235 		// chars unmatched!!!
236 		if(afterWild)
237 		{
238 			// we had a wildcard in exp...
239 			// let's use this jolly then
240 			exp = afterWild;
241 			str = nextStrToCheck;
242 			nextStrToCheck++;
243 			// and try to compare now
244 			continue;
245 		}
246 
247 		return false; // no match :(
248 	}
249 	*r1 = exp;
250 	*r2 = str;
251 	return (!(NOT_AT_END(str)));
252 
253 #undef NOT_AT_END
254 }
255 
kvi_matchWildExpr(const char * m1,const char * m2)256 bool kvi_matchWildExpr(const char * m1, const char * m2)
257 {
258 	//Matches two regular expressions containging wildcards (* and ?)
259 
260 	//          s1
261 	//          m1
262 	// mask1 : *xor
263 	// mask2 : xorand*xor
264 	//         m2
265 	//          s2
266 
267 	//                        s2
268 	//                       m2
269 	//                       |
270 	// XorT!xor@111.111.111.11
271 	//
272 	// *!*@*.net
273 	//      |
274 	//      m1
275 	//      s1
276 	//
277 
278 	if(!(m1 && m2 && (*m1)))
279 		return false;
280 	const char * savePos1 = nullptr;
281 	const char * savePos2 = m2;
282 	while(*m1)
283 	{
284 		//loop managed by m1 (initially first mask)
285 		if(*m1 == '*')
286 		{
287 			//Found a wildcard in m1
288 			savePos1 = ++m1; //move to the next char and save the position...this is our jolly
289 			if(!*savePos1)
290 				return true;   //last was a wildcard, matches everything ahead...
291 			savePos2 = m2 + 1; //next return state for the second string
292 			continue;          //and return
293 		}
294 		if(!(*m2))
295 			return false; //m2 finished and we had something to match here!
296 		if(tolower(*m1) == tolower(*m2))
297 		{
298 			//chars matched
299 			m1++; //Go ahead in the two strings
300 			m2++; //
301 			if((!(*m1)) && *m2 && savePos1)
302 			{
303 				//m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
304 				//retry matching the string following the * from the savePos2 (one char ahead last time)
305 				m1 = savePos1; //back to char after wildcard
306 				m2 = savePos2; //back to last savePos2
307 				savePos2++;    //next savePos2 will be next char
308 			}
309 		}
310 		else
311 		{
312 			if(*m2 == '*')
313 			{
314 				//A wlidcard in the second string
315 				//Invert the game : mask1 <-> mask2
316 				//mask2 now leads the game...
317 				savePos1 = m1;     //aux
318 				m1 = m2;           //...swap
319 				m2 = savePos1;     //...swap
320 				savePos1 = m1;     //sync save pos1
321 				savePos2 = m2 + 1; //sync save pos2
322 				continue;          //...and again
323 			}
324 			// m1 != m2, m1 != *, m2 != *
325 			if((*m1 == '?') || (*m2 == '?'))
326 			{
327 				m1++;
328 				m2++;
329 				if((!(*m1)) && *m2 && savePos1)
330 				{
331 					//m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
332 					//retry matching the string following the * from the savePos2 (one char ahead last time)
333 					m1 = savePos1; //back to char after wildcard
334 					m2 = savePos2; //back to last savePos2
335 					savePos2++;    //next savePos2 will be next char
336 				}
337 			}
338 			else
339 			{
340 				if(savePos1)
341 				{
342 					//Have a jolly man...allow not matching...
343 					m1 = savePos1; //go back to char after wildcard...need to rematch...
344 					m2 = savePos2; //back to last savePos2
345 					savePos2++;    //and set next savePos2
346 				}
347 				else
348 					return false; //No previous wildcards...not matched!
349 			}
350 		}
351 	}
352 	return (!(*m2)); //m1 surely finished, so for the match, m2 must be finished too
353 }
354 
355 /*
356 
357 	WARNING: Don't remove: working code but actually unused in KVIrc
358 			Later it might become useful
359 
360 bool kvi_matchWildExprCS(const char *m1,const char *m2)
361 {
362 	if(!(m1 && m2 && (*m1)))return false;
363 	const char * savePos1 = nullptr;
364 	const char * savePos2 = m2;
365 	while(*m1){ //loop managed by m1 (initially first mask)
366 		if(*m1=='*'){
367 			//Found a wildcard in m1
368 			savePos1 = ++m1;            //move to the next char and save the position...this is our jolly
369 			if(!*savePos1)return true;  //last was a wildcard, matches everything ahead...
370 			savePos2 = m2+1;            //next return state for the second string
371 			continue;                   //and return
372 		}
373 		if(!(*m2))return false;         //m2 finished and we had something to match here!
374 		if((*m1)==(*m2)){
375 			//chars matched
376 			m1++;                       //Go ahead in the two strings
377 			m2++;                       //
378 			if((!(*m1)) && *m2 && savePos1){
379 				//m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
380 				//retry matching the string following the * from the savePos2 (one char ahead last time)
381 				m1 = savePos1;          //back to char after wildcard
382 				m2 = savePos2;          //back to last savePos2
383 				savePos2++;             //next savePos2 will be next char
384 			}
385 		} else {
386 			if(*m2 == '*'){
387 				//A wlidcard in the second string
388 				//Invert the game : mask1 <-> mask2
389 				//mask2 now leads the game...
390 				savePos1 = m1;          //aux
391 				m1 = m2;                //...swap
392 				m2 = savePos1;          //...swap
393 				savePos1 = m1;          //sync save pos1
394 				savePos2 = m2 + 1;      //sync save pos2
395 				continue;               //...and again
396 			}
397 			if(savePos1){               //Have a jolly man...allow not matching...
398 				m1 = savePos1;          //go back to char after wildcard...need to rematch...
399 				m2 = savePos2;          //back to last savePos2
400 				savePos2++;             //and set next savePos2
401 			} else return false;        //No previous wildcards...not matched!
402 		}
403 	}
404 	return (!(*m2));                     //m1 surely finished, so for the match, m2 must be finished too
405 
406 }
407 */
408 
kvi_matchWildExprWithTerminator(const char * m1,const char * m2,char terminator,const char ** r1,const char ** r2)409 bool kvi_matchWildExprWithTerminator(const char * m1, const char * m2, char terminator,
410     const char ** r1, const char ** r2)
411 {
412 //Matches two regular expressions containging wildcards
413 
414 #define NOT_AT_END(__str) (*__str && (*__str != terminator))
415 
416 	bool bSwapped = false;
417 	if(!(m1 && m2 && (NOT_AT_END(m1))))
418 		return false;
419 	const char * savePos1 = nullptr;
420 	const char * savePos2 = m2;
421 	while(NOT_AT_END(m1))
422 	{
423 		//loop managed by m1 (initially first mask)
424 		if(*m1 == '*')
425 		{
426 			//Found a wildcard in m1
427 			savePos1 = ++m1; //move to the next char and save the position...this is our jolly
428 			if(!NOT_AT_END(savePos1))
429 			{
430 				//last was a wildcard, matches everything ahead...
431 				while(NOT_AT_END(m2))
432 					m2++;
433 				*r1 = bSwapped ? m2 : m1;
434 				*r2 = bSwapped ? m1 : m2;
435 				return true;
436 			}
437 			savePos2 = m2 + 1; //next return state for the second string
438 			continue;          //and return
439 		}
440 		if(!NOT_AT_END(m2))
441 			return false; //m2 finished and we had something to match here!
442 		if(tolower(*m1) == tolower(*m2))
443 		{
444 			//chars matched
445 			m1++; //Go ahead in the two strings
446 			m2++; //
447 			if((!NOT_AT_END(m1)) && NOT_AT_END(m2) && savePos1)
448 			{
449 				//m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
450 				//retry matching the string following the * from the savePos2 (one char ahead last time)
451 				m1 = savePos1; //back to char after wildcard
452 				m2 = savePos2; //back to last savePos2
453 				savePos2++;    //next savePos2 will be next char
454 			}
455 		}
456 		else
457 		{
458 			if(*m2 == '*')
459 			{
460 				//A wlidcard in the second string
461 				//Invert the game : mask1 <-> mask2
462 				//mask2 now leads the game...
463 				bSwapped = !bSwapped;
464 				savePos1 = m1;     //aux
465 				m1 = m2;           //...swap
466 				m2 = savePos1;     //...swap
467 				savePos1 = m1;     //sync save pos1
468 				savePos2 = m2 + 1; //sync save pos2
469 				continue;          //...and again
470 			}
471 			// m1 != m2, m1 != *, m2 != *
472 			if((*m1 == '?') || (*m2 == '?'))
473 			{
474 				m1++;
475 				m2++;
476 				if((!NOT_AT_END(m1)) && NOT_AT_END(m2) && savePos1)
477 				{
478 					//m1 finished, but m2 not yet and we have a savePosition for m1 (there was a wildcard)...
479 					//retry matching the string following the * from the savePos2 (one char ahead last time)
480 					m1 = savePos1; //back to char after wildcard
481 					m2 = savePos2; //back to last savePos2
482 					savePos2++;    //next savePos2 will be next char
483 				}
484 			}
485 			else
486 			{
487 				if(savePos1)
488 				{
489 					//Have a jolly man...allow not matching...
490 					m1 = savePos1; //go back to char after wildcard...need to rematch...
491 					m2 = savePos2; //back to last savePos2
492 					savePos2++;    //and set next savePos2
493 				}
494 				else
495 					return false; //No previous wildcards...not matched!
496 			}
497 		}
498 	}
499 	*r1 = bSwapped ? m2 : m1;
500 	*r2 = bSwapped ? m1 : m2;
501 
502 	return (!NOT_AT_END(m2)); //m1 surely finished, so for the match, m2 must be finished too
503 
504 #undef NOT_AT_END
505 }
506 
kvi_extractToken(KviCString & str,const char * aux_ptr,char sep)507 const char * kvi_extractToken(KviCString & str, const char * aux_ptr, char sep)
508 {
509 	KVI_ASSERT(aux_ptr);
510 	while(*aux_ptr && (*aux_ptr == sep))
511 		aux_ptr++;
512 	const char * p = aux_ptr;
513 	while(*p && (*p != sep))
514 		p++;
515 	str.m_len = p - aux_ptr;
516 	str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
517 	KviMemory::copy(str.m_ptr, aux_ptr, str.m_len);
518 	*(str.m_ptr + str.m_len) = '\0';
519 	while(*p && (*p == sep))
520 		p++;
521 	return p;
522 }
523 
kvi_extractUpTo(KviCString & str,const char * aux_ptr,char sep)524 const char * kvi_extractUpTo(KviCString & str, const char * aux_ptr, char sep)
525 {
526 	KVI_ASSERT(aux_ptr);
527 	const char * p = aux_ptr;
528 	while(*p && (*p != sep))
529 		p++;
530 	str.m_len = p - aux_ptr;
531 	str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
532 	KviMemory::copy(str.m_ptr, aux_ptr, str.m_len);
533 	*(str.m_ptr + str.m_len) = '\0';
534 	return p;
535 }
536 
kvi_vsnprintf(char * buffer,int len,const char * fmt,kvi_va_list list)537 int kvi_vsnprintf(char * buffer, int len, const char * fmt, kvi_va_list list)
538 {
539 	KVI_ASSERT(fmt);
540 	KVI_ASSERT(buffer);
541 	KVI_ASSERT(len > 0); //printing 0 characters is senseless
542 
543 	char * p;
544 	char * argString;
545 	long argValue;
546 	unsigned long argUValue;
547 
548 	//9999999999999999999999999999999\0
549 	char numberBuffer[32]; //enough ? 10 is enough for 32bit unsigned int...
550 	char * pNumBuf;
551 	unsigned int tmp;
552 
553 	for(p = buffer; *fmt; ++fmt)
554 	{
555 		if(len < 1)
556 			return (-1); //not enough space ... (in fact this could be len < 2 for the terminator)
557 		//copy up to a '%'
558 		if(*fmt != '%')
559 		{
560 			*p++ = *fmt;
561 			--len;
562 			continue;
563 		}
564 
565 		++fmt; //skip this '%'
566 		switch(*fmt)
567 		{
568 			case 's': //string
569 				argString = kvi_va_arg(list, char *);
570 				if(!argString)
571 					continue;
572 				argValue = (long)strlen(argString);
573 				//check for space...
574 				if(len <= argValue)
575 					return (-1); //not enough space for buffer and terminator
576 				while(*argString)
577 					*p++ = *argString++;
578 				len -= argValue;
579 				continue;
580 			case 'd': //signed integer
581 				argValue = kvi_va_arg(list, int);
582 				if(argValue < 0)
583 				{ //negative integer
584 					*p++ = '-';
585 					if(--len == 0)
586 						return (-1);
587 					argValue = -argValue; //need to have it positive
588 					// most negative integer exception (avoid completely senseless (non digit) responses)
589 					if(argValue < 0)
590 						argValue = 0; //we get -0 here
591 				}
592 				//write the number in a temporary buffer
593 				pNumBuf = numberBuffer;
594 				do
595 				{
596 					tmp = argValue / 10;
597 					*pNumBuf++ = argValue - (tmp * 10) + '0';
598 				} while((argValue = tmp));
599 				//copy now....
600 				argUValue = pNumBuf - numberBuffer; //length of the number string
601 				if(((uint)len) <= argUValue)
602 					return (-1); //not enough space for number and terminator
603 				do
604 				{
605 					*p++ = *--pNumBuf;
606 				} while(pNumBuf != numberBuffer);
607 				len -= argUValue;
608 				continue;
609 			case 'u':                                       //unsigned integer
610 				argUValue = kvi_va_arg(list, unsigned int); //many implementations place int here
611 				//write the number in a temporary buffer
612 				pNumBuf = numberBuffer;
613 				do
614 				{
615 					tmp = argUValue / 10;
616 					*pNumBuf++ = argUValue - (tmp * 10) + '0';
617 				} while((argUValue = tmp));
618 				//copy now....
619 				argValue = pNumBuf - numberBuffer; //length of the number string
620 				if(len <= argValue)
621 					return (-1); //not enough space for number and terminator
622 				do
623 				{
624 					*p++ = *--pNumBuf;
625 				} while(pNumBuf != numberBuffer);
626 				len -= argValue;
627 				continue;
628 			case 'x':                                       // hexadecimal unsigned integer
629 				argUValue = kvi_va_arg(list, unsigned int); //many implementations place int here
630 				//write the number in a temporary buffer
631 				pNumBuf = numberBuffer;
632 				do
633 				{
634 					tmp = argUValue / 16;
635 					*pNumBuf++ = hexdigits[argUValue % 16];
636 				} while((argUValue = tmp));
637 				//copy now....
638 				argValue = pNumBuf - numberBuffer; //length of the number string
639 				if(len <= argValue)
640 					return (-1); //not enough space for number and terminator
641 				do
642 				{
643 					*p++ = *--pNumBuf;
644 				} while(pNumBuf != numberBuffer);
645 				len -= argValue;
646 				continue;
647 			case 'c': //char
648 				//
649 				// I'm not sure about this...
650 				// In the linux kernel source the
651 				// unsigned char is extracted from an integer type.
652 				// We assume that gcc stacks a char argument
653 				// as sizeof(int) bytes value.
654 				// Is this always true ?
655 				//
656 				*p++ = (char)kvi_va_arg(list, int);
657 				--len;
658 				continue;
659 			case 'Q': // QString! (this should almost never happen)
660 			{
661 				QString * s = kvi_va_arg(list, QString *);
662 				QByteArray cs = (*s).toUtf8();
663 				const char * t = cs.data();
664 				if(!t)
665 					continue; // nothing to do
666 				//check for space...
667 				if(len <= (int)cs.length())
668 					return (-1); //not enough space for buffer and terminator
669 				while(*t)
670 					*p++ = *t++;
671 				len -= cs.length();
672 				continue;
673 			}
674 			default:        //a normal percent
675 				*p++ = '%'; //write it
676 				if(--len == 0)
677 					return (-1); //not enough space for next char or terminator
678 				if(*fmt)
679 				{                //this if is just in case that we have a % at the end of the string.
680 					*p++ = *fmt; //and write this char
681 					--len;
682 				}
683 				continue;
684 		}
685 	}
686 	if(len < 1)
687 		return (-1); //missing space for terminator
688 	*p = '\0';
689 	return p - buffer;
690 }
691 
692 //
693 // Nearly the same as the above function...
694 //
695 
kvi_irc_vsnprintf(char * buffer,const char * fmt,kvi_va_list list,bool * bTruncated)696 int kvi_irc_vsnprintf(char * buffer, const char * fmt, kvi_va_list list, bool * bTruncated)
697 {
698 	KVI_ASSERT(fmt);
699 	KVI_ASSERT(buffer);
700 	if(!(buffer && fmt))
701 		return false;
702 	char * p;
703 	char * argString;
704 	long argValue;
705 	unsigned long argUValue;
706 	char numberBuffer[64]; //enough ? 10 is enough for 32bit unsigned int...
707 	char * pNumBuf;
708 	unsigned int tmp;
709 	*bTruncated = false;
710 	int len = 512;
711 
712 	for(p = buffer; *fmt; ++fmt)
713 	{
714 		if(len < 3)
715 			goto truncate;
716 		//copy up to a '%'
717 		if(*fmt != '%')
718 		{
719 			*p++ = *fmt;
720 			--len;
721 			continue;
722 		}
723 		++fmt; //skip this '%'
724 		switch(*fmt)
725 		{
726 			case 's': //string
727 				argString = kvi_va_arg(list, char *);
728 				if(!argString)
729 					continue;
730 				//check for space...
731 				while(*argString)
732 				{
733 					*p++ = *argString++;
734 					if(--len < 3)
735 						goto truncate;
736 				}
737 				continue;
738 			case 'Q': // QString! (this should almost never happen)
739 			{
740 				QString * s = kvi_va_arg(list, QString *);
741 				QByteArray cs = (*s).toUtf8();
742 				const char * t = cs.data();
743 				if(!t)
744 					continue; // nothing to do
745 				while(*t)
746 				{
747 					*p++ = *t++;
748 					if(--len < 3)
749 						goto truncate;
750 				}
751 				continue;
752 			}
753 			case 'd': //signed integer
754 				argValue = kvi_va_arg(list, int);
755 				if(argValue < 0)
756 				{ //negative integer
757 					*p++ = '-';
758 					if(--len < 3)
759 						goto truncate;    //place just for CRLF
760 					argValue = -argValue; //need to have it positive
761 					if(argValue < 0)
762 						argValue = 0; // -0 (hack the exception)
763 				}
764 				//write the number in a temporary buffer
765 				pNumBuf = numberBuffer;
766 				do
767 				{
768 					tmp = argValue / 10;
769 					*pNumBuf++ = argValue - (tmp * 10) + '0';
770 				} while((argValue = tmp));
771 				//copy now....
772 				do
773 				{
774 					*p++ = *--pNumBuf;
775 					if(--len < 3)
776 						goto truncate;
777 				} while(pNumBuf != numberBuffer);
778 				continue;
779 			case 'u':                                       //unsigned integer
780 				argUValue = kvi_va_arg(list, unsigned int); //many implementations place int here
781 				//write the number in a temporary buffer
782 				pNumBuf = numberBuffer;
783 				do
784 				{
785 					tmp = argUValue / 10;
786 					*pNumBuf++ = argUValue - (tmp * 10) + '0';
787 				} while((argUValue = tmp));
788 				//copy now....
789 				if(--len < 3)
790 					goto truncate; //no place for digits
791 				do
792 				{
793 					*p++ = *--pNumBuf;
794 					if(--len < 3)
795 						goto truncate;
796 				} while(pNumBuf != numberBuffer);
797 				continue;
798 			case 'c': //char
799 				*p++ = (char)kvi_va_arg(list, int);
800 				--len;
801 				continue;
802 			default:        //a normal percent
803 				*p++ = '%'; //write it
804 				if(--len < 3)
805 					goto truncate; //not enough space for next char
806 				if(*fmt)
807 				{                //this if is just in case that we have a % at the end of the string.
808 					*p++ = *fmt; //and write this char
809 					--len;
810 				}
811 				continue;
812 		}
813 	}
814 	//successful finish
815 	KVI_ASSERT(len >= 2);
816 	*p++ = '\r';
817 	*p = '\n';
818 	return ((p - buffer) + 1);
819 truncate:
820 	KVI_ASSERT(len >= 2);
821 	*bTruncated = true;
822 	*p++ = '\r';
823 	*p = '\n';
824 	return ((p - buffer) + 1);
825 }
826 
827 #ifndef COMPILE_ix86_ASM
828 
kvi_strEqualCS(const char * str1,const char * str2)829 bool kvi_strEqualCS(const char * str1, const char * str2)
830 {
831 	KVI_ASSERT(str1);
832 	KVI_ASSERT(str2);
833 	if(!(str1 && str2))
834 		return false;
835 	unsigned char * s1 = (unsigned char *)str1;
836 	unsigned char * s2 = (unsigned char *)str2;
837 	while(*s1)
838 		if(*s1++ != *s2++)
839 			return false;
840 	return (*s1 == *s2);
841 }
842 
kvi_strEqualCSN(const char * str1,const char * str2,int len)843 bool kvi_strEqualCSN(const char * str1, const char * str2, int len)
844 {
845 	KVI_ASSERT(str1);
846 	KVI_ASSERT(str2);
847 	KVI_ASSERT(len >= 0);
848 	if(!(str1 && str2 && (len >= 0)))
849 		return false;
850 	unsigned char * s1 = (unsigned char *)str1;
851 	unsigned char * s2 = (unsigned char *)str2;
852 	while(len-- && *s1)
853 		if(*s1++ != *s2++)
854 			return false;
855 	return (len < 0);
856 }
857 
858 #endif
859 
kvi_strEqualCIN(const char * str1,const char * str2,int len)860 bool kvi_strEqualCIN(const char * str1, const char * str2, int len)
861 {
862 	KVI_ASSERT(str1);
863 	KVI_ASSERT(str2);
864 	KVI_ASSERT(len >= 0);
865 	if(!(str1 && str2 && (len >= 0)))
866 		return false;
867 	unsigned char * s1 = (unsigned char *)str1;
868 	unsigned char * s2 = (unsigned char *)str2;
869 	while(len-- && *s1)
870 		if(tolower(*s1++) != tolower(*s2++))
871 			return false;
872 	return (len < 0);
873 }
874 
kvi_strEqualCI(const char * str1,const char * str2)875 bool kvi_strEqualCI(const char * str1, const char * str2)
876 {
877 	KVI_ASSERT(str1);
878 	KVI_ASSERT(str2);
879 	if(!(str1 && str2))
880 		return false;
881 	unsigned char * s1 = (unsigned char *)str1;
882 	unsigned char * s2 = (unsigned char *)str2;
883 	while(*s1)
884 		if(tolower(*s1++) != tolower(*s2++))
885 			return false;
886 	return (*s1 == *s2);
887 }
888 
889 //
890 //note that greater here means that come AFTER in the alphabetic order
891 // return < 0 ---> str1 < str2
892 // return = 0 ---> str1 = str2
893 // return > 0 ---> str1 > str2
894 //
895 
kvi_strcmpCI(const char * str1,const char * str2)896 int kvi_strcmpCI(const char * str1, const char * str2)
897 {
898 	//abcd abce
899 	KVI_ASSERT(str1);
900 	KVI_ASSERT(str2);
901 	if(!(str1 && str2))
902 		return false;
903 	unsigned char * s1 = (unsigned char *)str1;
904 	unsigned char * s2 = (unsigned char *)str2;
905 	int diff;
906 	unsigned char rightchar;
907 	while(!(diff = (rightchar = tolower(*s1++)) - tolower(*s2++)))
908 		if(!rightchar)
909 			break;
910 	return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1
911 }
912 
913 //
914 //note that greater here means that come AFTER in the alphabetic order
915 // return < 0 ---> str1 < str2
916 // return = 0 ---> str1 = str2
917 // return > 0 ---> str1 > str2
918 //int kvi_strcmpCIN(const char *str1,const char *str2,int len)
919 //
920 
kvi_strcmpCS(const char * str1,const char * str2)921 int kvi_strcmpCS(const char * str1, const char * str2)
922 {
923 	//abcd abce
924 	KVI_ASSERT(str1);
925 	KVI_ASSERT(str2);
926 	if(!(str1 && str2))
927 		return false;
928 	unsigned char * s1 = (unsigned char *)str1;
929 	unsigned char * s2 = (unsigned char *)str2;
930 	int diff;
931 	while(!(diff = (*s1) - (*s2++)))
932 		if(!*s1++)
933 			break;
934 	return diff; //diff is nonzero or end of both was reached (it is positive if *s2 > *s1
935 }
936 
kvi_strMatchRevCS(const char * str1,const char * str2,int index)937 int kvi_strMatchRevCS(const char * str1, const char * str2, int index)
938 {
939 	KVI_ASSERT(str1);
940 	KVI_ASSERT(str2);
941 	if(!(str1 && str2))
942 		return false;
943 	char * s1 = (char *)str1;
944 	char * s2 = (char *)str2;
945 
946 	int curlen = (int)strlen(str1);
947 	int diff;
948 
949 	if(index < 0 || index >= curlen)
950 		index = curlen - 1;
951 
952 	s1 += index;
953 	while(*s2)
954 		s2++;
955 	s2--;
956 
957 	// now start comparing
958 	while(true)
959 	{
960 		/* in this case, we have str1 = "lo" and str2 = "hello" */
961 		if(s1 < str1 && !(s2 < str2))
962 			return 256;
963 		if(s2 < str2)
964 			return 0;
965 		if((diff = (*s1) - (*s2)))
966 			return diff;
967 		s1--;
968 		s2--;
969 	}
970 }
971 
KviCString()972 KviCString::KviCString()
973 {
974 	m_ptr = (char *)KviMemory::allocate(1);
975 	*m_ptr = '\0';
976 	m_len = 0;
977 }
978 
KviCString(const char * str)979 KviCString::KviCString(const char * str)
980 {
981 	//Deep copy constructor
982 	if(str)
983 	{
984 		//Deep copy
985 		m_len = (int)strlen(str);
986 		m_ptr = (char *)KviMemory::allocate(m_len + 1);
987 		KviMemory::copy(m_ptr, str, m_len + 1);
988 	}
989 	else
990 	{
991 		m_ptr = (char *)KviMemory::allocate(1);
992 		*m_ptr = '\0';
993 		m_len = 0;
994 	}
995 }
996 
KviCString(const QByteArray & str)997 KviCString::KviCString(const QByteArray & str)
998 {
999 	//Deep copy constructor
1000 	if(str.data())
1001 	{
1002 		//Deep copy
1003 		m_len = str.length();
1004 		m_ptr = (char *)KviMemory::allocate(m_len + 1);
1005 		KviMemory::copy(m_ptr, str, m_len + 1);
1006 	}
1007 	else
1008 	{
1009 		m_ptr = (char *)KviMemory::allocate(1);
1010 		*m_ptr = '\0';
1011 		m_len = 0;
1012 	}
1013 }
1014 
KviCString(const char * str,int len)1015 KviCString::KviCString(const char * str, int len)
1016 {
1017 	KVI_ASSERT(str);
1018 	//KVI_ASSERT(len <= ((int)strlen(str))); <-- we trust the user here (and a strlen() call may run AFTER len if data is not null terminated)
1019 	KVI_ASSERT(len >= 0);
1020 	m_len = len;
1021 	m_ptr = (char *)KviMemory::allocate(m_len + 1);
1022 	KviMemory::copy(m_ptr, str, m_len);
1023 	*(m_ptr + m_len) = '\0';
1024 }
1025 
KviCString(const char * bg,const char * end)1026 KviCString::KviCString(const char * bg, const char * end)
1027 {
1028 	KVI_ASSERT(bg);
1029 	KVI_ASSERT(end);
1030 	KVI_ASSERT(bg <= end);
1031 	m_len = end - bg;
1032 	m_ptr = (char *)KviMemory::allocate(m_len + 1);
1033 	KviMemory::copy(m_ptr, bg, m_len);
1034 	*(m_ptr + m_len) = '\0';
1035 }
1036 
KviCString(KviFormatConstructorTag,const char * fmt,...)1037 KviCString::KviCString(KviFormatConstructorTag, const char * fmt, ...)
1038 {
1039 	m_ptr = (char *)KviMemory::allocate(256);
1040 	//First try
1041 	kvi_va_list list;
1042 	kvi_va_start(list, fmt);
1043 	//print...with max 256 chars
1044 	m_len = kvi_vsnprintf(m_ptr, 256, fmt, list);
1045 	kvi_va_end(list);
1046 
1047 	//check if we failed
1048 	if(m_len < 0)
1049 	{
1050 		//yes, failed....
1051 		int dummy = 256;
1052 		do
1053 		{ //we failed, so retry with 256 more chars
1054 			dummy += 256;
1055 			//realloc
1056 			m_ptr = (char *)KviMemory::reallocate(m_ptr, dummy);
1057 			//print...
1058 			kvi_va_start(list, fmt);
1059 			m_len = kvi_vsnprintf(m_ptr, dummy, fmt, list);
1060 			kvi_va_end(list);
1061 		} while(m_len < 0);
1062 	}
1063 	//done...
1064 	//now m_len is the length of the written string not including the terminator...
1065 	//perfect! :)
1066 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1067 }
1068 
KviCString(const KviCString & str)1069 KviCString::KviCString(const KviCString & str)
1070 {
1071 	KVI_ASSERT(str.m_ptr);
1072 	m_len = str.m_len;
1073 	m_ptr = (char *)KviMemory::allocate(m_len + 1);
1074 	KviMemory::copy(m_ptr, str.m_ptr, m_len + 1);
1075 }
1076 
KviCString(const QString & str)1077 KviCString::KviCString(const QString & str)
1078 {
1079 	QByteArray sz = str.toUtf8();
1080 	if(sz.length() > 0)
1081 	{
1082 		m_len = sz.length();
1083 		m_ptr = (char *)KviMemory::allocate(m_len + 1);
1084 		KviMemory::copy(m_ptr, sz.data(), m_len + 1);
1085 	}
1086 	else
1087 	{
1088 		m_ptr = (char *)KviMemory::allocate(1);
1089 		*m_ptr = '\0';
1090 		m_len = 0;
1091 	}
1092 }
1093 
KviCString(char c,int fillLen)1094 KviCString::KviCString(char c, int fillLen)
1095 {
1096 	KVI_ASSERT(fillLen >= 0);
1097 	m_len = fillLen;
1098 	m_ptr = (char *)KviMemory::allocate(m_len + 1);
1099 	char * p = m_ptr;
1100 	while(fillLen--)
1101 		*p++ = c;
1102 	*p = '\0';
1103 }
1104 
KviCString(const kvi_wchar_t * unicode)1105 KviCString::KviCString(const kvi_wchar_t * unicode)
1106 {
1107 	if(!unicode)
1108 	{
1109 		m_len = 0;
1110 		m_ptr = (char *)KviMemory::allocate(1);
1111 		*m_ptr = 0;
1112 	}
1113 	else
1114 	{
1115 		m_len = kvi_wstrlen(unicode);
1116 		m_ptr = (char *)KviMemory::allocate(m_len + 1);
1117 		char * p = m_ptr;
1118 		while(*unicode)
1119 			*p++ = *unicode++;
1120 		*p = 0;
1121 	}
1122 }
1123 
KviCString(const kvi_wchar_t * unicode,int len)1124 KviCString::KviCString(const kvi_wchar_t * unicode, int len)
1125 {
1126 	m_len = len;
1127 	m_ptr = (char *)KviMemory::allocate(m_len + 1);
1128 	char * p = m_ptr;
1129 	char * end = p + len;
1130 	while(p != end)
1131 	{
1132 		*p++ = *unicode++;
1133 	}
1134 	*p = 0;
1135 }
1136 
~KviCString()1137 KviCString::~KviCString()
1138 {
1139 	KviMemory::free(m_ptr);
1140 }
1141 
operator =(const KviCString & str)1142 KviCString & KviCString::operator=(const KviCString & str)
1143 {
1144 	KVI_ASSERT(str.m_ptr);
1145 	KVI_ASSERT(str.m_ptr != m_ptr);
1146 	m_len = str.m_len;
1147 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1148 	KviMemory::copy(m_ptr, str.m_ptr, m_len + 1);
1149 	return (*this);
1150 }
1151 
operator =(const QByteArray & str)1152 KviCString & KviCString::operator=(const QByteArray & str)
1153 {
1154 	m_len = str.length();
1155 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1156 	if(str.data())
1157 		KviMemory::copy(m_ptr, str.data(), m_len + 1);
1158 	else
1159 		*m_ptr = 0;
1160 	return (*this);
1161 }
1162 
operator =(const char * str)1163 KviCString & KviCString::operator=(const char * str)
1164 {
1165 	//KVI_ASSERT(str);
1166 	if(str)
1167 	{
1168 		m_len = (int)strlen(str);
1169 		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1170 		KviMemory::move(m_ptr, str, m_len + 1);
1171 	}
1172 	else
1173 	{
1174 		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
1175 		*m_ptr = '\0';
1176 		m_len = 0;
1177 	}
1178 	return (*this);
1179 }
1180 
clear()1181 void KviCString::clear()
1182 {
1183 	m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
1184 	*m_ptr = '\0';
1185 	m_len = 0;
1186 }
1187 
hasNonWhiteSpaceData() const1188 bool KviCString::hasNonWhiteSpaceData() const
1189 {
1190 	const char * aux = m_ptr;
1191 	while(*aux)
1192 	{
1193 		if(((*aux) != ' ') && ((*aux) != '\t'))
1194 			return true;
1195 		aux++;
1196 	}
1197 	return false;
1198 }
1199 
bufferToHex(const char * buffer,int len)1200 void KviCString::bufferToHex(const char * buffer, int len)
1201 {
1202 	KVI_ASSERT(buffer);
1203 	m_len = (len * 2);
1204 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1205 	char * aux = m_ptr;
1206 	while(len)
1207 	{
1208 		*aux = hexdigits[(unsigned int)(((unsigned char)(*buffer)) / 16)];
1209 		aux++;
1210 		*aux = hexdigits[(unsigned int)(((unsigned char)(*buffer)) % 16)];
1211 		aux++;
1212 		len--;
1213 		buffer++;
1214 	}
1215 	*(m_ptr + m_len) = '\0';
1216 }
1217 
get_decimal_from_hex_digit_char(char dgt)1218 static char get_decimal_from_hex_digit_char(char dgt)
1219 {
1220 	if((dgt >= '0') && (dgt <= '9'))
1221 		return (dgt - '0');
1222 	if((dgt >= 'A') && (dgt <= 'F'))
1223 		return (10 + (dgt - 'A'));
1224 	if((dgt >= 'a') && (dgt <= 'f'))
1225 		return (10 + (dgt - 'a'));
1226 	return -1;
1227 }
1228 
hexToBuffer(char ** buffer,bool bNullToNewlines)1229 int KviCString::hexToBuffer(char ** buffer, bool bNullToNewlines)
1230 {
1231 	*buffer = nullptr;
1232 	if((m_len == 0) || (m_len & 1))
1233 		return -1; // this is an error
1234 	int len = (m_len / 2);
1235 	if(len < 1)
1236 		return -1;
1237 	*buffer = (char *)KviMemory::allocate(len);
1238 
1239 	char * ptr = *buffer;
1240 	char * aux = m_ptr;
1241 
1242 	while(*aux)
1243 	{
1244 		char temp = get_decimal_from_hex_digit_char(*aux);
1245 		if(temp == -1)
1246 		{
1247 			KviMemory::free(*buffer);
1248 			*buffer = nullptr;
1249 			return -1;
1250 		}
1251 		*ptr = temp * 16;
1252 		aux++;
1253 		temp = get_decimal_from_hex_digit_char(*aux);
1254 		if(temp == -1)
1255 		{
1256 			KviMemory::free(*buffer);
1257 			*buffer = nullptr;
1258 			return -1;
1259 		}
1260 		*ptr += temp;
1261 		aux++;
1262 		if(bNullToNewlines)
1263 			if(!(*ptr))
1264 				*ptr = '\n';
1265 		ptr++;
1266 	}
1267 	return len;
1268 }
1269 
1270 static const char * base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1271 
bufferToBase64(const char * buffer,int len)1272 void KviCString::bufferToBase64(const char * buffer, int len)
1273 {
1274 	m_len = (len / 3) << 2;
1275 	if(len % 3)
1276 		m_len += 4;
1277 
1278 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1279 
1280 	unsigned char aux1, aux2, aux3;
1281 	char * aux_ptr = m_ptr;
1282 	while(len > 2)
1283 	{
1284 		aux1 = (unsigned char)*buffer++;
1285 		aux2 = (unsigned char)*buffer++;
1286 		aux3 = (unsigned char)*buffer++;
1287 		*aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
1288 		*aux_ptr++ = base64_chars[((aux1 & 0x03) << 4) | ((aux2 & 0xF0) >> 4)];
1289 		*aux_ptr++ = base64_chars[((aux2 & 0x0F) << 2) | ((aux3 & 0xC0) >> 6)];
1290 		*aux_ptr++ = base64_chars[(aux3 & 0x3F)];
1291 		len -= 3;
1292 	}
1293 	switch(len)
1294 	{
1295 		case 2:
1296 			aux1 = (unsigned char)*buffer++;
1297 			aux2 = (unsigned char)*buffer++;
1298 			*aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
1299 			*aux_ptr++ = base64_chars[((aux1 & 0x03) << 4) | ((aux2 & 0xF0) >> 4)];
1300 			*aux_ptr++ = base64_chars[((aux2 & 0x0F) << 2)];
1301 			*aux_ptr++ = '=';
1302 			break;
1303 		case 1:
1304 			aux1 = (unsigned char)*buffer++;
1305 			aux2 = (unsigned char)*buffer++;
1306 			*aux_ptr++ = base64_chars[(aux1 & 0xFC) >> 2];
1307 			*aux_ptr++ = base64_chars[((aux1 & 0x03) << 4)];
1308 			*aux_ptr++ = '=';
1309 			*aux_ptr++ = '=';
1310 			break;
1311 	}
1312 	*aux_ptr = 0;
1313 }
1314 
get_base64_idx(char base64)1315 static unsigned char get_base64_idx(char base64)
1316 {
1317 	if((base64 >= 'A') && (base64 <= 'Z'))
1318 		return (base64 - 'A');
1319 	if((base64 >= 'a') && (base64 <= 'z'))
1320 		return ((base64 - 'a') + 26);
1321 	if((base64 >= '0') && (base64 <= '9'))
1322 		return ((base64 - '0') + 52);
1323 	if(base64 == '+')
1324 		return 62;
1325 	if(base64 == '/')
1326 		return 63;
1327 	if(base64 == '=')
1328 		return 64;
1329 	return 65;
1330 }
1331 
base64ToBuffer(char ** buffer,bool)1332 int KviCString::base64ToBuffer(char ** buffer, bool)
1333 {
1334 	*buffer = nullptr;
1335 	if((m_len == 0) || (m_len & 3))
1336 		return -1; // this is an error
1337 	int len = (m_len >> 2) * 3;
1338 	*buffer = (char *)KviMemory::allocate(len);
1339 
1340 	char * auxBuf = *buffer;
1341 
1342 	unsigned char aux1, aux2, aux3, aux4;
1343 	char * aux_ptr = m_ptr;
1344 
1345 	int newLen = len;
1346 
1347 	while(*aux_ptr)
1348 	{
1349 		if(newLen != len)
1350 		{
1351 			// ops... there was a padding and we still have chars after it
1352 			// this is an error
1353 			KviMemory::free(*buffer);
1354 			*buffer = nullptr;
1355 			return -1;
1356 		}
1357 		aux1 = get_base64_idx(*aux_ptr++);
1358 		aux2 = get_base64_idx(*aux_ptr++);
1359 		aux3 = get_base64_idx(*aux_ptr++);
1360 		aux4 = get_base64_idx(*aux_ptr++);
1361 		if((aux3 > 64) || (aux4 > 64))
1362 		{
1363 			// error
1364 			KviMemory::free(*buffer);
1365 			*buffer = nullptr;
1366 			return -1;
1367 		}
1368 		if((aux1 | aux2) > 63)
1369 		{
1370 			// again error...impossible padding
1371 			KviMemory::free(*buffer);
1372 			*buffer = nullptr;
1373 			return -1;
1374 		}
1375 		if(aux4 == 64)
1376 		{
1377 			if(aux3 == 64)
1378 			{
1379 				// Double padding, only one digit here
1380 				*auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4));
1381 				newLen -= 2;
1382 			}
1383 			else
1384 			{
1385 				// Single padding, two digits here
1386 				*auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4)); // >> 4 is a shr, not a ror! :)
1387 				*auxBuf++ = (char)((aux2 << 4) | (aux3 >> 2));
1388 				newLen -= 1;
1389 			}
1390 		}
1391 		else
1392 		{
1393 			if(aux3 == 64)
1394 			{
1395 				// error... impossible padding
1396 				KviMemory::free(*buffer);
1397 				*buffer = nullptr;
1398 				return -1;
1399 			}
1400 			else
1401 			{
1402 				// Ok, no padding, three digits here
1403 				*auxBuf++ = (char)((aux1 << 2) | (aux2 >> 4));
1404 				*auxBuf++ = (char)((aux2 << 4) | (aux3 >> 2));
1405 				*auxBuf++ = (char)((aux3 << 6) | aux4);
1406 			}
1407 		}
1408 	}
1409 
1410 	if(newLen != len)
1411 		*buffer = (char *)KviMemory::reallocate(*buffer, newLen);
1412 	return newLen;
1413 }
1414 
setStr(const char * str,int len)1415 KviCString & KviCString::setStr(const char * str, int len)
1416 {
1417 	if(!str)
1418 	{
1419 		clear();
1420 		return *this;
1421 	}
1422 	int alen = (int)strlen(str);
1423 	if((len < 0) || (len > alen))
1424 		m_len = alen;
1425 	else
1426 		m_len = len;
1427 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1428 	KviMemory::move(m_ptr, str, m_len);
1429 	*(m_ptr + m_len) = '\0';
1430 	return (*this);
1431 }
1432 
operator =(const QString & str)1433 KviCString & KviCString::operator=(const QString & str)
1434 {
1435 	QByteArray sz = str.toUtf8();
1436 	if(sz.length() > 0)
1437 	{
1438 		m_len = sz.length();
1439 		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1440 		KviMemory::copy(m_ptr, sz.data(), m_len + 1);
1441 	}
1442 	else
1443 	{
1444 		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
1445 		*m_ptr = '\0';
1446 		m_len = 0;
1447 	}
1448 	return (*this);
1449 }
1450 
operator =(char c)1451 KviCString & KviCString::operator=(char c)
1452 {
1453 	m_len = 1;
1454 	m_ptr = (char *)KviMemory::reallocate(m_ptr, 2);
1455 	*m_ptr = c;
1456 	*(m_ptr + 1) = '\0';
1457 	return (*this);
1458 }
1459 
append(char c)1460 void KviCString::append(char c)
1461 {
1462 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 2);
1463 	*(m_ptr + m_len) = c;
1464 	m_len++;
1465 	*(m_ptr + m_len) = '\0';
1466 }
1467 
append(const KviCString & str)1468 void KviCString::append(const KviCString & str)
1469 {
1470 	KVI_ASSERT(str.m_ptr);
1471 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + str.m_len + 1);
1472 	KviMemory::copy((m_ptr + m_len), str.m_ptr, str.m_len + 1);
1473 	m_len += str.m_len;
1474 }
1475 
append(const char * str)1476 void KviCString::append(const char * str)
1477 {
1478 	if(!str)
1479 		return;
1480 	int len = (int)strlen(str);
1481 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
1482 	KviMemory::copy((m_ptr + m_len), str, len + 1);
1483 	m_len += len;
1484 }
1485 
append(const QString & str)1486 void KviCString::append(const QString & str)
1487 {
1488 	QByteArray sz = str.toUtf8();
1489 	if(sz.length() < 1)
1490 		return;
1491 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + sz.length() + 1);
1492 	KviMemory::copy((m_ptr + m_len), sz.data(), sz.length() + 1);
1493 	m_len += sz.length();
1494 }
1495 
append(const char * str,int len)1496 void KviCString::append(const char * str, int len)
1497 {
1498 	KVI_ASSERT(str);
1499 	//	KVI_ASSERT(len <= ((int)strlen(str)));
1500 	KVI_ASSERT(len >= 0);
1501 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
1502 	KviMemory::copy((m_ptr + m_len), str, len);
1503 	m_len += len;
1504 	*(m_ptr + m_len) = '\0';
1505 }
1506 
append(KviFormatConstructorTag,const char * fmt,...)1507 void KviCString::append(KviFormatConstructorTag, const char * fmt, ...)
1508 {
1509 	int auxLen;
1510 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 256);
1511 	//First try
1512 	kvi_va_list list;
1513 	kvi_va_start(list, fmt);
1514 	//print...with max 256 chars
1515 	auxLen = kvi_vsnprintf(m_ptr + m_len, 256, fmt, list);
1516 	kvi_va_end(list);
1517 
1518 	//check if we failed
1519 	if(auxLen < 0)
1520 	{
1521 		//yes, failed....
1522 		int dummy = 256;
1523 		do
1524 		{ //we failed, so retry with 256 more chars
1525 			dummy += 256;
1526 			//realloc
1527 			m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + dummy);
1528 			//print...
1529 			kvi_va_start(list, fmt);
1530 			auxLen = kvi_vsnprintf(m_ptr + m_len, dummy, fmt, list);
1531 			kvi_va_end(list);
1532 		} while(auxLen < 0);
1533 	}
1534 	m_len += auxLen;
1535 	//done...
1536 	//now m_len is the length of the written string not including the terminator...
1537 	//perfect! :)
1538 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1539 }
1540 
extractFromString(const char * begin,const char * end)1541 void KviCString::extractFromString(const char * begin, const char * end)
1542 {
1543 	KVI_ASSERT(begin);
1544 	KVI_ASSERT(end);
1545 	KVI_ASSERT(end >= begin);
1546 	m_len = end - begin;
1547 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
1548 	KviMemory::copy(m_ptr, begin, m_len);
1549 	*(m_ptr + m_len) = '\0';
1550 }
1551 
prepend(const KviCString & str)1552 void KviCString::prepend(const KviCString & str)
1553 {
1554 	KVI_ASSERT(str.m_ptr);
1555 	KVI_ASSERT(str.m_ptr != m_ptr);
1556 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + str.m_len + 1);
1557 	KviMemory::move((m_ptr + str.m_len), m_ptr, m_len + 1); //move self
1558 	KviMemory::copy(m_ptr, str.m_ptr, str.m_len);
1559 	m_len += str.m_len;
1560 }
1561 
prepend(const char * str)1562 void KviCString::prepend(const char * str)
1563 {
1564 	if(!str)
1565 		return;
1566 	int len = (int)strlen(str);
1567 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
1568 	KviMemory::move((m_ptr + len), m_ptr, m_len + 1); //move self
1569 	KviMemory::copy(m_ptr, str, len);
1570 	m_len += len;
1571 }
1572 
prepend(const char * str,int len)1573 void KviCString::prepend(const char * str, int len)
1574 {
1575 	KVI_ASSERT(str);
1576 	KVI_ASSERT(len <= ((int)strlen(str)));
1577 	KVI_ASSERT(len >= 0);
1578 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
1579 	KviMemory::move((m_ptr + len), m_ptr, m_len + 1); //move self
1580 	KviMemory::copy(m_ptr, str, len);
1581 	m_len += len;
1582 }
1583 
1584 unsigned char iso88591_toUpper_map[256] = {
1585 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1586 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1587 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1588 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1589 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1590 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1591 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
1592 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
1593 	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
1594 	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1595 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
1596 	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
1597 	0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
1598 	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1599 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
1600 	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
1601 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
1602 	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1603 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
1604 	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1605 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
1606 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
1607 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
1608 	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1609 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
1610 	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1611 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
1612 	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1613 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
1614 	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
1615 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
1616 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1617 };
1618 
toUpperISO88591()1619 void KviCString::toUpperISO88591()
1620 {
1621 	char * p = m_ptr;
1622 	while(*p)
1623 	{
1624 		*p = (char)iso88591_toUpper_map[(unsigned char)*p];
1625 		p++;
1626 	}
1627 }
1628 
toUpper()1629 void KviCString::toUpper()
1630 {
1631 	char * p = m_ptr;
1632 	while(*p)
1633 	{
1634 		*p = toupper(*p);
1635 		p++;
1636 	}
1637 }
1638 
1639 unsigned char iso88591_toLower_map[256] = {
1640 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1641 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1642 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1643 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1644 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1645 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
1646 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
1647 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
1648 	0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
1649 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
1650 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
1651 	0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
1652 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
1653 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
1654 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
1655 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
1656 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
1657 	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
1658 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
1659 	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
1660 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
1661 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
1662 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
1663 	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
1664 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
1665 	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
1666 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
1667 	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
1668 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
1669 	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
1670 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
1671 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1672 };
1673 
toLowerISO88591()1674 void KviCString::toLowerISO88591()
1675 {
1676 	char * p = m_ptr;
1677 	while(*p)
1678 	{
1679 		*p = (char)iso88591_toLower_map[(unsigned char)*p];
1680 		p++;
1681 	}
1682 }
1683 
toLower()1684 void KviCString::toLower()
1685 {
1686 	char * p = m_ptr;
1687 	while(*p)
1688 	{
1689 		*p = tolower(*p);
1690 		p++;
1691 	}
1692 }
1693 
upper() const1694 KviCString KviCString::upper() const
1695 {
1696 	KviCString tmp(*this);
1697 	tmp.toUpper();
1698 	return tmp;
1699 }
1700 
upperISO88591() const1701 KviCString KviCString::upperISO88591() const
1702 {
1703 	KviCString tmp(*this);
1704 	tmp.toUpperISO88591();
1705 	return tmp;
1706 }
1707 
lower() const1708 KviCString KviCString::lower() const
1709 {
1710 	KviCString tmp(*this);
1711 	tmp.toLower();
1712 	return tmp;
1713 }
1714 
lowerISO88591() const1715 KviCString KviCString::lowerISO88591() const
1716 {
1717 	KviCString tmp(*this);
1718 	tmp.toLowerISO88591();
1719 	return tmp;
1720 }
1721 
left(int maxLen) const1722 KviCString KviCString::left(int maxLen) const
1723 {
1724 	if(maxLen <= 0)
1725 	{
1726 		KviCString empty;
1727 		return empty;
1728 	}
1729 	if(maxLen > m_len)
1730 		maxLen = m_len;
1731 	KviCString str(m_ptr, maxLen);
1732 	return str;
1733 }
1734 
right(int maxLen) const1735 KviCString KviCString::right(int maxLen) const
1736 {
1737 	if(maxLen <= 0)
1738 	{
1739 		KviCString empty;
1740 		return empty;
1741 	}
1742 	if(maxLen > m_len)
1743 		maxLen = m_len;
1744 	KviCString str((m_ptr + (m_len - maxLen)), maxLen);
1745 	return str;
1746 }
1747 
middle(int idx,int maxLen) const1748 KviCString KviCString::middle(int idx, int maxLen) const
1749 {
1750 	KVI_ASSERT(maxLen >= 0);
1751 	KVI_ASSERT(idx >= 0);
1752 	if((maxLen <= 0) || (idx < 0))
1753 	{ //max len negative...invalid params
1754 		KviCString ret;
1755 		return ret;
1756 	}
1757 	if((maxLen + idx) <= m_len)
1758 	{ //valid params
1759 		KviCString str(m_ptr + idx, maxLen);
1760 		return str;
1761 	}
1762 	if(idx < m_len)
1763 	{ //string shorter than requested
1764 		KviCString str(m_ptr + idx);
1765 		return str;
1766 	}
1767 	// idx out of bounds
1768 	KviCString ret;
1769 	return ret;
1770 }
1771 
splitToArray(char sep,int max,int * realCount) const1772 KviCString ** KviCString::splitToArray(char sep, int max, int * realCount) const
1773 {
1774 	KviCString ** strings = (KviCString **)KviMemory::allocate(sizeof(KviCString *));
1775 	int number = 0;
1776 	char * ptr = m_ptr;
1777 	char * last = ptr;
1778 	while((max > 0) && *ptr)
1779 	{
1780 		strings = (KviCString **)KviMemory::reallocate((void *)strings, sizeof(KviCString *) * (number + 2));
1781 		if(max > 1)
1782 		{
1783 			while(*ptr && (*ptr != sep))
1784 				ptr++;
1785 			strings[number] = new KviCString(last, ptr - last);
1786 		}
1787 		else
1788 		{
1789 			strings[number] = new KviCString(ptr);
1790 		}
1791 		number++;
1792 		max--;
1793 		if(*ptr)
1794 		{
1795 			ptr++;
1796 			last = ptr;
1797 		}
1798 	}
1799 	if(realCount)
1800 		*realCount = number;
1801 	strings[number] = nullptr;
1802 	return strings;
1803 }
1804 
freeArray(KviCString ** strings)1805 void KviCString::freeArray(KviCString ** strings)
1806 {
1807 	if(!strings)
1808 		return;
1809 	KviCString ** aux = strings;
1810 	while(*aux)
1811 	{
1812 		delete(*aux); // delete (KviCString *)
1813 		aux++;
1814 	}
1815 	KviMemory::free(strings);
1816 }
1817 
freeBuffer(char * buffer)1818 void KviCString::freeBuffer(char * buffer)
1819 {
1820 	if(!buffer)
1821 		return;
1822 	KviMemory::free(buffer);
1823 }
1824 
joinFromArray(KviCString ** strings,const char * sep,bool bLastSep)1825 void KviCString::joinFromArray(KviCString ** strings, const char * sep, bool bLastSep)
1826 {
1827 	setLen(0);
1828 	if(!strings)
1829 		return;
1830 
1831 	while(*strings)
1832 	{
1833 		append(*(*strings));
1834 		strings++;
1835 		if(*strings)
1836 		{
1837 			if(sep)
1838 				append(sep);
1839 		}
1840 		else
1841 		{
1842 			if(sep && bLastSep)
1843 				append(sep);
1844 		}
1845 	}
1846 }
1847 
insert(int idx,const char * data)1848 KviCString & KviCString::insert(int idx, const char * data)
1849 {
1850 	KVI_ASSERT(data);
1851 	if(idx <= m_len)
1852 	{
1853 		int len = (int)strlen(data);
1854 		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + len + 1);
1855 		KviMemory::move(m_ptr + idx + len, m_ptr + idx, (m_len - idx) + 1);
1856 		KviMemory::copy(m_ptr + idx, data, len);
1857 		m_len += len;
1858 	}
1859 	return (*this);
1860 }
1861 
insert(int idx,char c)1862 KviCString & KviCString::insert(int idx, char c)
1863 {
1864 	if(idx <= m_len)
1865 	{
1866 		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 2);
1867 		KviMemory::move(m_ptr + idx + 1, m_ptr + idx, (m_len - idx) + 1);
1868 		m_len++;
1869 		*(m_ptr + idx) = c;
1870 	}
1871 	return (*this);
1872 }
1873 
1874 // FIXME: #warning "Double check the following two functions !!!"
1875 
hexEncodeWithTable(const unsigned char table[256])1876 KviCString & KviCString::hexEncodeWithTable(const unsigned char table[256])
1877 {
1878 	char * aux = m_ptr;
1879 	char * begin = m_ptr;
1880 
1881 	char * n = nullptr;
1882 	int curSize = 0;
1883 
1884 	while(*aux)
1885 	{
1886 		if(table[*((unsigned char *)aux)] || (*aux == '%'))
1887 		{
1888 			int len = aux - begin;
1889 			n = (char *)KviMemory::reallocate(n, curSize + len + 3);
1890 			KviMemory::move(n + curSize, begin, len);
1891 			curSize += len;
1892 
1893 			n[curSize] = '%';
1894 			curSize++;
1895 			n[curSize] = hexdigits[(unsigned int)(((unsigned char)(*aux)) / 16)];
1896 			curSize++;
1897 			n[curSize] = hexdigits[(unsigned int)(((unsigned char)(*aux)) % 16)];
1898 			curSize++;
1899 
1900 			aux++;
1901 			begin = aux;
1902 		}
1903 		else
1904 			aux++;
1905 	}
1906 
1907 	int len = aux - begin;
1908 	n = (char *)KviMemory::reallocate(n, curSize + len + 1);
1909 	KviMemory::move(n + curSize, begin, len);
1910 	curSize += len;
1911 
1912 	n[curSize] = '\0';
1913 
1914 	KviMemory::free((void *)m_ptr);
1915 	m_ptr = n;
1916 	m_len = curSize;
1917 
1918 	return (*this);
1919 }
1920 
hexEncodeWhiteSpace()1921 KviCString & KviCString::hexEncodeWhiteSpace()
1922 {
1923 	static unsigned char ascii_jump_table[256] = {
1924 		// clang-format off
1925 		//	000 001 002 003 004 005 006 007   008 009 010 011 012 013 014 015
1926 		//	NUL SOH STX ETX EOT ENQ ACK BEL   BS  HT  LF  VT  FF  CR  SO  SI
1927 			1  ,1  ,1  ,1  ,1  ,1  ,1  ,1    ,1  ,1  ,1  ,1  ,1  ,1  ,1  ,1  ,
1928 		//	016 017 018 019 020 021 022 023   024 025 026 027 028 029 030 031
1929 		//	DLE DC1 DC2 DC3 DC4 NAK SYN ETB   CAN EM  SUB ESC FS  GS  RS  US
1930 			1  ,1  ,1  ,1  ,1  ,1  ,1  ,1    ,1  ,1  ,1  ,1  ,1  ,1  ,1  ,1  ,
1931 		//	032 033 034 035 036 037 038 039   040 041 042 043 044 045 046 047
1932 		//	    !   "   #   $   %   &   '     (   )   *   +   ,   -   .   /
1933 			1  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1934 		//	048 049 050 051 052 053 054 055   056 057 058 059 060 061 062 063
1935 		//	0   1   2   3   4   5   6   7     8   9   :   ;   <   =   >   ?
1936 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1937 		//	064 065 066 067 068 069 070 071   072 073 074 075 076 077 078 079
1938 		//	@   A   B   C   D   E   F   G     H   I   J   K   L   M   N   O
1939 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1940 		//	080 081 082 083 084 085 086 087   088 089 090 091 092 093 094 095
1941 		//	P   Q   R   S   T   U   V   W     X   Y   Z   [   \   ]   ^   _
1942 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1943 		//	096 097 098 099 100 101 102 103   104 105 106 107 108 109 110 111
1944 		//	`   a   b   c   d   e   f   g     h   i   j   k   l   m   n   o
1945 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1946 		//	112 113 114 115 116 117 118 119   120 121 122 123 124 125 126 127
1947 		//	p   q   r   s   t   u   v   w     x   y   z   {   |   }   ~   
1948 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1949 		//	128 129 130 131 132 133 134 135   136 137 138 139 140 141 142 143
1950 		//
1951 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1952 		//	144 145 146 147 148 149 150 151   152 153 154 155 156 157 158 159
1953 		//
1954 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1955 		//	160 161 162 163 164 165 166 167   168 169 170 171 172 173 174 175
1956 		//
1957 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1958 		//	176 177 178 179 180 181 182 183   184 185 186 187 188 189 190 191
1959 		//
1960 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1961 		//	192 193 194 195 196 197 198 199   200 201 202 203 204 205 206 207
1962 		//	�  �  �  �  �  �  �  �    �  �  �  �  �  �  �  �
1963 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1964 		//	208 209 210 211 212 213 214 215   216 217 218 219 220 221 222 223
1965 		//	�  �  �  �  �  �  �  �    �  �  �  �  �  �  �  �
1966 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1967 		//	224 225 226 227 228 229 230 231   232 233 234 235 236 237 238 239
1968 		//	�  �  �  �  �  �  �  �    �  �  �  �  �  �  �  �
1969 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
1970 		//	240 241 242 243 244 245 246 247   248 249 250 251 252 253 254 255
1971 		//	�  �  �  �  �  �  �  �
1972 			0  ,0  ,0  ,0  ,0  ,0  ,0  ,0    ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0
1973 		// clang-format on
1974 	};
1975 
1976 	return hexEncodeWithTable(ascii_jump_table);
1977 }
1978 
hexDecode(const char * pFrom)1979 KviCString & KviCString::hexDecode(const char * pFrom)
1980 {
1981 	// WARNING: pFrom can be also m_ptr here!
1982 	const char * aux = pFrom;
1983 	const char * begin = pFrom;
1984 
1985 	char * n = nullptr;
1986 	int curSize = 0;
1987 
1988 	while(*aux)
1989 	{
1990 		if(*aux == '%')
1991 		{
1992 			// move last block
1993 			int len = aux - begin;
1994 			n = (char *)KviMemory::reallocate(n, curSize + len + 1);
1995 			KviMemory::move(n + curSize, begin, len);
1996 			curSize += len;
1997 
1998 			// get the hex code
1999 			aux++;
2000 
2001 			char theChar = get_decimal_from_hex_digit_char(*aux);
2002 			if(theChar < 0)
2003 			{
2004 				n[curSize] = '%'; // wrong code...just a '%'
2005 				curSize++;
2006 			}
2007 			else
2008 			{
2009 				aux++;
2010 				char theChar2 = get_decimal_from_hex_digit_char(*aux);
2011 				if(theChar2 < 0)
2012 				{
2013 					// wrong code...just a '%' and step back
2014 					n[curSize] = '%';
2015 					curSize++;
2016 					aux--;
2017 				}
2018 				else
2019 				{
2020 					n[curSize] = (theChar * 16) + theChar2;
2021 					curSize++;
2022 					aux++;
2023 				}
2024 			}
2025 
2026 			begin = aux;
2027 		}
2028 		else
2029 			aux++;
2030 	}
2031 
2032 	int len = aux - begin;
2033 	n = (char *)KviMemory::reallocate(n, curSize + len + 2);
2034 	KviMemory::move(n + curSize, begin, len);
2035 	curSize += len;
2036 	n[curSize] = '\0';
2037 
2038 	KviMemory::free((void *)m_ptr);
2039 	m_ptr = n;
2040 	m_len = curSize;
2041 
2042 	return (*this);
2043 }
2044 
replaceAll(const char c,const char * str)2045 KviCString & KviCString::replaceAll(const char c, const char * str)
2046 {
2047 	int idx = findFirstIdx(c);
2048 	KviCString tmp;
2049 	while(idx >= 0)
2050 	{
2051 		if(idx > 0)
2052 			tmp += left(idx);
2053 		cutLeft(idx + 1);
2054 		tmp.append(str);
2055 		idx = findFirstIdx(c);
2056 	}
2057 	tmp.append(*this);
2058 	// Now copy
2059 	m_len = tmp.m_len;
2060 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2061 	KviMemory::copy(m_ptr, tmp.m_ptr, m_len + 1);
2062 	return (*this);
2063 }
2064 
replaceAll(const char * toFind,const char * str,bool bCaseS)2065 KviCString & KviCString::replaceAll(const char * toFind, const char * str, bool bCaseS)
2066 {
2067 	int len = (int)strlen(toFind);
2068 	int idx = findFirstIdx(toFind, bCaseS);
2069 	KviCString tmp;
2070 	while(idx >= 0)
2071 	{
2072 		if(idx > 0)
2073 			tmp += left(idx);
2074 		cutLeft(idx + len);
2075 		tmp.append(str);
2076 		idx = findFirstIdx(toFind, bCaseS);
2077 	}
2078 	tmp.append(*this);
2079 	// Now copy
2080 	m_len = tmp.m_len;
2081 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2082 	KviMemory::copy(m_ptr, tmp.m_ptr, m_len + 1);
2083 	return (*this);
2084 }
2085 
transliterate(const char * szToFind,const char * szReplacement)2086 KviCString & KviCString::transliterate(const char * szToFind, const char * szReplacement)
2087 {
2088 	while(*szToFind && *szReplacement)
2089 	{
2090 		char * p = m_ptr;
2091 		while(*p)
2092 		{
2093 			if(*p == *szToFind)
2094 				*p = *szReplacement;
2095 			++p;
2096 		}
2097 		++szToFind;
2098 		++szReplacement;
2099 	}
2100 	return (*this);
2101 }
2102 
occurrences(char c,bool caseS) const2103 int KviCString::occurrences(char c, bool caseS) const
2104 {
2105 	char * p = m_ptr;
2106 	int cnt = 0;
2107 	if(caseS)
2108 	{
2109 		while(*p)
2110 		{
2111 			if(*p == c)
2112 				cnt++;
2113 			p++;
2114 		}
2115 	}
2116 	else
2117 	{
2118 		char b = tolower(c);
2119 		while(*p)
2120 		{
2121 			if(tolower(*p) == b)
2122 				cnt++;
2123 			p++;
2124 		}
2125 	}
2126 	return cnt;
2127 }
2128 
occurrences(const char * str,bool caseS) const2129 int KviCString::occurrences(const char * str, bool caseS) const
2130 {
2131 	KVI_ASSERT(str);
2132 	char * p = m_ptr;
2133 	int cnt = 0;
2134 	int len = (int)strlen(str);
2135 	if(caseS)
2136 	{
2137 		while(*p)
2138 		{
2139 			if(*p == *str)
2140 			{
2141 				if(kvi_strEqualCSN(p, str, len))
2142 					cnt++;
2143 			}
2144 			p++;
2145 		}
2146 	}
2147 	else
2148 	{
2149 		while(*p)
2150 		{
2151 			char c = tolower(*str);
2152 			if(tolower(*p) == c)
2153 			{
2154 				if(kvi_strEqualCIN(p, str, len))
2155 					cnt++;
2156 			}
2157 			p++;
2158 		}
2159 	}
2160 	return cnt;
2161 }
2162 
contains(char c,bool caseS) const2163 bool KviCString::contains(char c, bool caseS) const
2164 {
2165 	char * p = m_ptr;
2166 	if(caseS)
2167 	{
2168 		while(*p)
2169 		{
2170 			if(*p == c)
2171 				return true;
2172 			p++;
2173 		}
2174 	}
2175 	else
2176 	{
2177 		char b = tolower(c);
2178 		while(*p)
2179 		{
2180 			if(tolower(*p) == b)
2181 				return true;
2182 			p++;
2183 		}
2184 	}
2185 	return false;
2186 }
2187 
contains(const char * str,bool caseS) const2188 bool KviCString::contains(const char * str, bool caseS) const
2189 {
2190 	KVI_ASSERT(str);
2191 	char * p = m_ptr;
2192 	int len = (int)strlen(str);
2193 	if(caseS)
2194 	{
2195 		while(*p)
2196 		{
2197 			if(*p == *str)
2198 			{
2199 				if(kvi_strEqualCSN(p, str, len))
2200 					return true;
2201 			}
2202 			p++;
2203 		}
2204 	}
2205 	else
2206 	{
2207 		while(*p)
2208 		{
2209 			char c = tolower(*str);
2210 			if(tolower(*p) == c)
2211 			{
2212 				if(kvi_strEqualCIN(p, str, len))
2213 					return true;
2214 			}
2215 			p++;
2216 		}
2217 	}
2218 	return false;
2219 }
2220 
setNum(long num)2221 KviCString & KviCString::setNum(long num)
2222 {
2223 	char numberBuffer[30];
2224 	bool bNegative = false;
2225 	long tmp;
2226 	char * p;
2227 	char * pNumBuf = numberBuffer;
2228 
2229 	// somebody can explain to me why 	-(-2147483648) = -2147483648 ? (2^31)
2230 	// it is like signed char x = 128 ---> 10000000 that is signed -0 (!?)
2231 	// mmmmh...or it is assumed to be -128 (a number representation exception)
2232 	// at least on my machine it happens...
2233 
2234 	// found the solution by myself today...
2235 	//
2236 	// ABS(3)              Linux Programmer's Manual              ABS(3)
2237 	// NAME
2238 	//        abs - computes the absolute value of an integer.
2239 	// ...
2240 	// DESCRIPTION
2241 	//        The abs() function computes the absolute value of the integer argument j.
2242 	// RETURN VALUE
2243 	//        Returns the absolute value of the integer argument.
2244 	// CONFORMING TO
2245 	//        SVID 3, POSIX, BSD 4.3, ISO 9899
2246 	// NOTE ##################################################################################
2247 	//        Trying to take the absolute value of the most negative integer is not defined.
2248 	// #######################################################################################
2249 
2250 	// so should i use temporaneous doubles to make calculations ?
2251 
2252 	if(num < 0)
2253 	{ //negative integer
2254 		bNegative = true;
2255 		num = -num; //need to have it positive
2256 		if(num < 0)
2257 		{	// 2^31 exception
2258 			// We need to avoid absurd responses like ".(./),." :)
2259 			num = 0; // we get a negative zero here...it is still an exception
2260 		}
2261 	}
2262 
2263 	//write the number in a temporary buffer (at least '0')
2264 	do
2265 	{
2266 		tmp = num / 10;
2267 		*pNumBuf++ = num - (tmp * 10) + '0';
2268 	} while((num = tmp));
2269 
2270 	//copy now....
2271 	m_len = pNumBuf - numberBuffer; //length of the number string
2272 	if(bNegative)
2273 	{
2274 		m_len++;
2275 		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2276 		p = m_ptr;
2277 		*p++ = '-';
2278 	}
2279 	else
2280 	{
2281 		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2282 		p = m_ptr;
2283 	}
2284 	do
2285 	{
2286 		*p++ = *--pNumBuf;
2287 	} while(pNumBuf != numberBuffer);
2288 	*(m_ptr + m_len) = '\0';
2289 	return (*this);
2290 }
2291 
setNum(unsigned long num)2292 KviCString & KviCString::setNum(unsigned long num)
2293 {
2294 	char numberBuffer[30];
2295 	unsigned long tmp;
2296 	char * p;
2297 	char * pNumBuf = numberBuffer;
2298 
2299 	//write the number in a temporary buffer (at least '0')
2300 	do
2301 	{
2302 		tmp = num / 10;
2303 		*pNumBuf++ = num - (tmp * 10) + '0';
2304 	} while((num = tmp));
2305 
2306 	//copy now....
2307 	m_len = pNumBuf - numberBuffer; //length of the number string
2308 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2309 	p = m_ptr;
2310 	do
2311 	{
2312 		*p++ = *--pNumBuf;
2313 	} while(pNumBuf != numberBuffer);
2314 	*(m_ptr + m_len) = '\0';
2315 	return (*this);
2316 }
2317 
toLongLong(bool * bOk) const2318 long long KviCString::toLongLong(bool * bOk) const
2319 {
2320 	long long result = 0;
2321 	if(bOk)
2322 		*bOk = false;
2323 	char * p = m_ptr;
2324 	bool bNeg = false;
2325 	while(isspace(*p))
2326 		p++; //skip spaces
2327 	if(*p == '-')
2328 	{
2329 		bNeg = true;
2330 		p++;
2331 	}
2332 	else
2333 	{
2334 		if(*p == '+')
2335 			p++;
2336 	}
2337 	if(isdigit(*p))
2338 	{ //point to something interesting ?
2339 		do
2340 		{
2341 			result = (result * 10) + (*p - '0');
2342 			p++;
2343 		} while(isdigit(*p));
2344 		if(bNeg)
2345 			result = -result;
2346 		while(isspace(*p))
2347 			p++; //skip trailing spaces
2348 		if(*p)
2349 			return 0; //if this is not the end...die.
2350 		if(bOk)
2351 			*bOk = true;
2352 		return result;
2353 	}
2354 	return 0;
2355 }
2356 
toULongLong(bool * bOk) const2357 unsigned long long KviCString::toULongLong(bool * bOk) const
2358 {
2359 	unsigned long long result = 0;
2360 	if(bOk)
2361 		*bOk = false;
2362 	char * p = m_ptr;
2363 	while(isspace(*p))
2364 		p++; //skip spaces
2365 	if(isdigit(*p))
2366 	{ //point to something interesting ?
2367 		do
2368 		{
2369 			result = (result * 10) + (*p - '0');
2370 			p++;
2371 		} while(isdigit(*p));
2372 		while(isspace(*p))
2373 			p++; //skip trailing spaces
2374 		if(*p)
2375 			return 0; //if this is not the end...die.
2376 		if(bOk)
2377 			*bOk = true;
2378 		return result;
2379 	}
2380 	return 0;
2381 }
2382 
toLong(bool * bOk) const2383 long KviCString::toLong(bool * bOk) const
2384 {
2385 	long result = 0;
2386 	if(bOk)
2387 		*bOk = false;
2388 	char * p = m_ptr;
2389 	bool bNeg = false;
2390 	while(isspace(*p))
2391 		p++; //skip spaces
2392 	if(*p == '-')
2393 	{
2394 		bNeg = true;
2395 		p++;
2396 	}
2397 	else
2398 	{
2399 		if(*p == '+')
2400 			p++;
2401 	}
2402 	if(isdigit(*p))
2403 	{ //point to something interesting ?
2404 		do
2405 		{
2406 			result = (result * 10) + (*p - '0');
2407 			p++;
2408 		} while(isdigit(*p));
2409 		if(bNeg)
2410 			result = -result;
2411 		while(isspace(*p))
2412 			p++; //skip trailing spaces
2413 		if(*p)
2414 			return 0; //if this is not the end...die.
2415 		if(bOk)
2416 			*bOk = true;
2417 		return result;
2418 	}
2419 	return 0;
2420 }
2421 
toULong(bool * bOk) const2422 unsigned long KviCString::toULong(bool * bOk) const
2423 {
2424 	unsigned long result = 0;
2425 	if(bOk)
2426 		*bOk = false;
2427 	char * p = m_ptr;
2428 	while(isspace(*p))
2429 		p++; //skip spaces
2430 	if(isdigit(*p))
2431 	{ //point to something interesting ?
2432 		do
2433 		{
2434 			result = (result * 10) + (*p - '0');
2435 			p++;
2436 		} while(isdigit(*p));
2437 		while(isspace(*p))
2438 			p++; //skip trailing spaces
2439 		if(*p)
2440 			return 0; //if this is not the end...die.
2441 		if(bOk)
2442 			*bOk = true;
2443 		return result;
2444 	}
2445 	return 0;
2446 }
2447 
toLongExt(bool * bOk,int base)2448 long KviCString::toLongExt(bool * bOk, int base)
2449 {
2450 	if(m_len == 0)
2451 	{
2452 		if(bOk)
2453 			*bOk = false;
2454 		return 0;
2455 	}
2456 	char * endptr;
2457 	long result = strtol(m_ptr, &endptr, base);
2458 	if(*endptr)
2459 	{
2460 		// must be whitespaces, otherwise there is trailing garbage inside
2461 		while(isspace(*endptr) && (*endptr))
2462 			endptr++;
2463 		if(*endptr)
2464 		{
2465 			// still not at the end
2466 			// trailing garbage not allowed
2467 			if(bOk)
2468 				*bOk = false;
2469 			return result;
2470 		}
2471 	}
2472 	if(bOk)
2473 		*bOk = true;
2474 	return result;
2475 }
2476 
cutLeft(int len)2477 KviCString & KviCString::cutLeft(int len)
2478 {
2479 	KVI_ASSERT(len >= 0);
2480 	if(len <= m_len)
2481 	{
2482 		m_len -= len;
2483 		KviMemory::move(m_ptr, m_ptr + len, m_len + 1);
2484 		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2485 	}
2486 	else
2487 	{
2488 		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
2489 		*m_ptr = '\0';
2490 		m_len = 0;
2491 	}
2492 	return (*this);
2493 }
2494 
cutRight(int len)2495 KviCString & KviCString::cutRight(int len)
2496 {
2497 	KVI_ASSERT(len >= 0);
2498 	if(len <= m_len)
2499 	{
2500 		m_len -= len;
2501 		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2502 		*(m_ptr + m_len) = '\0';
2503 	}
2504 	else
2505 	{
2506 		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
2507 		*m_ptr = '\0';
2508 		m_len = 0;
2509 	}
2510 	return (*this);
2511 }
2512 
cut(int idx,int len)2513 KviCString & KviCString::cut(int idx, int len)
2514 {
2515 	KVI_ASSERT(idx >= 0);
2516 	KVI_ASSERT(len >= 0);
2517 	if(idx < m_len)
2518 	{
2519 		// idx = 3 len = 3 m_len = 10
2520 		// 0123456789
2521 		// abcdefghij
2522 		//    ^  ^
2523 		//   p1  p2
2524 		char * p1 = m_ptr + idx;
2525 		if(len + idx > m_len)
2526 			len = m_len - idx;
2527 		char * p2 = p1 + len;
2528 		KviMemory::move(p1, p2, (m_len - (len + idx)) + 1);
2529 		m_len -= len;
2530 		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2531 	}
2532 	return (*this);
2533 }
2534 
cutToFirst(char c,bool bIncluded)2535 KviCString & KviCString::cutToFirst(char c, bool bIncluded)
2536 {
2537 	int idx = findFirstIdx(c);
2538 	if(idx != -1)
2539 		cutLeft(bIncluded ? idx + 1 : idx);
2540 	return (*this);
2541 }
2542 
leftToFirst(char c,bool bIncluded) const2543 KviCString KviCString::leftToFirst(char c, bool bIncluded) const
2544 {
2545 	int idx = findFirstIdx(c);
2546 	if(idx == -1)
2547 		return KviCString(*this);
2548 	return KviCString(m_ptr, bIncluded ? idx + 1 : idx);
2549 }
2550 
leftToLast(char c,bool bIncluded) const2551 KviCString KviCString::leftToLast(char c, bool bIncluded) const
2552 {
2553 	int idx = findLastIdx(c);
2554 	return KviCString(m_ptr, bIncluded ? idx + 1 : idx);
2555 }
2556 
cutFromFirst(char c,bool bIncluded)2557 KviCString & KviCString::cutFromFirst(char c, bool bIncluded)
2558 {
2559 	int idx = findFirstIdx(c);
2560 	if(idx != -1)
2561 		cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + 1)));
2562 	return (*this);
2563 }
2564 
cutToLast(char c,bool bIncluded)2565 KviCString & KviCString::cutToLast(char c, bool bIncluded)
2566 {
2567 	int idx = findLastIdx(c);
2568 	if(idx != -1)
2569 		cutLeft(bIncluded ? idx + 1 : idx);
2570 	return (*this);
2571 }
2572 
cutFromLast(char c,bool bIncluded)2573 KviCString & KviCString::cutFromLast(char c, bool bIncluded)
2574 {
2575 	int idx = findLastIdx(c);
2576 	if(idx != -1)
2577 		cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + 1)));
2578 	return (*this);
2579 }
2580 
cutToFirst(const char * c,bool bIncluded)2581 KviCString & KviCString::cutToFirst(const char * c, bool bIncluded)
2582 {
2583 	int len = (int)strlen(c);
2584 	int idx = findFirstIdx(c);
2585 	if(idx != -1)
2586 		cutLeft(bIncluded ? idx + len : idx);
2587 	return (*this);
2588 }
2589 
cutFromFirst(const char * c,bool bIncluded)2590 KviCString & KviCString::cutFromFirst(const char * c, bool bIncluded)
2591 {
2592 	int len = (int)strlen(c);
2593 	int idx = findFirstIdx(c);
2594 	if(idx != -1)
2595 		cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + len)));
2596 	return (*this);
2597 }
2598 
cutToLast(const char * c,bool bIncluded)2599 KviCString & KviCString::cutToLast(const char * c, bool bIncluded)
2600 {
2601 	int len = (int)strlen(c);
2602 	int idx = findLastIdx(c);
2603 	if(idx != -1)
2604 		cutLeft(bIncluded ? idx + len : idx);
2605 	return (*this);
2606 }
2607 
cutFromLast(const char * c,bool bIncluded)2608 KviCString & KviCString::cutFromLast(const char * c, bool bIncluded)
2609 {
2610 	int len = (int)strlen(c);
2611 	int idx = findLastIdx(c);
2612 	if(idx != -1)
2613 		cutRight(bIncluded ? (m_len - idx) : (m_len - (idx + len)));
2614 	return (*this);
2615 }
2616 
setLen(int iLen)2617 KviCString & KviCString::setLen(int iLen)
2618 {
2619 	KVI_ASSERT(iLen >= 0);
2620 	m_len = iLen;
2621 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2622 	*(m_ptr + m_len) = '\0';
2623 	return (*this);
2624 }
2625 
padRight(int iLen,const char c)2626 KviCString & KviCString::padRight(int iLen, const char c)
2627 {
2628 	KVI_ASSERT(iLen >= 0);
2629 	m_ptr = (char *)KviMemory::reallocate(m_ptr, iLen + 1);
2630 	*(m_ptr + iLen) = '\0';
2631 	if(iLen > m_len)
2632 		KviMemory::set(m_ptr + m_len, c, iLen - m_len);
2633 	m_len = iLen;
2634 	return (*this);
2635 }
2636 
stripLeftWhiteSpace()2637 KviCString & KviCString::stripLeftWhiteSpace()
2638 {
2639 	char * p = m_ptr;
2640 	while(isspace(*p))
2641 		p++;
2642 	m_len -= (p - m_ptr);
2643 	KviMemory::move(m_ptr, p, m_len + 1);
2644 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2645 	return (*this);
2646 }
2647 
stripLeft(char c)2648 KviCString & KviCString::stripLeft(char c)
2649 {
2650 	KVI_ASSERT(c != '\0');
2651 	char * p = m_ptr;
2652 	while(*p == c)
2653 		p++;
2654 	m_len -= (p - m_ptr);
2655 	KviMemory::move(m_ptr, p, m_len + 1);
2656 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2657 	return (*this);
2658 }
2659 
getToken(KviCString & str,char sep)2660 bool KviCString::getToken(KviCString & str, char sep)
2661 {
2662 	KVI_ASSERT(str.m_ptr);
2663 	KVI_ASSERT(str.m_ptr != m_ptr);
2664 	char * p = m_ptr;
2665 	//skip to the end
2666 	while(*p && (*p != sep))
2667 		p++;
2668 	//0123456789
2669 	//abcd xyz
2670 	//^   ^
2671 	str.m_len = p - m_ptr;
2672 	str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
2673 	KviMemory::copy(str.m_ptr, m_ptr, str.m_len);
2674 	*(str.m_ptr + str.m_len) = '\0';
2675 	while(*p && (*p == sep))
2676 		p++;
2677 	cutLeft(p - m_ptr);
2678 	return (m_len != 0);
2679 }
2680 
getLine(KviCString & str)2681 bool KviCString::getLine(KviCString & str)
2682 {
2683 	KVI_ASSERT(str.m_ptr);
2684 	KVI_ASSERT(str.m_ptr != m_ptr);
2685 	if(m_len == 0)
2686 		return false;
2687 	char * p = m_ptr;
2688 	//skip to the end
2689 	while(*p && (*p != '\n'))
2690 		p++;
2691 	//0123456789
2692 	//abcd xyz
2693 	//^   ^
2694 	str.m_len = p - m_ptr;
2695 	str.m_ptr = (char *)KviMemory::reallocate(str.m_ptr, str.m_len + 1);
2696 	KviMemory::copy(str.m_ptr, m_ptr, str.m_len);
2697 	*(str.m_ptr + str.m_len) = '\0';
2698 	p++;
2699 	cutLeft(p - m_ptr);
2700 	return true;
2701 }
2702 
getToken(char sep)2703 KviCString KviCString::getToken(char sep)
2704 {
2705 	char * p = m_ptr;
2706 	while(*p && (*p != sep))
2707 		p++;
2708 	KviCString ret(m_ptr, p);
2709 	while(*p && (*p == sep))
2710 		p++;
2711 	cutLeft(p - m_ptr);
2712 	return ret;
2713 }
2714 
vsprintf(const char * fmt,kvi_va_list list)2715 KviCString & KviCString::vsprintf(const char * fmt, kvi_va_list list)
2716 {
2717 	kvi_va_list save;
2718 	kvi_va_copy(save, list);
2719 
2720 	m_ptr = (char *)KviMemory::reallocate(m_ptr, 256);
2721 	//First try
2722 	//print...with max 256 chars
2723 	m_len = kvi_vsnprintf(m_ptr, 256, fmt, list);
2724 
2725 	//check if we failed
2726 	if(m_len < 0)
2727 	{
2728 		//yes, failed....
2729 		int dummy = 256;
2730 		do
2731 		{ //we failed, so retry with 256 more chars
2732 			dummy += 256;
2733 			//realloc
2734 			m_ptr = (char *)KviMemory::reallocate(m_ptr, dummy);
2735 			//print...
2736 			kvi_va_copy(list, save);
2737 			m_len = kvi_vsnprintf(m_ptr, dummy, fmt, list);
2738 		} while(m_len < 0);
2739 	}
2740 	//done...
2741 	//now m_len is the length of the written string not including the terminator...
2742 	//perfect! :)
2743 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2744 	kvi_va_end(save);
2745 	return (*this);
2746 }
2747 
sprintf(const char * fmt,...)2748 KviCString & KviCString::sprintf(const char * fmt, ...)
2749 {
2750 	m_ptr = (char *)KviMemory::reallocate(m_ptr, 256);
2751 	//First try
2752 	kvi_va_list list;
2753 	kvi_va_start(list, fmt);
2754 	//print...with max 256 chars
2755 	m_len = kvi_vsnprintf(m_ptr, 256, fmt, list);
2756 	kvi_va_end(list);
2757 
2758 	//check if we failed
2759 	if(m_len < 0)
2760 	{
2761 		//yes, failed....
2762 		int dummy = 256;
2763 		do
2764 		{ //we failed, so retry with 256 more chars
2765 			dummy += 256;
2766 			//realloc
2767 			m_ptr = (char *)KviMemory::reallocate(m_ptr, dummy);
2768 			//print...
2769 			kvi_va_start(list, fmt);
2770 			m_len = kvi_vsnprintf(m_ptr, dummy, fmt, list);
2771 			kvi_va_end(list);
2772 		} while(m_len < 0);
2773 	}
2774 	//done...
2775 	//now m_len is the length of the written string not including the terminator...
2776 	//perfect! :)
2777 	m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
2778 	return (*this);
2779 }
2780 
find(const char * str,int idx,bool caseS) const2781 int KviCString::find(const char * str, int idx, bool caseS) const
2782 {
2783 	if(idx >= m_len)
2784 		return -1;
2785 	char * p = m_ptr + idx;
2786 	int len = (int)strlen(str);
2787 	if(caseS)
2788 	{
2789 		for(;;)
2790 		{
2791 			while(*p && (*p != *str))
2792 				p++;
2793 			if(*p)
2794 			{
2795 				if(kvi_strEqualCSN(str, p, len))
2796 					return (p - m_ptr);
2797 				else
2798 					p++;
2799 			}
2800 			else
2801 				return -1;
2802 		}
2803 	}
2804 	else
2805 	{
2806 		for(;;)
2807 		{
2808 			char tmp = toupper(*str);
2809 			while(*p && (toupper(*p) != tmp))
2810 				p++;
2811 			if(*p)
2812 			{
2813 				if(kvi_strEqualCIN(str, p, len))
2814 					return (p - m_ptr);
2815 				else
2816 					p++;
2817 			}
2818 			else
2819 				return -1;
2820 		}
2821 	}
2822 }
2823 
find(char c,int idx) const2824 int KviCString::find(char c, int idx) const
2825 {
2826 	if(idx >= m_len)
2827 		return -1;
2828 	char * p = m_ptr + idx;
2829 	while(*p && (*p != c))
2830 		p++;
2831 	return (*p ? p - m_ptr : -1);
2832 }
2833 
findRev(const char * str,int idx,bool caseS) const2834 int KviCString::findRev(const char * str, int idx, bool caseS) const
2835 {
2836 	if((m_len + idx) < 0)
2837 		return -1;
2838 	char * p = m_ptr + m_len + idx;
2839 	int len = (int)strlen(str);
2840 	if(caseS)
2841 	{
2842 		for(;;)
2843 		{
2844 			while((p >= m_ptr) && (*p != *str))
2845 				p--;
2846 			if(p >= m_ptr)
2847 			{
2848 				if(kvi_strEqualCSN(str, p, len))
2849 					return (p - m_ptr);
2850 				else
2851 					p--;
2852 			}
2853 			else
2854 				return -1;
2855 		}
2856 	}
2857 	else
2858 	{
2859 		for(;;)
2860 		{
2861 			char tmp = toupper(*str);
2862 			while((p >= m_ptr) && (toupper(*p) != tmp))
2863 				p--;
2864 			if(p >= m_ptr)
2865 			{
2866 				if(kvi_strEqualCIN(str, p, len))
2867 					return (p - m_ptr);
2868 				else
2869 					p--;
2870 			}
2871 			else
2872 				return -1;
2873 		}
2874 	}
2875 }
2876 
findFirstIdx(char c) const2877 int KviCString::findFirstIdx(char c) const
2878 {
2879 	char * p = m_ptr;
2880 	while(*p && (*p != c))
2881 		p++;
2882 	return (*p ? p - m_ptr : -1);
2883 }
2884 
findFirstIdx(const char * str,bool caseS) const2885 int KviCString::findFirstIdx(const char * str, bool caseS) const
2886 {
2887 	// This function can't be used to search inside
2888 	// multibyte encoded strings... convert your
2889 	// code to QString and use QString::findRev().
2890 	// We must throw away KviCString at all in this case...
2891 
2892 	// return QString(m_ptr).find(QString(str),0,caseS);
2893 
2894 	// Both this KviCString and the const char * str are assumed
2895 	// to be in the proper (and same) encoding.
2896 	// If KviCString is in encoding A then QString(m_ptr) might
2897 	// or not be decoded correctly.
2898 	// Also if KviCString is in UTF-8 (for example), then
2899 	// a position in QString() does not map to the position in the char array
2900 	// since a single UNICODE char may use one or more bytes...
2901 
2902 	KVI_ASSERT(str);
2903 	char * p = m_ptr;
2904 	int len = (int)strlen(str);
2905 	if(caseS)
2906 	{
2907 		for(;;)
2908 		{
2909 			while(*p && (*p != *str))
2910 				p++;
2911 			if(*p)
2912 			{
2913 				if(kvi_strEqualCSN(str, p, len))
2914 					return (p - m_ptr);
2915 				else
2916 					p++;
2917 			}
2918 			else
2919 				return -1;
2920 		}
2921 	}
2922 	else
2923 	{
2924 		// this will NOT work for strings that aren't in the current system encoding :(
2925 		for(;;)
2926 		{
2927 			char tmp = toupper(*str);
2928 			while(*p && (toupper(*p) != tmp))
2929 				p++;
2930 			if(*p)
2931 			{
2932 				if(kvi_strEqualCIN(str, p, len))
2933 					return (p - m_ptr);
2934 				else
2935 					p++;
2936 			}
2937 			else
2938 				return -1;
2939 		}
2940 	}
2941 }
2942 
findLastIdx(char c) const2943 int KviCString::findLastIdx(char c) const
2944 {
2945 	//Empty string ?
2946 	if(m_len < 1)
2947 		return -1;
2948 	//p points to the last character in the string
2949 	char * p = ((m_ptr + m_len) - 1);
2950 	//go back until we find a match or we run to the first char in the string.
2951 	while((*p != c) && (p > m_ptr))
2952 		p--;
2953 	//if *p == c --> matched, else we are at the beginning of the string.
2954 	return ((*p == c) ? p - m_ptr : -1);
2955 }
2956 
findLastIdx(const char * str,bool caseS) const2957 int KviCString::findLastIdx(const char * str, bool caseS) const
2958 {
2959 	// This function can't be used to search inside
2960 	// multibyte encoded strings... convert your
2961 	// code to QString and use QString::findRev().
2962 	// We must throw away KviCString at all in this case...
2963 
2964 	// return QString(m_ptr).findRev(QString(str),-1,caseS);
2965 
2966 	KVI_ASSERT(str);
2967 	//Calc the len of the searched string
2968 	int len = (int)strlen(str);
2969 	//Too long ?
2970 	if(m_len < len)
2971 		return -1;
2972 	//p points to the last character in the string
2973 	char * p = ((m_ptr + m_len) - 1);
2974 	if(caseS)
2975 	{
2976 		for(;;)
2977 		{
2978 			//go back until we find a character that mathes or we run to the first char.
2979 			while((*p != *str) && (p > m_ptr))
2980 				p--;
2981 			if(*p == *str)
2982 			{
2983 				//maybe occurrence....
2984 				if(kvi_strEqualCSN(str, p, len))
2985 					return (p - m_ptr);
2986 				else
2987 				{
2988 					//Nope...continue if there is more data to check...
2989 					if(p == m_ptr)
2990 						return -1;
2991 					p--;
2992 				}
2993 			}
2994 			else
2995 				return -1; //Beginning of the string
2996 		}
2997 	}
2998 	else
2999 	{
3000 		// case insensitive
3001 		for(;;)
3002 		{
3003 			//go back until we find a character that mathes or we run to the first char.
3004 			char tmp = toupper(*str);
3005 			while((toupper(*p) != tmp) && (p > m_ptr))
3006 				p--;
3007 			if(toupper(*p) == tmp)
3008 			{
3009 				//maybe occurrence....
3010 				if(kvi_strEqualCIN(str, p, len))
3011 					return (p - m_ptr);
3012 				else
3013 				{
3014 					//Nope...continue if there is more data to check...
3015 					if(p == m_ptr)
3016 						return -1;
3017 					p--;
3018 				}
3019 			}
3020 			else
3021 				return -1; //Beginning of the string
3022 		}
3023 	}
3024 }
3025 
trim()3026 KviCString & KviCString::trim()
3027 {
3028 	// 0123456789
3029 	//    abcd   0
3030 	// ^        ^
3031 	// left   right
3032 	char * left = m_ptr;
3033 	char * right = m_ptr + m_len - 1;
3034 	// skip initial spaces
3035 	while(isspace(*left))
3036 		left++;
3037 	if(*left)
3038 	{
3039 		// valid string, left points to first non-space
3040 		while((right >= left) && isspace(*right))
3041 			right--;
3042 		// 0123456789
3043 		//    abcd   0
3044 		//    ^  ^
3045 		// left   right
3046 		m_len = (right - left) + 1;
3047 		KviMemory::move(m_ptr, left, m_len);
3048 		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
3049 		*(m_ptr + m_len) = '\0';
3050 	}
3051 	else
3052 	{
3053 		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
3054 		*m_ptr = '\0';
3055 		m_len = 0;
3056 	}
3057 	return (*this);
3058 }
3059 
stripRightWhiteSpace()3060 KviCString & KviCString::stripRightWhiteSpace()
3061 {
3062 	if(*m_ptr)
3063 	{
3064 		char * right = m_ptr + m_len - 1;
3065 		const char * start = right;
3066 		//isspace accepts 0..255 values in MSVC
3067 		while((right >= m_ptr) && ((unsigned)(*right + 1) <= 256) && isspace(*right))
3068 			right--;
3069 		if(right != start)
3070 		{
3071 			m_len = (right - m_ptr) + 1;
3072 			m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
3073 			*(m_ptr + m_len) = '\0';
3074 		}
3075 	}
3076 	return (*this);
3077 }
3078 
stripRight(char c)3079 KviCString & KviCString::stripRight(char c)
3080 {
3081 	if(*m_ptr)
3082 	{
3083 		char * right = m_ptr + m_len - 1;
3084 		const char * start = right;
3085 		while((right >= m_ptr) && (*right == c))
3086 			right--;
3087 		if(right != start)
3088 		{
3089 			m_len = (right - m_ptr) + 1;
3090 			m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
3091 			*(m_ptr + m_len) = '\0';
3092 		}
3093 	}
3094 	return (*this);
3095 }
3096 
stripSpace()3097 KviCString & KviCString::stripSpace()
3098 {
3099 	// 0123456789
3100 	//    abcd   0
3101 	// ^        ^
3102 	// left   right
3103 	char * left = m_ptr;
3104 	char * right = m_ptr + m_len - 1;
3105 	// skip initial spaces
3106 	while((*left == ' ') || (*left == '\t'))
3107 		left++;
3108 	if(*left)
3109 	{
3110 		// valid string, left points to first non-space
3111 		while((right >= left) && ((*right == ' ') || (*right == '\t')))
3112 			right--;
3113 		// 0123456789
3114 		//    abcd   0
3115 		//    ^  ^
3116 		// left   right
3117 		m_len = (right - left) + 1;
3118 		KviMemory::move(m_ptr, left, m_len);
3119 		m_ptr = (char *)KviMemory::reallocate(m_ptr, m_len + 1);
3120 		*(m_ptr + m_len) = '\0';
3121 	}
3122 	else
3123 	{
3124 		m_ptr = (char *)KviMemory::reallocate(m_ptr, 1);
3125 		*m_ptr = '\0';
3126 		m_len = 0;
3127 	}
3128 	return (*this);
3129 }
3130 
isNum() const3131 bool KviCString::isNum() const
3132 {
3133 	char * p = m_ptr;
3134 	while(isspace(*p))
3135 		p++;
3136 	if(*p == '-')
3137 		p++;
3138 	if(!isdigit(*p))
3139 		return false;
3140 	while(isdigit(*p))
3141 		p++;
3142 	while(isspace(*p))
3143 		p++;
3144 	return (*p == '\0');
3145 }
3146 
isUnsignedNum() const3147 bool KviCString::isUnsignedNum() const
3148 {
3149 	char * p = m_ptr;
3150 	while(isspace(*p))
3151 		p++;
3152 	if(!isdigit(*p))
3153 		return false;
3154 	while(isdigit(*p))
3155 		p++;
3156 	while(isspace(*p))
3157 		p++;
3158 	return (*p == '\0');
3159 }
3160 
3161 static KviCString g_szApplicationWideEmptyString;
3162 
emptyString()3163 KviCString & KviCString::emptyString()
3164 {
3165 	return g_szApplicationWideEmptyString;
3166 }
3167 
ext_contains(const char * data,const char * item,bool caseS)3168 bool KviCString::ext_contains(const char * data, const char * item, bool caseS)
3169 {
3170 	if(item && data)
3171 	{
3172 		int len = (int)strlen(item);
3173 		char c = tolower(*item);
3174 		if(caseS)
3175 		{
3176 			while(*data)
3177 			{
3178 				while(*data && (tolower(*data) != c))
3179 					data++;
3180 				if(*data)
3181 				{
3182 					if(kvi_strEqualCSN(item, data, len))
3183 						return true;
3184 					else
3185 						data++;
3186 				}
3187 			}
3188 		}
3189 		else
3190 		{
3191 			while(*data)
3192 			{
3193 				while(*data && (tolower(*data) != c))
3194 					data++;
3195 				if(*data)
3196 				{
3197 					if(kvi_strEqualCIN(item, data, len))
3198 						return true;
3199 					else
3200 						data++;
3201 				}
3202 			}
3203 		}
3204 	}
3205 	return false;
3206 }
3207