1 /*****************************************************************************/
2 /* Software Testing Automation Framework (STAF)                              */
3 /* (C) Copyright IBM Corp. 2001                                              */
4 /*                                                                           */
5 /* This software is licensed under the Eclipse Public License (EPL) V1.0.    */
6 /*****************************************************************************/
7 
8 #include "STAF.h"
9 #include <map>
10 #include <ctype.h>
11 #include <cstring>
12 #include "STAFString.h"
13 #include "STAFMutexSem.h"
14 #include "STAFConverter.h"
15 #include "STAFUtil.h"
16 #include "STAFTrace.h"
17 
18 ////////////////////////////////////////////////////////////////////////////////
19 
20 // defined constants
21 const unsigned int MIN     =   32;      // min alloc mem for strings
22 const unsigned int MAX     = 4096;      // best if it's a page size
23 const unsigned int DELTA   = 4096;      // best if it's a page size
24 const unsigned int ISCHAR  =    0;      // corb (character or byte parm)
25 const unsigned int ISBYTE  =    1;      // corb (character or byte parm)
26 
27 ////////////////////////////////////////////////////////////////////////////////
28 
29 struct STAFStringImplementation
30 {
31     char *pBuffer;
32     unsigned int fBuffLen;
33     unsigned int fCharLen;
34     unsigned int fByteLen;
35 };
36 
37 static const char SIZE_TABLE[] =
38 {
39     // This table allows for O(1) lookup of a char size.
40 
41     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
42     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
43     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
44     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
45     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
46     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
47     1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
48     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50     0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
51     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
52     3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
53     6, 6, 0, 0
54 };
55 
56 // Casting to (char *) gets rid of "warning: conversion from string literal to
57 // 'char *' is deprecated"
58 static const STAFStringImplementation CHAR_TABLE[] =
59 {
60     { (char *)"\x0",      1, 1, 1 }, { (char *)"\x20", 1, 1, 1 }, { (char *)"\x7b", 1, 1, 1 },
61     { (char *)"\x7d",     1, 1, 1 }, { (char *)"\x28", 1, 1, 1 }, { (char *)"\x29", 1, 1, 1 },
62     { (char *)"\x3c",     1, 1, 1 }, { (char *)"\x3e", 1, 1, 1 }, { (char *)"\x3a", 1, 1, 1 },
63     { (char *)"\x3b",     1, 1, 1 }, { (char *)"\x2c", 1, 1, 1 }, { (char *)"\x2e", 1, 1, 1 },
64     { (char *)"\x5c",     1, 1, 1 }, { (char *)"\x2f", 1, 1, 1 }, { (char *)"\x3d", 1, 1, 1 },
65     { (char *)"\x27",     1, 1, 1 }, { (char *)"\x22", 1, 1, 1 }, { (char *)"\x7c", 1, 1, 1 },
66     { (char *)"\xc0\x80", 2, 1, 2 }, { (char *)"\x23", 1, 1, 1 }, { (char *)"\x0d", 1, 1, 1 },
67     { (char *)"\x0a",     1, 1, 1 }, { (char *)"\x2a", 1, 1, 1 }, { (char *)"\x2d", 1, 1, 1 },
68     { (char *)"\x25",     1, 1, 1 }, { (char *)"\x3f", 1, 1, 1 }, { (char *)"\x5e", 1, 1, 1 },
69     { (char *)"\x26",     1, 1, 1 }, { (char *)"\x40", 1, 1, 1 }, { (char *)"\x09", 1, 1, 1 },
70     { (char *)"\x21",     1, 1, 1 }
71 };
72 
73 static const char *EMPTY_STRING = "";
74 
75 ////////////////////////////////////////////////////////////////////////////////
76 
77 // useful inline methods
78 
BYTES(char * c)79 inline int BYTES(char *c)      { return SIZE_TABLE[(unsigned char)*c];    }
SPACE(char * c)80 inline int SPACE(char *c)      { return (*c == 0x20);                     }
DIGIT(char * c)81 inline int DIGIT(char *c)      { return (*c >= 0x30 && *c <= 0x39);       }
ZERO(char * c)82 inline int ZERO(char *c)       { return (*c == 0x30);                     }
ASCII(char * c)83 inline int ASCII(char *c)      { return (BYTES(c) == 1);                  }
WHITESPACE(char * c)84 inline int WHITESPACE(char *c) { return (*c == 0x20 || *c == 0x09 ||
85                                          *c == 0x0A || *c == 0x0D);       }
PREV(char * c)86 inline char *PREV(char *c)     { while (!BYTES(--c))
87 	                                 ; // Silences empty body compiler warning
88                                  return c;                                }
NEXT(char * c)89 inline char *NEXT(char *c)     { c += BYTES(c); return c;                 }
REWB(char * c,unsigned int n)90 inline char *REWB(char *c, unsigned int n) { return c - n;                }
FWDB(char * c,unsigned int n)91 inline char *FWDB(char *c, unsigned int n) { return c + n;                }
REWC(char * c,unsigned int n)92 inline char *REWC(char *c, unsigned int n) { while (n--) c = PREV(c);
93                                              return c;                    }
FWDC(char * c,unsigned int n)94 inline char *FWDC(char *c, unsigned int n) { while (n--) c = NEXT(c);
95                                              return c;                    }
REWN(char * c,unsigned int n,unsigned int corb)96 inline char *REWN(char *c, unsigned int n, unsigned int corb)
97                          { return (corb ? REWB(c, n) : REWC(c, n));       }
FWDN(char * c,unsigned int n,unsigned int corb)98 inline char *FWDN(char *c, unsigned int n, unsigned int corb)
99                          { return (corb ? FWDB(c, n) : FWDC(c, n));       }
100 
101 // Determine the size of the new buffer to allocate.
102 // The new size will be at least MIN bytes and increases by powers
103 // of 2 up to MAX bytes; after that, allocation is done in increments of
104 // DELTA bytes.
getBufferSize(unsigned int len)105 unsigned int getBufferSize(unsigned int len)
106 {
107     unsigned int min = MIN;
108 
109     // find the minimum storage for the string (a power of 2 < max)
110 
111     while (min < len && min < MAX) min <<= 1;  // O(lg MAX)
112 
113     // if len is above the max mark, find what needs to be allocated in
114     // delta increments, i.e. if diff == 5 then alloc min + diff * delta
115 
116     int diff = len - MAX;
117 
118     diff = (diff > 0 ? (diff / DELTA) + 1 : 0);
119 
120     return min + diff * DELTA;
121 }
122 
123 ////////////////////////////////////////////////////////////////////////////////
124 
125 static const STAFString sStar(kUTF8_STAR);
126 static const STAFString sQuestion(kUTF8_QUESTION);
127 static const STAFString sWildCards(sStar + sQuestion);
128 
129 ////////////////////////////////////////////////////////////////////////////////
130 
getConverterInstance()131 STAFConverter *getConverterInstance()
132 {
133     static STAFMutexSem sConverterSem;
134     static STAFConverter *sConverterPtr = 0;
135 
136     if (sConverterPtr != 0) return sConverterPtr;
137 
138     STAFMutexSemLock lock(sConverterSem);
139     sConverterPtr = new STAFConverter();
140 
141     return sConverterPtr;
142 }
143 
144 
145 /***********************************************************************/
146 /* convertUInt64ToString - Creates a STAFString from an STAFUInt64_t   */
147 /*                         number.                                     */
148 /*                                                                     */
149 /* Accepts: (In)  The value to be represented as a string              */
150 /*          (In)  The base in which to represent the value [1..16]     */
151 /*          (In)  A pointer to the buffer                              */
152 /*          (Out) The length of the buffer                             */
153 /*          (In)  True to prepend negative symbol                      */
154 /*                                                                     */
155 /* Returns: the ptr position                                           */
156 /***********************************************************************/
convertUInt64ToString(STAFUInt64_t value,unsigned int base,char * ptr,unsigned int & len,bool negative)157 char* convertUInt64ToString(STAFUInt64_t value,
158                             unsigned int base,
159                             char *ptr,
160                             unsigned int &len,
161                             bool negative)
162 {
163     // ptr is a pointer to the buffer used to create the string
164     // equivalent of the numeric value, which ends up right justified.
165 
166     do
167     {
168         // 0x30 - 0x39 are ascii values for number 0-9
169         if ((*ptr = (value % base) + 0x30) > 0x39)
170             *ptr += 7;
171         ptr--;
172         len++;
173     }
174     while (value /= base);
175 
176    if (negative)
177    {
178        // Prepend a negative sign, "-".  (0x2d is ascii value for -)
179        *ptr = 0x2d;
180        len++;
181    }
182    else
183    {
184        ptr++; // Adjust ptr to beginning of the string
185    }
186 
187     return ptr;
188 }
189 
190 
STAFStringConstruct(STAFString_t * pString,const char * buffer,unsigned int len,unsigned int * osRC)191 STAFRC_t STAFStringConstruct(STAFString_t *pString,
192                              const char *buffer,
193                              unsigned int len, unsigned int *osRC)
194 {
195     // This is the master constructor and is used by all other constructors.
196     // this constructor allocates at least MIN bytes and increases by powers
197     // of 2 up to MAX bytes; after that, allocation is done in increments of
198     // DELTA bytes.
199 
200     // If buffer is 0 or len is 0, create an empty string
201 
202     if (pString == 0) return kSTAFInvalidObject;;
203 
204     *pString = new STAFStringImplementation;
205     STAFStringImplementation &str = **pString;
206 
207     if (buffer == 0 || len == 0)
208     {
209         str.pBuffer  = (char *)EMPTY_STRING;
210         str.fBuffLen = 0;
211         str.fCharLen = 0;
212         str.fByteLen = 0;
213         return kSTAFOk;
214     }
215 
216     // Determine the size of the new buffer to allocate.
217 
218     str.fBuffLen = getBufferSize(len);
219     str.pBuffer  = new char[str.fBuffLen];
220 
221     // Copy string into buffer
222 
223     memcpy(str.pBuffer, buffer, len);
224 
225     // Set byte length and compute char length of string
226 
227     str.fByteLen = len;
228 
229     // Calculate the length of the string in chars
230 
231     str.fCharLen = 0;
232 
233     char *ptr = (char *)(buffer);
234     char *lim = (char *)(buffer + len);
235 
236     while (ptr < lim)
237     {
238         str.fCharLen++;
239 
240         if (BYTES(ptr) == 0)
241         {
242             STAFTrace::trace(kSTAFTraceError,
243                              "STAFStringConstruct::Invalid UTF-8 data");
244             return kSTAFConverterError;
245         }
246 
247         ptr = NEXT(ptr);
248     }
249 
250     return kSTAFOk;
251 }
252 
253 
STAFStringConstructCopy(STAFString_t * pString,STAFStringConst_t aString,unsigned int * osRC)254 STAFRC_t STAFStringConstructCopy(STAFString_t *pString,
255                                  STAFStringConst_t aString,
256                                  unsigned int *osRC)
257 {
258     if (pString == 0) return kSTAFInvalidObject;
259 
260     if (aString == 0 || aString->fByteLen == 0)
261         return STAFStringConstruct(pString, 0, 0, osRC);
262 
263     return STAFStringConstruct(pString, aString->pBuffer,
264         aString->fByteLen, osRC);
265 }
266 
267 
268 
STAFStringConstructFromCurrentCodePage(STAFString_t * pString,const char * from,unsigned int len,unsigned int * osRC)269 STAFRC_t STAFStringConstructFromCurrentCodePage(STAFString_t *pString,
270                                                 const char *from,
271                                                 unsigned int len,
272                                                 unsigned int *osRC)
273 {
274     if (pString == 0) return kSTAFInvalidObject;
275 
276     if (from == 0 || len == 0)
277         return STAFStringConstruct(pString, 0, 0, osRC);
278 
279     STAFRC_t rc = kSTAFOk;
280 
281     STAFConverter *convPtr;
282     convPtr = getConverterInstance();
283 
284     const unsigned int SIZE = 4096;
285     const unsigned char *fromPtr = (unsigned char *)from;
286     unsigned int fromLen = len;
287     unsigned char *toPtr = new unsigned char[SIZE];
288     unsigned int toLen = SIZE;
289     std::string result = "";
290     unsigned int resultLen = 0;
291 
292     // now let's actually do the conversion
293     while (fromLen > 0)
294     {
295         int rc2 = convPtr->convertToUTF8(&fromPtr, &fromLen, toPtr, &toLen);
296 
297         if (rc2)
298         {
299             delete[] toPtr;
300             if (osRC) *osRC = 0;
301             return kSTAFConverterError;
302         }
303 
304         result += std::string((char *)toPtr, toLen);
305         resultLen += toLen;
306         toLen = SIZE;
307     }
308 
309     delete[] toPtr;
310 
311     return STAFStringConstruct(pString, result.data(), resultLen, osRC);
312 }
313 
STAFStringConstructFromUInt(STAFString_t * pString,unsigned int value,unsigned int base,unsigned int * osRC)314 STAFRC_t STAFStringConstructFromUInt(STAFString_t *pString,
315                                      unsigned int value,
316                                      unsigned int base,
317                                      unsigned int *osRC)
318 {
319     if (pString == 0) return kSTAFInvalidObject;
320 
321     if (base == 0 || base > 16) return kSTAFInvalidParm;
322 
323     // This buffer is used to create the string equivalent of value, which
324     // ends up right justified.  Then we pass that to the constructor
325 
326     char buffer[32];
327     unsigned int len = 0;
328 
329     char *ptr = convertUInt64ToString(
330         static_cast<STAFUInt64_t>(value), base, &buffer[31], len, false);
331 
332     return STAFStringConstruct(pString, ptr, len, osRC);
333 }
334 
STAFStringConstructFromUInt64(STAFString_t * pString,STAFUInt64_t value,unsigned int base,unsigned int * osRC)335 STAFRC_t STAFStringConstructFromUInt64(STAFString_t *pString,
336                                        STAFUInt64_t value,
337                                        unsigned int base,
338                                        unsigned int *osRC)
339 {
340     if (pString == 0) return kSTAFInvalidObject;
341 
342     if (base == 0 || base > 16) return kSTAFInvalidParm;
343 
344     // This buffer is used to create the string equivalent of value, which
345     // ends up right justified.  Then we pass that to the constructor
346 
347     char buffer[32];
348     unsigned int len = 0;
349 
350     char *ptr = convertUInt64ToString(value, base, &buffer[31], len, false);
351 
352     return STAFStringConstruct(pString, ptr, len, osRC);
353 }
354 
STAFStringConstructFromInt64(STAFString_t * pString,STAFInt64_t value,unsigned int base,unsigned int * osRC)355 STAFRC_t STAFStringConstructFromInt64(STAFString_t *pString,
356                                       STAFInt64_t value,
357                                       unsigned int base,
358                                       unsigned int *osRC)
359 {
360     if (pString == 0) return kSTAFInvalidObject;
361 
362     if (base == 0 || base > 16) return kSTAFInvalidParm;
363 
364     // This buffer is used to create the string equivalent of value, which
365     // ends up right justified.  Then we pass that to the constructor
366 
367     char buffer[32];
368     unsigned int len = 0;
369     bool negative = false;
370 
371     if (value < 0)
372     {
373         // Convert value to a positive number
374 
375         value = value * -1;
376         negative = true;
377     }
378 
379     char *ptr = convertUInt64ToString(
380         static_cast<STAFUInt64_t>(value), base, &buffer[31], len,
381         negative);
382 
383     return STAFStringConstruct(pString, ptr, len, osRC);
384 }
385 
STAFStringConstructSubString(STAFString_t * pSubStr,STAFStringConst_t aString,unsigned int index,unsigned int len,unsigned int corb,unsigned int * osRC)386 STAFRC_t STAFStringConstructSubString(STAFString_t *pSubStr,
387                                       STAFStringConst_t aString,
388                                       unsigned int index,
389                                       unsigned int len,
390                                       unsigned int corb,
391                                       unsigned int *osRC)
392 {
393     if (pSubStr == 0) return kSTAFInvalidObject;
394 
395     if (aString == 0 || aString->fByteLen == 0)
396         return STAFStringConstruct(pSubStr, 0, 0, osRC);
397 
398     char *ptr = aString->pBuffer;
399     char *lim = aString->pBuffer + aString->fByteLen;
400 
401     // if index is beyond string's length, return empty string
402 
403     if (index >= (corb ? aString->fByteLen : aString->fCharLen))
404         return STAFStringConstruct(pSubStr, 0, 0, osRC);
405 
406     ptr = FWDN(ptr, index, corb);
407 
408     // if len is beyond string's length - index, return rest of string
409 
410     if (len < (corb ? aString->fByteLen : aString->fCharLen) - index)
411         lim = FWDN(ptr, len, corb);
412 
413     return STAFStringConstruct(pSubStr, ptr, lim - ptr, osRC);
414 }
415 
416 
STAFStringConstructSubWord(STAFString_t * pWord,STAFStringConst_t aString,unsigned int index,unsigned int count,unsigned int * osRC)417 STAFRC_t STAFStringConstructSubWord(STAFString_t *pWord,
418                                     STAFStringConst_t aString,
419                                     unsigned int index,
420                                     unsigned int count,
421                                     unsigned int *osRC)
422 {
423     char *ptr  = 0;
424     char *lim  = 0;
425     char *str  = 0;
426     char *end  = 0;
427 
428     if (pWord == 0) return kSTAFInvalidObject;
429 
430     if (aString == 0) return kSTAFInvalidParm;
431 
432     ptr = aString->pBuffer;
433     lim = aString->pBuffer + aString->fByteLen;
434 
435     while (ptr < lim  && WHITESPACE(ptr))
436     {
437         ptr = NEXT(ptr);
438     }
439 
440     if (ptr >= lim)
441     {
442         return STAFStringConstruct(pWord, 0, 0, osRC);
443     }
444 
445     str = ptr;
446     end = PREV(lim);
447 
448     while (end >= str && WHITESPACE(end))
449     {
450         end = PREV(end);
451     }
452 
453     if (end < str)
454     {
455         return STAFStringConstruct(pWord, 0, 0, osRC);
456     }
457 
458     end = NEXT(end);
459 
460     while (ptr < end && index--)
461     {
462         while (ptr < end &&  WHITESPACE(ptr))
463         {
464             ptr = NEXT(ptr);
465         }
466 
467         if (ptr >= end)
468         {
469             break;
470         }
471 
472         while (ptr < end && !WHITESPACE(ptr))
473         {
474             ptr = NEXT(ptr);
475         }
476 
477         if (ptr >= end)
478         {
479             break;
480         }
481 
482         while (ptr < end &&  WHITESPACE(ptr))
483         {
484             ptr = NEXT(ptr);
485         }
486     }
487 
488     str = ptr;
489 
490     while (ptr < end && count--)
491     {
492         while (ptr < end &&  WHITESPACE(ptr))
493         {
494             ptr = NEXT(ptr);
495         }
496 
497         if (ptr >= end)
498         {
499             break;
500         }
501 
502         while (ptr < end && !WHITESPACE(ptr))
503         {
504             ptr = NEXT(ptr);
505         }
506     }
507 
508     end = ptr;
509 
510     return STAFStringConstruct(pWord, str, end - str, osRC);
511 }
512 
STAFStringConstructChar(STAFString_t * pChar,STAFUTF8Char_t aChar,unsigned int * osRC)513 STAFRC_t STAFStringConstructChar(STAFString_t *pChar,
514                                  STAFUTF8Char_t aChar,
515                                  unsigned int *osRC)
516 {
517     if (pChar == 0) return kSTAFInvalidObject;
518 
519     return STAFStringConstructCopy(pChar, &CHAR_TABLE[aChar],
520                                    osRC);
521 }
522 
STAFStringConstructJoin(STAFString_t * pString,STAFString_t aStringArray[],unsigned int arraySize,unsigned int * osRC)523 STAFRC_t STAFStringConstructJoin(STAFString_t *pString,
524                                  STAFString_t aStringArray[],
525                                  unsigned int arraySize,
526                                  unsigned int *osRC)
527 {
528     if (pString == 0) return kSTAFInvalidObject;
529 
530     *pString = new STAFStringImplementation;
531     STAFStringImplementation &str = **pString;
532 
533     // Determine the size of the new buffer to allocate by reading the
534     // string array and determine the combined length of all the strings
535     // in the array
536 
537     unsigned int joinByteLen = 0;
538     unsigned int joinCharLen = 0;
539     unsigned int i = 0;
540 
541     for (i = 0; i < arraySize; ++i)
542     {
543         if (aStringArray[i] == 0)
544             continue;
545 
546         joinByteLen += aStringArray[i]->fByteLen;
547         joinCharLen += aStringArray[i]->fCharLen;
548     }
549 
550     // If joinByteLen is 0, create an empty string
551 
552     if (joinByteLen == 0)
553     {
554         str.pBuffer  = (char *)EMPTY_STRING;
555         str.fBuffLen = 0;
556         str.fCharLen = 0;
557         str.fByteLen = 0;
558         return kSTAFOk;
559     }
560 
561     // Determine size of new buffer to allocate (with extra space)
562 
563     unsigned int joinBuffLen = getBufferSize(joinByteLen);
564 
565     // Allocate the buffer to contain all of the strings joined together
566 
567     char *newbuff = new char[joinBuffLen];
568 
569     memset(newbuff, 0, joinBuffLen);
570 
571     // Read string array and copy each string into the buffer
572 
573     unsigned int currLen = 0;
574 
575     for (i = 0; i < arraySize; ++i)
576     {
577         if ((aStringArray[i] == 0) ||
578             (aStringArray[i]->pBuffer == EMPTY_STRING))
579         {
580             continue;
581         }
582 
583         memcpy(newbuff + currLen, aStringArray[i]->pBuffer,
584                aStringArray[i]->fByteLen);
585 
586         currLen += aStringArray[i]->fByteLen;
587     }
588 
589     str.pBuffer = newbuff;
590     str.fBuffLen = joinBuffLen;
591     str.fCharLen = joinCharLen;
592     str.fByteLen = joinByteLen;
593 
594     return kSTAFOk;
595 }
596 
STAFStringAssign(STAFString_t aTarget,STAFStringConst_t aSource,unsigned int * osRC)597 STAFRC_t STAFStringAssign(STAFString_t aTarget,
598                           STAFStringConst_t aSource,
599                           unsigned int *osRC)
600 {
601     // if space allocated in target is not much larger (but
602     // sufficient to contain source), then just do a memcpy.
603     // if space allocated in target is much larger or space
604     // allocated in target is not sufficient, reallocate to
605     // the size of source and do memcpy.
606 
607     if ((aTarget->fBuffLen >= aSource->fBuffLen) &&
608         (aTarget->fBuffLen < 2 * aSource->fBuffLen))
609     {
610         memcpy(aTarget->pBuffer, aSource->pBuffer,
611                aSource->fByteLen);
612 
613         aTarget->fCharLen = aSource->fCharLen;
614         aTarget->fByteLen = aSource->fByteLen;
615     }
616     else
617     {
618         if (aTarget->pBuffer != EMPTY_STRING)
619             delete[] aTarget->pBuffer;
620         aTarget->pBuffer = new char[aSource->fBuffLen];
621 
622         memcpy(aTarget->pBuffer, aSource->pBuffer,
623                aSource->fByteLen);
624 
625         aTarget->fCharLen = aSource->fCharLen;
626         aTarget->fByteLen = aSource->fByteLen;
627         aTarget->fBuffLen = aSource->fBuffLen;
628     }
629 
630     return kSTAFOk;
631 }
632 
633 
STAFStringNumOfWords(STAFStringConst_t aString,unsigned int * num,unsigned int * osRC)634 STAFRC_t STAFStringNumOfWords(STAFStringConst_t aString,
635                               unsigned int *num,
636                               unsigned int *osRC)
637 {
638 
639     if (aString == 0) return kSTAFInvalidObject;
640 
641     if (num == 0) return kSTAFInvalidParm;
642 
643     char *ptr = aString->pBuffer;
644     char *lim = aString->pBuffer + aString->fByteLen;
645 
646     *num = 0;  // default to none
647 
648     while (ptr < lim)
649     {
650         // iterate while blank, when non-blank increment count,
651         // iterate while non-blank, loop
652 
653         while (ptr < lim && WHITESPACE(ptr))
654             ptr = NEXT(ptr);
655 
656         if (ptr >= lim) break;
657 
658         (*num)++;
659 
660         while (ptr < lim && !WHITESPACE(ptr))
661             ptr = NEXT(ptr);
662     }
663 
664     return kSTAFOk;
665 }
666 
667 
STAFStringGetBuffer(STAFStringConst_t aString,const char ** buffer,unsigned int * len,unsigned int * osRC)668 STAFRC_t STAFStringGetBuffer(STAFStringConst_t aString,
669                              const char **buffer,
670                              unsigned int *len,
671                              unsigned int *osRC)
672 {
673     if (aString == 0) return kSTAFInvalidObject;
674 
675     if (buffer == 0) return kSTAFInvalidParm;
676 
677     *buffer = aString->pBuffer;
678 
679     if (len) *len = aString->fByteLen;
680 
681     return kSTAFOk;
682 }
683 
684 
STAFStringToLowerCase(STAFString_t aString,unsigned int * osRC)685 STAFRC_t STAFStringToLowerCase(STAFString_t aString, unsigned int *osRC)
686 {
687     if (aString == 0) return kSTAFInvalidObject;
688 
689     // ASCII 0x41 .. 0x5a are upper -> | 0x20 -> lower
690 
691     char *ptr = aString->pBuffer;
692     char *lim = aString->pBuffer + aString->fByteLen;
693 
694     // XXX: may not work on other systems
695 
696     while (ptr < lim)
697     {
698         if (*ptr >= 0x41 && *ptr <= 0x5a)
699             *ptr |= 0x20;
700 
701         ptr = NEXT(ptr);
702     }
703 
704     return kSTAFOk;
705 }
706 
707 
STAFStringToUpperCase(STAFString_t aString,unsigned int * osRC)708 STAFRC_t STAFStringToUpperCase(STAFString_t aString, unsigned int *osRC)
709 {
710     if (aString == 0) return kSTAFInvalidObject;
711 
712     // ASCII 0x61 .. 0x7a are lower -> & 0xdf -> upper
713 
714     char *ptr = aString->pBuffer;
715     char *lim = aString->pBuffer + aString->fByteLen;
716 
717     // XXX: may not work on other systems
718 
719     while (ptr < lim)
720     {
721         if (*ptr >= 0x61 && *ptr <= 0x7a)
722             *ptr &= 0xdf;
723 
724         ptr = NEXT(ptr);
725     }
726 
727     return kSTAFOk;
728 }
729 
730 
STAFStringReplace(STAFString_t aString,STAFStringConst_t oldString,STAFStringConst_t newString,unsigned int * osRC)731 STAFRC_t STAFStringReplace(STAFString_t aString,
732                            STAFStringConst_t oldString,
733                            STAFStringConst_t newString,
734                            unsigned int *osRC)
735 {
736     unsigned int pos       = 0;
737     unsigned int next      = 0;
738     unsigned int ptrLen    = 0;
739     unsigned int limLen    = 0;
740     unsigned int oldStrLen = 0;
741     unsigned int newStrLen = 0;
742     char *ptr    = 0;
743     char *lim    = 0;
744     char *oldStr = 0;
745     char *newStr = 0;
746 
747     if (aString == 0) return kSTAFInvalidObject;
748 
749     if (oldString == 0 || newString == 0)
750         return kSTAFInvalidParm;
751 
752     ptr       = aString->pBuffer;
753     newStr    = newString->pBuffer;
754     newStrLen = newString->fByteLen;
755     STAFStringLength(oldString, &oldStrLen, ISBYTE, osRC);
756 
757     // For performance reasons, the following algorithm is used:
758     // 1) Check if there's at least one occurrences of the
759     //    replacement string, and if there's not, return.
760     // 2) Calculates a buffer/byte size that is large enough to contain
761     //    the entire new string and allocates this new buffer.
762     //    If the size of the replacement string is larger, then it
763     //    counts how many occurrences of the replacement string
764     //    exists and multiplies it by the size difference and and
765     //    and adds this to the existing string size.
766     // 3) Copies the content up to the first occurrence of the string
767     //    to replace to the new buffer.
768     // 4) In a loop, copies the replacement string to the new buffer
769     //    and finds the next occurrence to replace and copies the
770     //    content up to that occurrence to the new buffer and repeats
771     //    until no more occurrences are found.
772     // 5) Copies any remaining content to the new buffer.
773     int newBufSize = getBufferSize(aString->fByteLen);
774     int newBufByteLen = aString->fByteLen;
775 
776     // Check if at least one occurrence of the substring is
777     // found.  If 0 occurrences are found, return.
778     unsigned int subStringCount = 0;
779 
780     STAFStringCountSubStrings(aString, oldString, &subStringCount, osRC);
781 
782     if (subStringCount == 0) return kSTAFOk;
783 
784     if (oldStrLen < newStrLen)
785     {
786         // The length of the substring being replaced is less than
787         // the length of the replacement substring.
788 
789         // Calculate a buffer size and byte length that
790         // will be large enough to contain the entire string after
791         // all replacements have been done.
792         newBufSize    = getBufferSize(aString->fByteLen +
793                         ((newStrLen - oldStrLen) * subStringCount));
794         newBufByteLen += (newStrLen - oldStrLen) * subStringCount;
795     }
796     else
797     {
798         // The length of the substring being replaced is more than
799         // the length of the replacement substring, so we need
800         // to decrease the byte length.
801         newBufByteLen -= (oldStrLen - newStrLen) * subStringCount;
802     }
803 
804     // creating newBuffer and buffer pointer
805     char *newBuffer = new char[newBufSize];
806     unsigned int newBufferPtr = 0;
807 
808     if (newBuffer == 0) return kSTAFBaseOSError;
809 
810     memset(newBuffer, 0, newBufSize);
811 
812     // find the first occurrence and set it to pos
813     STAFStringFind(aString, oldString, next, ISBYTE, &pos, osRC);
814 
815     // Copy the beginning content up to the first occurrence
816     memcpy(newBuffer, aString->pBuffer, pos);
817     // increment the buffer position
818     newBufferPtr += pos;
819 
820     while (pos != 0xffffffff)
821     {
822         oldStr  = ptr + pos;
823         ptrLen  = oldStr - ptr;
824         lim     = oldStr + oldStrLen;
825         limLen  = aString->fByteLen - ptrLen - oldStrLen;
826         next    = pos + oldStrLen;
827 
828         // performing stringReplace
829         memcpy(newBuffer + newBufferPtr, newStr, newStrLen);
830         // increment the buffer position
831         newBufferPtr += newStrLen;
832 
833         // find the next occurrence and set it to pos
834         STAFStringFind(aString, oldString, next, ISBYTE, &pos, osRC);
835 
836         if (pos == 0xffffffff)
837         {
838             // if this is the last loop, store any remaining
839             // content into the newBuffer
840             memcpy(newBuffer + newBufferPtr, lim, limLen);
841         }
842         else
843         {
844             // else store the content up to the next occurrence
845             memcpy(newBuffer + newBufferPtr, lim, pos - next);
846             // increment the buffer position
847             newBufferPtr += (pos - next);
848         }
849     }
850 
851     // Clear out the original aString
852     if (aString->pBuffer != EMPTY_STRING)
853         delete[] aString->pBuffer;
854 
855     // Update aString to the newBuffer
856     aString->pBuffer  = newBuffer;
857     aString->fBuffLen = newBufSize;
858     aString->fByteLen = newBufByteLen;
859 
860     // a bummer, but since we keep this info, we need to recompute
861     // (not trivial to do while replacing since we allow substring
862     // replacement, as instead of char replacement)
863     aString->fCharLen = 0;
864 
865     ptr = (char *)aString->pBuffer;
866     lim = (char *)aString->pBuffer + aString->fByteLen;
867 
868     while (ptr < lim)
869     {
870         aString->fCharLen++;
871         ptr = NEXT(ptr);
872     }
873 
874     return kSTAFOk;
875 }
876 
877 
STAFStringToCurrentCodePage(STAFStringConst_t aString,char ** to,unsigned int * len,unsigned int * osRC)878 STAFRC_t STAFStringToCurrentCodePage(STAFStringConst_t aString,
879                                      char **to,
880                                      unsigned int *len,
881                                      unsigned int *osRC)
882 {
883     STAFRC_t rc = kSTAFOk;
884 
885     if (aString == 0) return kSTAFInvalidObject;
886 
887     STAFConverter *convPtr;
888     convPtr = getConverterInstance();
889 
890     const unsigned int SIZE = 4096;
891     const unsigned char *fromPtr = (unsigned char *)aString->pBuffer;
892     unsigned int fromLen = aString->fByteLen;
893     unsigned char *toPtr = new unsigned char[SIZE];
894     unsigned int toLen = SIZE;
895     std::string result = "";
896     unsigned int resultLen = 0;
897 
898     // now let's actually do the conversion
899     while (fromLen > 0)
900     {
901         int rc2 = convPtr->convertFromUTF8(&fromPtr, &fromLen, toPtr, &toLen);
902 
903         if (rc2)
904         {
905             delete[] toPtr;
906             if (osRC) *osRC = 0;
907             return kSTAFConverterError;
908         }
909 
910         result += std::string((char *)toPtr, toLen);
911         resultLen += toLen;
912         toLen = SIZE;
913     }
914 
915     delete[] toPtr;
916 
917     *to = new char[result.length() + 1];
918     memcpy(*to, result.data(), result.length());
919     (*to)[result.length()] = 0;
920     *len = result.length();
921 
922     return kSTAFOk;
923 }
924 
925 
STAFStringConcatenate(STAFString_t aString,STAFStringConst_t aSource,unsigned int * osRC)926 STAFRC_t STAFStringConcatenate(STAFString_t aString,
927                                STAFStringConst_t aSource,
928                                unsigned int *osRC)
929 {
930     if (aString == 0) return kSTAFInvalidObject;
931 
932     if (aSource == 0) return kSTAFInvalidParm;
933 
934     char *ptr = 0;
935 
936     // pre : t = "hello ", s = "world"
937     // post: t = "hello world", s = "world"
938 
939     if (aString->fBuffLen > aString->fByteLen + aSource->fByteLen)
940     {
941         ptr = aString->pBuffer + aString->fByteLen;
942         memcpy(ptr, aSource->pBuffer, aSource->fByteLen);
943         aString->fByteLen += aSource->fByteLen;
944         aString->fCharLen += aSource->fCharLen;
945     }
946     else
947     {
948         // Determine size of new buffer to allocate (with extra space)
949         int concatBufLen = getBufferSize(
950             aString->fByteLen + aSource->fByteLen);
951 
952         char *newbuff = new char[concatBufLen];
953 
954         if (newbuff == 0) return kSTAFBaseOSError;
955 
956         memset(newbuff, 0, concatBufLen);
957         memcpy(newbuff, aString->pBuffer, aString->fByteLen);
958         memcpy(newbuff + aString->fByteLen, aSource->pBuffer,
959                aSource->fByteLen);
960 
961         if (aString->pBuffer != EMPTY_STRING)
962             delete[] aString->pBuffer;
963 
964         aString->pBuffer = newbuff;
965         aString->fBuffLen = concatBufLen;
966         aString->fCharLen += aSource->fCharLen;
967         aString->fByteLen += aSource->fByteLen;
968     }
969 
970     return kSTAFOk;
971 }
972 
973 
STAFStringCountSubStrings(STAFStringConst_t aString,STAFStringConst_t aSubStr,unsigned int * count,unsigned int * osRC)974 STAFRC_t STAFStringCountSubStrings(STAFStringConst_t aString,
975                                    STAFStringConst_t aSubStr,
976                                    unsigned int *count,
977                                    unsigned int *osRC)
978 {
979     if ((aString == 0) || (aSubStr == 0)) return kSTAFInvalidObject;
980 
981     if (count == 0) return kSTAFInvalidParm;
982 
983     *count = 0;  // default to none found
984 
985     if (aSubStr->fByteLen <= aString->fByteLen)
986     {
987         // count number of times the substring is found within the string
988 
989         char *lim = aString->pBuffer + (aString->fByteLen - aSubStr->fByteLen);
990         char *ptr = aString->pBuffer;
991         const char *key = aSubStr->pBuffer;
992 
993         while (ptr <= lim)
994         {
995             // check lead bytes, if equal do comparison
996             if (*ptr == *key)
997             {
998                 if (memcmp(key, ptr, aSubStr->fByteLen) == 0)
999                     (*count)++;
1000             }
1001 
1002             ptr = NEXT(ptr);
1003         }
1004     }
1005 
1006     return kSTAFOk;
1007 }
1008 
1009 
STAFStringStripCharsOfType(STAFString_t aInOutStr,STAFUTF8CharType_t aType,unsigned int side,unsigned int * osRC)1010 STAFRC_t STAFStringStripCharsOfType(STAFString_t aInOutStr,
1011                                     STAFUTF8CharType_t aType,
1012                                     unsigned int side,
1013                                     unsigned int *osRC)
1014 {
1015     if (aInOutStr == 0 || side > 2) return kSTAFInvalidObject;
1016 
1017     // if 0 then left, if 1 then right, if 2 then both
1018 
1019     char *ptr = 0;
1020     char *lim = 0;
1021 
1022     if (aInOutStr->pBuffer == 0) return kSTAFOk;
1023 
1024     if (side == 1 || side == 2)
1025     {
1026         ptr = aInOutStr->pBuffer + aInOutStr->fByteLen;
1027         ptr = PREV(ptr);
1028         lim = aInOutStr->pBuffer;
1029 
1030         switch (aType)
1031         {
1032             case kUTF8_TYPE_WHITESPACE:
1033 
1034             while (ptr >= lim && WHITESPACE(ptr))
1035             {
1036                 aInOutStr->fByteLen -= BYTES(ptr);
1037                 aInOutStr->fCharLen--;
1038                 ptr = PREV(ptr);
1039             }
1040             break;
1041 
1042             case kUTF8_TYPE_SPACE:
1043 
1044             while (ptr >= lim && SPACE(ptr))
1045             {
1046                 aInOutStr->fByteLen -= BYTES(ptr);
1047                 aInOutStr->fCharLen--;
1048                 ptr = PREV(ptr);
1049             }
1050             break;
1051 
1052             case kUTF8_TYPE_ASCII:
1053 
1054             while (ptr >= lim && ASCII(ptr))
1055             {
1056                 aInOutStr->fByteLen -= BYTES(ptr);
1057                 aInOutStr->fCharLen--;
1058                 ptr = PREV(ptr);
1059             }
1060             break;
1061 
1062             case kUTF8_TYPE_DIGIT:
1063 
1064             while (ptr >= lim && DIGIT(ptr))
1065             {
1066                 aInOutStr->fByteLen -= BYTES(ptr);
1067                 aInOutStr->fCharLen--;
1068                 ptr = PREV(ptr);
1069             }
1070             break;
1071 
1072             case kUTF8_TYPE_ZERO:
1073 
1074             while (ptr >= lim && ZERO(ptr))
1075             {
1076                 aInOutStr->fByteLen -= BYTES(ptr);
1077                 aInOutStr->fCharLen--;
1078                 ptr = PREV(ptr);
1079             }
1080             break;
1081 
1082             default:
1083             break;
1084         }
1085     }
1086 
1087     if (side == 0 || side == 2)
1088     {
1089         ptr = aInOutStr->pBuffer;
1090         lim = aInOutStr->pBuffer + aInOutStr->fByteLen;
1091 
1092         switch (aType)
1093         {
1094             case kUTF8_TYPE_WHITESPACE:
1095 
1096             while (ptr < lim && WHITESPACE(ptr))
1097             {
1098                 aInOutStr->fByteLen -= BYTES(ptr);
1099                 aInOutStr->fCharLen--;
1100                 ptr = NEXT(ptr);
1101             }
1102             break;
1103 
1104             case kUTF8_TYPE_SPACE:
1105 
1106             while (ptr < lim && SPACE(ptr))
1107             {
1108                 aInOutStr->fByteLen -= BYTES(ptr);
1109                 aInOutStr->fCharLen--;
1110                 ptr = NEXT(ptr);
1111             }
1112             break;
1113 
1114             case kUTF8_TYPE_ASCII:
1115 
1116             while (ptr < lim && ASCII(ptr))
1117             {
1118                 aInOutStr->fByteLen -= BYTES(ptr);
1119                 aInOutStr->fCharLen--;
1120                 ptr = NEXT(ptr);
1121             }
1122             break;
1123 
1124             case kUTF8_TYPE_DIGIT:
1125 
1126             while (ptr < lim && DIGIT(ptr))
1127             {
1128                 aInOutStr->fByteLen -= BYTES(ptr);
1129                 aInOutStr->fCharLen--;
1130                 ptr = NEXT(ptr);
1131             }
1132             break;
1133 
1134             case kUTF8_TYPE_ZERO:
1135 
1136             while (ptr < lim && ZERO(ptr))
1137             {
1138                 aInOutStr->fByteLen -= BYTES(ptr);
1139                 aInOutStr->fCharLen--;
1140                 ptr = NEXT(ptr);
1141             }
1142             break;
1143 
1144             default:
1145             break;
1146         }
1147 
1148         memmove(aInOutStr->pBuffer, ptr, aInOutStr->fByteLen);
1149     }
1150 
1151     return kSTAFOk;
1152 }
1153 
1154 
STAFStringToUInt(STAFStringConst_t aString,unsigned int * value,unsigned int base,unsigned int * osRC)1155 STAFRC_t STAFStringToUInt(STAFStringConst_t aString, unsigned int *value,
1156                           unsigned int base, unsigned int *osRC)
1157 {
1158     if (aString == 0) return kSTAFInvalidObject;
1159 
1160     if (value == 0 || base == 0 || base > 16) return kSTAFInvalidParm;
1161 
1162     *value = 0;
1163 
1164     // Find the index of the first byte that isn't a zero
1165 
1166     unsigned int firstNonZeroIndex = 0;
1167 
1168     STAFRC_t rc = STAFStringFindFirstNotOf(
1169         aString, STAFString("0").getImpl(), 0, 0, &firstNonZeroIndex, osRC);
1170 
1171     if ((rc == 0) && (firstNonZeroIndex == 0xffffffff))
1172     {
1173         // String contains no non-zero characters, so the value is 0
1174         return kSTAFOk;
1175     }
1176 
1177     if ((aString->fByteLen - firstNonZeroIndex) > 10)
1178     {
1179         // Error if the string length (not including any leading zeros)
1180         // exceeds the number of digits in UINT_MAX (4294967295) which
1181         // is 10
1182 
1183         return kSTAFInvalidValue;
1184     }
1185 
1186     unsigned int number = 0;
1187 
1188     // Go to the last digit and work backwards
1189 
1190     char *ptr = aString->pBuffer + aString->fByteLen - 1;
1191     unsigned int dig, mult = 1;
1192     unsigned int digitPos = 1;  // Which digit, starting backwards
1193 
1194     while (ptr >= aString->pBuffer)
1195     {
1196         // If it's an ASCII A..F (or a..f), convert to its numeric value
1197 
1198         if ( ((*ptr | 0x20) >= 0x61) && ((*ptr | 0x20) <= 0x66) )
1199             dig = (*ptr | 0x20) - 0x57;  // A = 10, B = 11, ... and so on
1200         else if ( (*ptr >= 0x30) && (*ptr <= 0x39) )
1201             dig = *ptr - 0x30;  // '0' = 0, '1' = 1, ... and so on
1202         else
1203             return kSTAFInvalidValue;
1204 
1205         // If it's an invalid digit for this base, then error
1206 
1207         if (dig >= base) return kSTAFInvalidParm;  // invalid argument
1208 
1209         // If number will exceed UINT_MAX. then error
1210 
1211         if (((digitPos == 10) && (dig > 3) && (number > 294967295)) ||
1212             ((digitPos >  10) && (dig > 0)))
1213         {
1214             return kSTAFInvalidValue;  // Error since > 4294967295
1215         }
1216 
1217         number += dig * mult;
1218 
1219         mult *= base;
1220         ptr--;
1221         digitPos++;
1222     }
1223 
1224     *value = number;
1225 
1226     return kSTAFOk;
1227 }
1228 
1229 
1230 /* XXX: Commented out until get UINT64_MAX working on Solaris
1231 STAFRC_t STAFStringToUInt64(STAFStringConst_t aString, STAFUInt64_t *value,
1232                             unsigned int base, unsigned int *osRC)
1233 {
1234     if (aString == 0) return kSTAFInvalidObject;
1235 
1236     if (value == 0 || base == 0 || base > 16) return kSTAFInvalidParm;
1237 
1238     *value = 0;
1239 
1240     // Find the index of the first byte that isn't a zero
1241 
1242     unsigned int firstNonZeroIndex = 0;
1243 
1244     STAFRC_t rc = STAFStringFindFirstNotOf(
1245         aString, STAFString("0").getImpl(), 0, 0, &firstNonZeroIndex, osRC);
1246 
1247     if ((rc == 0) && (firstNonZeroIndex == 0xffffffff))
1248     {
1249         // String contains no non-zero characters, so the value is 0
1250         return kSTAFOk;
1251     }
1252 
1253     if ((aString->fByteLen - firstNonZeroIndex) > 20)
1254     {
1255         // Error if the string length (not including any leading zeros)
1256         // exceeds the number of digits in UINT64_MAX (18446744073709551615)
1257         // which is 20
1258 
1259         return kSTAFInvalidValue;
1260     }
1261 
1262     STAFUInt64_t number = 0;
1263 
1264     // Go to the last digit and work backwards
1265 
1266     char *ptr = aString->pBuffer + aString->fByteLen - 1;
1267     unsigned int dig;
1268     STAFUInt64_t mult = 1;
1269     unsigned int digitPos = 1;  // Which digit, starting backwards
1270 
1271     while (ptr >= aString->pBuffer)
1272     {
1273         // If it's an ASCII A..F (or a..f), convert to its numeric value
1274 
1275         if ( ((*ptr | 0x20) >= 0x61) && ((*ptr | 0x20) <= 0x66) )
1276             dig = (*ptr | 0x20) - 0x57;  // A = 10, B = 11, ... and so on
1277         else if ( (*ptr >= 0x30) && (*ptr <= 0x39) )
1278             dig = *ptr - 0x30;  // '0' = 0, '1' = 1, ... and so on
1279         else
1280             return kSTAFInvalidValue;
1281 
1282         // If it's an invalid digit for this base, then error
1283 
1284         if (dig >= base) return kSTAFInvalidParm;  // invalid argument
1285 
1286         // If number will exceed UINT64_MAX, then error
1287 
1288         if ((digitPos > 19) && (dig > 0) &&
1289             (number > UINT64_MAX_LESS_FIRST_DIGIT))
1290             return kSTAFInvalidValue;  // Error since > 18446744073709551615
1291 
1292         number += dig * mult;
1293 
1294         mult *= base;
1295         ptr--;
1296         digitPos++;
1297     }
1298 
1299     *value = number;
1300 
1301     return kSTAFOk;
1302 }
1303 */
1304 
1305 
STAFStringLength(STAFStringConst_t aString,unsigned int * len,unsigned int corb,unsigned int * osRC)1306 STAFRC_t STAFStringLength(STAFStringConst_t aString, unsigned int *len,
1307                           unsigned int corb, unsigned int *osRC)
1308 {
1309     if (aString == 0) return kSTAFInvalidObject;
1310 
1311     if (len == 0) return kSTAFInvalidParm;
1312 
1313     *len = (corb ? aString->fByteLen : aString->fCharLen);
1314 
1315     return kSTAFOk;
1316 }
1317 
1318 
STAFStringSizeOfChar(STAFStringConst_t aString,unsigned int index,unsigned int corb,unsigned int * len,unsigned int * osRC)1319 STAFRC_t STAFStringSizeOfChar(STAFStringConst_t aString,
1320                               unsigned int index,
1321                               unsigned int corb,
1322                               unsigned int *len, unsigned int *osRC)
1323 {
1324     if (aString == 0) return kSTAFInvalidObject;
1325 
1326     if (len == 0) return kSTAFInvalidParm;
1327 
1328     char *ptr = aString->pBuffer;
1329     char *lim = aString->pBuffer + aString->fByteLen;
1330 
1331     *len = 0;  // default to 0 (helps on error)
1332 
1333     // if index is beyond string's length, return error
1334 
1335     if (index >= (corb ? aString->fByteLen : aString->fCharLen))
1336         return kSTAFInvalidObject;  // invalid argument
1337 
1338     ptr = FWDN(ptr, index, corb);
1339 
1340     *len = BYTES(ptr);
1341 
1342     return kSTAFOk;
1343 }
1344 
1345 
STAFStringByteIndexOfChar(STAFStringConst_t aString,unsigned int index,unsigned int * pos,unsigned int * osRC)1346 STAFRC_t STAFStringByteIndexOfChar(STAFStringConst_t aString,
1347                                    unsigned int index, unsigned int *pos,
1348                                    unsigned int *osRC)
1349 {
1350     if (aString == 0) return kSTAFInvalidObject;
1351 
1352     if (pos == 0) return kSTAFInvalidParm;
1353 
1354     char *ptr = aString->pBuffer;
1355     char *lim = aString->pBuffer + aString->fByteLen;
1356 
1357     *pos = 0xffffffff;  // default to not found
1358 
1359     // if index is beyond string's length, return error
1360 
1361     if (index >= aString->fCharLen)
1362         return kSTAFInvalidObject;  // invalid argument
1363 
1364     ptr = FWDC(ptr, index);
1365 
1366     *pos = ptr - aString->pBuffer;
1367 
1368     return kSTAFOk;
1369 }
1370 
1371 
STAFStringIsCharsOfType(STAFStringConst_t aString,const STAFUTF8CharType_t aType,unsigned int * result,unsigned int * osRC)1372 STAFRC_t STAFStringIsCharsOfType(STAFStringConst_t aString,
1373                                  const STAFUTF8CharType_t aType,
1374                                  unsigned int *result,
1375                                  unsigned int *osRC)
1376 {
1377     if (aString == 0) return kSTAFInvalidObject;
1378 
1379     if (result == 0) return kSTAFInvalidParm;
1380 
1381     char *ptr = aString->pBuffer;
1382     char *lim = aString->pBuffer + aString->fByteLen;
1383 
1384     *result = 0;  // default to false
1385 
1386     switch (aType)
1387     {
1388         case kUTF8_TYPE_WHITESPACE:
1389 
1390             while (ptr < lim && WHITESPACE(ptr))
1391                 ptr = NEXT(ptr);
1392 
1393             if (ptr >= lim)
1394                 *result = 1;
1395 
1396             break;
1397 
1398         case kUTF8_TYPE_SPACE:
1399 
1400             while (ptr < lim && SPACE(ptr))
1401                 ptr = NEXT(ptr);
1402 
1403             if (ptr >= lim)
1404                 *result = 1;
1405 
1406             break;
1407 
1408         case kUTF8_TYPE_ASCII:
1409 
1410             while (ptr < lim && ASCII(ptr))
1411                 ptr = NEXT(ptr);
1412 
1413             if (ptr >= lim)
1414                 *result = 1;
1415 
1416             break;
1417 
1418         case kUTF8_TYPE_DIGIT:
1419 
1420             while (ptr < lim && DIGIT(ptr))
1421                 ptr = NEXT(ptr);
1422 
1423             if (ptr >= lim)
1424                 *result = 1;
1425 
1426             break;
1427 
1428         default:
1429             break;
1430     }
1431 
1432     return kSTAFOk;
1433 }
1434 
STAFStringIsEqualTo(STAFStringConst_t aFirst,STAFStringConst_t aSecond,STAFStringCaseSensitive_t sensitive,unsigned int * comparison,unsigned int * osRC)1435 STAFRC_t STAFStringIsEqualTo(STAFStringConst_t aFirst,
1436                              STAFStringConst_t aSecond,
1437                              STAFStringCaseSensitive_t sensitive,
1438                              unsigned int *comparison,
1439                              unsigned int *osRC)
1440 {
1441     if ((aFirst == 0) || (aSecond == 0)) return kSTAFInvalidObject;
1442 
1443     if (comparison == 0) return kSTAFInvalidParm;
1444 
1445     *comparison = 1;  // default to true
1446 
1447     if ( (aFirst->fByteLen != aSecond->fByteLen) ||
1448          (aFirst->fCharLen != aSecond->fCharLen) )
1449     {
1450         // different
1451         *comparison = 0;
1452     }
1453     else if (sensitive == kSTAFStringCaseInsensitive)  // case insensitive
1454     {
1455         char *ptr1, *ptr2, *lim1;
1456 
1457         ptr1 = aFirst->pBuffer;
1458         ptr2 = aSecond->pBuffer;
1459         lim1 = aFirst->pBuffer + aFirst->fByteLen;
1460 
1461         while (ptr1 < lim1 && *comparison)
1462         {
1463             if ( (*ptr1 >= 0x41 && *ptr1 <= 0x5a) ||
1464                  (*ptr1 >= 0x61 && *ptr1 <= 0x7a) )
1465             {
1466                 if ((*ptr1 | 0x20) != (*ptr2 | 0x20))
1467                     *comparison = 0;
1468             }
1469             else if (*ptr1 != *ptr2) *comparison = 0;
1470 
1471             ptr1 = NEXT(ptr1);
1472             ptr2 = NEXT(ptr2);
1473         }
1474     }
1475     else  // case sensitive, just do a memory comparison
1476     {
1477         if (memcmp(aFirst->pBuffer, aSecond->pBuffer, aFirst->fByteLen))
1478             *comparison = 0;
1479     }
1480 
1481     return kSTAFOk;
1482 }
1483 
1484 
STAFStringCompareTo(STAFStringConst_t aFirst,STAFStringConst_t aSecond,unsigned int * whichLess,unsigned int * osRC)1485 STAFRC_t STAFStringCompareTo(STAFStringConst_t aFirst,
1486                              STAFStringConst_t aSecond,
1487                              unsigned int *whichLess,
1488                              unsigned int *osRC)
1489 {
1490     if ((aFirst == 0) || (aSecond == 0)) return kSTAFInvalidObject;
1491 
1492     if (whichLess == 0) return kSTAFInvalidParm;
1493 
1494     unsigned int min = (aFirst->fByteLen <= aSecond->fByteLen ?
1495                         aFirst->fByteLen : aSecond->fByteLen);
1496 
1497     int cmp = memcmp(aFirst->pBuffer, aSecond->pBuffer, min);
1498 
1499     if (cmp <  0)
1500         *whichLess = 1;  // first one is less
1501     else if (cmp == 0)
1502     {
1503         // must actually ensure that sizes were equal, otherwise
1504         // mark the shorter one as being the "less" one
1505 
1506         if (aFirst->fByteLen == aSecond->fByteLen)
1507             *whichLess = 0;  // both are equal
1508         else if (aFirst->fByteLen < aSecond->fByteLen)
1509             *whichLess = 1;  // first one is less
1510         else
1511             *whichLess = 2;  // second one is less
1512     }
1513     else if (cmp >  0)
1514         *whichLess = 2;  // second one is less
1515 
1516     return kSTAFOk;
1517 }
1518 
1519 
STAFStringStartsWith(STAFStringConst_t aString,STAFStringConst_t startsWithString,unsigned int * startsWith,unsigned int * osRC)1520 STAFRC_t STAFStringStartsWith(STAFStringConst_t aString,
1521                               STAFStringConst_t startsWithString,
1522                               unsigned int *startsWith,
1523                               unsigned int *osRC)
1524 {
1525     if ((aString == 0) || (startsWithString == 0)) return kSTAFInvalidObject;
1526 
1527     if (startsWith == 0) return kSTAFInvalidParm;
1528 
1529     *startsWith = 0;
1530 
1531     if (aString->fByteLen >= startsWithString->fByteLen)
1532     {
1533         int cmp = memcmp(aString->pBuffer, startsWithString->pBuffer,
1534                          startsWithString->fByteLen);
1535 
1536         if (cmp == 0) *startsWith = 1;
1537     }
1538 
1539     return kSTAFOk;
1540 }
1541 
1542 
STAFStringContainsWildcard(STAFStringConst_t aString,unsigned int * hasWildcard,unsigned int * osRC)1543 STAFRC_t STAFStringContainsWildcard(STAFStringConst_t aString,
1544                                     unsigned int *hasWildcard,
1545                                     unsigned int *osRC)
1546 {
1547     if (aString == 0) return kSTAFInvalidObject;
1548 
1549     if (hasWildcard == 0) return kSTAFInvalidParm;
1550 
1551     *hasWildcard = 0;  // Default to does not contain a wildcard
1552 
1553     unsigned int theIndex = 0;
1554 
1555     STAFRC_t rc = STAFStringFindFirstOf(aString, sWildCards.getImpl(),
1556                                         0, 0, &theIndex, osRC);
1557 
1558     if ((rc == 0) && (theIndex != 0xffffffff))
1559         *hasWildcard = 1;   // Contains a wildcard
1560 
1561     return rc;
1562 }
1563 
1564 
STAFStringMatchesWildcards(STAFStringConst_t stringToCheck,STAFStringConst_t wildcardString,STAFStringCaseSensitive_t caseSensitive,unsigned int * matches,unsigned int * osRC)1565 STAFRC_t STAFStringMatchesWildcards(STAFStringConst_t stringToCheck,
1566                                     STAFStringConst_t wildcardString,
1567                                     STAFStringCaseSensitive_t caseSensitive,
1568                                     unsigned int *matches,
1569                                     unsigned int *osRC)
1570 {
1571     if (stringToCheck == 0) return kSTAFInvalidObject;
1572 
1573     if (matches == 0) return kSTAFInvalidParm;
1574 
1575     STAFRC_t retCode = kSTAFOk;
1576 
1577     try
1578     {
1579         STAFString testString(stringToCheck);
1580         STAFString wcString(wildcardString);
1581 
1582         if (caseSensitive == kSTAFStringCaseInsensitive)
1583         {
1584             testString.upperCase();
1585             wcString.upperCase();
1586         }
1587 
1588         unsigned int currWCIndex = 0;
1589         unsigned int nextWCIndex = 0;
1590         unsigned int wcCharIndex = 0;
1591         STAFString wcData;
1592         STAFString charData;
1593 
1594         unsigned int currTestIndex = 0;
1595         unsigned int nextTestIndex = 0;
1596         unsigned int deltaChars = 0;
1597         unsigned int numQuestions = 0;
1598         bool hasWildcard = false;
1599 
1600         if ((testString.length() == 0) && (wcString.length() == 0))
1601         {
1602             *matches = 1;
1603         }
1604         else if ((testString.length() == 0) &&
1605                  (wcString.findFirstNotOf(sStar) != STAFString::kNPos))
1606         {
1607             *matches = 0;
1608         }
1609         else if (wcString.length() == 0)
1610         {
1611             *matches = 0;
1612         }
1613         else if (wcString == testString)
1614         {
1615             *matches = 1;
1616             return retCode;
1617         }
1618         else if ((wcString.findFirstOf(sStar) == STAFString::kNPos) &&
1619                  (testString.length() != wcString.length()))
1620         {
1621             *matches = 0;
1622         }
1623         else if ((wcString.findFirstOf(sQuestion) != STAFString::kNPos) &&
1624                  (testString.length() < wcString.count(sQuestion)))
1625         {
1626             *matches = 0;
1627         }
1628         else *matches = 1;
1629 
1630         for (;
1631              (*matches != 0) && (currWCIndex < wcString.length()) &&
1632                  (nextTestIndex < testString.length());
1633              currWCIndex = nextWCIndex,
1634                  currTestIndex = nextTestIndex + charData.length())
1635         {
1636             wcCharIndex = wcString.findFirstNotOf(sWildCards, currWCIndex);
1637             wcData = wcString.subString(currWCIndex, wcCharIndex - currWCIndex);
1638             nextWCIndex = wcString.findFirstOf(sWildCards, wcCharIndex);
1639             charData = wcString.subString(wcCharIndex,
1640                                           nextWCIndex - wcCharIndex);
1641             hasWildcard = (wcData.count(sStar) > 0);
1642             numQuestions = wcData.count(sQuestion);
1643 
1644             if (charData.length() != 0)
1645                 nextTestIndex = testString.find(charData,
1646                                                 currTestIndex + numQuestions);
1647             else
1648                 nextTestIndex = testString.length();
1649 
1650             deltaChars = nextTestIndex - currTestIndex;
1651 
1652             if (!hasWildcard && (deltaChars > numQuestions))
1653                 *matches = 0;
1654             else if (nextTestIndex == STAFString::kNPos)
1655                 *matches = 0;
1656             else if (nextWCIndex == STAFString::kNPos)
1657             {
1658                 // Verify remaining characters in wildcard string match
1659                 STAFString wcRemainChars = wcString.subString(wcCharIndex,
1660                                                             wcString.length());
1661 
1662                 if (wcRemainChars.length() != 0)
1663                 {
1664                     if (testString.find(wcRemainChars, testString.length() -
1665                         wcRemainChars.length()) == STAFString::kNPos)
1666                     {
1667                         *matches = 0;
1668                     }
1669                 }
1670                 else if (currTestIndex == testString.length() && wcData == "?")
1671                 {
1672                     *matches = 0;
1673                 }
1674             }
1675         }
1676     }
1677     catch (...)
1678     { retCode = kSTAFUnknownError; }
1679 
1680     return retCode;
1681 }
1682 
1683 
STAFStringFind(STAFStringConst_t aString,STAFStringConst_t aSubStr,unsigned int index,unsigned int corb,unsigned int * pos,unsigned int * osRC)1684 STAFRC_t STAFStringFind(STAFStringConst_t aString,
1685                         STAFStringConst_t aSubStr,
1686                         unsigned int index, unsigned int corb,
1687                         unsigned int *pos,
1688                         unsigned int *osRC)
1689 {
1690     if ((aString == 0) || (aSubStr == 0)) return kSTAFInvalidObject;
1691 
1692     if (pos == 0) return kSTAFInvalidParm;
1693 
1694     char *ptr = aString->pBuffer;
1695     char *key = aSubStr->pBuffer;
1696     char *lim = aString->pBuffer + aString->fByteLen;
1697 
1698     // default to not found
1699     *pos = 0xffffffff;
1700 
1701     // This is legal.  If the user tries to find a string starting at an
1702     // index that is larger than the size of the string, then the search
1703     // string is simply not found.
1704 
1705     if (index >= (corb ? aString->fByteLen : aString->fCharLen))
1706         return kSTAFOk;
1707 
1708     ptr = FWDN(ptr, index, corb);
1709 
1710     unsigned int loc = index;
1711 
1712     // this is called "the naive search string algorithm",
1713     // I could use something like the Boyer-Moore, or KMP,
1714     // but it may not be worth the extra work for the size
1715     // of string we will be dealing with ;)
1716 
1717     // start searching for the substring, but only look for
1718     // lead byte, when found call memcmp to actually do the
1719     // matching
1720 
1721     while (ptr < lim)
1722     {
1723         // loop until ptr matches key
1724 
1725         while ((ptr < lim) && (*ptr != *key))
1726         {
1727             ptr = NEXT(ptr);
1728             loc++;
1729         }
1730 
1731         // if above limits then not found
1732 
1733         if (ptr >= lim) break;
1734 
1735         // avoid calling memcmp if out-of-bounds memory a-
1736         // reas are going to be touched
1737 
1738         if (ptr + aSubStr->fByteLen > lim)
1739             break;
1740 
1741         if (memcmp(ptr, key, aSubStr->fByteLen) == 0)
1742         {
1743             // if we dealt with chars, return char location,
1744             // else return byte location
1745             *pos = (corb ? ptr - aString->pBuffer : loc);
1746             break;
1747         }
1748 
1749         ptr = NEXT(ptr);
1750         loc++;
1751     }
1752 
1753     return kSTAFOk;
1754 }
1755 
1756 
STAFStringFindFirstOf(STAFStringConst_t aString,STAFStringConst_t aSet,unsigned int index,unsigned int corb,unsigned int * pos,unsigned int * osRC)1757 STAFRC_t STAFStringFindFirstOf(STAFStringConst_t aString,
1758                                STAFStringConst_t aSet,
1759                                unsigned int index, unsigned int corb,
1760                                unsigned int *pos,
1761                                unsigned int *osRC)
1762 {
1763     if ((aString == 0) || (aSet == 0)) return kSTAFInvalidObject;
1764 
1765     if (pos == 0) return kSTAFInvalidParm;
1766 
1767     unsigned int loc = 0;
1768     STAFRC_t rc = kSTAFOk;
1769     char *key = aString->pBuffer;
1770     char *lim = aString->pBuffer + aString->fByteLen;
1771 
1772     *pos = 0xffffffff;  // default to not found
1773 
1774     // if index is beyond string's length, just say not found
1775 
1776     if (index >= (corb ? aString->fByteLen : aString->fCharLen))
1777         return kSTAFOk;
1778 
1779     key = FWDN(key, index, corb);
1780 
1781     loc = index;
1782 
1783     struct STAFStringImplementation wrap;
1784 
1785     while (key < lim)
1786     {
1787         unsigned int pos2;
1788 
1789         wrap.pBuffer  = key;
1790         wrap.fBuffLen = BYTES(key);
1791         wrap.fByteLen = BYTES(key);
1792         wrap.fCharLen = 1;
1793 
1794         rc = STAFStringFind(aSet, &wrap, 0, 0, &pos2, osRC);
1795 
1796         if (rc) break;
1797 
1798         if (pos2 != 0xffffffff)
1799         {
1800             *pos = (corb ? key - aString->pBuffer : loc);
1801             break;
1802         }
1803 
1804         key = NEXT(key);
1805         loc++;
1806     }
1807 
1808     return rc;
1809 }
1810 
1811 
STAFStringFindLastOf(STAFStringConst_t aString,STAFStringConst_t aSet,unsigned int index,unsigned int corb,unsigned int * pos,unsigned int * osRC)1812 STAFRC_t STAFStringFindLastOf(STAFStringConst_t aString,
1813                               STAFStringConst_t aSet,
1814                               unsigned int index, unsigned int corb,
1815                               unsigned int *pos,
1816                               unsigned int *osRC)
1817 {
1818     if ((aString == 0) || (aSet == 0)) return kSTAFInvalidObject;
1819 
1820     if (pos == 0) return kSTAFInvalidParm;
1821 
1822     unsigned int loc = 0;
1823     STAFRC_t rc = kSTAFOk;
1824     char *key = aString->pBuffer + aString->fByteLen;
1825     char *lim = aString->pBuffer;
1826 
1827     *pos = 0xffffffff;  // default to not found
1828 
1829     // if index is beyond string's length, just say not found
1830 
1831     if (index >= (corb ? aString->fByteLen : aString->fCharLen))
1832         return kSTAFOk;
1833 
1834     lim = FWDN(lim, index, corb);
1835     key = REWN(key, 1, corb);
1836 
1837     loc = (corb ? aString->fByteLen - 1 : aString->fCharLen - 1);
1838 
1839     struct STAFStringImplementation wrap;
1840 
1841     while (key >= lim)
1842     {
1843         unsigned int pos2;
1844 
1845         wrap.pBuffer  = key;
1846         wrap.fBuffLen = BYTES(key);
1847         wrap.fByteLen = BYTES(key);
1848         wrap.fCharLen = 1;
1849 
1850         rc = STAFStringFind(aSet, &wrap, 0, 0, &pos2, osRC);
1851 
1852         if (rc) break;
1853 
1854         if (pos2 != 0xffffffff)
1855         {
1856             *pos = (corb ? key - aString->pBuffer : loc);
1857             break;
1858         }
1859 
1860         if (key == lim) break;
1861 
1862         key = PREV(key);
1863         loc--;
1864     }
1865 
1866     return rc;
1867 }
1868 
1869 
STAFStringFindFirstNotOf(STAFStringConst_t aString,STAFStringConst_t aSet,unsigned int index,unsigned int corb,unsigned int * pos,unsigned int * osRC)1870 STAFRC_t STAFStringFindFirstNotOf(STAFStringConst_t aString,
1871                                   STAFStringConst_t aSet,
1872                                   unsigned int index,
1873                                   unsigned int corb,
1874                                   unsigned int *pos,
1875                                   unsigned int *osRC)
1876 {
1877     if ((aString == 0) || (aSet == 0)) return kSTAFInvalidObject;
1878 
1879     if (pos == 0) return kSTAFInvalidParm;
1880 
1881     unsigned int loc = 0;
1882     STAFRC_t rc = kSTAFOk;
1883     char *key = aString->pBuffer;
1884     char *lim = aString->pBuffer + aString->fByteLen;
1885 
1886     *pos = 0xffffffff;  // default to not found
1887 
1888     // if index is beyond string's length, just say not found
1889 
1890     if (index >= (corb ? aString->fByteLen : aString->fCharLen))
1891         return kSTAFOk;
1892 
1893     key = FWDN(key, index, corb);
1894 
1895     loc = index;
1896 
1897     struct STAFStringImplementation wrap;
1898 
1899     while (key < lim)
1900     {
1901         unsigned int pos2;
1902 
1903         wrap.pBuffer  = key;
1904         wrap.fBuffLen = BYTES(key);
1905         wrap.fByteLen = BYTES(key);
1906         wrap.fCharLen = 1;
1907 
1908         rc = STAFStringFind(aSet, &wrap, 0, 0, &pos2, osRC);
1909 
1910         if (rc) break;
1911 
1912         if (pos2 == 0xffffffff)
1913         {
1914             *pos = (corb ? key - aString->pBuffer : loc);
1915             break;
1916         }
1917 
1918         key = NEXT(key);
1919         loc++;
1920     }
1921 
1922     return rc;
1923 }
1924 
1925 
STAFStringFindLastNotOf(STAFStringConst_t aString,STAFStringConst_t aSet,unsigned int index,unsigned int corb,unsigned int * pos,unsigned int * osRC)1926 STAFRC_t STAFStringFindLastNotOf(STAFStringConst_t aString,
1927                                  STAFStringConst_t aSet,
1928                                  unsigned int index,
1929                                  unsigned int corb,
1930                                  unsigned int *pos,
1931                                  unsigned int *osRC)
1932 {
1933     if ((aString == 0) || (aSet == 0)) return kSTAFInvalidObject;
1934 
1935     if (pos == 0) return kSTAFInvalidParm;
1936 
1937     unsigned int loc = 0;
1938     STAFRC_t rc = kSTAFOk;
1939     char *key = aString->pBuffer + aString->fByteLen;
1940     char *lim = aString->pBuffer;
1941 
1942     *pos = 0xffffffff;  // default to not found
1943 
1944     // if index is beyond string's length, just say not found
1945 
1946     if (index >= (corb ? aString->fByteLen : aString->fCharLen))
1947         return kSTAFOk;
1948 
1949     lim = FWDN(lim, index, corb);
1950     key = REWN(key, 1, corb);
1951 
1952     loc = (corb ? aString->fByteLen - 1 : aString->fCharLen - 1);
1953 
1954     struct STAFStringImplementation wrap;
1955 
1956     while (key >= lim)
1957     {
1958         unsigned int pos2;
1959 
1960         wrap.pBuffer  = key;
1961         wrap.fBuffLen = BYTES(key);
1962         wrap.fByteLen = BYTES(key);
1963         wrap.fCharLen = 1;
1964 
1965         rc = STAFStringFind(aSet, &wrap, 0, 0, &pos2, osRC);
1966 
1967         if (rc) break;
1968 
1969         if (pos2 == 0xffffffff)
1970         {
1971             *pos = (corb ? key - aString->pBuffer : loc);
1972             break;
1973         }
1974 
1975         key = PREV(key);
1976         loc--;
1977     }
1978 
1979     return rc;
1980 }
1981 
1982 
STAFStringDestruct(STAFString_t * pString,unsigned int * osRC)1983 STAFRC_t STAFStringDestruct(STAFString_t *pString, unsigned int *osRC)
1984 {
1985     if (pString == 0) return kSTAFInvalidObject;
1986 
1987     if ((*pString)->pBuffer != EMPTY_STRING)
1988         delete[] (*pString)->pBuffer;
1989 
1990     delete *pString;
1991 
1992     *pString = 0;
1993 
1994     return kSTAFOk;
1995 }
1996 
1997 
STAFStringFreeBuffer(const char * buffer,unsigned int * osRC)1998 STAFRC_t STAFStringFreeBuffer(const char *buffer, unsigned int *osRC)
1999 {
2000     if (buffer == 0) return kSTAFInvalidObject;
2001 
2002     // Note: WIN32 doesn't overload delete[] for const char* so we need
2003     // to cast it
2004     delete[] (char *)buffer;
2005 
2006     return kSTAFOk;
2007 }
2008