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