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.
strlenAsUint32(const char * s)50 static uint32 strlenAsUint32(const char *s)
51 	{
52 
53 	uint32 lengthAsUint32 = 0;
54 	ConvertUnsigned(strlen(s), &lengthAsUint32);
55 
56 	return lengthAsUint32;
57 
58 	}
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>
CheckSpaceLeftInBuffer(const T * currentPos,const T * bufferEnd,size_t space)68 static void CheckSpaceLeftInBuffer(const T *currentPos,
69 								   const T *bufferEnd,
70 								   size_t space)
71 	{
72 
73 	if (bufferEnd < currentPos || static_cast<size_t>(bufferEnd - currentPos) < space)
74 		{
75 		ThrowMemoryFull ("Buffer overrun");
76 		}
77 
78 	}
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.
ThrowNotHardened()94 static void ThrowNotHardened()
95 	{
96 	ThrowProgramError ("This function has not been security-hardened");
97 	}
98 
99 #if qMacOS
100 #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
101 
Extract_SystemEncoding(const dng_string & dngString,dng_memory_data & buffer)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 
Assign_SystemEncoding(dng_string & dngString,const char * otherString)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 
Assign_JIS_X208_1990(dng_string & dngString,const char * otherString)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 
Assign_Multibyte(dng_string & dngString,const char * otherString,TextEncoding encoding)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 
Extract_Multibyte(const dng_string & dngString,dng_memory_data & buffer,TextEncoding encoding)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 
Assign_SystemEncoding(dng_string & dngString,const char * otherString)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 
Extract_SystemEncoding(const dng_string & dngString,dng_memory_data & buffer)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 
Assign_JIS_X208_1990(dng_string & dngString,const char * otherString)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 
Assign_Multibyte(dng_string & dngString,const char * otherString,UINT encoding)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 
Extract_Multibyte(const dng_string & dngString,dng_memory_data & buffer,UINT encoding)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 
Assign_SystemEncoding(dng_string & dngString,const char * otherString)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 
Extract_SystemEncoding(const dng_string & dngString,dng_memory_data & buffer)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 
Assign_JIS_X208_1990(dng_string & dngString,const char * otherString)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 
IsASCII(const char * s)481 static bool IsASCII (const char *s)
482 	{
483 
484 	if (!s)
485 		{
486 
487 		return true;
488 
489 		}
490 
491 	while (true)
492 		{
493 
494 		uint8 c = (uint8) *(s++);
495 
496 		if (c == 0)
497 			{
498 
499 			break;
500 
501 			}
502 
503 		if (c & 0x80)
504 			{
505 
506 			return false;
507 
508 			}
509 
510 		}
511 
512 	return true;
513 
514 	}
515 
516 /*****************************************************************************/
517 
dng_string()518 dng_string::dng_string ()
519 
520 	:	fData ()
521 
522 	{
523 
524 	}
525 
526 /*****************************************************************************/
527 
dng_string(const dng_string & s)528 dng_string::dng_string (const dng_string &s)
529 
530 	:	fData ()
531 
532 	{
533 
534 	Set (s.Get ());
535 
536 	}
537 
538 /*****************************************************************************/
539 
operator =(const dng_string & s)540 dng_string & dng_string::operator= (const dng_string &s)
541 	{
542 
543 	if (this != &s)
544 		{
545 
546 		Set (s.Get ());
547 
548 		}
549 
550 	return *this;
551 
552 	}
553 
554 /*****************************************************************************/
555 
~dng_string()556 dng_string::~dng_string ()
557 	{
558 
559 	}
560 
561 /*****************************************************************************/
562 
Get() const563 const char * dng_string::Get () const
564 	{
565 
566 	if (fData.Buffer ())
567 		{
568 
569 		return fData.Buffer_char ();
570 
571 		}
572 
573 	return "";
574 
575 	}
576 
577 /*****************************************************************************/
578 
IsASCII() const579 bool dng_string::IsASCII () const
580 	{
581 
582 	return ::IsASCII (Get ());
583 
584 	}
585 
586 /*****************************************************************************/
587 
Set(const char * s)588 void dng_string::Set (const char *s)
589 	{
590 
591 	// Measure the new length.
592 
593 	uint32 newLen = (s != NULL ? strlenAsUint32 (s) : 0);
594 
595 	// If it is a NULL string, then clear the buffer.
596 
597 	if (newLen == 0)
598 		{
599 
600 		fData.Clear ();
601 
602 		}
603 
604 	// Else we need to copy the bytes.
605 
606 	else
607 		{
608 
609 		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 		if (newLen > oldLen)
616 			{
617 
618 			fData.Clear ();
619 
620 			fData.Allocate (SafeUint32Add (newLen, 1));
621 
622 			}
623 
624 		char *d = fData.Buffer_char ();
625 
626 		for (uint32 k = 0; k <= newLen; k++)
627 			{
628 
629 			d [k] = s [k];
630 
631 			}
632 
633 		}
634 
635 	}
636 
637 /*****************************************************************************/
638 
Set_ASCII(const char * s)639 void dng_string::Set_ASCII (const char *s)
640 	{
641 
642 	if (::IsASCII (s))
643 		{
644 
645 		Set (s);
646 
647 		}
648 
649 	else
650 		{
651 
652 		Set_SystemEncoding (s);
653 
654 		}
655 
656 	}
657 
658 /*****************************************************************************/
659 
Set_UTF8(const char * s)660 void dng_string::Set_UTF8 (const char *s)
661 	{
662 
663 	uint32 len = strlenAsUint32 (s);
664 
665 	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 	const uint32 destBufferLength = SafeUint32Add (SafeUint32Mult (len, 3), 1);
671 	dng_memory_data buffer (destBufferLength);
672 
673 	uint8 *d = buffer.Buffer_uint8 ();
674 	uint8 * const destEnd = d + destBufferLength;
675 
676 	while (s < sEnd)
677 		{
678 
679 		uint32 aChar = DecodeUTF8 (s, (uint32) (sEnd - s));
680 
681 		if (aChar > 0x7FFFFFFF)
682 			{
683 			aChar = kREPLACEMENT_CHARACTER;
684 			}
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 		if (aChar < 0x00000080)
696 			{
697 			CheckSpaceLeftInBuffer (d, destEnd, 1);
698 			*(d++) = (uint8) aChar;
699 			}
700 
701 		else if (aChar < 0x00000800)
702 			{
703 			CheckSpaceLeftInBuffer (d, destEnd, 2);
704 			*(d++) = (uint8) ((aChar >> 6) | 0x000000C0);
705 			*(d++) = (uint8) ((aChar & 0x0000003F) | 0x00000080);
706 			}
707 
708 		else if (aChar < 0x00010000)
709 			{
710 			CheckSpaceLeftInBuffer (d, destEnd, 3);
711 			*(d++) = (uint8) ( (aChar >> 12) | 0x000000E0);
712 			*(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
713 			*(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
714 			}
715 
716 		else if (aChar < 0x00200000)
717 			{
718 			CheckSpaceLeftInBuffer (d, destEnd, 4);
719 			*(d++) = (uint8) ( (aChar >> 18) | 0x000000F0);
720 			*(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
721 			*(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
722 			*(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
723 			}
724 
725 		else if (aChar < 0x04000000)
726 			{
727 			CheckSpaceLeftInBuffer (d, destEnd, 5);
728 			*(d++) = (uint8) ( (aChar >> 24) | 0x000000F8);
729 			*(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
730 			*(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
731 			*(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
732 			*(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
733 			}
734 
735 		else
736 			{
737 			CheckSpaceLeftInBuffer (d, destEnd, 6);
738 			*(d++) = (uint8) ( (aChar >> 30) | 0x000000FC);
739 			*(d++) = (uint8) (((aChar >> 24) & 0x0000003F) | 0x00000080);
740 			*(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
741 			*(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
742 			*(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
743 			*(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
744 			}
745 
746 		}
747 
748 	CheckSpaceLeftInBuffer (d, destEnd, 1);
749 	*d = 0;
750 
751 	Set (buffer.Buffer_char ());
752 
753 	}
754 
755 /*****************************************************************************/
756 
Get_SystemEncoding(dng_memory_data & buffer) const757 uint32 dng_string::Get_SystemEncoding (dng_memory_data &buffer) const
758 	{
759 
760 	if (IsASCII ())
761 		{
762 
763 		uint32 len = Length ();
764 
765 		const uint32 destBufferLength = SafeUint32Add (len, 1);
766 		buffer.Allocate (destBufferLength);
767 
768 		memcpy (buffer.Buffer (), Get (), destBufferLength);
769 
770 		return len;
771 
772 		}
773 
774 	else
775 		{
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 		dng_string temp (*this);
786 
787 		temp.ForceASCII ();
788 
789 		return temp.Get_SystemEncoding (buffer);
790 
791 		#endif
792 
793 		}
794 
795 	}
796 
797 /*****************************************************************************/
798 
Set_SystemEncoding(const char * s)799 void dng_string::Set_SystemEncoding (const char *s)
800 	{
801 
802 	if (::IsASCII (s))
803 		{
804 
805 		Set (s);
806 
807 		}
808 
809 	else
810 		{
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 		uint32 len = strlenAsUint32 (s);
822 
823 		const uint32 destBufferLength = SafeUint32Add (len, 1);
824 		dng_memory_data buffer (destBufferLength);
825 
826 		uint8 *d = buffer.Buffer_uint8 ();
827 		uint8 * const destEnd = d + destBufferLength;
828 
829 		while (*s)
830 			{
831 
832 			uint8 c = (uint8) *(s++);
833 
834 			if ((c & 0x80) == 0)
835 				{
836 
837 				CheckSpaceLeftInBuffer (d, destEnd, 1);
838 				*(d++) = c;
839 
840 				}
841 
842 			}
843 
844 		CheckSpaceLeftInBuffer (d, destEnd, 1);
845 		*d = 0;
846 
847 		Set (buffer.Buffer_char ());
848 
849 		#endif
850 
851 		}
852 
853 	}
854 
855 /*****************************************************************************/
856 
ValidSystemEncoding() const857 bool dng_string::ValidSystemEncoding () const
858 	{
859 
860 	if (IsASCII ())
861 		{
862 
863 		return true;
864 
865 		}
866 
867 	dng_memory_data buffer;
868 
869 	Get_SystemEncoding (buffer);
870 
871 	dng_string temp;
872 
873 	temp.Set_SystemEncoding (buffer.Buffer_char ());
874 
875 	return (*this == temp);
876 
877 	}
878 
879 /*****************************************************************************/
880 
Set_JIS_X208_1990(const char * s)881 void dng_string::Set_JIS_X208_1990 (const char *s)
882 	{
883 
884 	if (::IsASCII (s))
885 		{
886 
887 		Set (s);
888 
889 		}
890 
891 	else
892 		{
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 		Set_SystemEncoding (s);
903 
904 		#endif
905 
906 		}
907 
908 	}
909 
910 /*****************************************************************************/
911 
DecodeUTF8(const char * & s,uint32 maxBytes,bool * isValid)912 uint32 dng_string::DecodeUTF8 (const char *&s,
913 							   uint32 maxBytes,
914 							   bool *isValid)
915 	{
916 
917 	static const uint8 gUTF8Bytes [256] =
918 		{
919 		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 		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 		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 		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 		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 		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 		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 		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 		};
928 
929 	if (isValid)
930 		{
931 		*isValid = true;
932 		}
933 
934 	const uint8 *nBuf = (const uint8 *) s;
935 
936 	uint32 aChar = nBuf [0];
937 
938 	uint32 aSize = gUTF8Bytes [aChar];
939 
940 	if (aSize > maxBytes)
941 		{
942 
943 		s += maxBytes;
944 
945 		if (isValid)
946 			{
947 			*isValid = false;
948 			}
949 
950 		return kREPLACEMENT_CHARACTER;
951 
952 		}
953 
954 	s += aSize;
955 
956 	for (uint32 extra = 1; extra < aSize; extra++)
957 		{
958 
959 		if ((nBuf [extra] & 0xC0) != 0x80)
960 			{
961 
962 			if (isValid)
963 				{
964 				*isValid = false;
965 				}
966 
967 			return kREPLACEMENT_CHARACTER;
968 
969 			}
970 
971 		}
972 
973 	switch (aSize)
974 		{
975 
976 		case 0:
977 			{
978 
979 			s++;		// Don't get stuck in infinite loop
980 
981 			if (isValid)
982 				{
983 				*isValid = false;
984 				}
985 
986 			return kREPLACEMENT_CHARACTER;
987 
988 			}
989 
990 		case 1:
991 			{
992 
993 			return aChar;
994 
995 			}
996 
997 		case 2:
998 			{
999 
1000 			aChar = ((aChar << 6) + nBuf [1]) - (uint32) 0x00003080UL;
1001 
1002 			break;
1003 
1004 			}
1005 
1006 		case 3:
1007 			{
1008 
1009 			aChar =  ((((aChar << 6) + nBuf [1])
1010 							   << 6) + nBuf [2]) - (uint32) 0x000E2080UL;
1011 
1012 			break;
1013 
1014 			}
1015 
1016 		case 4:
1017 			{
1018 
1019 			aChar = ((((((aChar << 6) + nBuf [1])
1020 							    << 6) + nBuf [2])
1021 								<< 6) + nBuf [3]) - (uint32) 0x03C82080UL;
1022 
1023 			break;
1024 
1025 			}
1026 		}
1027 
1028 	if (aChar < 0x7F || aChar > 0x0010FFFF)
1029 		{
1030 
1031 		if (isValid)
1032 			{
1033 			*isValid = false;
1034 			}
1035 
1036 		return kREPLACEMENT_CHARACTER;
1037 
1038 		}
1039 
1040 	return aChar;
1041 
1042 	}
1043 
1044 /*****************************************************************************/
1045 
IsUTF8(const char * s)1046 bool dng_string::IsUTF8 (const char *s)
1047 	{
1048 
1049 	uint32 len = strlenAsUint32 (s);
1050 
1051 	const char *sEnd = s + len;
1052 
1053 	while (s < sEnd)
1054 		{
1055 
1056 		bool isValid = true;
1057 
1058 		(void) DecodeUTF8 (s, (uint32) (sEnd - s), &isValid);
1059 
1060 		if (!isValid)
1061 			{
1062 			return false;
1063 			}
1064 
1065 		}
1066 
1067 	return true;
1068 
1069 	}
1070 
1071 /*****************************************************************************/
1072 
Set_UTF8_or_System(const char * s)1073 void dng_string::Set_UTF8_or_System (const char *s)
1074 	{
1075 
1076 	if (::IsASCII (s))
1077 		{
1078 
1079 		Set (s);
1080 
1081 		}
1082 
1083 	else if (IsUTF8 (s))
1084 		{
1085 
1086 		Set_UTF8 (s);
1087 
1088 		}
1089 
1090 	else
1091 		{
1092 
1093 		Set_SystemEncoding (s);
1094 
1095 		}
1096 
1097 	}
1098 
1099 /*****************************************************************************/
1100 
Get_UTF16(dng_memory_data & buffer) const1101 uint32 dng_string::Get_UTF16 (dng_memory_data &buffer) const
1102 	{
1103 
1104 	uint32 count = 0;
1105 
1106 	const char *sPtr = Get ();
1107 
1108 	while (*sPtr)
1109 		{
1110 
1111 		uint32 x = DecodeUTF8 (sPtr);
1112 
1113 		if (x <= 0x0000FFFF ||
1114 			x >  0x0010FFFF)
1115 			{
1116 
1117 			count = SafeUint32Add (count, 1);
1118 
1119 			}
1120 
1121 		else
1122 			{
1123 
1124 			count = SafeUint32Add (count, 2);
1125 
1126 			}
1127 
1128 		}
1129 
1130 	const uint32 destBufferLength = SafeUint32Add (count, 1);
1131 	buffer.Allocate (destBufferLength, sizeof (uint16));
1132 
1133 	uint16 *dPtr = buffer.Buffer_uint16 ();
1134 	uint16 * const destEnd = dPtr + destBufferLength;
1135 
1136 	sPtr = Get ();
1137 
1138 	while (*sPtr)
1139 		{
1140 
1141 		uint32 x = DecodeUTF8 (sPtr);
1142 
1143 		if (x <= 0x0000FFFF)
1144 			{
1145 
1146 			CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
1147 			*(dPtr++) = (uint16) x;
1148 
1149 			}
1150 
1151 		else if (x > 0x0010FFFF)
1152 			{
1153 
1154 			CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
1155 			*(dPtr++) = (uint16) kREPLACEMENT_CHARACTER;
1156 
1157 			}
1158 
1159 		else
1160 			{
1161 
1162 			x -= 0x00010000;
1163 
1164 			CheckSpaceLeftInBuffer (dPtr, destEnd, 2);
1165 			*(dPtr++) = (uint16) ((x >> 10       ) + 0x0000D800);
1166 			*(dPtr++) = (uint16) ((x & 0x000003FF) + 0x0000DC00);
1167 
1168 			}
1169 
1170 		}
1171 
1172 	CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
1173 	*dPtr = 0;
1174 
1175 	return count;
1176 
1177 	}
1178 
1179 /*****************************************************************************/
1180 
Set_UTF16(const uint16 * s)1181 void dng_string::Set_UTF16 (const uint16 *s)
1182 	{
1183 
1184 	if (!s)
1185 		{
1186 		Clear ();
1187 		return;
1188 		}
1189 
1190 	bool swap = false;
1191 
1192 	if (s [0] == 0xFFFE)		// Swapped byte order marker
1193 		{
1194 		swap = true;
1195 		s++;
1196 		}
1197 
1198 	else if (s [0] == 0xFEFF)	// Non-swapped byte order marker
1199 		{
1200 		s++;
1201 		}
1202 
1203 	uint32 length16 = 0;
1204 
1205 	while (s [length16] != 0)
1206 		{
1207 		length16 = SafeUint32Add (length16, 1);
1208 		}
1209 
1210 	const uint16 *sEnd = s + length16;
1211 
1212 	const uint32 destBufferSize =
1213 		SafeUint32Add (SafeUint32Mult (length16, 6), 1);
1214 	dng_memory_data buffer (destBufferSize);
1215 
1216 	uint8 *d = buffer.Buffer_uint8 ();
1217 	uint8 * const destEnd = d + destBufferSize;
1218 
1219 	while (s < sEnd)
1220 		{
1221 
1222 		uint32 aChar = *s++;
1223 
1224 		if (swap)
1225 			{
1226 			aChar = ((aChar << 8) | (aChar >> 8)) & 0x0000FFFF;
1227 			}
1228 
1229 		if ((aChar >= 0x0000D800) && (aChar <= 0x0000DBFF) && (s < sEnd))
1230 			{
1231 
1232 			uint32 aLow = *s;
1233 
1234 			if (swap)
1235 				{
1236 				aLow = ((aLow << 8) | (aLow >> 8)) & 0x0000FFFF;
1237 				}
1238 
1239 			if ((aLow >= 0x0000DC00) && (aLow <= 0x0000DFFF))
1240 				{
1241 
1242 				aChar = ((aChar - 0x0000D800) << 10) +
1243 					    (aLow - 0x0000DC00) +
1244 					    0x00010000;
1245 
1246 				s++;
1247 
1248 				}
1249 
1250 			}
1251 
1252 		if (aChar > 0x7FFFFFFF)
1253 			{
1254 			aChar = kREPLACEMENT_CHARACTER;
1255 			}
1256 
1257 		if (aChar < 0x00000080)
1258 			{
1259 			CheckSpaceLeftInBuffer (d, destEnd, 1);
1260 			*(d++) = (uint8) aChar;
1261 			}
1262 
1263 		else if (aChar < 0x00000800)
1264 			{
1265 			CheckSpaceLeftInBuffer (d, destEnd, 2);
1266 			*(d++) = (uint8) ((aChar >> 6) | 0x000000C0);
1267 			*(d++) = (uint8) ((aChar & 0x0000003F) | 0x00000080);
1268 			}
1269 
1270 		else if (aChar < 0x00010000)
1271 			{
1272 			CheckSpaceLeftInBuffer (d, destEnd, 3);
1273 			*(d++) = (uint8) ( (aChar >> 12) | 0x000000E0);
1274 			*(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
1275 			*(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
1276 			}
1277 
1278 		else if (aChar < 0x00200000)
1279 			{
1280 			CheckSpaceLeftInBuffer (d, destEnd, 4);
1281 			*(d++) = (uint8) ( (aChar >> 18) | 0x000000F0);
1282 			*(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
1283 			*(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
1284 			*(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
1285 			}
1286 
1287 		else if (aChar < 0x04000000)
1288 			{
1289 			CheckSpaceLeftInBuffer (d, destEnd, 5);
1290 			*(d++) = (uint8) ( (aChar >> 24) | 0x000000F8);
1291 			*(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
1292 			*(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
1293 			*(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
1294 			*(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
1295 			}
1296 
1297 		else
1298 			{
1299 			CheckSpaceLeftInBuffer (d, destEnd, 6);
1300 			*(d++) = (uint8) ( (aChar >> 30) | 0x000000FC);
1301 			*(d++) = (uint8) (((aChar >> 24) & 0x0000003F) | 0x00000080);
1302 			*(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
1303 			*(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
1304 			*(d++) = (uint8) (((aChar >>  6) & 0x0000003F) | 0x00000080);
1305 			*(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
1306 			}
1307 
1308 		}
1309 
1310 	CheckSpaceLeftInBuffer (d, destEnd, 1);
1311 	*d = 0;
1312 
1313 	Set (buffer.Buffer_char ());
1314 
1315 	}
1316 
1317 /*****************************************************************************/
1318 
Clear()1319 void dng_string::Clear ()
1320 	{
1321 
1322 	Set (NULL);
1323 
1324 	}
1325 
1326 /*****************************************************************************/
1327 
Truncate(uint32 maxBytes)1328 void dng_string::Truncate (uint32 maxBytes)
1329 	{
1330 
1331 	uint32 len = Length ();
1332 
1333 	if (len > maxBytes)
1334 		{
1335 
1336 		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 		while (maxBytes > 0 && ((s [maxBytes]) & 0xC0) == 0x80)
1342 			{
1343 
1344 			maxBytes--;
1345 
1346 			}
1347 
1348 		s [maxBytes] = 0;
1349 
1350 		}
1351 
1352 	}
1353 
1354 /*****************************************************************************/
1355 
TrimTrailingBlanks()1356 bool dng_string::TrimTrailingBlanks ()
1357 	{
1358 
1359 	bool didTrim = false;
1360 
1361 	if (fData.Buffer ())
1362 		{
1363 
1364 		char *s = fData.Buffer_char ();
1365 
1366 		uint32 len = strlenAsUint32 (s);
1367 
1368 		while (len > 0 && s [len - 1] == ' ')
1369 			{
1370 			len--;
1371 			didTrim = true;
1372 			}
1373 
1374 		s [len] = 0;
1375 
1376 		}
1377 
1378 	return didTrim;
1379 
1380 	}
1381 
1382 /*****************************************************************************/
1383 
TrimLeadingBlanks()1384 bool dng_string::TrimLeadingBlanks ()
1385 	{
1386 
1387 	bool didTrim = false;
1388 
1389 	const char *s = Get ();
1390 
1391 	while (*s == ' ')
1392 		{
1393 		s++;
1394 		didTrim = true;
1395 		}
1396 
1397 	if (didTrim)
1398 		{
1399 		Set (s);
1400 		}
1401 
1402 	return didTrim;
1403 
1404 	}
1405 
1406 /*****************************************************************************/
1407 
IsEmpty() const1408 bool dng_string::IsEmpty () const
1409 	{
1410 
1411 	const char *s = Get ();
1412 
1413 	return *s == 0;
1414 
1415 	}
1416 
1417 /*****************************************************************************/
1418 
Length() const1419 uint32 dng_string::Length () const
1420 	{
1421 
1422 	const char *s = Get ();
1423 
1424 	return strlenAsUint32 (s);
1425 
1426 	}
1427 
1428 /*****************************************************************************/
1429 
operator ==(const dng_string & s) const1430 bool dng_string::operator== (const dng_string &s) const
1431 	{
1432 
1433 	const char *s1 =   Get ();
1434 	const char *s2 = s.Get ();
1435 
1436 	return strcmp (s1, s2) == 0;
1437 
1438 	}
1439 
1440 /*****************************************************************************/
1441 
Matches(const char * t,const char * s,bool case_sensitive)1442 bool dng_string::Matches (const char *t,
1443 						  const char *s,
1444 						  bool case_sensitive)
1445 	{
1446 
1447 	while (*s != 0)
1448 		{
1449 
1450 		char c1 = *(s++);
1451 		char c2 = *(t++);
1452 
1453 		if (!case_sensitive)
1454 			{
1455 			c1 = ForceUppercase (c1);
1456 			c2 = ForceUppercase (c2);
1457 			}
1458 
1459 		if (c1 != c2)
1460 			{
1461 			return false;
1462 			}
1463 
1464 		}
1465 
1466 	return (*t == 0);
1467 
1468 	}
1469 
1470 /*****************************************************************************/
1471 
Matches(const char * s,bool case_sensitive) const1472 bool dng_string::Matches (const char *s,
1473 						  bool case_sensitive) const
1474 	{
1475 
1476 	return dng_string::Matches (Get (), s, case_sensitive);
1477 
1478 	}
1479 
1480 /*****************************************************************************/
1481 
StartsWith(const char * s,bool case_sensitive) const1482 bool dng_string::StartsWith (const char *s,
1483 						     bool case_sensitive) const
1484 	{
1485 
1486 	const char *t = Get ();
1487 
1488 	while (*s != 0)
1489 		{
1490 
1491 		char c1 = *(s++);
1492 		char c2 = *(t++);
1493 
1494 		if (!case_sensitive)
1495 			{
1496 			c1 = ForceUppercase (c1);
1497 			c2 = ForceUppercase (c2);
1498 			}
1499 
1500 		if (c1 != c2)
1501 			{
1502 			return false;
1503 			}
1504 
1505 		}
1506 
1507 	return true;
1508 
1509 	}
1510 
1511 /*****************************************************************************/
1512 
EndsWith(const char * s,bool case_sensitive) const1513 bool dng_string::EndsWith (const char *s,
1514 						   bool case_sensitive) const
1515 	{
1516 
1517 	uint32 len1 = Length ();
1518 
1519 	uint32 len2 = strlenAsUint32 (s);
1520 
1521 	if (len1 < len2)
1522 		{
1523 		return false;
1524 		}
1525 
1526 	const char *t = Get () + (len1 - len2);
1527 
1528 	while (*s != 0)
1529 		{
1530 
1531 		char c1 = *(s++);
1532 		char c2 = *(t++);
1533 
1534 		if (!case_sensitive)
1535 			{
1536 			c1 = ForceUppercase (c1);
1537 			c2 = ForceUppercase (c2);
1538 			}
1539 
1540 		if (c1 != c2)
1541 			{
1542 			return false;
1543 			}
1544 
1545 		}
1546 
1547 	return true;
1548 
1549 	}
1550 
1551 /*****************************************************************************/
1552 
Contains(const char * s,bool case_sensitive,int32 * match_offset) const1553 bool dng_string::Contains (const char *s,
1554 						   bool case_sensitive,
1555 						   int32 *match_offset) const
1556 	{
1557 
1558 	if (match_offset)
1559 		{
1560 		*match_offset = -1;
1561 		}
1562 
1563 	uint32 len1 = Length ();
1564 
1565 	uint32 len2 = strlenAsUint32 (s);
1566 
1567 	if (len1 < len2)
1568 		{
1569 		return false;
1570 		}
1571 
1572 	uint32 offsets = len1 - len2;
1573 
1574 	for (uint32 offset = 0; offset <= offsets; offset++)
1575 		{
1576 
1577 		const char *ss = s;
1578 		const char *tt = Get () + offset;
1579 
1580 		while (*ss != 0)
1581 			{
1582 
1583 			char c1 = *(ss++);
1584 			char c2 = *(tt++);
1585 
1586 			if (!case_sensitive)
1587 				{
1588 				c1 = ForceUppercase (c1);
1589 				c2 = ForceUppercase (c2);
1590 				}
1591 
1592 			if (c1 != c2)
1593 				{
1594 				goto tryNextOffset;
1595 				}
1596 
1597 			}
1598 
1599 		if (match_offset)
1600 			{
1601 			*match_offset = offset;
1602 			}
1603 
1604 		return true;
1605 
1606 		tryNextOffset:	;
1607 
1608 		}
1609 
1610 	return false;
1611 
1612 	}
1613 
1614 /*****************************************************************************/
1615 
Replace(const char * old_string,const char * new_string,bool case_sensitive)1616 bool dng_string::Replace (const char *old_string,
1617 						  const char *new_string,
1618 						  bool case_sensitive)
1619 	{
1620 
1621 	int32 match_offset = -1;
1622 
1623 	if (Contains (old_string,
1624 				  case_sensitive,
1625 				  &match_offset))
1626 		{
1627 
1628 		uint32 len1 = Length ();
1629 
1630 		uint32 len2 = strlenAsUint32 (old_string);
1631 		uint32 len3 = strlenAsUint32 (new_string);
1632 
1633 		if (len2 == len3)
1634 			{
1635 
1636 			strncpy (fData.Buffer_char () + match_offset,
1637 					 new_string,
1638 					 len3);
1639 
1640 			}
1641 
1642 		else if (len2 > len3)
1643 			{
1644 
1645 			strncpy (fData.Buffer_char () + match_offset,
1646 					 new_string,
1647 					 len3);
1648 
1649 			const char *s = fData.Buffer_char () + match_offset + len2;
1650 				  char *d = fData.Buffer_char () + match_offset + len3;
1651 
1652 			uint32 extra = len1 - match_offset - len2 + 1;	// + 1 for NULL termination
1653 
1654 			for (uint32 j = 0; j < extra; j++)
1655 				{
1656 				*(d++) = *(s++);
1657 				}
1658 
1659 			}
1660 
1661 		else
1662 			{
1663 
1664 			// "len1 - len2" cannot wrap around because we know that if this
1665 			// string contains old_string, len1 >= len2 must hold.
1666 			dng_memory_data tempBuffer (
1667 				SafeUint32Add (SafeUint32Add (len1 - len2, len3), 1));
1668 
1669 			if (match_offset)
1670 				{
1671 
1672 				strncpy (tempBuffer.Buffer_char (),
1673 						 fData     .Buffer_char (),
1674 						 match_offset);
1675 
1676 				}
1677 
1678 			if (len3)
1679 				{
1680 
1681 				strncpy (tempBuffer.Buffer_char () + match_offset,
1682 						 new_string,
1683 						 len3);
1684 
1685 				}
1686 
1687 			uint32 extra = len1 - match_offset - len2 + 1;	// + 1 for NULL termination
1688 
1689 			strncpy (tempBuffer.Buffer_char () + match_offset + len3,
1690 					 fData     .Buffer_char () + match_offset + len2,
1691 					 extra);
1692 
1693 			Set (tempBuffer.Buffer_char ());
1694 
1695 			}
1696 
1697 		return true;
1698 
1699 		}
1700 
1701 	return false;
1702 
1703 	}
1704 
1705 /*****************************************************************************/
1706 
TrimLeading(const char * s,bool case_sensitive)1707 bool dng_string::TrimLeading (const char *s,
1708 						      bool case_sensitive)
1709 	{
1710 
1711 	if (StartsWith (s, case_sensitive))
1712 		{
1713 
1714 		Set (Get () + strlenAsUint32 (s));
1715 
1716 		return true;
1717 
1718 		}
1719 
1720 	return false;
1721 
1722 	}
1723 
1724 /*****************************************************************************/
1725 
Append(const char * s)1726 void dng_string::Append (const char *s)
1727 	{
1728 
1729 	uint32 len2 = strlenAsUint32 (s);
1730 
1731 	if (len2)
1732 		{
1733 
1734 		uint32 len1 = Length ();
1735 
1736 		dng_memory_data temp (SafeUint32Add (SafeUint32Add (len1, len2), 1));
1737 
1738 		char *buffer = temp.Buffer_char ();
1739 
1740 		if (len1)
1741 			{
1742 			memcpy (buffer, Get (), len1);
1743 			}
1744 
1745 		memcpy (buffer + len1, s, len2 + 1);
1746 
1747 		Set (buffer);
1748 
1749 		}
1750 
1751 	}
1752 
1753 /*****************************************************************************/
1754 
SetUppercase()1755 void dng_string::SetUppercase ()
1756 	{
1757 
1758 	if (fData.Buffer ())
1759 		{
1760 
1761 		uint32 len = Length ();
1762 
1763 		char *dPtr = fData.Buffer_char ();
1764 
1765 		for (uint32 j = 0; j < len; j++)
1766 			{
1767 
1768 			char c = dPtr [j];
1769 
1770 			if (c >= 'a' && c <= 'z')
1771 				{
1772 
1773 				dPtr [j] = c - 'a' + 'A';
1774 
1775 				}
1776 
1777 			}
1778 
1779 		}
1780 
1781 	}
1782 
1783 /*****************************************************************************/
1784 
SetLowercase()1785 void dng_string::SetLowercase ()
1786 	{
1787 
1788 	if (fData.Buffer ())
1789 		{
1790 
1791 		uint32 len = Length ();
1792 
1793 		char *dPtr = fData.Buffer_char ();
1794 
1795 		for (uint32 j = 0; j < len; j++)
1796 			{
1797 
1798 			char c = dPtr [j];
1799 
1800 			if (c >= 'A' && c <= 'Z')
1801 				{
1802 
1803 				dPtr [j] = c - 'A' + 'a';
1804 
1805 				}
1806 
1807 			}
1808 
1809 		}
1810 
1811 	}
1812 
1813 /*****************************************************************************/
1814 
SetLineEndings(char ending)1815 void dng_string::SetLineEndings (char ending)
1816 	{
1817 
1818 	if (fData.Buffer ())
1819 		{
1820 
1821 		const char *sPtr = fData.Buffer_char ();
1822 		      char *dPtr = fData.Buffer_char ();
1823 
1824 		while (*sPtr)
1825 			{
1826 
1827 			char c = *(sPtr++);
1828 
1829 			char nc = sPtr [0];
1830 
1831 			if ((c == '\r' && nc == '\n') ||
1832 				(c == '\n' && nc == '\r'))
1833 				{
1834 
1835 				sPtr++;
1836 
1837 				if (ending)
1838 					{
1839 					*(dPtr++) = ending;
1840 					}
1841 
1842 				}
1843 
1844 			else if (c == '\n' ||
1845 					 c == '\r')
1846 				{
1847 
1848 				if (ending)
1849 					{
1850 					*(dPtr++) = ending;
1851 					}
1852 
1853 				}
1854 
1855 			else
1856 				{
1857 
1858 				*(dPtr++) = c;
1859 
1860 				}
1861 
1862 			}
1863 
1864 		*dPtr = 0;
1865 
1866 		}
1867 
1868 	}
1869 
1870 /*****************************************************************************/
1871 
StripLowASCII()1872 void dng_string::StripLowASCII ()
1873 	{
1874 
1875 	if (fData.Buffer ())
1876 		{
1877 
1878 		const char *sPtr = fData.Buffer_char ();
1879 		      char *dPtr = fData.Buffer_char ();
1880 
1881 		while (*sPtr)
1882 			{
1883 
1884 			char c = *(sPtr++);
1885 
1886 			if (c == '\r' || c == '\n' || (uint8) c >= ' ')
1887 				{
1888 
1889 				*(dPtr++) = c;
1890 
1891 				}
1892 
1893 			}
1894 
1895 		*dPtr = 0;
1896 
1897 		}
1898 
1899 	}
1900 
1901 /*****************************************************************************/
1902 
NormalizeAsCommaSeparatedNumbers()1903 void dng_string::NormalizeAsCommaSeparatedNumbers ()
1904 	{
1905 
1906 	if (fData.Buffer ())
1907 		{
1908 
1909 		const char *sPtr = fData.Buffer_char ();
1910 			  char *dPtr = fData.Buffer_char ();
1911 
1912 		bool commaInserted = false;
1913 
1914 		while (*sPtr)
1915 			{
1916 
1917 			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 			if (isdigit ((int) c) || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E')
1923 				{
1924 
1925 				*(dPtr++) = (char) c;
1926 
1927 				if (commaInserted)
1928 					{
1929 
1930 					commaInserted = false;
1931 
1932 					}
1933 
1934 				}
1935 
1936 			else if (!commaInserted)
1937 				{
1938 
1939 				*(dPtr++) = ',';
1940 
1941 				commaInserted = true;
1942 
1943 				}
1944 
1945 			}
1946 
1947 		*dPtr = 0;
1948 
1949 		}
1950 
1951 	}
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 
ForceASCII()2066 void dng_string::ForceASCII ()
2067 	{
2068 
2069 	if (!IsASCII ())
2070 		{
2071 
2072 		uint32 tempBufferSize =
2073 			SafeUint32Add (SafeUint32Mult(Length(), 3), 1);
2074 		dng_memory_data tempBuffer (tempBufferSize);
2075 
2076 		char *dPtr = tempBuffer.Buffer_char ();
2077 		char * const destEnd = dPtr + tempBufferSize;
2078 
2079 		const char *sPtr = Get ();
2080 
2081 		while (*sPtr)
2082 			{
2083 
2084 			uint32 x = DecodeUTF8 (sPtr);
2085 
2086 			if (x <= 0x007F)
2087 				{
2088 
2089 				CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
2090 				*(dPtr++) = (char) x;
2091 
2092 				}
2093 
2094 			else
2095 				{
2096 
2097 				const char *ascii = NULL;
2098 
2099 				const uint32 kTableEntrys = sizeof (kUnicodeToLowASCII    ) /
2100 									        sizeof (kUnicodeToLowASCII [0]);
2101 
2102 				for (uint32 entry = 0; entry < kTableEntrys; entry++)
2103 					{
2104 
2105 					if (kUnicodeToLowASCII [entry] . unicode == x)
2106 						{
2107 
2108 						ascii = kUnicodeToLowASCII [entry] . ascii;
2109 
2110 						break;
2111 
2112 						}
2113 
2114 					}
2115 
2116 				if (ascii)
2117 					{
2118 
2119 					while (*ascii)
2120 						{
2121 
2122 						CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
2123 						*(dPtr++) = *(ascii++);
2124 
2125 						}
2126 
2127 					}
2128 
2129 				else
2130 					{
2131 
2132 					CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
2133 					*(dPtr++) ='?';
2134 
2135 					}
2136 
2137 				}
2138 
2139 			}
2140 
2141 		CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
2142 		*dPtr = 0;
2143 
2144 		Set (tempBuffer.Buffer_char ());
2145 
2146 		}
2147 
2148 	}
2149 
2150 /******************************************************************************/
2151 
2152 static dng_mutex gProtectUCCalls ("gProtectUCCalls");
2153 
2154 /******************************************************************************/
2155 
Compare(const dng_string & s) const2156 int32 dng_string::Compare (const dng_string &s) const
2157 	{
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 		{
2326 
2327 		for (uint32 pass = 0; pass < 2; pass++)
2328 			{
2329 
2330 			const char *aPtr =   Get ();
2331 			const char *bPtr = s.Get ();
2332 
2333 			while (*aPtr || *bPtr)
2334 				{
2335 
2336 				if (!bPtr)
2337 					{
2338 					return 1;
2339 					}
2340 
2341 				else if (!aPtr)
2342 					{
2343 					return -1;
2344 					}
2345 
2346 				uint32 a = DecodeUTF8 (aPtr);
2347 				uint32 b = DecodeUTF8 (bPtr);
2348 
2349 				// Ignore case on first compare pass.
2350 
2351 				if (pass == 0)
2352 					{
2353 
2354 					if (a >= (uint32) 'a' && a <= (uint32) 'z')
2355 						{
2356 						a = a - (uint32) 'a' + (uint32) 'A';
2357 						}
2358 
2359 					if (b >= (uint32) 'a' && b <= (uint32) 'z')
2360 						{
2361 						b = b - (uint32) 'a' + (uint32) 'A';
2362 						}
2363 
2364 					}
2365 
2366 				if (b > a)
2367 					{
2368 					return 1;
2369 					}
2370 
2371 				else if (a < b)
2372 					{
2373 					return -1;
2374 					}
2375 
2376 				}
2377 
2378 			}
2379 
2380 		}
2381 
2382 	#endif
2383 
2384 	return 0;
2385 
2386 	}
2387 
2388 /*****************************************************************************/
2389