1 // -*- Mode: C++; tab-width: 2; -*-
2 // vi: set ts=2:
3 //
4 
5 #include <BALL/DATATYPE/string.h>
6 
7 #include <QString>
8 #include <QByteArray>
9 
10 #include <cstdio>
11 #include <cstdarg>
12 #include <limits>
13 
14 #include <algorithm>
15 
16 using std::ostream;
17 using std::istream;
18 using std::stringstream;
19 using std::endl;
20 using std::ends;
21 using std::vector;
22 
23 namespace BALL
24 {
25 
26 #ifndef BALL_HAVE_VSNPRINTF
BALLString_vsnprintf(char * s,size_t n,const char * format,va_list ap)27 	int BALLString_vsnprintf(char* s, size_t n, const char* format,  va_list ap)
28 	{
29 		// this is an ugly hack - this is safe only up to
30 		// the static buffer size - no time to implement
31 		// something more sophisticated... OK
32 		char* tmp = new char[65536];
33 		vsprintf(tmp, format, ap);
34 		if (n > 65535)
35 		{
36 			n = 65535;
37 		}
38 		strncpy(s, tmp, n - 1);
39 		s[n - 1] = (char)0;
40 		delete [] tmp;
41 		return (int)strlen(s);
42 	}
43 #	define vsnprintf BALLString_vsnprintf
44 #endif
45 
46 	const char* String::CHARACTER_CLASS__ASCII_ALPHA = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
47 	const char* String::CHARACTER_CLASS__ASCII_ALPHANUMERIC = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
48 	const char* String::CHARACTER_CLASS__ASCII_LOWER = "abcdefghijklmnopqrstuvwxyz";
49 	const char* String::CHARACTER_CLASS__ASCII_NUMERIC = "0123456789";
50 	const char* String::CHARACTER_CLASS__ASCII_UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
51 	const char* String::CHARACTER_CLASS__WHITESPACE = " \n\t\r\f\v";
52 	const char* String::CHARACTER_CLASS__QUOTES = "\"";
53 
54 	const Size String::EndPos = std::numeric_limits<Size>::max();
55 
56 	const String String::EMPTY("");
57 
58 	String::CompareMode String::compare_mode_ = String::CASE_SENSITIVE;
59 
UnboundSubstring(const char * file,int line)60 	Substring::UnboundSubstring::UnboundSubstring(const char* file, int line)
61 		:	Exception::GeneralException(file, line, "UnboundSubstring", "trying to use a substring that was not bound to a string.")
62 	{
63 	}
64 
InvalidSubstring(const char * file,int line)65 	Substring::InvalidSubstring::InvalidSubstring(const char* file, int line)
66 		:	Exception::GeneralException(file, line, "InvalidSubstring", "the substring is not valid")
67 	{
68 	}
69 
Substring()70 	Substring::Substring()
71 		:	bound_(0),
72 			from_((Index)String::EndPos),
73 			to_((Index)String::EndPos)
74 	{
75 	}
76 
Substring(const Substring & substring,bool)77 	Substring::Substring(const Substring& substring, bool /* deep */)
78 		:	bound_(substring.bound_),
79 			from_(substring.from_),
80 			to_(substring.to_)
81 	{
82 	}
83 
Substring(const String & s,Index from,Size len)84 	Substring::Substring(const String& s, Index from, Size len)
85 	{
86 		s.validateRange_(from, len);
87 
88 		bound_	= (String *)& s;
89 		from_		= from;
90 		to_			= from + (Index)len - 1;
91 	}
92 
~Substring()93 	Substring::~Substring()
94 	{
95 	}
96 
dump(ostream & s,Size depth) const97 	void Substring::dump(ostream& s, Size depth) const
98 	{
99 		if (bound_ == 0)
100 		{
101 			throw UnboundSubstring(__FILE__, __LINE__);
102 		}
103 
104 		BALL_DUMP_STREAM_PREFIX(s);
105 
106 		BALL_DUMP_DEPTH(s, depth);
107 		s << "  bound String: " << (void *)bound_ << endl;
108 
109 		BALL_DUMP_DEPTH(s, depth);
110 		s << "  from index: " << from_ << endl;
111 
112 		BALL_DUMP_DEPTH(s, depth);
113 		s << "  to index: " << to_ << endl;
114 
115 		BALL_DUMP_DEPTH(s, depth);
116 		s << "  string: ";
117 
118 		const char *end_of_string = bound_->c_str() + to_;
119 
120 		for (const char* ptr = bound_->c_str() + from_; ptr <= end_of_string; ptr++)
121 			s << *ptr;
122 
123 		s << endl;
124 
125 		BALL_DUMP_STREAM_SUFFIX(s);
126 	}
127 
operator <<(ostream & s,const Substring & substring)128 	ostream& operator << (ostream &s, const Substring& substring)
129 	{
130 		if (substring.isBound() == false)
131 		{
132 			return s;
133 		}
134 
135 		const char* char_ptr = substring.bound_->c_str() + substring.from_;
136 		const char* end_of_string = substring.bound_->c_str() + substring.to_;
137 
138 		while (char_ptr <= end_of_string)
139 		{
140 			s.put(*char_ptr++);
141 		}
142 
143 		return s;
144 	}
145 
String(const QString & string)146 	String::String(const QString& string)
147 	{
148 		assign(string.toLocal8Bit().data());
149 	}
150 
String(const QByteArray & string)151 	String::String(const QByteArray& string)
152 	{
153 		assign(string.data());
154 	}
155 
String(const char * char_ptr,Index from,Size len)156 	String::String(const char* char_ptr, Index from, Size len)
157  	 : string()
158 	{
159  	 validateCharPtrRange_(from, len, char_ptr);
160  	 if (len > 0)
161  	 {
162  	   assign(char_ptr + from, len);
163  	 }
164 	}
165 
166 	// hand-coded create method
create(bool,bool empty) const167 	void* String::create(bool /* deep */, bool empty) const
168 	{
169 		void* ptr;
170 		if (empty == true)
171 		{
172 			ptr = (void*)new String;
173 		}
174 		else
175 		{
176 			ptr = (void*)new String(*this);
177 		}
178 
179 		return ptr;
180 	}
181 
String(Size buffer_size,const char * format,...)182 	String::String(Size buffer_size, const char* format, ... )
183 		: string()
184 	{
185 		if (buffer_size <= 0)
186 		{
187 			throw Exception::IndexUnderflow(__FILE__, __LINE__);
188 		}
189 
190 		if (format == 0)
191 		{
192        throw Exception::NullPointer(__FILE__, __LINE__);
193 		}
194 
195 		char* buffer = new char[buffer_size];
196 		memset(buffer, 0, buffer_size);
197 
198 		va_list var_arg_list;
199 		va_start(var_arg_list, format);
200 		vsnprintf(buffer, (Size)buffer_size, format, var_arg_list);
201 		va_end(var_arg_list);
202 
203 		// this is a safeguard for strange vsnprintf implementations
204 		buffer[buffer_size-1] = '\0';
205 
206 		assign(buffer);
207 
208 		delete [] buffer;
209 	}
210 
211 #ifdef BALL_HAS_SSTREAM
String(std::stringstream & s)212 	String::String(std::stringstream& s)
213 #else
214 	String::String(std::strstream& s)
215 #endif
216 		: string("")
217 	{
218 		s >> (*this);
219 	}
220 
221 #	define BALL_STRING_DEFINE_CONSTRUCTOR_METHOD(type, format_string) \
222 	String::String(type t)\
223 	{ \
224 		setlocale(LC_NUMERIC, "C"); \
225 		char buffer[128]; \
226 	\
227 		sprintf(buffer, format_string, t); \
228 		assign(buffer);\
229 	}\
230 
231 	BALL_STRING_DEFINE_CONSTRUCTOR_METHOD(short, "%hd")
232 	BALL_STRING_DEFINE_CONSTRUCTOR_METHOD(unsigned short, "%hu")
233 	BALL_STRING_DEFINE_CONSTRUCTOR_METHOD(int, "%d")
234 	BALL_STRING_DEFINE_CONSTRUCTOR_METHOD(unsigned int, "%u")
235 	BALL_STRING_DEFINE_CONSTRUCTOR_METHOD(long, "%ld")
236 	BALL_STRING_DEFINE_CONSTRUCTOR_METHOD(unsigned long, "%lu")
237 #ifdef BALL_ALLOW_LONG64_TYPE_OVERLOADS
238 	BALL_STRING_DEFINE_CONSTRUCTOR_METHOD(LongIndex, "%lld")
239 	BALL_STRING_DEFINE_CONSTRUCTOR_METHOD(LongSize, "%llu")
240 #endif
241 	BALL_STRING_DEFINE_CONSTRUCTOR_METHOD(float, "%f")
242 	BALL_STRING_DEFINE_CONSTRUCTOR_METHOD(double, "%f")
243 
244 	#undef BALL_STRING_DEFINE_CONSTRUCTOR_METHOD
245 
~String()246 	String::~String()
247 	{
248 	}
249 
set(const String & s)250 	void String::set(const String& s)
251 	{
252 		std::string::operator = (s);
253 	}
254 
set(const String & s,Index from,Size len)255 	void String::set(const String& s, Index from, Size len)
256 	{
257 		s.validateRange_(from, len);
258 
259 		if (len == 0)
260 		{
261 			erase();
262 		}
263 		else
264 		{
265 			assign(s.c_str() + from, len);
266 		}
267 	}
268 
set(const char * s,Index from,Size len)269 	void String::set(const char* s, Index from, Size len)
270 	{
271 		validateCharPtrRange_(from, len, s);
272 
273 		if (len == 0)
274 		{
275 			erase();
276 		}
277 		else
278 		{
279 			assign(s + from, len);
280 		}
281 	}
282 
set(Size buffer_size,const char * format,...)283 	void String::set(Size buffer_size, const char *format, ... )
284 	{
285 		if (buffer_size <= 0)
286 		{
287 		  throw Exception::IndexUnderflow(__FILE__, __LINE__);
288 		}
289 
290 		if (format == 0)
291 		{
292 			throw Exception::NullPointer(__FILE__, __LINE__);
293 		}
294 
295 		char* buffer = new char[buffer_size];
296 		memset(buffer, 0, buffer_size);
297 
298 		va_list var_arg_list;
299 		va_start(var_arg_list, format);
300 		vsnprintf(buffer, (Size)buffer_size, format, var_arg_list);
301 		va_end(var_arg_list);
302 
303 		// this is a safeguard for strange vsnprintf implementations
304 		buffer[buffer_size-1] = '\0';
305 
306 		assign(buffer);
307 
308 		delete [] buffer;
309 	}
310 
311 #	define BALL_STRING_DEFINE_SET_METHOD(type, format_string) \
312 	void String::set(type t)\
313 	{ \
314 		char buffer[128]; \
315 	\
316 		sprintf(buffer, format_string, t); \
317 	\
318 		assign(buffer);\
319 	}
320 
321 	BALL_STRING_DEFINE_SET_METHOD(short, "%hd")
322 	BALL_STRING_DEFINE_SET_METHOD(unsigned short, "%hu")
323 	BALL_STRING_DEFINE_SET_METHOD(int, "%d")
324 	BALL_STRING_DEFINE_SET_METHOD(unsigned int, "%u")
325 	BALL_STRING_DEFINE_SET_METHOD(long, "%ld")
326 	BALL_STRING_DEFINE_SET_METHOD(unsigned long, "%lu")
327 #ifdef BALL_ALLOW_LONG64_TYPE_OVERLOADS
328 	BALL_STRING_DEFINE_SET_METHOD(LongIndex, "%lld")
329 	BALL_STRING_DEFINE_SET_METHOD(LongSize, "%llu")
330 #endif
331 	BALL_STRING_DEFINE_SET_METHOD(float, "%f")
332 	BALL_STRING_DEFINE_SET_METHOD(double, "%f")
333 
334 	#undef BALL_STRING_DEFINE_SET_METHOD
335 
get(char * char_ptr,Index from,Size max_len) const336   void String::get(char* char_ptr, Index from, Size max_len) const
337 	{
338 		validateIndex_(from);
339 
340 		if (max_len == 0)
341 		{
342 			return;
343 		}
344 
345 		Size len = std::min(max_len, (Size)(size() - from));
346 
347 		const char*	string_ptr = &(c_str()[from]);
348 
349 		Size i = 0;
350 		while (i < len)
351 		{
352 			*char_ptr = *string_ptr;
353 
354 			char_ptr++;
355 			string_ptr++;
356 			i++;
357 		}
358 		*char_ptr = '\0';
359 	}
360 
toBool() const361 	bool String::toBool() const
362 	{
363 		string::size_type str_index = find_first_not_of(CHARACTER_CLASS__WHITESPACE);
364 
365 		if (size() == 0)
366 		{
367 			return true;
368 		}
369 
370 		if (str_index != string::npos)
371 		{
372 			Size index = (Index)str_index;
373 			if (!(c_str()[index] == '0' && (isWhitespace(c_str()[index + 1]) == true || c_str()[index + 1] == '\0'))
374 					&& !(c_str()[index++] == 'f'
375 					&& c_str()[index++] == 'a'
376 					&& c_str()[index++] == 'l'
377 					&& c_str()[index++] == 's'
378 					&& c_str()[index++] == 'e'
379 					&& (isWhitespace(c_str()[index]) == true || c_str()[index] == '\0')))
380 			{
381 				return true;
382 			}
383 		}
384 
385 		return false;
386 	}
387 
toShort() const388 	short String::toShort() const
389 	{
390 		if (!isFloat())
391 		{
392 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
393 		}
394 
395 		errno = 0;
396 		int i = atoi(c_str());
397 
398 		if ((errno == ERANGE) || (i < (int)std::numeric_limits<short>::min()) || (i > (int)std::numeric_limits<short>::max()))
399 		{
400 			errno = 0;
401 			throw Exception::InvalidFormat(__FILE__, __LINE__, string("out of range: ") + c_str());
402 		}
403 		errno = 0;
404 
405 		return (short)i;
406 	}
407 
toUnsignedShort() const408 	unsigned short String::toUnsignedShort() const
409 	{
410 		if (!isFloat())
411 		{
412 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
413 		}
414 
415 		errno = 0;
416 		int i = atoi(c_str());
417 
418 		if ((errno == ERANGE) || (i < (int)0) || (i > (int)std::numeric_limits<unsigned short>::max()))
419 		{
420 			errno = 0;
421 			throw Exception::InvalidFormat(__FILE__, __LINE__, string("out of range: ") + c_str());
422 		}
423 		errno = 0;
424 
425 		return (unsigned short)i;
426 	}
427 
428 
toInt() const429 	int String::toInt() const
430 	{
431 		if (!isFloat())
432 		{
433 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
434 		}
435 
436 		errno = 0;
437 		int i = atoi(c_str());
438 
439 		if (errno == ERANGE)
440 		{
441 			throw Exception::InvalidFormat(__FILE__, __LINE__, string("out of range: ") + string(c_str()));
442 		}
443 
444 		return i;
445 	}
446 
447 
toUnsignedInt() const448 	unsigned int String::toUnsignedInt() const
449 	{
450 		if (!isFloat())
451 		{
452 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
453 		}
454 
455 		errno = 0;
456 		unsigned int ui = (unsigned int)strtoul(c_str(), (char **)0, 10);
457 
458 		if (errno == ERANGE)
459 		{
460 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
461 		}
462 
463 		return ui;
464 	}
465 
466 
toLong() const467 	long String::toLong() const
468 	{
469 		if (!isFloat())
470 		{
471 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
472 		}
473 
474 		errno = 0;
475 		long l = atol(c_str());
476 
477 		if (errno == ERANGE)
478 		{
479 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
480 		}
481 
482 		return l;
483 	}
484 
485 
toUnsignedLong() const486 	unsigned long String::toUnsignedLong() const
487 	{
488 		if (!isFloat())
489 		{
490 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
491 		}
492 
493 		errno = 0;
494 		unsigned long ul = strtoul(c_str(), (char **)0, 10);
495 
496 		if (errno == ERANGE)
497 		{
498 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
499 		}
500 
501 		return ul;
502 	}
503 
504 
toFloat() const505 	float String::toFloat() const
506 	{
507 		if (!isFloat())
508 		{
509 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
510 		}
511 
512 		errno = 0;
513 		float f = (float)atof(c_str());
514 
515 		if (errno == ERANGE)
516 		{
517 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
518 		}
519 
520 		return f;
521 	}
522 
523 
toDouble() const524 	double String::toDouble() const
525 	{
526 		if (!isFloat())
527 		{
528 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
529 		}
530 		errno = 0;
531 		double d = atof(c_str());
532 
533 		if (errno == ERANGE)
534 		{
535 			throw Exception::InvalidFormat(__FILE__, __LINE__, string(c_str()));
536 		}
537 
538 		return d;
539 	}
540 
toLower(Index from,Size len)541 	void String::toLower(Index from, Size len)
542 	{
543 		validateRange_(from, len);
544 
545 		std::transform(begin()+from, begin()+from+len, begin()+from, ::tolower);
546 	}
547 
toUpper(Index from,Size len)548 	void String::toUpper(Index from, Size len)
549 	{
550 		validateRange_(from, len);
551 
552 		std::transform(begin()+from, begin()+from+len, begin()+from, ::toupper);
553 	}
554 
countFields(const char * delimiters) const555 	Size String::countFields(const char* delimiters) const
556 	{
557 		if (delimiters == 0)
558 		{
559 			throw Exception::NullPointer(__FILE__, __LINE__);
560 		}
561 
562 		Size number_of_fields = 0;
563 
564 		const char* end_char = &c_str()[size()];
565 		const char* current_delimiter = 0;
566 		const char* current_char = c_str();
567 
568 		while (current_char < end_char)
569 		{
570 			for (; current_char < end_char; ++current_char)
571 			{
572 				current_delimiter = (char*)strchr(delimiters, *current_char);
573 
574 				if (current_delimiter == 0)
575 				{
576 					break;
577 				}
578 			}
579 
580 			if (current_char < end_char)
581 			{
582 				++number_of_fields;
583 				++current_char;
584 			}
585 
586 			for (; current_char < end_char; ++current_char)
587 			{
588 				current_delimiter = (char*)strchr(delimiters, *current_char);
589 
590 				if (current_delimiter != 0)
591 				{
592 					break;
593 				}
594 			}
595 		}
596 
597 		return number_of_fields;
598 	}
599 
countFieldsQuoted(const char * delimiters,const char * quotes) const600 	Size String::countFieldsQuoted(const char* delimiters, const char* quotes) const
601 	{
602 		if ((delimiters == 0) || (quotes == 0))
603 		{
604 			throw Exception::NullPointer(__FILE__, __LINE__);
605 		}
606 
607 		Size number_of_fields = 0;
608 
609 		const char* end_char = &c_str()[size()];
610 		const char* current_delimiter = 0;
611 		const char* current_char = c_str();
612 		const char* current_quote = 0;
613 		const char* last_quote = 0;
614 
615 		while (current_char < end_char)
616 		{
617 			for (; current_char < end_char; ++current_char)
618 			{
619 				current_quote = (char*)strchr(quotes, *current_char);
620 
621 				if (current_quote != 0)
622 				{
623 					if (last_quote == 0)
624 					{
625 						last_quote = current_char;
626 					}
627 					else
628 					{
629 						// if the same quote character is used again,
630 						// it is a closing quote
631 						if (*last_quote == *current_quote)
632 						{
633 							last_quote = 0;
634 						}
635 					}
636 				}
637 
638 				if ((last_quote == 0) && (current_quote != current_char))
639 				{
640 					current_delimiter = (char*)strchr(delimiters, *current_char);
641 
642 					if (current_delimiter == 0)
643 					{
644 						break;
645 					}
646 				}
647 			}
648 
649 			if (current_char < end_char)
650 			{
651 				++number_of_fields;
652 				++current_char;
653 			}
654 
655 			for (; current_char < end_char; ++current_char)
656 			{
657 				current_quote = (char*)strchr(quotes, *current_char);
658 
659 				if (current_quote != 0)
660 				{
661 					if (last_quote == 0)
662 					{
663 						last_quote = current_char;
664 					}
665 					else
666 					{
667 						// if the same quote character is used again,
668 						// it is a closing quote
669 						if (*last_quote == *current_quote)
670 						{
671 							last_quote = 0;
672 						}
673 					}
674 				}
675 
676 				if (last_quote == 0)
677 				{
678 					current_delimiter = (char*)strchr(delimiters, *current_char);
679 
680 					if (current_delimiter != 0)
681 					{
682 						break;
683 					}
684 				}
685 			}
686 		}
687 
688 		return number_of_fields;
689 	}
690 
getField(Index index,const char * delimiters,Index * from_and_next_field) const691 	String String::getField(Index index, const char* delimiters, Index* from_and_next_field) const
692 	{
693 		if ((from_and_next_field != 0) && (*from_and_next_field < 0))
694 		{
695 			throw Exception::IndexUnderflow(__FILE__, __LINE__, *from_and_next_field, 0);
696 		}
697 
698 		if (delimiters == 0)
699 		{
700 			throw Exception::NullPointer(__FILE__, __LINE__);
701 		}
702 
703 		// allow also negative indices (last field == -1)
704 		if (index < 0)
705 		{
706 			index = (Index)countFields(delimiters) + index;
707 			if (index < 0)
708 			{
709 				throw Exception::IndexUnderflow(__FILE__, __LINE__, index);
710 			}
711 		}
712 
713 		const char *end = &c_str()[size()];
714 		Index current_index = 0;
715 		const char *current_delimiter = 0;
716 		const char *current_char = &c_str()[from_and_next_field == 0 ? 0 : *from_and_next_field];
717 		const char *field_begin = 0;
718 
719 		while (current_char < end)
720 		{
721 			for (; current_char < end; ++current_char)
722 			{
723 				current_delimiter = (char*)strchr(delimiters, *current_char);
724 
725 				if (current_delimiter == 0)
726 				{
727 					break;
728 				}
729 			}
730 
731 			if (current_index == index)
732 			{
733 				field_begin = current_char;
734 
735 				for (++current_char; current_char < end; ++current_char)
736 				{
737 					current_delimiter = (char*)strchr(delimiters, *current_char);
738 
739 						if (current_delimiter != 0)
740 						{
741 							break;
742 						}
743 				}
744 
745 				if (from_and_next_field != 0)
746 				{
747 					if (current_char >= end)
748 					{
749 						*from_and_next_field = (Index)EndPos;
750 					}
751 					else
752 					{
753 						*from_and_next_field = (Index)(current_char - c_str());
754 					}
755 				}
756 
757 				if (field_begin < end)
758 				{
759 					return String(field_begin, 0, (Size)(current_char - field_begin));
760 				}
761 			}
762 
763 			++current_index;
764 
765 			for (; current_char < end; ++current_char)
766 			{
767 				current_delimiter = (char*)strchr(delimiters, *current_char);
768 
769 				if (current_delimiter != 0)
770 				{
771 					break;
772 				}
773 			}
774 		}
775 
776 		if (from_and_next_field != 0)
777 		{
778 			*from_and_next_field = (Index)EndPos;
779 		}
780 
781 		return String();
782 	}
783 
eatDelimiters_(const char * start,const char * end,const char * delimiters)784 	const char* eatDelimiters_(const char* start, const char* end, const char* delimiters)
785 	{
786 		const char* current_delimiter = (char*)strchr(delimiters, *start);
787 		while ((current_delimiter != 0) && (start < end))
788 		{
789 			start++;
790 			current_delimiter = (char*)strchr(delimiters, *start);
791 		}
792 
793 		return start;
794 	}
795 
getFieldQuoted(Index index,const char * delimiters,const char * quotes,Index * from_and_next_field) const796 	String String::getFieldQuoted(Index index, const char* delimiters,
797 																const char* quotes, Index* from_and_next_field) const
798 	{
799 		if ((from_and_next_field != 0) && (*from_and_next_field < 0))
800 		{
801 			throw Exception::IndexUnderflow(__FILE__, __LINE__, *from_and_next_field, 0);
802 		}
803 
804 		if ((delimiters == 0) || (quotes == 0))
805 		{
806 			throw Exception::NullPointer(__FILE__, __LINE__);
807 		}
808 
809 		// allow also negative indices (last field == -1)
810 		if (index < 0)
811 		{
812 			index = (Index)countFieldsQuoted(delimiters) + index;
813 			if (index < 0)
814 			{
815 				throw Exception::IndexUnderflow(__FILE__, __LINE__, index);
816 			}
817 		}
818 
819 		String field;
820 		const char* end = &c_str()[size()];
821 		Index current_index = -1;
822 		const char* current_delimiter = 0;
823 		const char* current_quote = 0;
824 		const char* last_quote = 0;
825 		const char* current_char = &c_str()[from_and_next_field == 0 ? 0 : *from_and_next_field];
826 
827 		do
828 		{
829 			current_char = eatDelimiters_(current_char, end, delimiters);
830 			current_index++;
831 
832 			// we are at the start of a new field
833 			while (current_char < end)
834 			{
835 				current_quote = (char*)strchr(quotes, *current_char);
836 				if (current_quote != 0)
837 				{
838 					if (last_quote != 0)
839 					{
840 						// reached the terminating quote
841 						if (*last_quote == *current_quote)
842 						{
843 							last_quote = 0;
844 						}
845 						else
846 						{
847 							// just another quote character which doesn't matter
848 							if (index == current_index)
849 							{
850 								field += *current_char;
851 							}
852 						}
853 					}
854 					else
855 					{
856 						// this is a new quote
857 						last_quote = current_quote;
858 					}
859 				}
860 				else
861 				{
862 					if (last_quote == 0)
863 					{
864 						current_delimiter = (char*)strchr(delimiters, *current_char);
865 						if (current_delimiter != 0)
866 						{
867 							// we found a delimiter
868 							// continue with the outer loop -> eat these delimiters!
869 							break;
870 						}
871 					}
872 					if (current_index == index)
873 					{
874 						field += *current_char;
875 					}
876 				}
877 
878 				current_char++;
879 			}
880 
881 			if (current_index == index)
882 			{
883 				break;
884 			}
885 		}
886 		while ((current_char < end) && (current_index < index));
887 
888 		if (from_and_next_field != 0)
889 		{
890 			*from_and_next_field = (Index)(current_char - &(c_str()[0]));
891 			if (current_char >= end)
892 			{
893 				*from_and_next_field = (Index)EndPos;
894 			}
895 		}
896 
897 		return field;
898 	}
899 
split(String string_array[],Size array_size,const char * delimiters,Index from) const900 	Size String::split(String string_array[], Size array_size, const char* delimiters, Index from) const
901 	{
902 		Size	array_index = 0;
903 
904 		if (array_size < 1)
905 		{
906 			return 0;
907 		}
908 
909 		while(from != (Index)EndPos)
910 		{
911 			string_array[array_index] = getField(0, delimiters, &from);
912 
913 			if (string_array[array_index] != "")
914 			{
915 				array_index++;
916 			}
917 
918 			if (array_index == array_size)
919 			{
920 				return array_index;
921 			}
922 		}
923 
924 		return array_index;
925 	}
926 
split(vector<String> & strings,const char * delimiters,Index from) const927 	Size String::split(vector<String>& strings, const char* delimiters, Index from) const
928 	{
929 		// clear the vector anyway
930 		strings.clear();
931 
932 		while(from != (Index)EndPos)
933 		{
934 			String field = getField(0, delimiters, &from);
935 
936 			if (field != "")
937 			{
938 				strings.push_back(field);
939 			}
940 		}
941 
942 		return (Size)strings.size();
943 	}
944 
splitQuoted(vector<String> & strings,const char * delimiters,const char * quotes,Index from) const945 	Size String::splitQuoted(vector<String>& strings, const char* delimiters, const char* quotes, Index from) const
946 	{
947 		// clear the vector anyway
948 		strings.clear();
949 
950 		while (from != (Index)EndPos)
951 		{
952 			String field = getFieldQuoted(0, delimiters, quotes, &from);
953 
954 			if (field != "")
955 			{
956 				strings.push_back(field);
957 			}
958 		}
959 
960 		return (Size)strings.size();
961 	}
962 
trimLeft(const char * trimmed_chars)963 	String& String::trimLeft(const char* trimmed_chars)
964 	{
965 		if ((trimmed_chars == 0) || (size() == 0))
966 		{
967 			return *this;
968 		}
969 
970 		string::size_type index = find_first_not_of(trimmed_chars);
971 
972 		if (index != string::npos)
973 		{
974 			// erase the whitespace characters on the left
975 			erase(0, index);
976 		}
977 		else
978 		{
979 			// if nothing was found, the string might contain only whitespaces!
980 			String trimmed(trimmed_chars);
981 			if (trimmed.has((*this)[0]))
982 			{
983 				assign("");
984 			}
985 		}
986 
987 		return *this;
988 	}
989 
trimRight(const char * trimmed_chars)990 	String& String::trimRight(const char* trimmed_chars)
991 	{
992 		if (trimmed_chars == 0 ||
993 				size() == 0)
994 		{
995 			return *this;
996 		}
997 
998 		string::size_type index = find_last_not_of(trimmed_chars);
999 
1000 		if (index != string::npos)
1001 		{
1002 			// delete the whitespace characters on the right hand side
1003 			erase(index + 1);
1004 		}
1005 		else
1006 		{
1007 			// if nothing was found, the string might contain only whitespaces!
1008 			String trimmed(trimmed_chars);
1009 			if (trimmed.has((*this)[size() - 1]))
1010 			{
1011 				assign("");
1012 			}
1013 		}
1014 
1015 		return *this;
1016 	}
1017 
operator +(const char * char_ptr,const String & s)1018 	String operator + (const char* char_ptr, const String& s)
1019 	{
1020 		String result(char_ptr);
1021 		result.append(s);
1022 		return result;
1023 	}
1024 
operator +(char c,const String & s)1025 	String operator + (char c, const String& s)
1026 	{
1027 		String result(c);
1028 		result.append(s);
1029 		return result;
1030 	}
1031 
hasPrefix(const String & s) const1032 	bool String::hasPrefix(const String& s) const
1033 	{
1034 		if (s.size() > size())
1035 		{
1036 			return false;
1037 		}
1038 		if (s.size() == 0)
1039 		{
1040 			return true;
1041 		}
1042 
1043 		return (memcmp(c_str(), s.c_str(), s.size()) == 0);
1044 	}
1045 
hasSuffix(const String & s) const1046 	bool String::hasSuffix(const String& s) const
1047 	{
1048 		if (s.size() > size())
1049 		{
1050 			return false;
1051 		}
1052 		if (s.size() == 0)
1053 		{
1054 			return true;
1055 		}
1056 
1057 		int result = memcmp(c_str() + size() - s.size(), s.c_str(), s.size());
1058 
1059 		return (result == 0);
1060 	}
1061 
1062 
1063 	#define BALL_STRING_DEFINE_IS_CLASS_METHOD(func, isclass) \
1064 	bool func() const\
1065 	{ \
1066 		const char* end = &c_str()[size()]; \
1067 	 \
1068 		for (const char* ptr = c_str(); ptr < end; ptr++) \
1069 			if (!isclass(*ptr)) \
1070 				return false; \
1071 	 \
1072 		return true; \
1073 	}
1074 
BALL_STRING_DEFINE_IS_CLASS_METHOD(String::isAlpha,isAlpha)1075 	BALL_STRING_DEFINE_IS_CLASS_METHOD(String::isAlpha,  isAlpha)
1076 	BALL_STRING_DEFINE_IS_CLASS_METHOD(String::isAlnum,  isAlnum)
1077 	BALL_STRING_DEFINE_IS_CLASS_METHOD(String::isDigit,  isDigit)
1078 	BALL_STRING_DEFINE_IS_CLASS_METHOD(String::isWhitespace,  isWhitespace)
1079 	BALL_STRING_DEFINE_IS_CLASS_METHOD(String::isSpace,  isSpace)
1080 
1081 	#undef BALL_STRING_DEFINE_IS_CLASS_METHOD
1082 
1083 	String& String::reverse(Index from, Size len)
1084 	{
1085 		validateRange_(from, len);
1086 
1087 		std::reverse(begin()+from, begin()+from+len);
1088 		return *this;
1089 	}
1090 
compare(const String & s,Index from,Size len) const1091 	int String::compare(const String& s, Index from, Size len) const
1092 	{
1093 		validateRange_(from, len);
1094 
1095 		if ((this == &s) && (from == 0))
1096 		{
1097 			return 0;
1098 		}
1099 
1100 		Size newlen = std::min((Size)s.size(), len);
1101 
1102 		int result = 0;
1103 		if (compare_mode_ == CASE_INSENSITIVE)
1104 		{
1105 			const char* s1 = c_str() + from;
1106 			const char* s2 = s.c_str();
1107 
1108 			for (; newlen > 0; s1++, s2++, newlen--)
1109 			{
1110 				result = tolower(*s1) - tolower(*s2);
1111 
1112 				if (result != 0)
1113 				{
1114 					break;
1115 				}
1116 			}
1117 		}
1118 		else
1119 		{
1120 			result = strncmp(c_str() + from, s.c_str(), newlen);
1121 		}
1122 
1123 		if ((result == 0) && (len != newlen))
1124 		{
1125 			result = (int)len - (int)s.size();
1126 		}
1127 
1128 		return result;
1129 	}
1130 
compare(const String & s,Index from) const1131 	int String::compare(const String& s, Index from) const
1132 	{
1133 		validateIndex_(from);
1134 
1135 		if ((this == &s) && (from == 0))
1136 		{
1137 			return 0;
1138 		}
1139 
1140 		Size len = (Size)(size() - from);
1141 		Size newlen = std::min((Size)s.size(), len);
1142 
1143 		int result = 0;
1144 		if (compare_mode_ == CASE_INSENSITIVE)
1145 		{
1146 			const char* s1 = c_str() + from;
1147 			const char* s2 = s.c_str();
1148 
1149 			for (; newlen > 0; s1++, s2++, newlen--)
1150 			{
1151 				result = tolower(*s1) - tolower(*s2);
1152 
1153 				if (result != 0)
1154 				{
1155 					break;
1156 				}
1157 			}
1158 
1159 		}
1160 		else
1161 		{
1162 			result = strncmp(c_str() + from, s.c_str(), newlen);
1163 		}
1164 
1165 		if (result == 0)
1166 		{
1167 			result = (int)len - (int)s.size();
1168 		}
1169 
1170 		return result;
1171 	}
1172 
compare(const char * char_ptr,Index from,Size len) const1173 	int String::compare(const char* char_ptr, Index from, Size len) const
1174 	{
1175 		if (char_ptr == 0)
1176 		{
1177 			throw Exception::NullPointer(__FILE__, __LINE__);
1178 		}
1179 
1180 		validateRange_(from, len);
1181 
1182 		if ((c_str() + from) == char_ptr)
1183 		{
1184 			return 0;
1185 		}
1186 
1187 		Size newlen = (Size)strlen(char_ptr);
1188 
1189 		newlen = std::min(len, newlen);
1190 
1191 		int result = 0;
1192 		if (compare_mode_ == CASE_INSENSITIVE)
1193 		{
1194 			const char* ptr1 = c_str() + from;
1195 			const char* ptr2 = char_ptr;
1196 
1197 			for (; newlen > 0; ptr1++, ptr2++)
1198 			{
1199 				newlen--;
1200 				result = tolower(*ptr1) - tolower(*ptr2);
1201 
1202 				if (result != 0)
1203 				{
1204 					break;
1205 				}
1206 			}
1207 
1208 		}
1209 		else
1210 		{
1211 			result = strncmp(c_str() + from, char_ptr, newlen);
1212 		}
1213 
1214 		if ((result == 0) && (len != newlen))
1215 		{
1216 			result = (int)size() - (int)from - (int)strlen(char_ptr);
1217 		}
1218 
1219 		return result;
1220 	}
1221 
compare(const char * char_ptr,Index from) const1222 	int String::compare(const char* char_ptr, Index from) const
1223 	{
1224 		if (char_ptr == 0)
1225 		{
1226 			throw Exception::NullPointer(__FILE__, __LINE__);
1227 		}
1228 
1229 		// indices may be given as negative arguments: start from the end
1230 		// -1 therefore means the last bit.
1231 		Size string_size = (Size)size();
1232 		if (from < 0)
1233 		{
1234 			from = (Index)string_size + from;
1235 
1236 			// if the value is out of bounds - throw an exception
1237 			// and leave it...
1238 			if (from < 0)
1239 			{
1240 				throw Exception::IndexUnderflow(__FILE__, __LINE__, from, string_size);
1241 			}
1242 		}
1243 
1244 		if ((Size)from > string_size)
1245 		{
1246 			throw Exception::IndexOverflow(__FILE__, __LINE__, from, string_size);
1247 		}
1248 
1249 		Size len = string_size - from;
1250 
1251 		if ((c_str() + from) == char_ptr)
1252 		{
1253 			return 0;
1254 		}
1255 
1256 		Size newlen = std::min((Size)strlen(char_ptr), len);
1257 
1258 		newlen = len;
1259 
1260 		int result = 0;
1261 
1262 		if (compare_mode_ == CASE_INSENSITIVE)
1263 		{
1264 			const char* ptr1 = c_str() + from;
1265 			const char* ptr2 = char_ptr;
1266 
1267 			for (; newlen > 0; ptr1++, ptr2++)
1268 			{
1269 				newlen--;
1270 				result = tolower(*ptr1) - tolower(*ptr2);
1271 
1272 				if (result != 0)
1273 				{
1274 					break;
1275 				}
1276 			}
1277 
1278 		}
1279 		else
1280 		{
1281 			result = strncmp(c_str() + from, char_ptr, newlen);
1282 		}
1283 
1284 		if ((result == 0) && (len == newlen))
1285 		{
1286 			return (int)string_size - (int)from - (int)strlen(char_ptr);
1287 		}
1288 
1289 		return result;
1290 	}
1291 
getline(istream & s,String & str,char delimiter)1292 	istream& getline(istream& s, String& str, char delimiter)
1293 	{
1294 		char c;
1295 
1296 		str.destroy();
1297 
1298 		while (s.get(c))
1299 		{
1300 			if (c == delimiter)
1301 			{
1302 				break;
1303 			}
1304 			str.append(1, c);
1305 		}
1306 
1307 		return s;
1308 	}
1309 
dump(ostream & s,Size depth) const1310 	void String::dump(ostream &s, Size depth) const
1311 	{
1312 		BALL_DUMP_STREAM_PREFIX(s);
1313 
1314 		BALL_DUMP_DEPTH(s, depth);
1315 		s << "  capacity: " << capacity() << endl;
1316 
1317 		BALL_DUMP_DEPTH(s, depth);
1318 		s << "  size: " << size() << endl;
1319 
1320 		BALL_DUMP_DEPTH(s, depth);
1321 		s << "  string: ";
1322 
1323 		const char* end_ptr = &c_str()[size()];
1324 
1325 		for (const char *char_ptr = c_str(); char_ptr < end_ptr; char_ptr++)
1326 			s << *char_ptr;
1327 
1328 		s << endl;
1329 
1330 		BALL_DUMP_STREAM_SUFFIX(s);
1331 	}
1332 
substitute(const String & to_replace,const String & replacing)1333 	Size String::substitute(const String& to_replace, const String& replacing)
1334 	{
1335 		Size replaced_size = (Size)to_replace.size();
1336 
1337 		string::size_type found = 0;
1338 		if (to_replace != "")
1339 		{
1340 			found = find(to_replace);
1341 		}
1342 
1343 		if (found != string::npos)
1344 		{
1345 			replace(found, replaced_size, replacing);
1346 		}
1347 
1348 		return ((found == string::npos) ? EndPos : (Size)found);
1349 	}
1350 
1351 
validateIndex_(Index & index) const1352 	void String::validateIndex_(Index& index) const
1353 	{
1354 		// indices may be given as negative arguments: start from the end
1355 		// -1 therefore means the last bit.
1356 		Size string_size = (Size)size();
1357 		if (index < 0)
1358 		{
1359 			index = (Index)string_size + index;
1360 
1361 			// if the value is out of bounds - throw an exception
1362 			// and leave it...
1363 			if (index < 0)
1364 			{
1365 				throw Exception::IndexUnderflow(__FILE__, __LINE__, index, string_size);
1366 			}
1367 		}
1368 
1369 		if ((Size)index > string_size)
1370 		{
1371 			throw Exception::IndexOverflow(__FILE__, __LINE__, index, string_size);
1372 		}
1373 	}
1374 
validateRange_(Index & from,Size & len) const1375 	void String::validateRange_(Index& from, Size& len) const
1376 	{
1377 		Size string_size = (Size)size();
1378 
1379     // indices may be given as negative arguments: start from the end
1380     // -1 therefore means the last character of the string.
1381     if (from < 0)
1382 		{
1383       from = (Index)string_size + from;
1384 
1385 			// if the values are out of bounds - throw an exception
1386 			// and leave it...
1387 			if (from < 0)
1388 			{
1389 				throw Exception::IndexUnderflow(__FILE__, __LINE__, from, string_size);
1390 			}
1391 		}
1392 
1393     if (((Size)from > string_size) || ((string_size > 0) && ((Size)from == string_size) && (len != 0)))
1394 		{
1395       throw Exception::IndexOverflow(__FILE__, __LINE__, from, string_size);
1396 		}
1397 
1398 		if (len == EndPos)
1399 		{
1400 			len = string_size - from;
1401 		}
1402 
1403 		if (len > (string_size - from))
1404 		{
1405 			throw Exception::IndexOverflow(__FILE__, __LINE__, (Index)len, string_size);
1406 		}
1407  	}
1408 
validateRange_(Index & from,Size & len) const1409 	void Substring::validateRange_(Index& from, Size& len) const
1410 	{
1411 		Size size = to_ - from_ + 1;
1412 
1413     // indices may be given as negative arguments: start from the end
1414     // -1 therefore means the to bit.
1415     if (from < 0)
1416 		{
1417       from = (Index)size + from;
1418 
1419 			// if the values are out of bounds - throw an exception
1420 			// and leave it...
1421 			if (from < 0)
1422 			{
1423 				throw Exception::IndexUnderflow(__FILE__, __LINE__, from, size);
1424 			}
1425 		}
1426 
1427     if (((Size)from > size) || ((size > 0) && ((Size)from == size)))
1428 		{
1429       throw Exception::IndexOverflow(__FILE__, __LINE__, from, size);
1430 		}
1431 
1432 		if (len == String::EndPos)
1433 		{
1434 			len = size - from;
1435 		}
1436 
1437 		if (len > (size - from))
1438 		{
1439 			throw Exception::IndexOverflow(__FILE__, __LINE__, (Index)len, size);
1440 		}
1441  	}
1442 
validateCharPtrRange_(Index & from,Size & len,const char * char_ptr)1443 	void String::validateCharPtrRange_(Index& from, Size& len, const char* char_ptr)
1444 	{
1445 		if (char_ptr == 0)
1446 		{
1447 			throw Exception::NullPointer(__FILE__, __LINE__);
1448 		}
1449 
1450 		Size total_len = (Size)strlen(char_ptr);
1451 
1452     // indices may be given as negative arguments: start from the end
1453     // -1 therefore means the to bit.
1454     if (from < 0)
1455 		{
1456       from = (Index)total_len + from;
1457 
1458 			// if the values are out of bounds - throw an exception
1459 			// and leave it...
1460 			if (from < 0)
1461 			{
1462 				throw Exception::IndexUnderflow(__FILE__, __LINE__, from, len);
1463 			}
1464 		}
1465 
1466     if (((Size)from > total_len) || ((total_len > 0) && ((Size)from == total_len)))
1467 		{
1468       throw Exception::IndexOverflow(__FILE__, __LINE__, from, len);
1469 		}
1470 
1471 		if (len == EndPos)
1472 		{
1473 			len = total_len - from;
1474 		}
1475 
1476 		if (len > (total_len - from))
1477 		{
1478 			throw Exception::IndexOverflow(__FILE__, __LINE__, (Index)len, total_len);
1479 		}
1480  	}
1481 
operator ==(const char * char_ptr) const1482 	bool Substring::operator == (const char* char_ptr) const
1483 	{
1484 		if (bound_ == 0)
1485 		{
1486 			throw UnboundSubstring(__FILE__, __LINE__);
1487 		}
1488 
1489 		if (char_ptr == 0)
1490 		{
1491 			throw Exception::NullPointer(__FILE__, __LINE__);
1492 		}
1493 
1494 		// to prevent compiler warning:
1495 		if ((signed)strlen(char_ptr) != (to_ - from_ +1))
1496 		{
1497 			return false;
1498 		}
1499 		return (bound_->compare(char_ptr, from_, to_ - from_ + 1) == 0);
1500 	}
1501 
1502 
operator !=(const char * char_ptr) const1503 	bool Substring::operator != (const char* char_ptr) const
1504 	{
1505 		if (bound_ == 0)
1506 		{
1507 			throw UnboundSubstring(__FILE__, __LINE__);
1508 		}
1509 		if (char_ptr == 0)
1510 		{
1511 			throw Exception::NullPointer(__FILE__, __LINE__);
1512 		}
1513 		// to prevent compiler warning:
1514 		if ((signed)strlen(char_ptr) != (to_ - from_ +1))
1515 		{
1516 			return true;
1517 		}
1518 		return (bound_->compare(char_ptr, from_, to_ - from_ + 1) != 0);
1519 	}
1520 
1521 
bind(const Substring & s,Index from,Size len)1522 	Substring& Substring::bind(const Substring& s, Index from, Size len)
1523 	{
1524 		s.validateRange_(from, len);
1525 
1526 		bound_ = s.bound_;
1527 		from 	+= s.from_;
1528 		to_ 	 = s.from_ + (Index)len - 1;
1529 		from_  = from;
1530 
1531 		return *this;
1532 	}
1533 
1534 
set(const char * char_ptr,Size size)1535 	void Substring::set(const char* char_ptr, Size size)
1536 	{
1537 		if (bound_ == 0)
1538 		{
1539 			throw UnboundSubstring(__FILE__, __LINE__);
1540 		}
1541 		if (char_ptr == 0)
1542 		{
1543 			throw Exception::NullPointer(__FILE__, __LINE__);
1544 		}
1545 		if (size == 0)
1546 		{
1547 			throw Exception::SizeUnderflow(__FILE__, __LINE__);
1548 		}
1549 
1550 		if (size == String::EndPos)
1551 		{
1552 			bound_->replace(from_, to_ - from_ + 1, string(char_ptr));
1553 		}
1554 		else
1555 		{
1556 			bound_->replace(from_, to_ - from_ + 1, char_ptr, size);
1557 		}
1558 	}
1559 
1560 
operator ==(const Substring & s) const1561 	bool Substring::operator == (const Substring& s) const
1562 	{
1563 		if (bound_ == 0 || s.bound_ == 0)
1564 		{
1565 			throw UnboundSubstring(__FILE__, __LINE__);
1566 		}
1567 		if ((s.to_ - s.from_) != (to_ - from_))
1568 		{
1569 			return false;
1570 		}
1571 		return (bound_->compare(s.c_str() + from_, from_, to_ - from_ + 1) == 0);
1572 	}
1573 
1574 
operator !=(const Substring & s) const1575 	bool Substring::operator != (const Substring& s) const
1576 	{
1577 		if (bound_ == 0 || s.bound_ == 0)
1578 		{
1579 			throw UnboundSubstring(__FILE__, __LINE__);
1580 		}
1581 		if ((s.to_ - s.from_) != (to_ - from_))
1582 		{
1583 			return true;
1584 		}
1585 		return (bound_->compare(s.c_str() + from_, from_, to_ - from_ + 1) != 0);
1586 	}
1587 
1588 
before(const String & s,Index from) const1589 	Substring String::before(const String& s, Index from) const
1590 	{
1591 		Position found = EndPos;
1592 		if (s != "")
1593 		{
1594 			found = (Position)find(s, from);
1595 		}
1596 
1597 		if (found == 0 || found == EndPos)
1598 		{
1599 			return Substring(*this, 0, 0);
1600 		}
1601 
1602 		return getSubstring(0, found);
1603 	}
1604 
1605 
through(const String & s,Index from) const1606 	Substring String::through (const String& s, Index from) const
1607 	{
1608 		Position found = EndPos;
1609 		if (s != "")
1610 		{
1611 			found = (Position)find(s, from);
1612 		}
1613 
1614 		if (found == EndPos)
1615 		{
1616 			return Substring(*this, 0, 0);
1617 		}
1618 
1619 		return getSubstring(0, found + (Size)s.size());
1620 	}
1621 
1622 
from(const String & s,Index from) const1623 	Substring String::from(const String& s, Index from) const
1624 	{
1625 		if (s == "")
1626 		{
1627 			return getSubstring(0);
1628 		}
1629 
1630 		Size found = (Size)find(s, from);
1631 
1632 		if (found == EndPos)
1633 		{
1634 			return Substring(*this, -1, 0);
1635 		}
1636 
1637 		return getSubstring((Index)found);
1638 	}
1639 
1640 
after(const String & s,Index from) const1641 	Substring String::after(const String& s, Index from) const
1642 
1643 	{
1644 		if (s == "")
1645 		{
1646 			return getSubstring(0);
1647 		}
1648 
1649 		Position found = (Position)find(s, from);
1650 
1651 		if ((found == EndPos) || (found + s.size() >= size()))
1652 		{
1653 			return Substring(*this, -1, 0);
1654 		}
1655 
1656 		return getSubstring((Index)found + (Index)s.size());
1657 	}
1658 
1659 
right(Size len) const1660 	Substring String::right(Size len) const
1661 	{
1662 		// to save calls to size()
1663 		Size s = (Size)size();
1664 		if (len > s)
1665 		{
1666 			len = s;
1667 		}
1668 
1669 		Index from = (Index)s - (Index)len;
1670 
1671 		if (len > 0)
1672 		{
1673 			from = (Index)s - (Index)len;
1674 		}
1675 		else
1676 		{
1677 			if (s > 0)
1678 			{
1679 				from = (Index)s - 1;
1680 			}
1681 			else
1682 			{
1683 				from = 0;
1684 			}
1685 		}
1686 
1687 		return Substring(*this, from, len);
1688 	}
1689 
1690 
1691 // ================================================== Base64 methods
1692 
1693 char String::B64Chars_[64] = {
1694   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
1695   'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
1696   'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
1697   't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
1698   '8', '9', '+', '/'
1699 };
1700 
1701 int String::Index_64_[128] = {
1702 			-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
1703 			-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
1704 			-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
1705 			52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
1706 			-1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
1707 			15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
1708 			-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
1709 			41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
1710 };
1711 
1712 #define base64val_(c) Index_64_[(unsigned int)(c)]
1713 
encodeBase64()1714 String String::encodeBase64()
1715 {
1716 	Size in_length((Size)this->size());
1717 	const char* in = this->c_str();
1718 	String out;
1719 
1720   while (in_length >= 3)
1721   {
1722     out += B64Chars_[in[0] >> 2];
1723     out += B64Chars_[((in[0] << 4) & 0x30) | (in[1] >> 4)];
1724     out += B64Chars_[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
1725     out += B64Chars_[in[2] & 0x3f];
1726     in_length   -= 3;
1727     in    			+= 3;
1728   }
1729 
1730   if (in_length > 0)
1731   {
1732     unsigned char fragment;
1733 
1734     out += B64Chars_[in[0] >> 2];
1735     fragment = (in[0] << 4) & 0x30;
1736     if (in_length > 1)
1737 		{
1738       fragment |= in[1] >> 4;
1739 		}
1740 		out += B64Chars_[fragment];
1741     out += (in_length < 2) ? '=' : B64Chars_[(in[1] << 2) & 0x3c];
1742     out += '=';
1743   }
1744 
1745 	return out;
1746 }
1747 
decodeBase64()1748 String String::decodeBase64()
1749 {
1750 	const char* in = this->c_str();
1751 	String out;
1752 
1753 	unsigned char digit4;
1754   do
1755   {
1756     unsigned char digit1 = in[0];
1757     if (digit1 > 127 || base64val_ (digit1) == -1) //-1 == BAD
1758 		{
1759 			return String::EMPTY;
1760 		}
1761 
1762 		unsigned char digit2 = in[1];
1763     if (digit2 > 127 || base64val_ (digit2) == -1)
1764 		{
1765 			return String::EMPTY;
1766 		}
1767 
1768 		unsigned char digit3 = in[2];
1769     if (digit3 > 127 || ((digit3 != '=') && (base64val_ (digit3) == -1)))
1770 		{
1771 			return String::EMPTY;
1772 		}
1773 
1774 		digit4 = in[3];
1775     if (digit4 > 127 || ((digit4 != '=') && (base64val_ (digit4) == -1)))
1776 		{
1777 			return String::EMPTY;
1778 		}
1779 
1780 		in += 4;
1781 
1782     // digits are already sanity-checked
1783     out += (base64val_(digit1) << 2) | (base64val_(digit2) >> 4);
1784     if (digit3 != '=')
1785     {
1786       out += ((base64val_(digit2) << 4) & 0xf0) | (base64val_(digit3) >> 2);
1787       if (digit4 != '=')
1788       {
1789 				out += ((base64val_(digit3) << 6) & 0xc0) | base64val_(digit4);
1790       }
1791     }
1792   }
1793   while (*in && digit4 != '=');
1794 
1795   return out;
1796 }
1797 
1798 #	ifdef BALL_NO_INLINE_FUNCTIONS
1799 #		include <BALL/DATATYPE/string.iC>
1800 #	endif
1801 
1802 } // namespace BALL
1803