Home | History | Annotate | Download | only in 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 	{
     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>
     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.
     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 
    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 	{
    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 
    518 dng_string::dng_string ()
    519 
    520 	:	fData ()
    521 
    522 	{
    523 
    524 	}
    525 
    526 /*****************************************************************************/
    527 
    528 dng_string::dng_string (const dng_string &s)
    529 
    530 	:	fData ()
    531 
    532 	{
    533 
    534 	Set (s.Get ());
    535 
    536 	}
    537 
    538 /*****************************************************************************/
    539 
    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 
    556 dng_string::~dng_string ()
    557 	{
    558 
    559 	}
    560 
    561 /*****************************************************************************/
    562 
    563 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 
    579 bool dng_string::IsASCII () const
    580 	{
    581 
    582 	return ::IsASCII (Get ());
    583 
    584 	}
    585 
    586 /*****************************************************************************/
    587 
    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 
    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 
    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 
    757 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 
    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 
    857 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 
    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 
    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 
   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 
   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 
   1101 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 
   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 
   1319 void dng_string::Clear ()
   1320 	{
   1321 
   1322 	Set (NULL);
   1323 
   1324 	}
   1325 
   1326 /*****************************************************************************/
   1327 
   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 
   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 
   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 
   1408 bool dng_string::IsEmpty () const
   1409 	{
   1410 
   1411 	const char *s = Get ();
   1412 
   1413 	return *s == 0;
   1414 
   1415 	}
   1416 
   1417 /*****************************************************************************/
   1418 
   1419 uint32 dng_string::Length () const
   1420 	{
   1421 
   1422 	const char *s = Get ();
   1423 
   1424 	return strlenAsUint32 (s);
   1425 
   1426 	}
   1427 
   1428 /*****************************************************************************/
   1429 
   1430 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 
   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 
   1472 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 
   1482 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 
   1513 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 
   1553 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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   2156 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