1 /*
2  *  JLib - Jacob's Library.
3  *  Copyright (C) 2003, 2004  Juan Carlos Seijo P�rez
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Juan Carlos Seijo P�rez
20  *  jacob@mainreactor.net
21  */
22 
23 /** Text string class.
24  * @file    JString.h
25  * @author  Juan Carlos Seijo P�rez
26  * @date    19/04/2003
27  * @version 0.0.1 - 19/04/2003 - First version.
28  */
29 
30 #ifndef _JSTRING_INCLUDED
31 #define _JSTRING_INCLUDED
32 
33 #include <JLib/Util/JTypes.h>
34 #include <stdio.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <JLib/Util/JLoadSave.h>
39 
40 class JString : public JLoadSave
41 {
42   friend bool operator==(const char *s1, const JString& s2);
43   friend bool operator==(const JString& s1, const char *s2);
44   friend bool operator!=(const char *s1, const JString& s2);
45   friend bool operator!=(const JString& s1, const char *s2);
46   friend bool operator>(const char *s1, const JString& s2);
47   friend bool operator<(const char *s1, const JString& s2);
48   friend bool operator>=(const char *s1, const JString& s2);
49   friend bool operator<=(const char *s1, const JString& s2);
50   //friend const JString operator+(const char *s1, const JString &s2);
51   friend const JString operator+(const JString &s1,  const char *s2);
52 	friend const JString operator+(const JString &s1,  const JString &s2);
53 
54 protected:
55   char *data;           // Caracteres
56   u32 length;  // Longitud
57 
58 public:
59 
60   /** Creates an empty string.
61    */
62   inline JString();
63 
64   /** Creates a string that is a copy of the given string.
65    * @param  s String to be copied.
66    */
67   inline JString(const char *s);
68 
69   /** Creates a string from a substring of the given string.
70    * @param  s String.
71    * @param  start Start of the substring.
72    * @param  end Of the substring, -1 for the string length.
73    */
74   inline JString(const JString& s, u32 start, u32 end = (u32)-1);
75 
76   /** Creates a string from a substring of the given string.
77    * @param  s String.
78    * @param  start Start of the substring.
79    * @param  end Of the substring, -1 for the string length.
80    */
81   inline JString(const char *s, u32 start, u32 end = (u32)-1);
82 
83   /** Creates a string that is a copy of the given string.
84    * @param  s String to be copied.
85    */
86   inline JString(const JString& s);
87 
88   /** Destroys this string and frees the allocated resources.
89    */
90   inline virtual ~JString();
91 
92   /** Clears the string.
93    */
94   inline void Clear();
95 
96   /** Compares this string to another one.
97    * @param  s Another string.
98    * @return <b>true</b> if they are equal, <b>false</b> otherwise.
99    */
100   inline bool Equals(const JString& s) const;
101 
102   /** Compares this string to another one.
103    * @param  s Another string.
104    * @return <b>true</b> if they are equal, <b>false</b> otherwise.
105    */
106   inline bool operator==(const JString& s) const;
107 
108   /** Compares this string to another one.
109    * @param  s Another string.
110    * @return 0 i they are equal, >0 if this string is ASCII-greater than the given, <0 if its ASCII-lower.
111    */
112   inline s32 CompareTo(const JString& s) const;
113 
114   /** Compares this string to another one.
115    * @param  s Another string.
116    * @return 0 i they are equal, >0 if this string is ASCII-greater than the given, <0 if its ASCII-lower.
117    */
118   inline s32 CompareTo(const char *s) const;
119 
120   /** Test if this string is ASCII-greater than another.
121    * @param  s Another string.
122    * @return <b>true</b> if so, <b>false</b> otherwise.
123    */
124   inline bool operator>(const JString& s) const;
125 
126   /** Test if this string is ASCII-lower than another.
127    * @param  s Another string.
128    * @return <b>true</b> if so, <b>false</b> otherwise.
129    */
130   inline bool operator<(const JString& s) const;
131 
132   /** Test if this string is ASCII-greater or equal than another.
133    * @param  s Another string.
134    * @return <b>true</b> if so, <b>false</b> otherwise.
135    */
136   inline bool operator>=(const JString& s) const;
137 
138   /** Test if this string is ASCII-lower or equal than another.
139    * @param  s Another string.
140    * @return <b>true</b> if so, <b>false</b> otherwise.
141    */
142   inline bool operator<=(const JString& s) const;
143 
144   /** Compares this string to another one.
145    * @param  s Another string.
146    * @return <b>true</b> if they are different, <b>false</b> otherwise.
147    */
148   inline bool operator!=(const JString& s) const;
149 
150   /** Returns the char at the given pos.
151    * @param  pos Index of the character to be retrieved.
152    */
153   inline char& operator[](s32 pos);
154 
155   /** Assigns a copy of the given string to this one.
156    * @param  s Another string.
157    */
158   inline void operator=(const char *s);
159 
160   /** Assigns a copy of the given string to this one.
161    * @param  s Another string.
162    */
163   inline void operator=(const JString &s);
164 
165   /** Returns the internal character array.
166    * @return internal character array.
167    */
168   inline const char* Str() const;
169 
170 
171   /** Appends the given string to this one.
172    * @param  s Another string.
173    */
174   inline void Append(const JString& s);
175 
176   /** Appends the given string to this one.
177    * @param  s Another string.
178    */
179   inline void Append(const char * s);
180 
181   /** Appends the given string to this one.
182    * @param  s Another string.
183    */
184   inline void operator+=(const JString& s);
185 
186   /** Appends the given string to this one.
187    * @param  s Another string.
188    */
189   inline void operator+=(const char *s);
190 
191   /** Appends the given char to this string.
192    * @param  c Character to append.
193    */
194   inline void Append(char c);
195 
196   /** Appends the given char to this string.
197    * @param  c Character to append.
198    */
199   inline void operator+=(char c);
200 
201   /** Creates a string from a format string (as printf uses).
202    * @param  fmt Format string.
203    * @param  ... Format parameters.
204    * @return <b>true</b> if it could be formatted, <b>false</b> otherwise.
205    */
206   inline bool Format(const char *fmt, ...);
207 
208   /** Converts this string to uppercase.
209    */
210   inline void Uppercase();
211 
212   /** Converts this string to lowercase.
213    */
214   inline void Lowercase();
215 
216   /** Searchs for the given character from the given position within the string.
217    * @param  c Character to be found.
218    * @param  from Index within the string where to start the search (inclusive).
219    * @return index of the character searched or -1 if it wasn't found.
220    */
221   inline s32 Find(char c, u32 from = 0);
222 
223   /** Searchs for the last index of the given character from the given position within the string.
224    * @param  c Character to be found.
225    * @param  from Index within the string where to start the search (inclusive).
226    * @return index of the character searched or -1 if it wasn't found.
227    */
228   inline s32 FindLast(char c, u32 from = 0);
229 
230   /** Searchs for the index of the given string from the given position within this string.
231    * @param  str String to be found.
232    * @param  from Index within the string where to start the search (inclusive).
233    * @return index of the character searched or -1 if it wasn't found.
234    */
235   inline s32 Find(const char *str, u32 from = 0);
236 
237   /** Searchs for the last index of the given string from the given position within this string.
238    * @param  str String to be found.
239    * @param  from Index within the string where to start the search (inclusive).
240    * @return index of the character searched or -1 if it wasn't found.
241    */
242   inline s32 FindLast(const char *str, u32 from = 0);
243 
244   /** Replaces pat with rep from the given index, max number of times within this string.
245    * @param  pat Character to look for.
246    * @param  rep Character to replace pat with.
247    * @param  from Start index within the string where to start the search (inclusive).
248    * @param  max Maximum number of replacements to be made.
249    * @return Number of replacements doen.
250    */
251   inline s32 Replace(const char pat, const char rep, u32 from = 0, u32 max = 0);
252 
253   /** Replaces pat with rep from the given index, max number of times within this string.
254    * @param  pat String pattern to look for.
255    * @param  rep String replacement to replace pat with.
256    * @param  from Start index within the string where to start the search (inclusive).
257    * @param  max Maximum number of replacements to be made.
258    * @return Number of replacements doen.
259    */
260   inline s32 Replace(const char *pat, const char *rep, u32 from = 0, u32 max = 0);
261 
262   /** Returns a string that is a substring of this string.
263    * @param  start Substring start position.
264    * @param  end Substring end position.
265    * @return Substring.
266    */
267   inline const JString Substring(u32 start, u32 end = (u32)-1);
268 
269 
270   /** Cast to const char * type.
271    * @return const char * string.
272    */
273   inline operator const char *() const {return data;}  // Cast a cadena
274 
275 
276   /** Returns the length of this string.
277    * @return Length of this string.
278    */
Length()279   inline u32 Length() const {return length;} // Devuelve la longitud
280 
281   // Lee la cadena de un fichero (longitud + cadena)
282 
283   /** Reads a string from a JRW object (length in four bytes + characters)
284    * @param  f JRW object.
285    * @return 0 if succeeded, 1 if I/O error, 2 if data integrity error.
286    */
287   inline u32 Load(JRW &f);
288 
289   // Escribe la cadena a un fichero (longitud + cadena)
290 
291   /** Writes a string to a JRW object (length in four bytes + characters)
292    * @param  f JRW object.
293    * @return 0 if succeeded, 1 if I/O error, 2 if data integrity error.
294    */
295   inline u32 Save(JRW &f);
296 };
297 
298 /** Test the equality of two strings.
299  * @param  s1 First string.
300  * @param  s1 Second string.
301  * @return <b>true</b> if they are equal, <b>false</b> otherwise.
302  */
303 inline bool operator==(const char *s1, const JString& s2)
304 {
305   return (strcmp(s1, s2.data) == 0);
306 }
307 
308 /** Test the equality of two strings.
309  * @param  s1 First string.
310  * @param  s1 Second string.
311  * @return <b>true</b> if they are equal, <b>false</b> otherwise.
312  */
313 inline bool operator==(const JString& s1, const char *s2)
314 {
315   return (strcmp(s1.data, s2) == 0);
316 }
317 
318 /** Test if the given strings are different.
319  * @param  s1 First string.
320  * @param  s1 Second string.
321  * @return <b>true</b> if so, <b>false</b> otherwise.
322  */
323 inline bool operator!=(const char *s1, const JString& s2)
324 {
325   return (strcmp(s1, s2.data) != 0);
326 }
327 
328 /** Test if the given strings are different.
329  * @param  s1 First string.
330  * @param  s1 Second string.
331  * @return <b>true</b> if so, <b>false</b> otherwise.
332  */
333 inline bool operator!=(const JString& s1, const char *s2)
334 {
335   return (strcmp(s1.data, s2) != 0);
336 }
337 
338 /** Test if the first string is ASCII-greater than the second.
339  * @param  s1 First string.
340  * @param  s1 Second string.
341  * @return <b>true</b> if so, <b>false</b> otherwise.
342  */
343 inline bool operator>(const char *s1, const JString& s2)
344 {
345   return (strcmp(s1, s2.data) > 0);
346 }
347 
348 /** Test if the first string is ASCII-lower than the second.
349  * @param  s1 First string.
350  * @param  s1 Second string.
351  * @return <b>true</b> if so, <b>false</b> otherwise.
352  */
353 inline bool operator<(const char *s1, const JString& s2)
354 {
355   return (strcmp(s1, s2.data) < 0);
356 }
357 
358 /** Test if the first string is ASCII-greater or equal than the second.
359  * @param  s1 First string.
360  * @param  s1 Second string.
361  * @return <b>true</b> if so, <b>false</b> otherwise.
362  */
363 inline bool operator>=(const char *s1, const JString& s2)
364 {
365   return (strcmp(s1, s2.data) >= 0);
366 }
367 
368 /** Test if the first string is ASCII-lower or equal than the second.
369  * @param  s1 First string.
370  * @param  s1 Second string.
371  * @return <b>true</b> if so, <b>false</b> otherwise.
372  */
373 inline bool operator<=(const char *s1, const JString& s2)
374 {
375   return (strcmp(s1, s2.data) <= 0);
376 }
377 
378 // Constructor
JString()379 JString::JString() : length(0)
380 {
381   data = new char[1];
382   data [0] = '\0';
383 }
384 
385 // Constructor
JString(const char * s)386 JString::JString(const char *s)
387 {
388   if (s)
389   {
390     length = (u32)strlen(s);
391     data = new char[length + 1];
392     strcpy(data, s);
393   }
394   else
395   {
396     data = new char[1];
397     data [0] = '\0';
398     length = 0;
399   }
400 }
401 
402 // Constructor de subcadena
JString(const JString & s,u32 start,u32 end)403 inline JString::JString(const JString& s, u32 start, u32 end)
404 {
405   if (end == (u32)-1)
406     end = s.Length();
407 
408   if (start >= 0 && start < s.Length() && end > start && end <= s.Length())
409   {
410     length = end - start;
411     data = new char[length + 1];
412     strncpy(data, s.data + start, length);
413     data[length] = '\0';
414   }
415   else
416   {
417     data = new char[1];
418     data [0] = '\0';
419     length = 0;
420   }
421 }
422 
423 // Constructor de subcadena
JString(const char * s,u32 start,u32 end)424 inline JString::JString(const char *s, u32 start, u32 end)
425 {
426   if (s)
427   {
428     u32 len = (u32)strlen(s);
429     if (end == (u32)-1)
430       end = len;
431 
432     if (start >= 0 && start < len && end > start && end <= len)
433     {
434       length = end - start;
435       data = new char[length + 1];
436       strncpy(data, s + start, length);
437       data[length] = '\0';
438     }
439     else
440     {
441       data = new char[1];
442       data [0] = '\0';
443       length = 0;
444     }
445   }
446   else
447   {
448     data = new char[1];
449     data [0] = '\0';
450     length = 0;
451   }
452 }
453 
454 // Constructor copia
JString(const JString & s)455 JString::JString(const JString &s)
456 {
457   length = s.length;
458   data = new char[length + 1];
459   strcpy(data, s.data);
460 }
461 
462 // Destructor
~JString()463 JString::~JString()
464 {
465   delete[] data;
466 }
467 
468 // Borra la cadena
Clear()469 inline void JString::Clear()
470 {
471   delete[] data;
472   data = new char[1];
473 
474   // La cadena no tiene estado 'nulo', como mucho estar� vac�a
475   data [0] = '\0';
476   length = 0;
477 }
478 
479 // �Son iguales?
Equals(const JString & s)480 inline bool JString::Equals(const JString& s) const
481 {
482   return (strcmp(data, s.data) == 0);
483 }
484 
485 // �Son iguales?
486 inline bool JString::operator==(const JString& s) const
487 {
488   return (strcmp(data, s.data) == 0);
489 }
490 
491 // Comparaci�n de cadenas
CompareTo(const JString & s)492 inline s32 JString::CompareTo(const JString &s) const
493 {
494   return (strcmp(data, s.data));
495 }
496 
497 // Comparaci�n de cadenas
CompareTo(const char * s)498 inline s32 JString::CompareTo(const char *s) const
499 {
500   return (strcmp(data, s));
501 }
502 
503 // �Es la primera mayor?
504 inline bool JString::operator>(const JString& s) const
505 {
506   return (strcmp(data, s.data) > 0);
507 }
508 
509 // �Es la primera menor?
510 inline bool JString::operator<(const JString& s) const
511 {
512   return (strcmp(data, s.data) < 0);
513 }
514 
515 // �Es la primera mayor o igual?
516 inline bool JString::operator>=(const JString& s) const
517 {
518   return (strcmp(data, s.data) >= 0);
519 }
520 
521 // �Es la primera menor o igual?
522 inline bool JString::operator<=(const JString& s) const
523 {
524   return (strcmp(data, s.data) <= 0);
525 }
526 
527 // �Son diferentes?
528 inline bool JString::operator!=(const JString& s) const
529 {
530   return (strcmp(data, s.data) != 0);
531 }
532 
533 // Devuelve el caracter en la posici�n dada
534 inline char& JString::operator[](s32 pos)
535 {
536   return data[pos];
537 }
538 
539 // Asignaci�n
540 inline void JString::operator=(const char *s)
541 {
542   if (s)
543   {
544     u32 len;
545 
546     len = (u32)strlen(s);
547     if (len > length)
548     {
549       delete[] data;
550       data = new char[len + 1];
551     }
552 
553     length = len;
554     strcpy(data, s);
555   }
556   else
557   {
558     delete[] data;
559     data = new char[1];
560     data[0] = '\0';
561     length = 0;
562   }
563 }
564 
565 // Asignaci�n
566 inline void JString::operator=(const JString &s)
567 {
568   if (s.Length() > length)
569   {
570     delete[] data;
571     data = new char[s.length + 1];
572   }
573   length = s.length;
574   strcpy(data, s.data);
575 }
576 
577 // Devuelve el array de caracteres
Str()578 inline const char* JString::Str() const
579 {
580   return ((const char*)data);
581 }
582 
583 // Concatenaci�n de cadenas
Append(const JString & s)584 inline void JString::Append(const JString& s)
585 {
586   if (s.length)
587   {
588     u32 len;
589     len = s.length;
590 
591     char *strAux = new char[length + len + 1];
592     strAux[0] = 0;
593 
594     strcpy(strAux, data);
595     delete[] data;
596 
597     // Evita contar los caracteres en strcat(), ya que sabemos la longitud
598     strcpy(strAux + length, s.data);
599 
600     data = strAux;
601     length += len;
602   }
603 }
604 
605 // Concatenaci�n de cadenas
Append(const char * s)606 inline void JString::Append(const char *s)
607 {
608   u32 len = (u32)strlen(s);
609 
610   if (len)
611   {
612     char *strAux = new char[length + len + 1];
613     strAux[0] = 0;
614 
615     strcpy(strAux, data);
616     delete[] data;
617 
618     // Evita contar los caracteres en strcat(), ya que sabemos la longitud
619     strcpy(strAux + length, s);
620 
621     data = strAux;
622     length += len;
623   }
624 }
625 
626 // Concatenaci�n de cadenas
627 inline void JString::operator+=(const JString& s)
628 {
629   if (s.length)
630   {
631     u32 len;
632     len = s.length;
633 
634     char *strAux = new char[length + len + 1];
635     strAux[0] = 0;
636 
637     strcpy(strAux, data);
638 
639     // Evita contar los caracteres en strcat(), ya que sabemos la longitud
640     strcpy(strAux + length, s.data);
641 
642     delete[] data;
643     data = strAux;
644     length += len;
645   }
646 }
647 
648 // Concatenaci�n de cadenas
649 inline void JString::operator+=(const char *s)
650 {
651   u32 len = (u32)strlen(s);
652 
653   if (len)
654   {
655     char *strAux = new char[length + len + 1];
656     strAux[0] = 0;
657 
658     strcpy(strAux, data);
659     delete[] data;
660 
661     // Evita contar los caracteres en strcat(), ya que sabemos la longitud
662     strcpy(strAux + length, s);
663 
664     data = strAux;
665     length += len;
666   }
667 }
668 
669 // Concatena la cadena
670 inline const JString operator+(const JString &s1,  const char *s2)
671 {
672 	JString s(s1);
673 	s.Append(s2);
674 	return s;
675 }
676 
677 inline const JString operator+(const JString &s1,  const JString &s2)
678 {
679 	JString s(s1);
680 	s.Append(s2);
681 	return s;
682 }
683 
684 inline const JString operator+(const char *s1, const JString& s2)
685 {
686 	JString s(s1);
687 	s.Append(s2);
688 	return s;
689 }
690 
691 // Concatena un caracter
Append(char c)692 inline void JString::Append(char c)
693 {
694   if (c)
695   {
696     char *strAux = new char[length + 2];
697     strAux[0] = 0;
698 
699     if (data)
700     {
701       strcpy(strAux, data);
702       delete[] data;
703     }
704 
705     strAux[length] = c;
706     data = strAux;
707     length += 1;
708     strAux[length] = 0;
709   }
710 }
711 
712 // Concatena un caracter
713 inline void JString::operator+=(char c)
714 {
715   if (c)
716   {
717     char *strAux = new char[length + 2];
718     strAux[0] = 0;
719 
720     if (data)
721     {
722       strcpy(strAux, data);
723       delete[] data;
724     }
725 
726     strAux[length] = c;
727     data = strAux;
728     length += 1;
729     strAux[length] = 0;
730   }
731 }
732 
733 // Formatea la cadena tipo printf
Format(const char * fmt,...)734 inline bool JString::Format(const char *fmt, ...)
735 {
736 	int n, size = 0;
737 	char *p = 0;
738 
739 	va_list ap;
740 
741 	while (1)
742 	{
743 		// Intenta escribir hasta que la escritura tenga �xito
744 		va_start(ap, fmt);
745 		n = vsnprintf (p, size, fmt, ap);
746 		va_end(ap);
747 
748 		// Si tiene �xito, sale del bucle para asignar la nueva cadena
749 		if (n > -1 && n < size)
750 			break;
751 
752 		// Si no, intenta determinar el espacio necesario
753 		if (n > -1)    // Esto ocurre con glibc >= 2.1
754 		{
755 			// Justo lo necesario
756 			size = n+1;
757 		}
758 		else           // Esto ocurre con glibc < 2.1
759 		{
760 			// Incrementa el tama�o
761 			size += (64 + size);
762 		}
763 
764 		if (p)
765 		{
766 			delete[] p;
767 		}
768 
769 		if ((p = new char[size]) == 0)
770 		{
771 			// No hay memoria
772 			return false;
773 		}
774 	}
775 
776 	delete[] data;
777 	data = p;
778 	length = size - 1;
779 
780 	return true;
781 }
782 
783 // Convierte a may�sculas
Uppercase()784 void JString::Uppercase()
785 {
786 	char *p = data;
787 	while (*p)
788 	{
789 		*p = toupper(*p);
790 		++p;
791 	}
792 }
793 
794 // Convierte a min�sculas
Lowercase()795 void JString::Lowercase()
796 {
797 	char *p = data;
798 	while (*p)
799 	{
800 		*p = tolower(*p);
801 		++p;
802 	}
803 }
804 
805 // Devuelve la posici�n del primer car�cter c desde el comienzo de la cadena
Find(char c,u32 from)806 s32 JString::Find(char c, u32 from)
807 {
808 	if (from >= length)
809 	{
810 		return -1;
811 	}
812 
813 	char *p;
814 	if ((p = strchr(data + from, c)))
815 	{
816 		if (p > data)
817 			return p - data;
818 		else
819 			return data - p;
820 	}
821 
822 	return -1;
823 }
824 
825 // Devuelve la posici�n del �ltimo car�cter c desde el comienzo de la cadena
FindLast(char c,u32 from)826 s32 JString::FindLast(char c, u32 from)
827 {
828 	if (from >= length)
829 	{
830 		return -1;
831 	}
832 
833 	char *p;
834 	if ((p = strrchr(data + from, c)))
835 	{
836 		if (p > data)
837 			return p - data;
838 		else
839 			return data - p;
840 	}
841 
842 	return -1;
843 }
844 
845 // Devuelve la posici�n de la cadena str desde el comienzo de la cadena
Find(const char * str,u32 from)846 s32 JString::Find(const char *str, u32 from)
847 {
848 	if (from >= length)
849 	{
850 		return -1;
851 	}
852 
853 	char *p;
854 	if ((p = strstr(data + from, str)))
855 	{
856 		if (p > data)
857 			return p - data;
858 		else
859 			return data - p;
860 	}
861 
862 	return -1;
863 }
864 
865 // Reemplaza las ocurrencias 'pat' con 'rep' desde 'from', hasta 'max' veces
Replace(const char pat,const char rep,u32 from,u32 max)866 s32 JString::Replace(const char pat, const char rep, u32 from, u32 max)
867 {
868 	s32 i, num = 0;
869 
870 	while ((i = Find(pat, from)) > -1)
871 	{
872 		data[i] = rep;
873 		++num;
874 	}
875 
876 	return num;
877 }
878 
879 // Reemplaza las ocurrencias 'pat' con 'rep' desde 'from', hasta 'max' veces
Replace(const char * pat,const char * rep,u32 from,u32 max)880 s32 JString::Replace(const char *pat, const char *rep, u32 from, u32 max)
881 {
882 	s32 cur, patLen, repLen, num = 0;
883 
884 	patLen = strlen(pat);
885 	repLen = strlen(rep);
886 
887 	if (patLen == repLen)
888 	{
889 		// Caso especial, esto se hace m�s r�pido
890 		while ((cur = Find(pat, from)) > -1)
891 		{
892 			strncpy(data + cur, rep, repLen);
893 			++num;
894 			from = cur + patLen;
895 		}
896 
897 		return num;
898 	}
899 
900 	JString str(*this, 0, from);
901 
902 	while ((cur = Find(pat, from)) > -1)
903 	{
904 		str += Substring(from, cur);
905 		str += rep;
906 		++num;
907 		from = cur + patLen;
908 	}
909 
910 	str += Substring(from);
911 	*this = str;
912 
913 	return num;
914 }
915 
916 // Devuelve una subcadena de esta cadena
Substring(u32 start,u32 end)917 inline const JString JString::Substring(u32 start, u32 end)
918 {
919 	return JString(*this, start, end);
920 }
921 
922 // Lee la cadena de un fichero (longitud + cadena)
Load(JRW & f)923 inline u32 JString::Load(JRW &f)
924 {
925   f.ReadLE32(&length);
926   delete[] data;
927   data = new char[length + 1];
928   f.Read(data, length);
929   data[length] = 0;
930 
931   return 0;
932 }
933 
934 // Escribe la cadena a un fichero (longitud + cadena)
Save(JRW & f)935 inline u32 JString::Save(JRW &f)
936 {
937   f.WriteLE32(&length);
938   f.Write(data, length);
939 
940   return 0;
941 }
942 
943 #endif // _JSTRING_INCLUDED
944