Coverage Report

Created: 2026-01-10 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dng_sdk/source/dng_string.cpp
Line
Count
Source
1
/*****************************************************************************/
2
// Copyright 2006-2007 Adobe Systems Incorporated
3
// All Rights Reserved.
4
//
5
// NOTICE:  Adobe permits you to use, modify, and distribute this file in
6
// accordance with the terms of the Adobe license agreement accompanying it.
7
/*****************************************************************************/
8
9
/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_string.cpp#2 $ */ 
10
/* $DateTime: 2012/07/31 22:04:34 $ */
11
/* $Change: 840853 $ */
12
/* $Author: tknoll $ */
13
14
/*****************************************************************************/
15
16
#include "dng_string.h"
17
18
#include "dng_assertions.h"
19
#include "dng_exceptions.h"
20
#include "dng_flags.h"
21
#include "dng_mutex.h"
22
#include "dng_utils.h"
23
#include "dng_safe_arithmetic.h"
24
25
#if qMacOS
26
#include <TargetConditionals.h>
27
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
28
#include <MobileCoreServices/MobileCoreServices.h>
29
#else
30
#include <CoreServices/CoreServices.h>
31
#endif  // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
32
#endif  // qMacOS
33
34
#if qWinOS
35
#include <windows.h>
36
#endif
37
38
#if qiPhone || qAndroid || qLinux
39
#include <ctype.h> // for isdigit
40
#endif
41
42
/*****************************************************************************/
43
44
const uint32 kREPLACEMENT_CHARACTER = 0x0000FFFD;
45
46
/*****************************************************************************/
47
48
// Returns the length of the zero-terminated string 's'. Throws a dng_exception
49
// if the length of 's' is too large to be represented as a uint32_t.
50
static uint32 strlenAsUint32(const char *s)
51
10.1M
  {
52
  
53
10.1M
  uint32 lengthAsUint32 = 0;
54
10.1M
  ConvertUnsigned(strlen(s), &lengthAsUint32);
55
  
56
10.1M
  return lengthAsUint32;
57
  
58
10.1M
  }
59
60
// Checks whether there is enough space left in the buffer pointed to by
61
// 'currentPos' to write at least 'space' elements of type T (to positions
62
// currentPos[0] through currentPos[space - 1]. Throws a dng_exception if there
63
// is not enough space left in the buffer.
64
// 'bufferEnd' should point one element beyond the end of the buffer. For
65
// example, if the buffer is "T buffer[3];", then bufferEnd should point to
66
// T + 3.
67
template <class T>
68
static void CheckSpaceLeftInBuffer(const T *currentPos,
69
                   const T *bufferEnd,
70
                   size_t space)
71
32.9M
  {
72
  
73
32.9M
  if (bufferEnd < currentPos || static_cast<size_t>(bufferEnd - currentPos) < space)
74
0
    {
75
0
    ThrowMemoryFull ("Buffer overrun");
76
0
    }
77
  
78
32.9M
  }
dng_string.cpp:void CheckSpaceLeftInBuffer<unsigned char>(unsigned char const*, unsigned char const*, unsigned long)
Line
Count
Source
71
32.8M
  {
72
  
73
32.8M
  if (bufferEnd < currentPos || static_cast<size_t>(bufferEnd - currentPos) < space)
74
0
    {
75
0
    ThrowMemoryFull ("Buffer overrun");
76
0
    }
77
  
78
32.8M
  }
dng_string.cpp:void CheckSpaceLeftInBuffer<unsigned short>(unsigned short const*, unsigned short const*, unsigned long)
Line
Count
Source
71
7.46k
  {
72
  
73
7.46k
  if (bufferEnd < currentPos || static_cast<size_t>(bufferEnd - currentPos) < space)
74
0
    {
75
0
    ThrowMemoryFull ("Buffer overrun");
76
0
    }
77
  
78
7.46k
  }
Unexecuted instantiation: dng_string.cpp:void CheckSpaceLeftInBuffer<char>(char const*, char const*, unsigned long)
79
80
/*****************************************************************************/
81
82
// Throws an exception to notify the user of code that has not been security
83
// hardened and prevent execution of that code.
84
//
85
// Though the DNG SDK in general has been security-hardened, this does not apply
86
// to the following Mac-OS- and Windows-specific functions. Calls to
87
// ThrowNotHardened() have been added to these functions to alert callers of
88
// this fact.
89
//
90
// If you're trying to use a function that calls ThrowNotHardened(), you need to
91
// fix the security issues noted in the comment next to the ThrowNotHardened()
92
// call. Once you have fixed these issues, obtain a security review for the
93
// fixes. This may require fuzzing of the modified code on the target platform.
94
static void ThrowNotHardened()
95
0
  {
96
0
  ThrowProgramError ("This function has not been security-hardened");
97
0
  }
98
99
#if qMacOS
100
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
101
102
static uint32 Extract_SystemEncoding (const dng_string &dngString,
103
                      dng_memory_data &buffer)
104
  {
105
    // TODO: Needs implementation.
106
    ThrowProgramError ("Extract_SystemEncoding() not implemented on iOS");
107
    return 0;
108
  }
109
110
static void Assign_SystemEncoding (dng_string &dngString,
111
                     const char *otherString)
112
  {
113
    // TODO: Needs implementation.
114
    ThrowProgramError ("Assign_SystemEncoding() not implemented on iOS");
115
116
  }
117
118
static void Assign_JIS_X208_1990 (dng_string &dngString,
119
                    const char *otherString)
120
  {
121
    // TODO: Needs implementation.
122
    ThrowProgramError ("Assign_JIS_X208_1990() not implemented on iOS");
123
  }
124
125
#else
126
127
static void Assign_Multibyte (dng_string &dngString,
128
                const char *otherString,
129
                TextEncoding encoding)
130
  {
131
  
132
  // This function contains security-vulnerable code. Do not use.
133
  // The particular vulnerabilities are:
134
  // - Casting the result of strlen() to a uint32 may case truncation. (Use
135
  //   strlenAsUint32() instead.)
136
  // - The computation of aBufSize and the subsequent addition of 1 in the
137
  //   call to the dng_memory_data constructor may wrap around.
138
  ThrowNotHardened();
139
  
140
  uint32 aSize = (uint32) strlen (otherString);
141
  
142
  if (aSize > 0)
143
    {
144
    
145
    uint32 aBufSize = aSize * 6 + 256;
146
    
147
    dng_memory_data aBuf (aBufSize + 1);
148
    
149
    UnicodeMapping aMapping;
150
    
151
    aMapping.unicodeEncoding = ::CreateTextEncoding (kTextEncodingUnicodeV3_0,
152
                             kUnicodeNoSubset,
153
                             kUnicodeUTF8Format);
154
                             
155
    aMapping.otherEncoding   = encoding;
156
    aMapping.mappingVersion  = kUnicodeUseLatestMapping;
157
158
    TextToUnicodeInfo aInfo = NULL;
159
    
160
    if (::CreateTextToUnicodeInfo (&aMapping, &aInfo) == noErr)
161
      {
162
    
163
      ByteCount aInput  = 0;
164
      ByteCount aOutput = 0;
165
      
166
      ::ConvertFromTextToUnicode (aInfo,
167
                    aSize,
168
                      otherString,
169
                      kUnicodeUseFallbacksMask |
170
                      kUnicodeLooseMappingsMask,
171
                      0,
172
                      NULL,
173
                      NULL,
174
                      NULL,
175
                      aBufSize,
176
                      &aInput,
177
                      &aOutput,
178
                      (UniChar *) aBuf.Buffer ());
179
                     
180
      ::DisposeTextToUnicodeInfo (&aInfo);
181
      
182
      if (aOutput > 0 && aOutput <= aBufSize)
183
        {
184
      
185
        char *aBufChar = aBuf.Buffer_char ();
186
      
187
        aBufChar [aOutput] = 0;
188
        
189
        dngString.Set (aBufChar);
190
        
191
        return;
192
        
193
        }
194
              
195
      }
196
197
    }
198
    
199
  dngString.Clear ();
200
201
  }
202
203
static uint32 Extract_Multibyte (const dng_string &dngString,
204
                   dng_memory_data &buffer,
205
                   TextEncoding encoding)
206
  {
207
  
208
  // This function contains security-vulnerable code. Do not use.
209
  // The particular vulnerabilities are:
210
  // - The computation of aBufSize may wrap around.
211
  // - The computation of the argument to buffer.Allocate() may overflow; the
212
  //   conversion to uint32 is also problematic.
213
  // - The signed-to-unsigned conversion in the return statement "
214
  //   return (uint32) aOutput;" may be problematic.
215
  ThrowNotHardened();
216
  
217
  uint32 aSize = dngString.Length ();
218
  
219
  if (aSize > 0)
220
    {
221
  
222
    uint32 aBufSize = (aSize * 2) + 256;
223
    
224
    dng_memory_data tempBuffer (aBufSize);
225
    
226
    UnicodeMapping aMapping;
227
    
228
    aMapping.unicodeEncoding = ::CreateTextEncoding (kTextEncodingUnicodeV3_0,
229
                             kUnicodeNoSubset,
230
                             kUnicodeUTF8Format);
231
                             
232
    aMapping.otherEncoding   = encoding;
233
    aMapping.mappingVersion  = kUnicodeUseLatestMapping;
234
235
    UnicodeToTextInfo aInfo = NULL;
236
    
237
    if (::CreateUnicodeToTextInfo (&aMapping, &aInfo) == noErr)
238
      {
239
      
240
      ByteCount aInput  = 0;
241
      ByteCount aOutput = 0;
242
      
243
      ::ConvertFromUnicodeToText (aInfo,
244
                    aSize,
245
                    (const UniChar *) dngString.Get (),
246
                      kUnicodeUseFallbacksMask  |
247
                      kUnicodeLooseMappingsMask |
248
                      kUnicodeDefaultDirectionMask,
249
                      0,
250
                      NULL,
251
                      NULL,
252
                      NULL,
253
                      aBufSize,
254
                      &aInput,
255
                      &aOutput,
256
                      tempBuffer.Buffer_char ());
257
                      
258
      ::DisposeUnicodeToTextInfo (&aInfo);
259
      
260
      if (aOutput > 0)
261
        {
262
        
263
        buffer.Allocate ((uint32) (aOutput + 1));
264
        
265
        memcpy (buffer.Buffer (),
266
            tempBuffer.Buffer (),
267
            aOutput);
268
            
269
        buffer.Buffer_char () [aOutput] = 0;
270
        
271
        return (uint32) aOutput;
272
        
273
        }
274
        
275
      }
276
      
277
    }
278
    
279
  buffer.Allocate (1);
280
  
281
  buffer.Buffer_char () [0] = 0;
282
  
283
  return 0;
284
  
285
  }
286
  
287
static void Assign_SystemEncoding (dng_string &dngString,
288
                     const char *otherString)
289
  { 
290
  
291
  TextEncoding aEncoding;
292
  
293
  ::UpgradeScriptInfoToTextEncoding (smSystemScript,
294
                     kTextLanguageDontCare,
295
                     kTextRegionDontCare,
296
                     NULL,
297
                     &aEncoding);
298
                     
299
  Assign_Multibyte (dngString,
300
            otherString,
301
            aEncoding);
302
303
  }
304
  
305
static uint32 Extract_SystemEncoding (const dng_string &dngString,
306
                      dng_memory_data &buffer)
307
  { 
308
  
309
  TextEncoding aEncoding;
310
  
311
  ::UpgradeScriptInfoToTextEncoding (smSystemScript,
312
                     kTextLanguageDontCare,
313
                     kTextRegionDontCare,
314
                     NULL,
315
                     &aEncoding);
316
                     
317
  return Extract_Multibyte (dngString,
318
                  buffer,
319
                  aEncoding);
320
321
  }
322
  
323
static void Assign_JIS_X208_1990 (dng_string &dngString,
324
                    const char *otherString)
325
  {
326
  
327
  Assign_Multibyte (dngString,
328
            otherString,
329
            kTextEncodingJIS_X0208_90);
330
331
  }
332
333
#endif  // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
334
#endif  // qMacOS
335
336
/*****************************************************************************/
337
338
#if qWinOS
339
340
static void Assign_Multibyte (dng_string &dngString,
341
                const char *otherString,
342
                UINT encoding)
343
  {
344
  
345
  // This function contains security-vulnerable code. Do not use.
346
  // The particular vulnerabilities are:
347
  // - Converting the return value of strlen() to int may cause overflow.
348
  // - The computation of aBufChars and of the argument to the dng_memory_data
349
  //   constructor may overflow. Additionally, there is an implicit
350
  //   signed-to-unsigned conversion in the call to the dng_memory_data
351
  //   constructor.
352
  ThrowNotHardened();
353
  
354
  DNG_ASSERT (sizeof (WCHAR) == 2, "WCHAR must be 2 bytes");
355
  
356
  int aSize = (int) strlen (otherString);
357
  
358
  if (aSize > 0)
359
    {
360
    
361
    int aBufChars = aSize * 3 + 128;
362
    
363
    dng_memory_data aBuf ((aBufChars + 1) << 1);
364
    
365
    int aResult = ::MultiByteToWideChar (encoding,
366
                       0,
367
                       otherString,
368
                       aSize,
369
                       (WCHAR *) aBuf.Buffer (),
370
                       aBufChars);
371
                       
372
    if (aResult > 0 && aResult <= aBufChars)
373
      {
374
      
375
      uint16 * aUTF16 = aBuf.Buffer_uint16 ();
376
      
377
      aUTF16 [aResult] = 0;
378
      
379
      dngString.Set_UTF16 (aUTF16);
380
    
381
      return;
382
      
383
      }
384
      
385
    }
386
    
387
  dngString.Clear ();
388
  
389
  }
390
391
static uint32 Extract_Multibyte (const dng_string &dngString,
392
                   dng_memory_data &buffer,
393
                   UINT encoding)
394
  {
395
  
396
  // This function contains security-vulnerable code. Do not use.
397
  // The particular vulnerabilities are:
398
  // - Converting the return value of dngString.Get_UTF16() may cause
399
  //   overflow.
400
  // - The computation of dBufSize may overflow.
401
  // - The calls to the dng_memory_data constructor and to buffer.Allocate()
402
  //   trigger implicit conversions of int to uint32 that may be problematic.
403
  // - The memcpy() call triggers an implicit conversion of aResult to a
404
  //   size_t, which may be problematic.
405
  // - The conversion of aResult to a uint32 in the return statement may be
406
  //   problematic.
407
  ThrowNotHardened();
408
  
409
  DNG_ASSERT (sizeof (WCHAR) == 2, "WCHAR must be 2 bytes");
410
  
411
  dng_memory_data sBuffer;
412
  
413
  int aCount = dngString.Get_UTF16 (sBuffer);
414
  
415
  int dBufSize = aCount * 2 + 256;
416
  
417
  dng_memory_data dBuffer (dBufSize);
418
  
419
  int aResult = ::WideCharToMultiByte (encoding,
420
                     0,
421
                     (WCHAR *) sBuffer.Buffer (),
422
                     aCount,
423
                     dBuffer.Buffer_char (),
424
                     dBufSize,
425
                     NULL,
426
                     NULL);
427
                     
428
  if (aResult < 0)
429
    aResult = 0;
430
    
431
  buffer.Allocate (aResult + 1);
432
  
433
  memcpy (buffer.Buffer (),
434
      dBuffer.Buffer (),
435
      aResult);
436
      
437
  buffer.Buffer_char () [aResult] = 0;
438
439
  return (uint32) aResult;
440
  
441
  }
442
443
static void Assign_SystemEncoding (dng_string &dngString,
444
                     const char *otherString)
445
  { 
446
  
447
  Assign_Multibyte (dngString,
448
            otherString,
449
            ::GetACP ());
450
451
  }
452
  
453
static uint32 Extract_SystemEncoding (const dng_string &dngString,
454
                      dng_memory_data &buffer)
455
  { 
456
  
457
  return Extract_Multibyte (dngString,
458
                  buffer,
459
                  ::GetACP ());
460
461
  }
462
  
463
static void Assign_JIS_X208_1990 (dng_string &dngString,
464
                    const char *otherString)
465
  {
466
  
467
  // From MSDN documentation: 20932 = JIS X 0208-1990 & 0121-1990
468
  
469
  const UINT kJIS = 20932;
470
  
471
  Assign_Multibyte (dngString,
472
            otherString,
473
            kJIS);
474
475
  }
476
477
#endif
478
479
/*****************************************************************************/
480
481
static bool IsASCII (const char *s)
482
875k
  {
483
  
484
875k
  if (!s)
485
18.2k
    {
486
    
487
18.2k
    return true;
488
    
489
18.2k
    }
490
  
491
4.21M
  while (true)
492
4.21M
    {
493
    
494
4.21M
    uint8 c = (uint8) *(s++);
495
    
496
4.21M
    if (c == 0)
497
644k
      {
498
      
499
644k
      break;
500
      
501
644k
      }
502
    
503
3.57M
    if (c & 0x80)
504
213k
      {
505
      
506
213k
      return false;
507
      
508
213k
      }
509
      
510
3.57M
    }
511
    
512
644k
  return true;
513
  
514
857k
  }
515
516
/*****************************************************************************/
517
518
dng_string::dng_string ()
519
520
34.2M
  : fData ()
521
  
522
34.2M
  {
523
  
524
34.2M
  }
525
526
/*****************************************************************************/
527
528
dng_string::dng_string (const dng_string &s)
529
530
5.57M
  : fData ()
531
  
532
5.57M
  {
533
  
534
5.57M
  Set (s.Get ());
535
  
536
5.57M
  }
537
538
/*****************************************************************************/
539
540
dng_string & dng_string::operator= (const dng_string &s)
541
11.5k
  {
542
  
543
11.5k
  if (this != &s)
544
11.5k
    {
545
    
546
11.5k
    Set (s.Get ());
547
        
548
11.5k
    }
549
    
550
11.5k
  return *this;
551
  
552
11.5k
  }
553
554
/*****************************************************************************/
555
556
dng_string::~dng_string ()
557
39.8M
  {
558
  
559
39.8M
  }
560
        
561
/*****************************************************************************/
562
563
const char * dng_string::Get () const
564
11.7M
  {
565
  
566
11.7M
  if (fData.Buffer ())
567
1.28M
    {
568
    
569
1.28M
    return fData.Buffer_char ();
570
    
571
1.28M
    }
572
    
573
10.5M
  return "";
574
  
575
11.7M
  }
576
577
/*****************************************************************************/
578
579
bool dng_string::IsASCII () const
580
340k
  {
581
  
582
340k
  return ::IsASCII (Get ());
583
    
584
340k
  }
585
    
586
/*****************************************************************************/
587
588
void dng_string::Set (const char *s)
589
6.91M
  {
590
  
591
  // Measure the new length.
592
  
593
6.91M
  uint32 newLen = (s != NULL ? strlenAsUint32 (s) : 0);
594
  
595
  // If it is a NULL string, then clear the buffer.
596
  
597
6.91M
  if (newLen == 0)
598
5.93M
    {
599
    
600
5.93M
    fData.Clear ();
601
    
602
5.93M
    }
603
    
604
  // Else we need to copy the bytes.
605
  
606
979k
  else
607
979k
    {
608
  
609
979k
    uint32 oldLen = Length ();
610
      
611
    // We might be setting this string to a sub-string of itself,
612
    // so don't reallocate the data unless the string is getting
613
    // longer.
614
    
615
979k
    if (newLen > oldLen)
616
902k
      {
617
      
618
902k
      fData.Clear ();
619
      
620
902k
      fData.Allocate (SafeUint32Add (newLen, 1));
621
      
622
902k
      }
623
      
624
979k
    char *d = fData.Buffer_char ();
625
      
626
51.2M
    for (uint32 k = 0; k <= newLen; k++)
627
50.2M
      {
628
      
629
50.2M
      d [k] = s [k];
630
      
631
50.2M
      }
632
      
633
979k
    }
634
        
635
6.91M
  }
636
637
/*****************************************************************************/
638
639
void dng_string::Set_ASCII (const char *s)
640
55.6k
  {
641
  
642
55.6k
  if (::IsASCII (s))
643
55.6k
    {
644
    
645
55.6k
    Set (s);
646
    
647
55.6k
    }
648
    
649
24
  else
650
24
    {
651
  
652
24
    Set_SystemEncoding (s);
653
654
24
    }
655
  
656
55.6k
  }
657
    
658
/*****************************************************************************/
659
660
void dng_string::Set_UTF8 (const char *s)
661
10.7k
  {
662
  
663
10.7k
  uint32 len = strlenAsUint32 (s);
664
  
665
10.7k
  const char *sEnd = s + len;
666
  
667
  // Worst case expansion is 1-byte characters expanding to
668
  // replacement character, which requires 3 bytes.
669
  
670
10.7k
  const uint32 destBufferLength = SafeUint32Add (SafeUint32Mult (len, 3), 1);
671
10.7k
  dng_memory_data buffer (destBufferLength);
672
  
673
10.7k
  uint8 *d = buffer.Buffer_uint8 ();
674
10.7k
  uint8 * const destEnd = d + destBufferLength;
675
  
676
3.24M
  while (s < sEnd)
677
3.23M
    {
678
    
679
3.23M
    uint32 aChar = DecodeUTF8 (s, (uint32) (sEnd - s));
680
    
681
3.23M
    if (aChar > 0x7FFFFFFF)
682
0
      {
683
0
      aChar = kREPLACEMENT_CHARACTER;
684
0
      }
685
      
686
    #if qDNGValidate
687
    
688
    if (aChar == kREPLACEMENT_CHARACTER)
689
      {
690
      ReportWarning ("Expected UTF-8 value is not valid UTF-8 (or contains a kREPLACEMENT_CHARACTER)");
691
      }
692
    
693
    #endif
694
      
695
3.23M
    if (aChar < 0x00000080) 
696
3.21M
      {
697
3.21M
      CheckSpaceLeftInBuffer (d, destEnd, 1);
698
3.21M
      *(d++) = (uint8) aChar;
699
3.21M
      }
700
      
701
17.8k
    else if (aChar < 0x00000800)
702
8.19k
      {
703
8.19k
      CheckSpaceLeftInBuffer (d, destEnd, 2);
704
8.19k
      *(d++) = (uint8) ((aChar >> 6) | 0x000000C0);
705
8.19k
      *(d++) = (uint8) ((aChar & 0x0000003F) | 0x00000080);
706
8.19k
      }
707
      
708
9.63k
    else if (aChar < 0x00010000)
709
3.30k
      {
710
3.30k
      CheckSpaceLeftInBuffer (d, destEnd, 3);
711
3.30k
      *(d++) = (uint8) ( (aChar >> 12) | 0x000000E0);
712
3.30k
      *(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
713
3.30k
      *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
714
3.30k
      }
715
      
716
6.33k
    else if (aChar < 0x00200000)
717
6.33k
      {
718
6.33k
      CheckSpaceLeftInBuffer (d, destEnd, 4);
719
6.33k
      *(d++) = (uint8) ( (aChar >> 18) | 0x000000F0);
720
6.33k
      *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
721
6.33k
      *(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
722
6.33k
      *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
723
6.33k
      }
724
      
725
0
    else if (aChar < 0x04000000)
726
0
      {
727
0
      CheckSpaceLeftInBuffer (d, destEnd, 5);
728
0
      *(d++) = (uint8) ( (aChar >> 24) | 0x000000F8);
729
0
      *(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
730
0
      *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
731
0
      *(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
732
0
      *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
733
0
      }
734
      
735
0
    else
736
0
      {
737
0
      CheckSpaceLeftInBuffer (d, destEnd, 6);
738
0
      *(d++) = (uint8) ( (aChar >> 30) | 0x000000FC);
739
0
      *(d++) = (uint8) (((aChar >> 24) & 0x0000003F) | 0x00000080);
740
0
      *(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
741
0
      *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
742
0
      *(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
743
0
      *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
744
0
      }
745
      
746
3.23M
    }
747
    
748
10.7k
  CheckSpaceLeftInBuffer (d, destEnd, 1);
749
10.7k
  *d = 0;
750
  
751
10.7k
  Set (buffer.Buffer_char ());
752
  
753
10.7k
  }
754
  
755
/*****************************************************************************/
756
757
uint32 dng_string::Get_SystemEncoding (dng_memory_data &buffer) const
758
0
  {
759
  
760
0
  if (IsASCII ())
761
0
    {
762
    
763
0
    uint32 len = Length ();
764
    
765
0
    const uint32 destBufferLength = SafeUint32Add (len, 1);
766
0
    buffer.Allocate (destBufferLength);
767
768
0
    memcpy (buffer.Buffer (), Get (), destBufferLength);
769
    
770
0
    return len;
771
    
772
0
    }
773
    
774
0
  else
775
0
    {
776
    
777
    #if qMacOS || qWinOS
778
    
779
    return Extract_SystemEncoding (*this, buffer);
780
    
781
    #else
782
    
783
    // Fallback logic to force the string to ASCII.
784
    
785
0
    dng_string temp (*this);
786
    
787
0
    temp.ForceASCII ();
788
    
789
0
    return temp.Get_SystemEncoding (buffer);
790
    
791
0
    #endif
792
    
793
0
    }
794
  
795
0
  }
796
    
797
/*****************************************************************************/
798
799
void dng_string::Set_SystemEncoding (const char *s)
800
99.8k
  {
801
  
802
99.8k
  if (::IsASCII (s))
803
0
    {
804
    
805
0
    Set (s);
806
    
807
0
    }
808
    
809
99.8k
  else
810
99.8k
    {
811
    
812
    #if qMacOS || qWinOS
813
  
814
    Assign_SystemEncoding (*this, s);
815
    
816
    #else
817
    
818
    // Fallback logic that just grabs the ASCII characters and
819
    // ignores the non-ASCII characters.
820
    
821
99.8k
    uint32 len = strlenAsUint32 (s);
822
    
823
99.8k
    const uint32 destBufferLength = SafeUint32Add (len, 1);
824
99.8k
    dng_memory_data buffer (destBufferLength);
825
    
826
99.8k
    uint8 *d = buffer.Buffer_uint8 ();
827
99.8k
    uint8 * const destEnd = d + destBufferLength;
828
    
829
31.2M
    while (*s)
830
31.1M
      {
831
      
832
31.1M
      uint8 c = (uint8) *(s++);
833
      
834
31.1M
      if ((c & 0x80) == 0)
835
28.9M
        {
836
        
837
28.9M
        CheckSpaceLeftInBuffer (d, destEnd, 1);
838
28.9M
        *(d++) = c;
839
        
840
28.9M
        }
841
        
842
31.1M
      }
843
      
844
99.8k
    CheckSpaceLeftInBuffer (d, destEnd, 1);
845
99.8k
    *d = 0;
846
    
847
99.8k
    Set (buffer.Buffer_char ());
848
      
849
99.8k
    #endif
850
  
851
99.8k
    }
852
853
99.8k
  }
854
    
855
/*****************************************************************************/
856
857
bool dng_string::ValidSystemEncoding () const
858
0
  {
859
  
860
0
  if (IsASCII ())
861
0
    {
862
    
863
0
    return true;
864
    
865
0
    }
866
    
867
0
  dng_memory_data buffer;
868
  
869
0
  Get_SystemEncoding (buffer);
870
  
871
0
  dng_string temp;
872
  
873
0
  temp.Set_SystemEncoding (buffer.Buffer_char ());
874
  
875
0
  return (*this == temp);
876
  
877
0
  }
878
    
879
/*****************************************************************************/
880
881
void dng_string::Set_JIS_X208_1990 (const char *s)
882
919
  {
883
  
884
919
  if (::IsASCII (s))
885
554
    {
886
    
887
554
    Set (s);
888
    
889
554
    }
890
    
891
365
  else
892
365
    {
893
    
894
    #if qMacOS || qWinOS
895
  
896
    Assign_JIS_X208_1990 (*this, s);
897
    
898
    #else
899
    
900
    // Fallback to the ASCII extraction logic.
901
    
902
365
    Set_SystemEncoding (s);
903
    
904
365
    #endif
905
  
906
365
    }
907
  
908
919
  }
909
910
/*****************************************************************************/
911
912
uint32 dng_string::DecodeUTF8 (const char *&s,
913
                 uint32 maxBytes,
914
                 bool *isValid)
915
7.81M
  {
916
  
917
7.81M
  static const uint8 gUTF8Bytes [256] =
918
7.81M
    {
919
7.81M
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
920
7.81M
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
921
7.81M
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
922
7.81M
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
923
7.81M
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
924
7.81M
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
925
7.81M
    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
926
7.81M
    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0
927
7.81M
    };
928
    
929
7.81M
  if (isValid)
930
4.57M
    {
931
4.57M
    *isValid = true;
932
4.57M
    }
933
      
934
7.81M
  const uint8 *nBuf = (const uint8 *) s;
935
  
936
7.81M
  uint32 aChar = nBuf [0];
937
  
938
7.81M
  uint32 aSize = gUTF8Bytes [aChar];
939
  
940
7.81M
  if (aSize > maxBytes)
941
12.9k
    {
942
    
943
12.9k
    s += maxBytes;
944
    
945
12.9k
    if (isValid)
946
12.9k
      {
947
12.9k
      *isValid = false;
948
12.9k
      }
949
      
950
12.9k
    return kREPLACEMENT_CHARACTER;
951
    
952
12.9k
    }
953
    
954
7.80M
  s += aSize;
955
956
7.92M
  for (uint32 extra = 1; extra < aSize; extra++)
957
149k
    {
958
    
959
149k
    if ((nBuf [extra] & 0xC0) != 0x80)
960
33.1k
      {
961
      
962
33.1k
      if (isValid)
963
33.1k
        {
964
33.1k
        *isValid = false;
965
33.1k
        }
966
        
967
33.1k
      return kREPLACEMENT_CHARACTER;
968
969
33.1k
      }
970
    
971
149k
    }
972
  
973
7.77M
  switch (aSize)
974
7.77M
    {
975
    
976
49.6k
    case 0:
977
49.6k
      {
978
      
979
49.6k
      s++;    // Don't get stuck in infinite loop
980
      
981
49.6k
      if (isValid)
982
49.6k
        {
983
49.6k
        *isValid = false;
984
49.6k
        }
985
      
986
49.6k
      return kREPLACEMENT_CHARACTER;
987
      
988
0
      }
989
      
990
7.66M
    case 1:
991
7.66M
      {
992
      
993
7.66M
      return aChar;
994
      
995
0
      }
996
      
997
26.5k
    case 2:
998
26.5k
      {
999
      
1000
26.5k
      aChar = ((aChar << 6) + nBuf [1]) - (uint32) 0x00003080UL;
1001
      
1002
26.5k
      break;
1003
      
1004
0
      }
1005
      
1006
18.8k
    case 3:
1007
18.8k
      {
1008
      
1009
18.8k
      aChar =  ((((aChar << 6) + nBuf [1])
1010
18.8k
                 << 6) + nBuf [2]) - (uint32) 0x000E2080UL;
1011
                 
1012
18.8k
      break;
1013
      
1014
0
      }
1015
               
1016
15.9k
    case 4:
1017
15.9k
      {
1018
      
1019
15.9k
      aChar = ((((((aChar << 6) + nBuf [1])
1020
15.9k
                  << 6) + nBuf [2])
1021
15.9k
                << 6) + nBuf [3]) - (uint32) 0x03C82080UL;
1022
                
1023
15.9k
      break;
1024
      
1025
0
      }
1026
7.77M
    }
1027
    
1028
61.2k
  if (aChar < 0x7F || aChar > 0x0010FFFF)
1029
3.65k
    {
1030
    
1031
3.65k
    if (isValid)
1032
3.65k
      {
1033
3.65k
      *isValid = false;
1034
3.65k
      }
1035
    
1036
3.65k
    return kREPLACEMENT_CHARACTER;
1037
      
1038
3.65k
    }
1039
  
1040
57.5k
  return aChar;
1041
  
1042
61.2k
  }
1043
1044
/*****************************************************************************/
1045
1046
bool dng_string::IsUTF8 (const char *s)
1047
110k
  {
1048
  
1049
110k
  uint32 len = strlenAsUint32 (s);
1050
  
1051
110k
  const char *sEnd = s + len;
1052
  
1053
4.58M
  while (s < sEnd)
1054
4.57M
    {
1055
    
1056
4.57M
    bool isValid = true;
1057
    
1058
4.57M
    (void) DecodeUTF8 (s, (uint32) (sEnd - s), &isValid);
1059
    
1060
4.57M
    if (!isValid)
1061
99.4k
      {
1062
99.4k
      return false;
1063
99.4k
      }
1064
      
1065
4.57M
    }
1066
  
1067
10.7k
  return true;
1068
  
1069
110k
  }
1070
1071
/*****************************************************************************/
1072
1073
void dng_string::Set_UTF8_or_System (const char *s)
1074
378k
  {
1075
  
1076
378k
  if (::IsASCII (s))
1077
268k
    {
1078
    
1079
268k
    Set (s);
1080
    
1081
268k
    }
1082
    
1083
110k
  else if (IsUTF8 (s))
1084
10.7k
    {
1085
    
1086
10.7k
    Set_UTF8 (s);
1087
    
1088
10.7k
    }
1089
    
1090
99.4k
  else
1091
99.4k
    {
1092
    
1093
99.4k
    Set_SystemEncoding (s);
1094
    
1095
99.4k
    }
1096
  
1097
378k
  }
1098
1099
/*****************************************************************************/
1100
1101
uint32 dng_string::Get_UTF16 (dng_memory_data &buffer) const
1102
372
  {
1103
  
1104
372
  uint32 count = 0;
1105
  
1106
372
  const char *sPtr = Get ();
1107
  
1108
7.46k
  while (*sPtr)
1109
7.09k
    {
1110
    
1111
7.09k
    uint32 x = DecodeUTF8 (sPtr);
1112
    
1113
7.09k
    if (x <= 0x0000FFFF ||
1114
185
      x >  0x0010FFFF)
1115
6.91k
      {
1116
      
1117
6.91k
      count = SafeUint32Add (count, 1);
1118
      
1119
6.91k
      }
1120
      
1121
185
    else
1122
185
      {
1123
      
1124
185
      count = SafeUint32Add (count, 2);
1125
      
1126
185
      }
1127
      
1128
7.09k
    }
1129
1130
372
  const uint32 destBufferLength = SafeUint32Add (count, 1);
1131
372
  buffer.Allocate (destBufferLength, sizeof (uint16));
1132
  
1133
372
  uint16 *dPtr = buffer.Buffer_uint16 ();
1134
372
  uint16 * const destEnd = dPtr + destBufferLength;
1135
  
1136
372
  sPtr = Get ();
1137
  
1138
7.46k
  while (*sPtr)
1139
7.09k
    {
1140
    
1141
7.09k
    uint32 x = DecodeUTF8 (sPtr);
1142
    
1143
7.09k
    if (x <= 0x0000FFFF)
1144
6.91k
      {
1145
      
1146
6.91k
      CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
1147
6.91k
      *(dPtr++) = (uint16) x;
1148
      
1149
6.91k
      }
1150
    
1151
185
    else if (x > 0x0010FFFF)
1152
0
      {
1153
      
1154
0
      CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
1155
0
      *(dPtr++) = (uint16) kREPLACEMENT_CHARACTER;
1156
      
1157
0
      }
1158
      
1159
185
    else
1160
185
      {
1161
      
1162
185
      x -= 0x00010000;
1163
      
1164
185
      CheckSpaceLeftInBuffer (dPtr, destEnd, 2);
1165
185
      *(dPtr++) = (uint16) ((x >> 10       ) + 0x0000D800);
1166
185
      *(dPtr++) = (uint16) ((x & 0x000003FF) + 0x0000DC00);
1167
      
1168
185
      }
1169
      
1170
7.09k
    }
1171
    
1172
372
  CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
1173
372
  *dPtr = 0;
1174
  
1175
372
  return count;
1176
1177
372
  }
1178
    
1179
/*****************************************************************************/
1180
1181
void dng_string::Set_UTF16 (const uint16 *s)
1182
3.89k
  {
1183
  
1184
3.89k
  if (!s)
1185
0
    {
1186
0
    Clear ();
1187
0
    return;
1188
0
    }
1189
  
1190
3.89k
  bool swap = false;
1191
  
1192
3.89k
  if (s [0] == 0xFFFE)    // Swapped byte order marker
1193
868
    {
1194
868
    swap = true;
1195
868
    s++;
1196
868
    }
1197
    
1198
3.03k
  else if (s [0] == 0xFEFF)  // Non-swapped byte order marker
1199
510
    {
1200
510
    s++;
1201
510
    }
1202
1203
3.89k
  uint32 length16 = 0;
1204
  
1205
603k
  while (s [length16] != 0)
1206
599k
    {
1207
599k
    length16 = SafeUint32Add (length16, 1);
1208
599k
    }
1209
    
1210
3.89k
  const uint16 *sEnd = s + length16;
1211
  
1212
3.89k
  const uint32 destBufferSize =
1213
3.89k
    SafeUint32Add (SafeUint32Mult (length16, 6), 1);
1214
3.89k
  dng_memory_data buffer (destBufferSize);
1215
  
1216
3.89k
  uint8 *d = buffer.Buffer_uint8 ();
1217
3.89k
  uint8 * const destEnd = d + destBufferSize;
1218
  
1219
602k
  while (s < sEnd)
1220
598k
    {
1221
    
1222
598k
    uint32 aChar = *s++;
1223
    
1224
598k
    if (swap)
1225
11.1k
      {
1226
11.1k
      aChar = ((aChar << 8) | (aChar >> 8)) & 0x0000FFFF;
1227
11.1k
      }
1228
      
1229
598k
    if ((aChar >= 0x0000D800) && (aChar <= 0x0000DBFF) && (s < sEnd)) 
1230
13.3k
      {
1231
        
1232
13.3k
      uint32 aLow = *s;
1233
        
1234
13.3k
      if (swap)
1235
1.33k
        {
1236
1.33k
        aLow = ((aLow << 8) | (aLow >> 8)) & 0x0000FFFF;
1237
1.33k
        }
1238
      
1239
13.3k
      if ((aLow >= 0x0000DC00) && (aLow <= 0x0000DFFF))
1240
1.16k
        {
1241
        
1242
1.16k
        aChar = ((aChar - 0x0000D800) << 10) +
1243
1.16k
              (aLow - 0x0000DC00) +
1244
1.16k
              0x00010000;
1245
        
1246
1.16k
        s++;
1247
        
1248
1.16k
        }
1249
        
1250
13.3k
      }
1251
      
1252
598k
    if (aChar > 0x7FFFFFFF)
1253
0
      {
1254
0
      aChar = kREPLACEMENT_CHARACTER;
1255
0
      }
1256
      
1257
598k
    if (aChar < 0x00000080) 
1258
5.33k
      {
1259
5.33k
      CheckSpaceLeftInBuffer (d, destEnd, 1);
1260
5.33k
      *(d++) = (uint8) aChar;
1261
5.33k
      }
1262
      
1263
592k
    else if (aChar < 0x00000800)
1264
16.8k
      {
1265
16.8k
      CheckSpaceLeftInBuffer (d, destEnd, 2);
1266
16.8k
      *(d++) = (uint8) ((aChar >> 6) | 0x000000C0);
1267
16.8k
      *(d++) = (uint8) ((aChar & 0x0000003F) | 0x00000080);
1268
16.8k
      }
1269
      
1270
576k
    else if (aChar < 0x00010000)
1271
574k
      {
1272
574k
      CheckSpaceLeftInBuffer (d, destEnd, 3);
1273
574k
      *(d++) = (uint8) ( (aChar >> 12) | 0x000000E0);
1274
574k
      *(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
1275
574k
      *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
1276
574k
      }
1277
      
1278
1.16k
    else if (aChar < 0x00200000)
1279
1.16k
      {
1280
1.16k
      CheckSpaceLeftInBuffer (d, destEnd, 4);
1281
1.16k
      *(d++) = (uint8) ( (aChar >> 18) | 0x000000F0);
1282
1.16k
      *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
1283
1.16k
      *(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
1284
1.16k
      *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
1285
1.16k
      }
1286
      
1287
0
    else if (aChar < 0x04000000)
1288
0
      {
1289
0
      CheckSpaceLeftInBuffer (d, destEnd, 5);
1290
0
      *(d++) = (uint8) ( (aChar >> 24) | 0x000000F8);
1291
0
      *(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
1292
0
      *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
1293
0
      *(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
1294
0
      *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
1295
0
      }
1296
      
1297
0
    else
1298
0
      {
1299
0
      CheckSpaceLeftInBuffer (d, destEnd, 6);
1300
0
      *(d++) = (uint8) ( (aChar >> 30) | 0x000000FC);
1301
0
      *(d++) = (uint8) (((aChar >> 24) & 0x0000003F) | 0x00000080);
1302
0
      *(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
1303
0
      *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
1304
0
      *(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
1305
0
      *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
1306
0
      }
1307
      
1308
598k
    }
1309
    
1310
3.89k
  CheckSpaceLeftInBuffer (d, destEnd, 1);
1311
3.89k
  *d = 0;
1312
  
1313
3.89k
  Set (buffer.Buffer_char ());
1314
  
1315
3.89k
  }
1316
        
1317
/*****************************************************************************/
1318
1319
void dng_string::Clear ()
1320
214k
  {
1321
  
1322
214k
  Set (NULL);
1323
  
1324
214k
  }
1325
    
1326
/*****************************************************************************/
1327
1328
void dng_string::Truncate (uint32 maxBytes)
1329
40
  {
1330
  
1331
40
  uint32 len = Length ();
1332
  
1333
40
  if (len > maxBytes)
1334
40
    {
1335
    
1336
40
    uint8 *s = fData.Buffer_uint8 ();
1337
    
1338
    // Don't truncate on an extension character.  Extensions characters
1339
    // in UTF-8 have the 0x80 bit set and the 0x40 bit clear.
1340
    
1341
40
    while (maxBytes > 0 && ((s [maxBytes]) & 0xC0) == 0x80)
1342
0
      {
1343
      
1344
0
      maxBytes--;
1345
      
1346
0
      }
1347
      
1348
40
    s [maxBytes] = 0;
1349
    
1350
40
    }
1351
  
1352
40
  }
1353
    
1354
/*****************************************************************************/
1355
1356
bool dng_string::TrimTrailingBlanks ()
1357
250k
  {
1358
  
1359
250k
  bool didTrim = false;
1360
  
1361
250k
  if (fData.Buffer ())
1362
170k
    {
1363
    
1364
170k
    char *s = fData.Buffer_char ();
1365
    
1366
170k
    uint32 len = strlenAsUint32 (s);
1367
    
1368
274k
    while (len > 0 && s [len - 1] == ' ')
1369
104k
      {
1370
104k
      len--;
1371
104k
      didTrim = true;
1372
104k
      }
1373
      
1374
170k
    s [len] = 0;
1375
    
1376
170k
    }
1377
    
1378
250k
  return didTrim;
1379
    
1380
250k
  }
1381
        
1382
/*****************************************************************************/
1383
1384
bool dng_string::TrimLeadingBlanks ()
1385
0
  {
1386
  
1387
0
  bool didTrim = false;
1388
  
1389
0
  const char *s = Get ();
1390
  
1391
0
  while (*s == ' ')
1392
0
    {
1393
0
    s++;
1394
0
    didTrim = true;
1395
0
    }
1396
    
1397
0
  if (didTrim)
1398
0
    {
1399
0
    Set (s);
1400
0
    }
1401
    
1402
0
  return didTrim;
1403
    
1404
0
  }
1405
        
1406
/*****************************************************************************/
1407
1408
bool dng_string::IsEmpty () const
1409
1.95M
  {
1410
  
1411
1.95M
  const char *s = Get ();
1412
  
1413
1.95M
  return *s == 0;
1414
  
1415
1.95M
  }
1416
    
1417
/*****************************************************************************/
1418
1419
uint32 dng_string::Length () const
1420
3.04M
  {
1421
  
1422
3.04M
  const char *s = Get ();
1423
  
1424
3.04M
  return strlenAsUint32 (s);
1425
  
1426
3.04M
  }
1427
1428
/*****************************************************************************/
1429
1430
bool dng_string::operator== (const dng_string &s) const
1431
63.3k
  {
1432
  
1433
63.3k
  const char *s1 =   Get ();
1434
63.3k
  const char *s2 = s.Get ();
1435
  
1436
63.3k
  return strcmp (s1, s2) == 0; 
1437
  
1438
63.3k
  }
1439
1440
/*****************************************************************************/
1441
1442
bool dng_string::Matches (const char *t,
1443
              const char *s,
1444
              bool case_sensitive)
1445
86.3k
  {
1446
  
1447
301k
  while (*s != 0)
1448
272k
    {
1449
    
1450
272k
    char c1 = *(s++);
1451
272k
    char c2 = *(t++);
1452
    
1453
272k
    if (!case_sensitive)
1454
26.8k
      {
1455
26.8k
      c1 = ForceUppercase (c1);
1456
26.8k
      c2 = ForceUppercase (c2);
1457
26.8k
      }
1458
      
1459
272k
    if (c1 != c2)
1460
58.1k
      {
1461
58.1k
      return false;
1462
58.1k
      }
1463
      
1464
272k
    }
1465
    
1466
28.1k
  return (*t == 0);
1467
  
1468
86.3k
  }
1469
1470
/*****************************************************************************/
1471
1472
bool dng_string::Matches (const char *s,
1473
              bool case_sensitive) const
1474
86.3k
  {
1475
  
1476
86.3k
  return dng_string::Matches (Get (), s, case_sensitive);
1477
  
1478
86.3k
  }
1479
1480
/*****************************************************************************/
1481
1482
bool dng_string::StartsWith (const char *s,
1483
                 bool case_sensitive) const
1484
81.7k
  {
1485
  
1486
81.7k
  const char *t = Get ();
1487
  
1488
83.4k
  while (*s != 0)
1489
83.2k
    {
1490
    
1491
83.2k
    char c1 = *(s++);
1492
83.2k
    char c2 = *(t++);
1493
    
1494
83.2k
    if (!case_sensitive)
1495
83.2k
      {
1496
83.2k
      c1 = ForceUppercase (c1);
1497
83.2k
      c2 = ForceUppercase (c2);
1498
83.2k
      }
1499
      
1500
83.2k
    if (c1 != c2)
1501
81.5k
      {
1502
81.5k
      return false;
1503
81.5k
      }
1504
      
1505
83.2k
    }
1506
    
1507
245
  return true;
1508
  
1509
81.7k
  }
1510
1511
/*****************************************************************************/
1512
1513
bool dng_string::EndsWith (const char *s,
1514
               bool case_sensitive) const
1515
2.28k
  {
1516
  
1517
2.28k
  uint32 len1 = Length ();
1518
  
1519
2.28k
  uint32 len2 = strlenAsUint32 (s);
1520
  
1521
2.28k
  if (len1 < len2)
1522
0
    {
1523
0
    return false;
1524
0
    }
1525
    
1526
2.28k
  const char *t = Get () + (len1 - len2);
1527
  
1528
2.29k
  while (*s != 0)
1529
2.29k
    {
1530
    
1531
2.29k
    char c1 = *(s++);
1532
2.29k
    char c2 = *(t++);
1533
    
1534
2.29k
    if (!case_sensitive)
1535
2.29k
      {
1536
2.29k
      c1 = ForceUppercase (c1);
1537
2.29k
      c2 = ForceUppercase (c2);
1538
2.29k
      }
1539
      
1540
2.29k
    if (c1 != c2)
1541
2.28k
      {
1542
2.28k
      return false;
1543
2.28k
      }
1544
      
1545
2.29k
    }
1546
    
1547
0
  return true;
1548
  
1549
2.28k
  }
1550
1551
/*****************************************************************************/
1552
1553
bool dng_string::Contains (const char *s,
1554
               bool case_sensitive,
1555
               int32 *match_offset) const
1556
0
  {
1557
  
1558
0
  if (match_offset)
1559
0
    {
1560
0
    *match_offset = -1;
1561
0
    }
1562
  
1563
0
  uint32 len1 = Length ();
1564
  
1565
0
  uint32 len2 = strlenAsUint32 (s);
1566
  
1567
0
  if (len1 < len2)
1568
0
    {
1569
0
    return false;
1570
0
    }
1571
    
1572
0
  uint32 offsets = len1 - len2;
1573
    
1574
0
  for (uint32 offset = 0; offset <= offsets; offset++)
1575
0
    {
1576
    
1577
0
    const char *ss = s;
1578
0
    const char *tt = Get () + offset;
1579
    
1580
0
    while (*ss != 0)
1581
0
      {
1582
      
1583
0
      char c1 = *(ss++);
1584
0
      char c2 = *(tt++);
1585
      
1586
0
      if (!case_sensitive)
1587
0
        {
1588
0
        c1 = ForceUppercase (c1);
1589
0
        c2 = ForceUppercase (c2);
1590
0
        }
1591
        
1592
0
      if (c1 != c2)
1593
0
        {
1594
0
        goto tryNextOffset;
1595
0
        }
1596
        
1597
0
      }
1598
      
1599
0
    if (match_offset)
1600
0
      {
1601
0
      *match_offset = offset;
1602
0
      }
1603
  
1604
0
    return true;
1605
    
1606
0
    tryNextOffset:  ;
1607
    
1608
0
    }
1609
    
1610
0
  return false;
1611
  
1612
0
  }
1613
    
1614
/*****************************************************************************/
1615
1616
bool dng_string::Replace (const char *old_string,
1617
              const char *new_string,
1618
              bool case_sensitive)
1619
0
  {
1620
  
1621
0
  int32 match_offset = -1;
1622
  
1623
0
  if (Contains (old_string,
1624
0
          case_sensitive,
1625
0
          &match_offset))
1626
0
    {
1627
    
1628
0
    uint32 len1 = Length ();
1629
    
1630
0
    uint32 len2 = strlenAsUint32 (old_string);
1631
0
    uint32 len3 = strlenAsUint32 (new_string);
1632
    
1633
0
    if (len2 == len3)
1634
0
      {
1635
      
1636
0
      strncpy (fData.Buffer_char () + match_offset,
1637
0
           new_string,
1638
0
           len3);
1639
      
1640
0
      }
1641
      
1642
0
    else if (len2 > len3)
1643
0
      {
1644
      
1645
0
      strncpy (fData.Buffer_char () + match_offset,
1646
0
           new_string,
1647
0
           len3);
1648
           
1649
0
      const char *s = fData.Buffer_char () + match_offset + len2;
1650
0
          char *d = fData.Buffer_char () + match_offset + len3;
1651
          
1652
0
      uint32 extra = len1 - match_offset - len2 + 1;  // + 1 for NULL termination
1653
      
1654
0
      for (uint32 j = 0; j < extra; j++)
1655
0
        {
1656
0
        *(d++) = *(s++);
1657
0
        }
1658
      
1659
0
      }
1660
      
1661
0
    else
1662
0
      {
1663
      
1664
      // "len1 - len2" cannot wrap around because we know that if this
1665
      // string contains old_string, len1 >= len2 must hold.
1666
0
      dng_memory_data tempBuffer (
1667
0
        SafeUint32Add (SafeUint32Add (len1 - len2, len3), 1));
1668
      
1669
0
      if (match_offset)
1670
0
        {
1671
        
1672
0
        strncpy (tempBuffer.Buffer_char (),
1673
0
             fData     .Buffer_char (),
1674
0
             match_offset);
1675
             
1676
0
        }
1677
        
1678
0
      if (len3)
1679
0
        {
1680
1681
0
        strncpy (tempBuffer.Buffer_char () + match_offset,
1682
0
             new_string,
1683
0
             len3);
1684
             
1685
0
        }
1686
        
1687
0
      uint32 extra = len1 - match_offset - len2 + 1;  // + 1 for NULL termination
1688
      
1689
0
      strncpy (tempBuffer.Buffer_char () + match_offset + len3,
1690
0
           fData     .Buffer_char () + match_offset + len2,
1691
0
           extra);
1692
           
1693
0
      Set (tempBuffer.Buffer_char ());
1694
1695
0
      }
1696
      
1697
0
    return true;
1698
    
1699
0
    }
1700
    
1701
0
  return false;
1702
  
1703
0
  }
1704
    
1705
/*****************************************************************************/
1706
1707
bool dng_string::TrimLeading (const char *s,
1708
                  bool case_sensitive)
1709
0
  {
1710
  
1711
0
  if (StartsWith (s, case_sensitive))
1712
0
    {
1713
    
1714
0
    Set (Get () + strlenAsUint32 (s));
1715
    
1716
0
    return true;
1717
    
1718
0
    }
1719
  
1720
0
  return false;
1721
  
1722
0
  }
1723
1724
/*****************************************************************************/
1725
1726
void dng_string::Append (const char *s)
1727
13.9k
  {
1728
  
1729
13.9k
  uint32 len2 = strlenAsUint32 (s);
1730
  
1731
13.9k
  if (len2)
1732
13.9k
    {
1733
  
1734
13.9k
    uint32 len1 = Length ();
1735
    
1736
13.9k
    dng_memory_data temp (SafeUint32Add (SafeUint32Add (len1, len2), 1));
1737
    
1738
13.9k
    char *buffer = temp.Buffer_char ();
1739
    
1740
13.9k
    if (len1)
1741
13.9k
      {
1742
13.9k
      memcpy (buffer, Get (), len1);
1743
13.9k
      }
1744
      
1745
13.9k
    memcpy (buffer + len1, s, len2 + 1);
1746
    
1747
13.9k
    Set (buffer);
1748
    
1749
13.9k
    }
1750
  
1751
13.9k
  }
1752
    
1753
/*****************************************************************************/
1754
1755
void dng_string::SetUppercase ()
1756
0
  {
1757
  
1758
0
  if (fData.Buffer ())
1759
0
    {
1760
    
1761
0
    uint32 len = Length ();
1762
    
1763
0
    char *dPtr = fData.Buffer_char ();
1764
    
1765
0
    for (uint32 j = 0; j < len; j++)
1766
0
      {
1767
      
1768
0
      char c = dPtr [j];
1769
      
1770
0
      if (c >= 'a' && c <= 'z')
1771
0
        {
1772
        
1773
0
        dPtr [j] = c - 'a' + 'A';
1774
        
1775
0
        }
1776
        
1777
0
      }
1778
      
1779
0
    }
1780
    
1781
0
  }
1782
    
1783
/*****************************************************************************/
1784
1785
void dng_string::SetLowercase ()
1786
0
  {
1787
  
1788
0
  if (fData.Buffer ())
1789
0
    {
1790
    
1791
0
    uint32 len = Length ();
1792
    
1793
0
    char *dPtr = fData.Buffer_char ();
1794
    
1795
0
    for (uint32 j = 0; j < len; j++)
1796
0
      {
1797
      
1798
0
      char c = dPtr [j];
1799
      
1800
0
      if (c >= 'A' && c <= 'Z')
1801
0
        {
1802
        
1803
0
        dPtr [j] = c - 'A' + 'a';
1804
        
1805
0
        }
1806
        
1807
0
      }
1808
      
1809
0
    }
1810
    
1811
0
  }
1812
    
1813
/*****************************************************************************/
1814
1815
void dng_string::SetLineEndings (char ending)
1816
0
  {
1817
  
1818
0
  if (fData.Buffer ())
1819
0
    {
1820
    
1821
0
    const char *sPtr = fData.Buffer_char ();
1822
0
          char *dPtr = fData.Buffer_char ();
1823
    
1824
0
    while (*sPtr)
1825
0
      {
1826
      
1827
0
      char c = *(sPtr++);
1828
      
1829
0
      char nc = sPtr [0];
1830
      
1831
0
      if ((c == '\r' && nc == '\n') ||
1832
0
        (c == '\n' && nc == '\r'))
1833
0
        {
1834
        
1835
0
        sPtr++;
1836
        
1837
0
        if (ending)
1838
0
          {
1839
0
          *(dPtr++) = ending;
1840
0
          }
1841
        
1842
0
        }
1843
        
1844
0
      else if (c == '\n' ||
1845
0
           c == '\r')
1846
0
        {
1847
        
1848
0
        if (ending)
1849
0
          {
1850
0
          *(dPtr++) = ending;
1851
0
          }
1852
        
1853
0
        }
1854
        
1855
0
      else
1856
0
        {
1857
        
1858
0
        *(dPtr++) = c;
1859
        
1860
0
        }
1861
        
1862
0
      }
1863
      
1864
0
    *dPtr = 0;
1865
    
1866
0
    }
1867
    
1868
0
  }
1869
    
1870
/*****************************************************************************/
1871
1872
void dng_string::StripLowASCII ()
1873
0
  {
1874
  
1875
0
  if (fData.Buffer ())
1876
0
    {
1877
    
1878
0
    const char *sPtr = fData.Buffer_char ();
1879
0
          char *dPtr = fData.Buffer_char ();
1880
    
1881
0
    while (*sPtr)
1882
0
      {
1883
      
1884
0
      char c = *(sPtr++);
1885
      
1886
0
      if (c == '\r' || c == '\n' || (uint8) c >= ' ')
1887
0
        {
1888
        
1889
0
        *(dPtr++) = c;
1890
        
1891
0
        }
1892
              
1893
0
      }
1894
1895
0
    *dPtr = 0;
1896
    
1897
0
    }
1898
    
1899
0
  }
1900
1901
/*****************************************************************************/
1902
1903
void dng_string::NormalizeAsCommaSeparatedNumbers ()
1904
0
  {
1905
  
1906
0
  if (fData.Buffer ())
1907
0
    {
1908
    
1909
0
    const char *sPtr = fData.Buffer_char ();
1910
0
        char *dPtr = fData.Buffer_char ();
1911
    
1912
0
    bool commaInserted = false;
1913
1914
0
    while (*sPtr)
1915
0
      {
1916
      
1917
0
      uint32 c = DecodeUTF8 (sPtr);
1918
      
1919
      // Support number formats such as "3", "+3.0", "-3.1416", "314.16e-2",
1920
      // "0.31416E1", but no hex/octal number representations.
1921
1922
0
      if (isdigit ((int) c) || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E')
1923
0
        {
1924
        
1925
0
        *(dPtr++) = (char) c;
1926
        
1927
0
        if (commaInserted)
1928
0
          {
1929
1930
0
          commaInserted = false;
1931
1932
0
          }
1933
        
1934
0
        } 
1935
1936
0
      else if (!commaInserted) 
1937
0
        {
1938
        
1939
0
        *(dPtr++) = ',';
1940
1941
0
        commaInserted = true;
1942
        
1943
0
        }
1944
      
1945
0
      }
1946
    
1947
0
    *dPtr = 0;
1948
    
1949
0
    }
1950
  
1951
0
  }
1952
1953
/******************************************************************************/
1954
1955
// Unicode to low-ASCII strings table.
1956
1957
struct UnicodeToLowASCIIEntry
1958
  {
1959
  uint32 unicode;
1960
  const char *ascii;
1961
  };
1962
  
1963
static const UnicodeToLowASCIIEntry kUnicodeToLowASCII [] =
1964
  {
1965
  { 0x00A0, " "   },
1966
  { 0x00A1, "!"   },
1967
  { 0x00A9, "(C)" },
1968
  { 0x00AA, "a"   },
1969
  { 0x00AB, "<<"  },
1970
  { 0x00AC, "!"   },
1971
  { 0x00AE, "(R)" },
1972
  { 0x00B0, "dg"  },
1973
  { 0x00B1, "+-"  },
1974
  { 0x00B7, "."   },
1975
  { 0x00BA, "o"   },
1976
  { 0x00BB, ">>"  },
1977
  { 0x00BF, "?"   },
1978
  { 0x00C0, "A"   },
1979
  { 0x00C1, "A"   },
1980
  { 0x00C2, "A"   },
1981
  { 0x00C3, "A"   },
1982
  { 0x00C4, "A"   },
1983
  { 0x00C5, "A"   },
1984
  { 0x00C6, "AE"  },
1985
  { 0x00C7, "C"   },
1986
  { 0x00C8, "E"   },
1987
  { 0x00C9, "E"   },
1988
  { 0x00CA, "E"   },
1989
  { 0x00CB, "E"   },
1990
  { 0x00CC, "I"   },
1991
  { 0x00CD, "I"   },
1992
  { 0x00CE, "I"   },
1993
  { 0x00CF, "I"   },
1994
  { 0x00D1, "N"   },
1995
  { 0x00D2, "O"   },
1996
  { 0x00D3, "O"   },
1997
  { 0x00D4, "O"   },
1998
  { 0x00D5, "O"   },
1999
  { 0x00D6, "O"   },
2000
  { 0x00D8, "O"   },
2001
  { 0x00D9, "U"   },
2002
  { 0x00DA, "U"   },
2003
  { 0x00DB, "U"   },
2004
  { 0x00DC, "U"   },
2005
  { 0x00DD, "Y"   },
2006
  { 0x00E0, "a"   },
2007
  { 0x00E1, "a"   },
2008
  { 0x00E2, "a"   },
2009
  { 0x00E3, "a"   },
2010
  { 0x00E4, "a"   },
2011
  { 0x00E5, "a"   },
2012
  { 0x00E6, "ae"  },
2013
  { 0x00E7, "c"   },
2014
  { 0x00E8, "e"   },
2015
  { 0x00E9, "e"   },
2016
  { 0x00EA, "e"   },
2017
  { 0x00EB, "e"   },
2018
  { 0x00EC, "i"   },
2019
  { 0x00ED, "i"   },
2020
  { 0x00EE, "i"   },
2021
  { 0x00EF, "i"   },
2022
  { 0x00F1, "n"   },
2023
  { 0x00F2, "o"   },
2024
  { 0x00F3, "o"   },
2025
  { 0x00F4, "o"   },
2026
  { 0x00F5, "o"   },
2027
  { 0x00F6, "o"   },
2028
  { 0x00F7, "/"   },
2029
  { 0x00F8, "o"   },
2030
  { 0x00F9, "u"   },
2031
  { 0x00FA, "u"   },
2032
  { 0x00FB, "u"   },
2033
  { 0x00FC, "u"   },
2034
  { 0x00FD, "y"   },
2035
  { 0x00FF, "y"   },
2036
  { 0x0131, "i"   },
2037
  { 0x0152, "OE"  },
2038
  { 0x0153, "oe"  },
2039
  { 0x0178, "Y"   },
2040
  { 0x2013, "-"   },
2041
  { 0x2014, "-"   },
2042
  { 0x2018, "'"   },
2043
  { 0x2019, "'"   },
2044
  { 0x201A, ","   },
2045
  { 0x201C, "\""  },
2046
  { 0x201D, "\""  },
2047
  { 0x201E, ",,"  },
2048
  { 0x2022, "."   },
2049
  { 0x2026, "..." },
2050
  { 0x2039, "<"   },
2051
  { 0x203A, ">"   },
2052
  { 0x2044, "/"   },
2053
  { 0x2122, "TM"  },
2054
  { 0x2206, "d"   },
2055
  { 0x2211, "S"   },
2056
  { 0x2260, "!="  },
2057
  { 0x2264, "<="  },
2058
  { 0x2265, ">="  },
2059
  { 0x2318, "#"   },
2060
  { 0xFB01, "fi"  },
2061
  { 0xFB02, "fl"  }
2062
  };
2063
  
2064
/******************************************************************************/
2065
2066
void dng_string::ForceASCII ()
2067
0
  {
2068
  
2069
0
  if (!IsASCII ())
2070
0
    {
2071
    
2072
0
    uint32 tempBufferSize =
2073
0
      SafeUint32Add (SafeUint32Mult(Length(), 3), 1);
2074
0
    dng_memory_data tempBuffer (tempBufferSize);
2075
    
2076
0
    char *dPtr = tempBuffer.Buffer_char ();
2077
0
    char * const destEnd = dPtr + tempBufferSize;
2078
    
2079
0
    const char *sPtr = Get ();
2080
    
2081
0
    while (*sPtr)
2082
0
      {
2083
      
2084
0
      uint32 x = DecodeUTF8 (sPtr);
2085
      
2086
0
      if (x <= 0x007F)
2087
0
        {
2088
        
2089
0
        CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
2090
0
        *(dPtr++) = (char) x;
2091
        
2092
0
        }
2093
        
2094
0
      else
2095
0
        {
2096
        
2097
0
        const char *ascii = NULL;
2098
        
2099
0
        const uint32 kTableEntrys = sizeof (kUnicodeToLowASCII    ) /
2100
0
                          sizeof (kUnicodeToLowASCII [0]);
2101
        
2102
0
        for (uint32 entry = 0; entry < kTableEntrys; entry++)
2103
0
          {
2104
          
2105
0
          if (kUnicodeToLowASCII [entry] . unicode == x)
2106
0
            {
2107
            
2108
0
            ascii = kUnicodeToLowASCII [entry] . ascii;
2109
            
2110
0
            break;
2111
            
2112
0
            }
2113
            
2114
0
          }
2115
          
2116
0
        if (ascii)
2117
0
          {
2118
          
2119
0
          while (*ascii)
2120
0
            {
2121
            
2122
0
            CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
2123
0
            *(dPtr++) = *(ascii++);
2124
            
2125
0
            }
2126
            
2127
0
          }
2128
          
2129
0
        else
2130
0
          {
2131
          
2132
0
          CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
2133
0
          *(dPtr++) ='?';
2134
          
2135
0
          }
2136
        
2137
0
        }
2138
        
2139
0
      }
2140
      
2141
0
    CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
2142
0
    *dPtr = 0;
2143
      
2144
0
    Set (tempBuffer.Buffer_char ());
2145
    
2146
0
    }
2147
  
2148
0
  }
2149
  
2150
/******************************************************************************/
2151
2152
static dng_mutex gProtectUCCalls ("gProtectUCCalls");
2153
        
2154
/******************************************************************************/
2155
2156
int32 dng_string::Compare (const dng_string &s) const
2157
0
  {
2158
  
2159
  #if qMacOS
2160
  #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
2161
  
2162
    // TODO: Needs implementation.
2163
    ThrowProgramError ("Compare() not implemented on iOS");
2164
    return 0;
2165
    
2166
  #else
2167
2168
    {
2169
  
2170
    dng_memory_data aStrA;
2171
    dng_memory_data aStrB;
2172
    
2173
    uint32 aLenA = this->Get_UTF16 (aStrA);
2174
    uint32 aLenB = s    .Get_UTF16 (aStrB);
2175
    
2176
    if (aLenA > 0)
2177
      {
2178
      
2179
      if (aLenB > 0)
2180
        {
2181
        
2182
        // For some Mac OS versions anyway, UCCompareTextDefault is not
2183
        // thread safe.
2184
        
2185
        dng_lock_mutex lockMutex (&gProtectUCCalls);
2186
2187
        UCCollateOptions aOptions = kUCCollateStandardOptions |
2188
                      kUCCollatePunctuationSignificantMask;
2189
                         
2190
        SInt32 aOrder = -1;
2191
        
2192
        Boolean aEqual = false;
2193
        
2194
        OSStatus searchStatus = ::UCCompareTextDefault (aOptions,
2195
                                aStrA.Buffer_uint16 (),
2196
                                aLenA,
2197
                                aStrB.Buffer_uint16 (),
2198
                                aLenB,
2199
                                &aEqual,
2200
                                &aOrder);
2201
                                
2202
        if (searchStatus == noErr)
2203
          {
2204
          
2205
          if (aEqual || (aOrder == 0))
2206
            {
2207
            return 0;
2208
            }
2209
  
2210
          else
2211
            {
2212
            return (aOrder > 0) ? 1 : -1;
2213
            }
2214
            
2215
          }
2216
          
2217
        else
2218
          {
2219
          
2220
          DNG_REPORT ("UCCompareTextDefault failed");
2221
          
2222
          return -1;
2223
          
2224
          }
2225
2226
        }
2227
2228
      else
2229
        {
2230
        return 1;
2231
        }
2232
2233
      }
2234
      
2235
    else
2236
      {
2237
      
2238
      if (aLenB > 0)
2239
        {
2240
        return -1;
2241
        }
2242
        
2243
      else
2244
        {
2245
        return 0;
2246
        }
2247
        
2248
      }
2249
      
2250
    }
2251
  
2252
  #endif  // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
2253
2254
  #elif qWinOS
2255
  
2256
    {
2257
2258
    dng_memory_data aStrA;
2259
    dng_memory_data aStrB;
2260
    
2261
    uint32 aLenA = this->Get_UTF16 (aStrA);
2262
    uint32 aLenB = s    .Get_UTF16 (aStrB);
2263
      
2264
    if (aLenA > 0)
2265
      {
2266
        
2267
      if (aLenB > 0)
2268
        {
2269
2270
        LCID locale = LOCALE_SYSTEM_DEFAULT;
2271
2272
        DWORD aFlags = NORM_IGNOREWIDTH;
2273
        
2274
        int aOrder = ::CompareStringW (locale, 
2275
                         aFlags,
2276
                         (const WCHAR *) aStrA.Buffer_uint16 (), 
2277
                         aLenA,
2278
                         (const WCHAR *) aStrB.Buffer_uint16 (), 
2279
                         aLenB);
2280
2281
        if (aOrder == CSTR_EQUAL)
2282
          {
2283
          return 0;
2284
          }
2285
2286
        else if (aOrder == CSTR_GREATER_THAN)
2287
          {
2288
          return 1;
2289
          } 
2290
        
2291
        else 
2292
          {
2293
          return -1;
2294
          }
2295
2296
        }
2297
2298
      else 
2299
        {
2300
        return 1;
2301
        }
2302
2303
      }
2304
2305
    else 
2306
      {
2307
2308
      if (aLenB > 0) 
2309
        {
2310
        return -1;
2311
        } 
2312
      else
2313
        {
2314
        return 0;
2315
        }
2316
2317
      }
2318
    
2319
    }
2320
    
2321
  #else
2322
  
2323
  // Fallback to a pure Unicode sort order.
2324
  
2325
0
    {
2326
    
2327
0
    for (uint32 pass = 0; pass < 2; pass++)
2328
0
      {
2329
    
2330
0
      const char *aPtr =   Get ();
2331
0
      const char *bPtr = s.Get ();
2332
      
2333
0
      while (*aPtr || *bPtr)
2334
0
        {
2335
        
2336
0
        if (!bPtr)
2337
0
          {
2338
0
          return 1;
2339
0
          }
2340
  
2341
0
        else if (!aPtr)
2342
0
          {
2343
0
          return -1;
2344
0
          }
2345
          
2346
0
        uint32 a = DecodeUTF8 (aPtr);
2347
0
        uint32 b = DecodeUTF8 (bPtr);
2348
        
2349
        // Ignore case on first compare pass.
2350
        
2351
0
        if (pass == 0)
2352
0
          {
2353
          
2354
0
          if (a >= (uint32) 'a' && a <= (uint32) 'z')
2355
0
            {
2356
0
            a = a - (uint32) 'a' + (uint32) 'A';
2357
0
            }
2358
            
2359
0
          if (b >= (uint32) 'a' && b <= (uint32) 'z')
2360
0
            {
2361
0
            b = b - (uint32) 'a' + (uint32) 'A';
2362
0
            }
2363
        
2364
0
          }
2365
          
2366
0
        if (b > a)
2367
0
          {
2368
0
          return 1;
2369
0
          }
2370
          
2371
0
        else if (a < b)
2372
0
          {
2373
0
          return -1;
2374
0
          }
2375
          
2376
0
        }
2377
        
2378
0
      }
2379
      
2380
0
    }
2381
    
2382
0
  #endif
2383
      
2384
0
  return 0;
2385
  
2386
0
  }
2387
2388
/*****************************************************************************/