home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / Found / FWString / SLStrRep.cpp < prev    next >
Encoding:
Text File  |  1996-09-17  |  46.8 KB  |  1,603 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                SLStrRep.cpp
  4. //    Release Version:    $ ODF 2 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFound.hpp"
  11.  
  12. #ifndef PRSTRREP_H
  13. #include "PRStrRep.h"
  14. #endif
  15.  
  16. #ifndef SLPRIDEB_H
  17. #include "SLPriDeb.h"
  18. #endif
  19.  
  20. #ifndef SLPRIMEM_H
  21. #include "SLPriMem.h"
  22. #endif
  23.  
  24. // ----- Foundation Includes -----
  25.  
  26. #ifndef FWPRIDEB_H
  27. #include "FWPriDeb.h"
  28. #endif
  29.  
  30. #ifdef FW_BUILD_MAC
  31. #include <OSA.h>
  32. #endif
  33.  
  34. #ifdef FW_BUILD_MAC
  35. #include <Script.h>
  36. #endif
  37.  
  38. #ifndef _ERRORDEF_
  39. #include "ErrorDef.xh"
  40. #endif
  41.  
  42. #ifdef FW_BUILD_MAC
  43. #include <TextUtils.h>
  44. #endif
  45.  
  46. #ifdef FW_BUILD_MAC
  47. #include <fp.h>
  48. #endif
  49.  
  50. #ifdef FW_BUILD_MAC
  51. #pragma segment Strings
  52. #endif
  53.  
  54. //========================================================================================
  55. //    gEmptyStringRep
  56. //========================================================================================
  57.  
  58. static FW_Locale gDefaultLocaleData = 
  59. {
  60. #ifdef FW_BUILD_MAC
  61.     smRoman,        // fScriptCode
  62.     langEnglish        // fLangCode
  63. #endif
  64. #ifdef FW_BUILD_WIN
  65.     0,
  66.     0
  67. #endif
  68. };
  69.  
  70. static FW_SPrivStringRep gEmptyStringRep = 
  71. {
  72.     {    // ODIText fText;
  73.         kODTraditionalMacText,            // format
  74.         {
  75.             sizeof(gDefaultLocaleData),    // _maximum
  76.             sizeof(gDefaultLocaleData),    // _length
  77.             (unsigned char*) &gDefaultLocaleData            // _buffer
  78.         }
  79.     },
  80.     {    // FW_ODITextParams    fParams;
  81.         (char*) &gDefaultLocaleData+sizeof(gDefaultLocaleData),    // fTextStart
  82.         0,                                // fTextByteLength
  83.         0                                // fTextByteCapacity
  84.     },
  85.     100,                                // fRefCount
  86.     true,                                // fUsingStaticBuffer
  87.     false                                // fLocked
  88. };
  89.  
  90. //----------------------------------------------------------------------------------------
  91. //    FW_PrivInitStringData - call once after static initialization
  92. //----------------------------------------------------------------------------------------
  93.  
  94. void FW_PrivInitStringData()
  95. {
  96.     // Set the gDefaultLocaleData to the system script and language
  97. #ifdef FW_BUILD_MAC
  98.     gDefaultLocaleData.fScriptCode = ::GetScriptManagerVariable(smSysScript);
  99.     gDefaultLocaleData.fLangCode = ::GetScriptVariable(gDefaultLocaleData.fScriptCode, smScriptLang);
  100. #endif    
  101. #ifdef FW_BUILD_WIN
  102.     // Not yet implemented
  103. #endif    
  104. }
  105.  
  106. //----------------------------------------------------------------------------------------
  107. //    FW_PrivGetDefaultLocale - return default (system) locale
  108. //----------------------------------------------------------------------------------------
  109.  
  110. FW_Locale FW_PrivGetDefaultLocale()
  111. {
  112.     return gDefaultLocaleData;
  113. }
  114.  
  115. //========================================================================================
  116. //    FW_SPrivStringRep Functions
  117. //========================================================================================
  118.  
  119. //----------------------------------------------------------------------------------------
  120. //    FW_Check
  121. //----------------------------------------------------------------------------------------
  122.  
  123.  
  124. #ifdef FW_DEBUG
  125.     static void FW_Check(FW_HString self, long minRefCount)
  126.     {
  127.         // No need for FW_ERR_TRY block
  128.         FW_PlatformError error;
  129.         FW_PRIV_ASSERT(self);
  130.         FW_PRIV_ASSERT(self->fRefCount>=minRefCount);
  131.         FW_PRIV_ASSERT(0 <= self->fText.text._length);
  132.         FW_PRIV_ASSERT(self->fText.text._length <= self->fText.text._maximum);
  133.         FW_PRIV_ASSERT(self->fText.text._buffer!=0);
  134.  
  135.         FW_ODITextParams params;
  136.         FW_TextParams_GetParams(&self->fText, ¶ms, &error);
  137.         FW_PRIV_ASSERT(error == 0);
  138.         FW_PRIV_ASSERT(self->fParams.fTextStart == params.fTextStart);
  139.         FW_PRIV_ASSERT(self->fParams.fTextByteLength == params.fTextByteLength);
  140.         FW_PRIV_ASSERT(self->fParams.fTextByteCapacity == params.fTextByteCapacity);
  141.         FW_PRIV_ASSERT(self->fParams.fTextByteLength <= self->fParams.fTextByteCapacity);
  142.     }
  143.     #define FW_CHECK(self) FW_Check(self, 1);
  144. #else
  145.     #define FW_CHECK(self)
  146. #endif
  147.  
  148. #ifdef FW_DEBUG
  149. #define CHECK_ERROR if (*error) { Debugger(); return 0; } else 0
  150. #else
  151. #define CHECK_ERROR if (*error) { return 0; } else 0
  152. #endif
  153.  
  154. //----------------------------------------------------------------------------------------
  155. //    StringRep_Clone
  156. //----------------------------------------------------------------------------------------
  157. // Conditionally creates a copy.  If the reference count of the
  158. // self is exactly one, or if self is locked, then self is simply returned, unchanged.
  159. // If the reference count of self is greater than one, then 
  160. // its contents are cloned, and self's reference count is decremented.
  161. // The reference count of the copy is set to 1.
  162. // Note that this function conserves the total reference count.
  163.  
  164. // If a clone is performed out, there are two possible outcomes. This illustration
  165. // demonstrates the semantics of cloning when two string objects share a common
  166. // representation. For simplification, there are only two strings involved -
  167. // the string being cloned, and one other string. In practice, there can
  168. // be additional clients of the common representation.
  169.  
  170. //    Prior to cloning, the object graph looks as follows:
  171. //
  172. //    cloneString     otherString
  173. //        |             |        
  174. //        \            /
  175. //         \           /
  176. //        \       /
  177. //           rep1
  178. //               |
  179. //               |
  180. //             buffer1
  181.  
  182. // Depending on whether or not the representation object is the empty string,
  183. // there will be one of two outcomes. The first illustration depicts the outcome
  184. // when the representation object is the empty string. First a new representation
  185. // object is created. A new buffer is created. The new representation is initialized
  186. // to point at the new buffer. The second illustration depicts the outcome when
  187. // the representation object is not the empty string. First a new representation
  188. // object is created. The new representation is initialized to point at the
  189. // existing buffer. Then a new buffer is created. The old representation object
  190. // is set to point at the new buffer. The data from the old buffer is then
  191. // copied into the new buffer. This logic is required specifically to prevent
  192. // dynamic strings from pointing at buffers owned by bound strings, while the
  193. // bounds strings point at heap-based buffers.
  194.  
  195. //    cloneString        otherString
  196. //        |                |
  197. //        |                |
  198. //      rep2              rep1
  199. //        |                |
  200. //        |                |
  201. //      buffer2        buffer1
  202.  
  203.  
  204. //    cloneString        otherString
  205. //        |                |
  206. //        |                |
  207. //      rep2              rep1
  208. //        |                |
  209. //        |                |
  210. //      buffer1        buffer2
  211.  
  212. static FW_HString StringRep_Clone(FW_HString self, FW_PlatformError *error);
  213.  
  214. static FW_HString StringRep_Clone(FW_HString self, FW_PlatformError *error)
  215. {
  216.     *error = 0;
  217.     FW_CHECK(self);
  218.     
  219.     FW_PRIV_ASSERT(self->fRefCount>=1);
  220.     FW_HString clone = self;
  221.     if ((!self->fLocked) && (self->fRefCount > 1))
  222.     {
  223.         FW_HString newBuffer;
  224.         FW_HString oldBuffer;
  225.         
  226.         clone = (FW_SPrivStringRep*)FW_PrimitiveAllocateBlock(sizeof(FW_SPrivStringRep));
  227.         if (clone == NULL)
  228.         {
  229.             *error = kODErrOutOfMemory;
  230.             return 0;
  231.         }
  232.         
  233.         *clone = *self;
  234.  
  235.         // If the representation being cloned is the empty string, then
  236.         // the clone 
  237.         if (self == &gEmptyStringRep)
  238.         {
  239.             newBuffer = clone;
  240.             oldBuffer = self;
  241.         }
  242.         else
  243.         {
  244.             newBuffer = self;
  245.             oldBuffer = clone;
  246.         }
  247.         
  248.         newBuffer->fRefCount = 0;
  249.         newBuffer->fText.text._buffer = (unsigned char*)
  250.                             FW_PrimitiveAllocateBlock(oldBuffer->fText.text._maximum);
  251.         if (newBuffer->fText.text._buffer == NULL)
  252.         {
  253.             *error = kODErrOutOfMemory;
  254.             return 0;
  255.         }
  256.         newBuffer->fUsingStaticBuffer = false;
  257.         newBuffer->fLocked = false;
  258.         ::FW_PrimitiveCopyMemory(oldBuffer->fText.text._buffer,
  259.                             newBuffer->fText.text._buffer,
  260.                             oldBuffer->fText.text._length);
  261.         ::FW_TextParams_GetParams(&newBuffer->fText, &newBuffer->fParams, error);
  262.         CHECK_ERROR;
  263.         ::FW_PrivString_Acquire(newBuffer);
  264.         ::FW_PrivString_Release(oldBuffer);
  265.     }
  266.     
  267.     FW_CHECK(self);
  268.     
  269.     return clone;
  270. }
  271. //----------------------------------------------------------------------------------------
  272. //    FW_PrivString_NewRepWithStaticBuffer
  273. //----------------------------------------------------------------------------------------
  274.  
  275. FW_HString FW_PrivString_NewRepWithStaticBuffer(unsigned char* buffer,
  276.                                     FW_ByteCount bufferLen)
  277. {
  278.     FW_HString rep = (FW_SPrivStringRep*) 
  279.                             FW_PrimitiveAllocateBlock(sizeof(FW_SPrivStringRep));
  280.     if (rep != NULL)
  281.     {
  282.         FW_PRIV_ASSERT(bufferLen > sizeof(FW_Locale));
  283.         FW_Locale* locale = (FW_Locale*) buffer;
  284.         *locale = gDefaultLocaleData;
  285.         
  286.         rep->fText.format = kODTraditionalMacText;
  287.         rep->fText.text._buffer = buffer;
  288.         rep->fText.text._maximum = bufferLen;
  289.         rep->fText.text._length = sizeof(gDefaultLocaleData);
  290.         
  291.         rep->fParams.fTextStart = (char*) buffer + sizeof(gDefaultLocaleData);
  292.         rep->fParams.fTextByteLength = 0;
  293.         rep->fParams.fTextByteCapacity = bufferLen - sizeof(gDefaultLocaleData);
  294.         
  295.         rep->fRefCount = 0;
  296.         rep->fUsingStaticBuffer = true;
  297.         rep->fLocked = false;
  298.     }
  299.     
  300.     return rep;
  301. }
  302.  
  303. //----------------------------------------------------------------------------------------
  304. //    FW_PrivString_ReleaseStaticBuffer
  305. //----------------------------------------------------------------------------------------
  306.  
  307. void FW_PrivString_ReleaseStaticBuffer(FW_HString self, FW_PlatformError* error)
  308. {
  309.     // This function should only be called from the destructor of bounded string
  310.     // classes.  When a bounded string class is being destroyed, the static buffer
  311.     // can no longer be used.  There are several cases that must be considered:
  312.     //
  313.     // 1) The StringRep is no longer using the static buffer because some
  314.     // operation caused the buffer to be reallocated (e.g. an append operation
  315.     // caused the string to grow beyond the capacity of the buffer).  In this
  316.     // case, the buffer has already been released, and nothing needs to be done.
  317.     // 
  318.     // 2) The StringRep is still using the static buffer, but the reference
  319.     // count is 1.  In that case, the last reference is about to be released
  320.     // and the whole rep will be blown away.  We don't need to save the contents
  321.     // of the buffer, and we especially do not want to clear the fUsingStaticBuffer
  322.     // flag, because that would cause FW_PrivString_Release to erroneously attempt
  323.     // to delete the buffer, which would likely corrupt the heap.  This means
  324.     // the correct thing is again to do nothing.
  325.     //
  326.     // 3) The stringRep is still using the static buffer, but the reference
  327.     // count is greater than 1.  In that case, a dynamic buffer must be allocated
  328.     // for the contents of the string.  We can safely mark the string as no longer
  329.     // using the static buffer (i.e. set fUsingStaticBuffer to false), since
  330.     // FW_PrivString_Release will only decrement the reference count and not
  331.     // delete the rep.
  332.  
  333.     *error = 0;
  334.     FW_CHECK(self);
  335.  
  336.     if (self->fRefCount>1 && self->fUsingStaticBuffer)
  337.     {
  338.         unsigned char* newBuffer = (unsigned char*) 
  339.                             FW_PrimitiveAllocateBlock(self->fText.text._maximum);
  340.         if (newBuffer == NULL)
  341.         {
  342.             *error = kODErrOutOfMemory;
  343.             return;
  344.         }
  345.         ::FW_PrimitiveCopyMemory(self->fText.text._buffer, 
  346.                             newBuffer, 
  347.                             self->fText.text._length);
  348.         self->fText.text._buffer = newBuffer;
  349.         self->fUsingStaticBuffer = false;
  350.         ::FW_TextParams_GetParams(&self->fText, &self->fParams, error);
  351.     }
  352. }
  353.  
  354. //----------------------------------------------------------------------------------------
  355. //    FW_PrivString_LockString
  356. //----------------------------------------------------------------------------------------
  357.  
  358. FW_HString FW_PrivString_LockString(FW_HString self, FW_PlatformError* error)
  359. {
  360.     FW_HString rep = self;
  361.     if (!rep->fLocked)
  362.     {
  363.         rep = ::StringRep_Clone(rep, error);
  364.         if (*error != 0)
  365.             return 0;
  366.         rep->fLocked = true;
  367.         rep->fRefCount = 0;
  368.     }
  369.     return rep;
  370. }
  371.  
  372. //----------------------------------------------------------------------------------------
  373. //    FW_PrivString_AcquireEmptyString
  374. //----------------------------------------------------------------------------------------
  375.  
  376. FW_HString FW_PrivString_AcquireEmptyString()
  377. {
  378.     FW_HString rep = &gEmptyStringRep;
  379.     ::FW_PrivString_Acquire(rep);
  380.     return rep;
  381. }
  382.  
  383. //----------------------------------------------------------------------------------------
  384. //    FW_PrivString_AcquireEmptyStringWithLocale
  385. //----------------------------------------------------------------------------------------
  386.  
  387. FW_HString FW_PrivString_AcquireEmptyStringWithLocale(FW_Locale locale, FW_PlatformError* error)
  388. {
  389.     FW_HString rep = &gEmptyStringRep;
  390.     ::FW_PrivString_Acquire(rep);
  391.     rep = ::StringRep_Clone(rep, error);
  392.     if (*error != 0)
  393.         return 0;
  394.     ::FW_TextParams_SetLocale(&rep->fText, locale, &rep->fParams, error);
  395.     if (*error != 0)
  396.         return 0;
  397. #ifdef FW_DEBUG
  398.     ::FW_Check(rep, 0);
  399. #endif
  400.     return rep;
  401. }
  402.  
  403. //----------------------------------------------------------------------------------------
  404. //    FW_PrivString_Acquire
  405. //----------------------------------------------------------------------------------------
  406.  
  407. void FW_PrivString_Acquire(FW_HString self)
  408. {
  409. #ifdef FW_DEBUG
  410.     ::FW_Check(self, 0);
  411. #endif
  412.     ++self->fRefCount;
  413. }
  414.  
  415. //----------------------------------------------------------------------------------------
  416. //    FW_PrivString_Release
  417. //----------------------------------------------------------------------------------------
  418.  
  419. void FW_PrivString_Release(FW_HString self)
  420. {
  421.     FW_CHECK(self);
  422.     if(--self->fRefCount == 0)
  423.     {
  424.         if (self->fLocked)
  425.         {
  426.             self->fLocked = false;
  427.             self->fRefCount = 1;
  428.         }
  429.         else
  430.         {
  431.             if (!self->fUsingStaticBuffer)
  432.                 FW_PrimitiveFreeBlock(self->fText.text._buffer);
  433.             FW_PrimitiveFreeBlock(self);
  434.         }
  435.     }
  436. }
  437.  
  438. //----------------------------------------------------------------------------------------
  439. //    FW_PrivString_GetByteLength
  440. //----------------------------------------------------------------------------------------
  441.  
  442. FW_ByteCount FW_PrivString_GetByteLength(FW_HString self)
  443. {
  444.     FW_CHECK(self);
  445.     return self->fParams.fTextByteLength;
  446. }
  447.  
  448. //----------------------------------------------------------------------------------------
  449. //    FW_PrivString_GetCapacity
  450. //----------------------------------------------------------------------------------------
  451.  
  452. FW_ByteCount FW_PrivString_GetCapacity(FW_HString self)
  453. {
  454.     FW_CHECK(self);
  455.     return self->fParams.fTextByteCapacity;
  456. }
  457.  
  458. //----------------------------------------------------------------------------------------
  459. //    FW_PrivString_GetCharacterLength
  460. //----------------------------------------------------------------------------------------
  461.  
  462. FW_CharacterCount FW_PrivString_GetCharacterLength(FW_HString self, FW_PlatformError* error)
  463. {
  464.     FW_CHECK(self);
  465.     FW_CharacterCount result = self->fParams.fTextByteLength;// assume singlebyte locale
  466.     if (!::FW_LocaleIsSingleByte(self->fParams.fTextLocale))
  467.     {
  468.         FW_BytePosition knownStart = 0;
  469.         FW_BytePosition position = 0;
  470.         result = 0;
  471.         while (position < self->fParams.fTextByteLength)
  472.         {
  473.             FW_Boolean isStart = ::FW_TextParams_IsCharacterStart(&self->fText, knownStart, position, error);
  474.             if (*error)
  475.                 return 0;
  476.             if (isStart)
  477.             {
  478.                 knownStart = position;
  479.                 result++;
  480.             }
  481.             position++;
  482.         }
  483.     }
  484.     return result;
  485. }
  486.  
  487. //----------------------------------------------------------------------------------------
  488. //    FW_PrivString_SetCapacity
  489. //----------------------------------------------------------------------------------------
  490. FW_HString FW_PrivString_SetCapacity(FW_HString self,
  491.                                      FW_ByteCount newCapacity, 
  492.                                      FW_PlatformError* error)
  493. {
  494.     FW_HString rep = ::StringRep_Clone(self, error);
  495.     if (*error)
  496.         return 0;
  497.  
  498.     ::FW_TextParams_SetCapacity(&rep->fText,
  499.                                 newCapacity, 
  500.                                 !rep->fUsingStaticBuffer,
  501.                                 &rep->fParams, 
  502.                                 error);
  503.     return rep;
  504. }
  505.  
  506. //----------------------------------------------------------------------------------------
  507. //    FW_PrivString_RevealODIText
  508. //----------------------------------------------------------------------------------------
  509.  
  510. ODIText* FW_PrivString_RevealODIText(FW_HString self)
  511. {
  512.     FW_CHECK(self);
  513.     return &self->fText;
  514. }
  515.  
  516. //----------------------------------------------------------------------------------------
  517. //    FW_PrivString_RevealBuffer
  518. //----------------------------------------------------------------------------------------
  519.  
  520. const char*    FW_PrivString_RevealBuffer(FW_HString self)
  521. {
  522.     FW_CHECK(self);
  523.     return self->fParams.fTextStart;
  524. }
  525.  
  526. //----------------------------------------------------------------------------------------
  527. //    FW_PrivString_RevealLocale
  528. //----------------------------------------------------------------------------------------
  529. FW_Locale* FW_PrivString_RevealLocale(FW_HString self)
  530. {
  531.     FW_CHECK(self);
  532.     return &self->fParams.fTextLocale;
  533. }
  534.  
  535. //----------------------------------------------------------------------------------------
  536. //    FW_PrivString_GetLocale
  537. //----------------------------------------------------------------------------------------
  538.  
  539. void FW_PrivString_GetLocale(FW_HString self, FW_Locale* locale)
  540. {
  541.     FW_CHECK(self);
  542.     *locale = self->fParams.fTextLocale;
  543. }
  544.  
  545. //----------------------------------------------------------------------------------------
  546. //    FW_PrivString_Retrieve
  547. //----------------------------------------------------------------------------------------
  548.  
  549. void FW_PrivString_Retrieve(FW_HString self, 
  550.             char* destination, 
  551.             FW_ByteCount numberBytes, 
  552.             FW_BytePosition position)
  553.  
  554. {
  555.     FW_CHECK(self);
  556.     ::FW_PrimitiveCopyMemory(self->fParams.fTextStart+position, destination, numberBytes);
  557. }
  558.  
  559. //----------------------------------------------------------------------------------------
  560. //    FW_PrivString_Delete
  561. //----------------------------------------------------------------------------------------
  562.  
  563. FW_HString FW_PrivString_Delete(FW_HString self, 
  564.                                 FW_ByteCount numberBytes, 
  565.                                 FW_BytePosition position, 
  566.                                 FW_PlatformError* error)
  567. {
  568.     FW_HString rep = ::StringRep_Clone(self, error);
  569.     if (*error)
  570.         return 0;
  571.  
  572.     ::FW_PrimitiveCopyMemory(rep->fParams.fTextStart+position+numberBytes, 
  573.                             rep->fParams.fTextStart+position, 
  574.                             rep->fParams.fTextByteLength-position-numberBytes);
  575.  
  576.     ::FW_TextParams_SetLength(&rep->fText, 
  577.                             rep->fParams.fTextByteLength-numberBytes, 
  578.                             &rep->fParams, error);
  579.     if (*error)
  580.         return 0;
  581.  
  582.     return rep;
  583. }
  584.  
  585. //----------------------------------------------------------------------------------------
  586. //    FW_PrivString_Truncate
  587. //----------------------------------------------------------------------------------------
  588.  
  589. FW_HString FW_PrivString_Truncate(FW_HString self, 
  590.                                 FW_BytePosition position, 
  591.                                 FW_PlatformError* error)
  592. {
  593.     FW_HString rep = ::StringRep_Clone(self, error);
  594.     if (*error)
  595.         return 0;
  596.  
  597.     FW_PRIV_ASSERT(position>=0);
  598.     FW_PRIV_ASSERT(position<=rep->fParams.fTextByteLength);
  599.     
  600.     ::FW_TextParams_SetLength(&rep->fText, position, &rep->fParams, error);
  601.     if (*error)
  602.         return 0;
  603.  
  604.     return rep;
  605. }
  606.  
  607. //----------------------------------------------------------------------------------------
  608. //    FW_PrivString_InsertBytes
  609. //----------------------------------------------------------------------------------------
  610.  
  611. FW_HString FW_PrivString_InsertBytes(FW_HString self, 
  612.                                 const char* bytes, 
  613.                                 FW_ByteCount numberBytes,  
  614.                                 FW_BytePosition position, 
  615.                                 FW_PlatformError* error)
  616. {
  617.     FW_HString rep = ::StringRep_Clone(self, error);
  618.     CHECK_ERROR;
  619.  
  620.     FW_PRIV_ASSERT(bytes);
  621.     FW_PRIV_ASSERT(numberBytes>=0);
  622.     FW_PRIV_ASSERT(position>=0);
  623.     FW_PRIV_ASSERT(position<=rep->fParams.fTextByteLength);
  624.  
  625.     // ensure string will have sufficient capacity
  626.     ::FW_TextParams_SetCapacity(&rep->fText, 
  627.                             rep->fParams.fTextByteLength+numberBytes, 
  628.                             !rep->fUsingStaticBuffer,
  629.                             &rep->fParams, error);
  630.     CHECK_ERROR;
  631.     FW_PRIV_ASSERT(rep->fParams.fTextByteLength+numberBytes 
  632.                     <= rep->fParams.fTextByteCapacity);
  633.  
  634.     // move end of string to new position and make room for insertion
  635.     ::FW_PrimitiveCopyMemory(rep->fParams.fTextStart+position, 
  636.                             rep->fParams.fTextStart+position+numberBytes, 
  637.                             rep->fParams.fTextByteLength-position);
  638.  
  639.     // insert bytes into position in rep
  640.     ::FW_PrimitiveCopyMemory(bytes, 
  641.                             rep->fParams.fTextStart+position, 
  642.                             numberBytes);
  643.  
  644.     // update for the new length
  645.     ::FW_TextParams_SetLength(&rep->fText, 
  646.                             rep->fParams.fTextByteLength+numberBytes, 
  647.                             &rep->fParams, error);
  648.     CHECK_ERROR;
  649.  
  650.     return rep;
  651. }
  652.  
  653. //----------------------------------------------------------------------------------------
  654. //    FW_PrivString_InsertODIText
  655. //----------------------------------------------------------------------------------------
  656.  
  657. FW_HString FW_PrivString_InsertODIText(FW_HString self, 
  658.                                     ODIText* text, 
  659.                                     FW_BytePosition position, 
  660.                                     FW_PlatformError* error)
  661. {
  662.     // No need for FW_ERR_TRY block
  663.     FW_ODITextParams params;
  664.     ::FW_TextParams_GetParams(text, ¶ms, error);
  665.     if (*error)
  666.         return 0;
  667.  
  668.     FW_HString result = ::FW_PrivString_InsertBytes(self, 
  669.                                         params.fTextStart, 
  670.                                         params.fTextByteLength, 
  671.                                         position,
  672.                                         error);
  673.     if (*error)
  674.         return 0;
  675.     return result;
  676. }
  677.  
  678. //----------------------------------------------------------------------------------------
  679. //    FW_PrivString_InsertStringRep
  680. //----------------------------------------------------------------------------------------
  681.  
  682. FW_HString FW_PrivString_InsertStringRep(FW_HString self, 
  683.                                         FW_HString other, 
  684.                                         FW_BytePosition position, 
  685.                                         FW_PlatformError* error)
  686. {
  687.     // No need for FW_ERR_TRY block
  688.     FW_CHECK(other);
  689.     FW_HString result = ::FW_PrivString_InsertBytes(self, 
  690.                                         other->fParams.fTextStart, 
  691.                                         other->fParams.fTextByteLength, 
  692.                                         position,
  693.                                         error);
  694.     if (*error)
  695.         return 0;
  696.     return result;
  697. }
  698.  
  699. //----------------------------------------------------------------------------------------
  700. //    FW_PrivString_ReplaceAllBytes
  701. //----------------------------------------------------------------------------------------
  702.  
  703. FW_HString FW_PrivString_ReplaceAllBytes(FW_HString self,
  704.                                         const char* bytes, 
  705.                                         FW_ByteCount numberBytes, 
  706.                                         FW_PlatformError* error)
  707. {
  708.     FW_HString rep = ::StringRep_Clone(self, error);
  709.     if (*error)
  710.         return 0;
  711.  
  712.     // ensure string will have sufficient capacity
  713.     ::FW_TextParams_SetCapacity(&rep->fText,
  714.                                 numberBytes, 
  715.                                 !rep->fUsingStaticBuffer,
  716.                                 &rep->fParams, 
  717.                                 error);
  718.     if (*error)
  719.         return 0;
  720.  
  721.     // Copy bytes into rep
  722.     ::FW_PrimitiveCopyMemory(bytes, rep->fParams.fTextStart, numberBytes);
  723.  
  724.     // update for the new length
  725.     ::FW_TextParams_SetLength(&rep->fText, numberBytes, &rep->fParams, error);
  726.     if (*error)
  727.         return 0;
  728.  
  729.     return rep;
  730. }
  731.  
  732. //----------------------------------------------------------------------------------------
  733. //    FW_PrivString_ReplaceAllODIText
  734. //----------------------------------------------------------------------------------------
  735.  
  736. FW_HString FW_PrivString_ReplaceAllODIText(FW_HString self, 
  737.                                         ODIText* text, 
  738.                                         FW_PlatformError* error)
  739. {
  740.     // No need for FW_ERR_TRY block
  741.     FW_HString result;
  742.     
  743.     FW_ODITextParams params;
  744.     ::FW_TextParams_GetParams(text, ¶ms, error);
  745.     if (*error)
  746.         return 0;
  747.  
  748.     result = ::FW_PrivString_ReplaceAllBytes(self, 
  749.                                         params.fTextStart, 
  750.                                         params.fTextByteLength,
  751.                                         error);
  752.     if (*error)
  753.         return 0;
  754.     
  755.     ::FW_TextParams_SetLocale(&result->fText, params.fTextLocale, &result->fParams, error);
  756.  
  757.     return result;
  758. }
  759.  
  760. //----------------------------------------------------------------------------------------
  761. //    FW_PrivString_ReplaceAllStringRep
  762. //----------------------------------------------------------------------------------------
  763.  
  764. FW_HString FW_PrivString_ReplaceAllStringRep(FW_HString self, 
  765.                                         FW_HString other, 
  766.                                         FW_PlatformError* error)
  767. {
  768.     // No need for FW_ERR_TRY block
  769.     FW_HString result = self;
  770.     if (self != other)
  771.     {
  772.         if (self->fLocked)
  773.         {
  774.             result = ::FW_PrivString_ReplaceAllBytes(self, 
  775.                                                 other->fParams.fTextStart, 
  776.                                                 other->fParams.fTextByteLength,
  777.                                                 error);
  778.             if (*error)
  779.                 return 0;
  780.  
  781.             ::FW_TextParams_SetLocale(&result->fText, other->fParams.fTextLocale, &result->fParams, error);
  782.         }
  783.         else
  784.         {
  785.             ::FW_PrivString_Acquire(other);
  786.             ::FW_PrivString_Release(self);
  787.             result = other;
  788.         }
  789.     }
  790.     return result;
  791. }
  792.  
  793. //----------------------------------------------------------------------------------------
  794. //    FW_PrivString_AppendBytes
  795. //----------------------------------------------------------------------------------------
  796.  
  797. FW_HString FW_PrivString_AppendBytes(FW_HString self,
  798.                                     const char* bytes, 
  799.                                     FW_ByteCount numberBytes, 
  800.                                     FW_PlatformError* error)
  801. {
  802.     // No need for FW_ERR_TRY block
  803.     FW_HString result = ::FW_PrivString_InsertBytes(self, 
  804.                                                 bytes, 
  805.                                                 numberBytes, 
  806.                                                 self->fParams.fTextByteLength,
  807.                                                 error);
  808.     CHECK_ERROR;
  809.     return result;
  810. }
  811.  
  812. //----------------------------------------------------------------------------------------
  813. //    FW_PrivString_AppendODIText
  814. //----------------------------------------------------------------------------------------
  815.  
  816. FW_HString FW_PrivString_AppendODIText(FW_HString self, 
  817.                                     ODIText* text, 
  818.                                     FW_PlatformError* error)
  819. {
  820.     // No need for FW_ERR_TRY block
  821.     FW_HString result = ::FW_PrivString_InsertODIText(self, 
  822.                                                     text, 
  823.                                                     self->fParams.fTextByteLength, 
  824.                                                     error);
  825.     CHECK_ERROR;
  826.     return result;
  827. }
  828.  
  829. //----------------------------------------------------------------------------------------
  830. //    FW_PrivString_AppendStringRep
  831. //----------------------------------------------------------------------------------------
  832.  
  833. FW_HString FW_PrivString_AppendStringRep(FW_HString self, 
  834.                                         FW_HString other, 
  835.                                         FW_PlatformError* error)
  836. {
  837.     // No need for FW_ERR_TRY block
  838.     FW_HString result = ::FW_PrivString_InsertStringRep(self, 
  839.                                         other, 
  840.                                         self->fParams.fTextByteLength, 
  841.                                         error);
  842.     if (*error)
  843.         return 0;
  844.     return result;
  845. }
  846.  
  847. //----------------------------------------------------------------------------------------
  848. //    FW_PrivString_PrependBytes
  849. //----------------------------------------------------------------------------------------
  850.  
  851. FW_HString FW_PrivString_PrependBytes(FW_HString self,
  852.                                     const char* bytes, 
  853.                                     FW_ByteCount numberBytes, 
  854.                                     FW_PlatformError* error)
  855. {
  856.     // No need for FW_ERR_TRY block
  857.     FW_HString result = ::FW_PrivString_InsertBytes(self, bytes, numberBytes, 0, error);
  858.     if (*error)
  859.         return 0;
  860.     return result;
  861. }
  862.  
  863. //----------------------------------------------------------------------------------------
  864. //    FW_PrivString_PrependODIText
  865. //----------------------------------------------------------------------------------------
  866.  
  867. FW_HString FW_PrivString_PrependODIText(FW_HString self, 
  868.                                         ODIText* text, 
  869.                                         FW_PlatformError* error)
  870. {
  871.     // No need for FW_ERR_TRY block
  872.     FW_HString result = ::FW_PrivString_InsertODIText(self, text, 0, error);
  873.     if (*error)
  874.         return 0;
  875.     return result;
  876. }
  877.  
  878. //----------------------------------------------------------------------------------------
  879. //    FW_PrivString_PrependStringRep
  880. //----------------------------------------------------------------------------------------
  881.  
  882. FW_HString FW_PrivString_PrependStringRep(FW_HString self, 
  883.                                         FW_HString other, 
  884.                                         FW_PlatformError* error)
  885. {
  886.     // No need for FW_ERR_TRY block
  887.     FW_HString result = ::FW_PrivString_InsertStringRep(self, other, 0, error);
  888.     if (*error)
  889.         return 0;
  890.     return result;
  891. }
  892.  
  893. //----------------------------------------------------------------------------------------
  894. //    FW_PrivString_ExportCString
  895. //----------------------------------------------------------------------------------------
  896.  
  897. void FW_PrivString_ExportCString(FW_HString self, char* buffer)
  898. {
  899.     const char nul = 0;
  900.     ::FW_PrivString_Retrieve(self, buffer, self->fParams.fTextByteLength, 0);
  901.     buffer[self->fParams.fTextByteLength] = nul;
  902. }
  903.  
  904. //----------------------------------------------------------------------------------------
  905. //    FW_PrivString_ExportPascalString
  906. //----------------------------------------------------------------------------------------
  907.  
  908. void FW_PrivString_ExportPascalString(FW_HString self, FW_PascalChar* buffer)
  909. {
  910.     ::FW_PrivString_Retrieve(self, (char*)buffer+1, self->fParams.fTextByteLength, 0);
  911.     buffer[0] = FW_PascalChar(self->fParams.fTextByteLength);
  912. }
  913.  
  914. //----------------------------------------------------------------------------------------
  915. //    FW_PrivString_ToUpper
  916. //----------------------------------------------------------------------------------------
  917.  
  918. FW_HString FW_PrivString_ToUpper(FW_HString self, FW_PlatformError* error)
  919. {
  920.     FW_HString rep = ::StringRep_Clone(self, error);
  921.     if (*error)
  922.         return 0;
  923. #ifdef FW_BUILD_MAC
  924.     ::UppercaseText(rep->fParams.fTextStart, 
  925.                     rep->fParams.fTextByteLength, 
  926.                     rep->fParams.fTextLocale.fScriptCode);
  927.     *error = ::ResError();
  928.     if (*error)
  929.         return 0;
  930. #elif defined FW_BUILD_WIN
  931.     //??? Need an international implementation for windows
  932.     for (int i=0; i<rep->fParams.fTextByteLength; i++)
  933.         rep->fParams.fTextStart[i] = toupper(rep->fParams.fTextStart[i]);
  934. #endif
  935.     return rep;
  936. }
  937.  
  938. //----------------------------------------------------------------------------------------
  939. //    FW_PrivString_ToLower
  940. //----------------------------------------------------------------------------------------
  941.  
  942. FW_HString FW_PrivString_ToLower(FW_HString self, FW_PlatformError* error)
  943. {
  944.     FW_HString rep = ::StringRep_Clone(self, error);
  945.     if (*error)
  946.         return 0;
  947. #ifdef FW_BUILD_MAC
  948.     ::LowercaseText(rep->fParams.fTextStart, 
  949.                     rep->fParams.fTextByteLength, 
  950.                     rep->fParams.fTextLocale.fScriptCode);
  951.     *error = ::ResError();
  952.     if (*error)
  953.         return 0;
  954. #elif defined FW_BUILD_WIN
  955.     //??? Need an international implementation for windows
  956.     for (int i=0; i<rep->fParams.fTextByteLength; i++)
  957.         rep->fParams.fTextStart[i] = tolower(rep->fParams.fTextStart[i]);
  958. #endif
  959.     return rep;
  960. }
  961.  
  962. //----------------------------------------------------------------------------------------
  963. //    RabinKarpSearch
  964. //
  965. // Reference: Introduction to Algorithms, By Corment, Leiserson & Rivest, page 860
  966. // Note: The standard library function strstr is possibly as efficient as RabinKarpSearch,
  967. // but unfortunately it assumes that both strings are NUL terminated ISO strings.  ODIText
  968. // data structures are not necessarily NUL terminated, so we can't use strstr.  Note also
  969. // that there are algorithms more efficient than Rabin-Karp, but they're more complicated
  970. // to implement, and unlikely to be significantly better than Rabin-Karp for most common
  971. // string searching tasks.  Developers creating text engines will probably keep their text
  972. // in some other kind of data structure and will have their own searching functions.
  973. //----------------------------------------------------------------------------------------
  974.  
  975. static unsigned long RadixPower(unsigned long radix, 
  976.                                 unsigned long power, 
  977.                                 unsigned long modulus)
  978. {
  979.     unsigned long result = 1;
  980.     while (--power > 0)
  981.         result = (result * radix) % modulus;
  982.     return result;
  983. }
  984.  
  985. class CPrivCharIterator
  986. {
  987. public:
  988.     CPrivCharIterator() {}
  989.     CPrivCharIterator(const unsigned char* pos, int delta) : fPos(pos), fDelta(delta) {}
  990.     CPrivCharIterator(const CPrivCharIterator& other) : fPos(other.fPos), fDelta(other.fDelta) {}
  991.     void operator++() { fPos += fDelta; }
  992.     operator const unsigned char*() const { return fPos; }
  993.     int operator==(const CPrivCharIterator& other) const { return fPos==other.fPos; }
  994.     int operator!=(const CPrivCharIterator& other) const { return fPos!=other.fPos; }
  995.     void operator=(const CPrivCharIterator& other) { fPos=other.fPos; fDelta=other.fDelta; }
  996.     unsigned char operator*() const { return *fPos; }
  997.     
  998. private:
  999.     const unsigned char* fPos;
  1000.     int fDelta;
  1001. };
  1002.  
  1003. const unsigned long kRadix = 256;
  1004. const unsigned long kModulus = (1L<<24) - 3;    // this is the largest prime less than 2**24
  1005.  
  1006. static unsigned long RunValue(CPrivCharIterator& begin, CPrivCharIterator& limit)
  1007. {
  1008.     unsigned long value = 0;
  1009.     CPrivCharIterator i;
  1010.     for (i=begin; i!=limit; ++i)
  1011.     {
  1012.         unsigned char c = *i;
  1013.         value = (kRadix*value + c) % kModulus;
  1014.     }
  1015.     return value;
  1016. }
  1017.  
  1018. static int PrivCompare(const CPrivCharIterator& pat, 
  1019.                         const CPrivCharIterator& window, 
  1020.                         const CPrivCharIterator& patLimit)
  1021. {
  1022.     CPrivCharIterator i=pat;
  1023.     CPrivCharIterator w=window;
  1024.     
  1025.     while (i!=patLimit)
  1026.     {
  1027.         if (*i != *w)
  1028.             return 0;
  1029.         ++i;
  1030.         ++w;
  1031.     }
  1032.     return 1;
  1033. }
  1034.  
  1035. static long RabinKarpSearch(const unsigned char* text, 
  1036.                             const unsigned char* pat, 
  1037.                             long n, // length of text
  1038.                             long m,    // length of pat
  1039.                             int searchForwards = 1)
  1040. {
  1041.     long shift = -1;
  1042.     if (m <= 0)
  1043.         return shift;
  1044.     if (m > n)
  1045.         return shift;
  1046.     
  1047.     const unsigned long h = RadixPower(kRadix, m, kModulus);
  1048.  
  1049.     CPrivCharIterator wbegin;
  1050.     CPrivCharIterator wend;
  1051.     CPrivCharIterator wlimit;
  1052.     CPrivCharIterator pbegin;
  1053.     CPrivCharIterator pend;
  1054.  
  1055.     if (searchForwards)
  1056.     {
  1057.         wbegin = CPrivCharIterator(text, 1);
  1058.         wend = CPrivCharIterator(text+m, 1);
  1059.         wlimit = CPrivCharIterator(text+n-m+1, 0);
  1060.         pbegin = CPrivCharIterator(pat, 1);
  1061.         pend = CPrivCharIterator(pat+m, 1);
  1062.     }
  1063.     else
  1064.     {
  1065.         wbegin = CPrivCharIterator(text+n-1, -1);
  1066.         wend = CPrivCharIterator(text+n-m-1, -1);
  1067.         wlimit = CPrivCharIterator(text-1, 0);
  1068.         pbegin = CPrivCharIterator(pat+m-1, -1);
  1069.         pend = CPrivCharIterator(pat-1, -1);
  1070.     }
  1071.  
  1072.     unsigned long p = RunValue(pbegin, pend);
  1073.     unsigned long t = RunValue(wbegin, wend);
  1074.  
  1075.     while (wbegin != wlimit)
  1076.     {
  1077.         if ((p == t) && PrivCompare(pbegin, wbegin, pend))
  1078.         {
  1079.             shift = (const unsigned char*)wbegin - text;
  1080.             break;
  1081.         }
  1082.  
  1083.         unsigned char c = *wbegin;
  1084.         ++wbegin;
  1085.  
  1086.         if (wbegin != wlimit)
  1087.         {
  1088.             // subtract out the oldest character
  1089.             unsigned long z = (c*h) % kModulus;
  1090.             if (t >= z)
  1091.                 t -= z;
  1092.             else
  1093.                 t = t + kModulus - z;
  1094.  
  1095.             // add in the new character
  1096.             c = *wend;
  1097.             t = (kRadix*t + c) % kModulus;
  1098.  
  1099.             ++wend;
  1100.             FW_ASSERT(t == RunValue(wbegin, wend));
  1101.         }
  1102.         
  1103.     }
  1104.     
  1105.     if (shift != -1 && !searchForwards)
  1106.     {
  1107.         shift -= (m-1);
  1108.     }
  1109.     
  1110.     return shift;
  1111. }
  1112.  
  1113. //----------------------------------------------------------------------------------------
  1114. //    FW_PrivString_FindCharacter
  1115. //----------------------------------------------------------------------------------------
  1116.  
  1117. static Boolean PrivIsCharacterMatch(FW_HString self, 
  1118.                                 FW_ByteCount i,
  1119.                                 FW_ByteCount *foundPosition)
  1120. {
  1121.     Boolean result = false;
  1122.     FW_PlatformError error = 0;
  1123.     if (::FW_LocaleIsSingleByte(self->fParams.fTextLocale)
  1124.         || FW_TextParams_IsCharacterStart(&self->fText, 0, i, &error))
  1125.     {
  1126.         FW_ASSERT(error == 0);
  1127.         result = true;
  1128.         *foundPosition = i;
  1129.     }
  1130.     return result;
  1131. }
  1132.  
  1133. const FW_LChar kLowByteMask = 0x0FF;
  1134. const FW_LChar kLowByteAntiMask = ~kLowByteMask;
  1135.  
  1136. static void LCharToBytes(FW_LChar c, char* bytes)
  1137. {
  1138.     *bytes++ = c >> 8;
  1139.     *bytes = c & kLowByteMask;
  1140. }
  1141.  
  1142. FW_Boolean FW_PrivString_FindCharacter(FW_HString self, 
  1143.                         FW_LChar character, 
  1144.                         FW_ByteCount *foundPosition, 
  1145.                         FW_ByteCount startPosition,
  1146.                         FW_FindDirection direction)
  1147. {
  1148.     FW_Boolean result = false;    // assume failure to find character
  1149.     
  1150.     if ((character & kLowByteAntiMask) == 0)
  1151.     {
  1152.         // If the character we're searching for is a single byte character
  1153.         // then we can use a simple char-by-char scan
  1154.         register char c = (char) (character & kLowByteMask);
  1155.         register const char* text = self->fParams.fTextStart;
  1156.         if (direction == FW_kForwards)
  1157.         {
  1158.             for (FW_ByteCount i=startPosition; i<self->fParams.fTextByteLength; i++)
  1159.             {
  1160.                 if ((text[i] == c) && (result=PrivIsCharacterMatch(self, i, foundPosition)) == true)
  1161.                     break;
  1162.             }
  1163.         }
  1164.         else
  1165.         {
  1166.             for (FW_ByteCount i=startPosition; i>=0; i--)
  1167.             {
  1168.                 if ((text[i] == c) && (result=PrivIsCharacterMatch(self, i, foundPosition)) == true)
  1169.                     break;
  1170.             }
  1171.         }
  1172.     }
  1173.     else if (!::FW_LocaleIsSingleByte(self->fParams.fTextLocale))
  1174.     {
  1175.         // If we've gotten to here, we have a locale that is not single-byte,
  1176.         // and we're searching for a character that is not a single-byte character.
  1177.         // We handle that case by making a single-character string and then doing
  1178.         // a substring search.
  1179.         char bytes[2];
  1180.         LCharToBytes(character, bytes);
  1181.         *foundPosition = RabinKarpSearch((const unsigned char*)self->fParams.fTextStart+startPosition, 
  1182.                             (const unsigned char*)bytes, 
  1183.                             self->fParams.fTextByteLength-startPosition,
  1184.                             2,    // length of pat
  1185.                             direction == FW_kForwards);
  1186.         result = *foundPosition != -1;
  1187.         if (result)
  1188.         {
  1189.             *foundPosition += startPosition;
  1190.         }
  1191.     }
  1192.     else
  1193.     {
  1194.         // If we've gotten to here, we're trying to find a multi-byte character
  1195.         // in a single-byte locale string. By definition, that must fail, right?
  1196.         // Since result is already set to false, we don't have to do anything.
  1197.     }
  1198.     return result;
  1199. }
  1200.  
  1201. //----------------------------------------------------------------------------------------
  1202. //    FW_PrivString_FindSubString
  1203. //----------------------------------------------------------------------------------------
  1204.  
  1205. FW_Boolean FW_PrivString_FindSubString(FW_HString self, 
  1206.                         FW_HString subString, 
  1207.                         FW_ByteCount *foundPosition, 
  1208.                         FW_ByteCount startPosition)
  1209. {
  1210.     *foundPosition = RabinKarpSearch((const unsigned char*) self->fParams.fTextStart+startPosition,
  1211.                                 (const unsigned char*) subString->fParams.fTextStart,
  1212.                                 self->fParams.fTextByteLength-startPosition,
  1213.                                 subString->fParams.fTextByteLength);
  1214.     if (*foundPosition != -1)
  1215.         *foundPosition += startPosition;
  1216.     return (*foundPosition != -1);
  1217. }
  1218.  
  1219. //----------------------------------------------------------------------------------------
  1220. //    FW_PrivString_Substitute
  1221. //----------------------------------------------------------------------------------------
  1222.  
  1223. FW_HString FW_PrivString_Substitute(FW_HString self, 
  1224.                         FW_HString searchString, 
  1225.                         FW_HString substitutionString, 
  1226.                         FW_Boolean* wasReplaced, 
  1227.                         FW_PlatformError* error)
  1228. {
  1229.     FW_HString rep = self;
  1230.     FW_ByteCount foundPosition;
  1231.     *wasReplaced = false;
  1232.     if (::FW_PrivString_FindSubString(self, searchString, &foundPosition, 0))
  1233.     {
  1234.         FW_HString temp;
  1235.         rep = ::StringRep_Clone(self, error);
  1236.         temp = ::FW_PrivString_Delete(rep, 
  1237.                                     FW_PrivString_GetByteLength(searchString), 
  1238.                                     foundPosition,
  1239.                                     error);
  1240.         if (*error)
  1241.             return 0;
  1242.         FW_PRIV_ASSERT(temp == rep);
  1243.         temp = ::FW_PrivString_InsertStringRep(rep, 
  1244.                                         substitutionString, 
  1245.                                         foundPosition, 
  1246.                                         error);
  1247.         if (*error)
  1248.             return 0;
  1249.         FW_PRIV_ASSERT(temp == rep);
  1250.         *wasReplaced = true;
  1251.     }
  1252.     return rep;
  1253. }
  1254.  
  1255. //----------------------------------------------------------------------------------------
  1256. //    FW_WinHackTextCompare
  1257. //----------------------------------------------------------------------------------------
  1258.  
  1259. #ifdef FW_BUILD_WIN
  1260. // This is a hack.  It does a byte level compare.
  1261. // We need the proper text compare routine for windows
  1262. static FW_StringCompareResult FW_WinHackTextCompare(
  1263.                         const char *p1, 
  1264.                         const char *p2,
  1265.                         FW_ByteCount len1,
  1266.                         FW_ByteCount len2)
  1267. {
  1268.     FW_ByteCount len = len1;
  1269.     int result = 0;     // assume strings are equal
  1270.     if (len1 < len2)
  1271.         result = -1;    // now assume string 1 is less because it's shorter
  1272.     else if (len1 > len2)
  1273.     {
  1274.         result = 1;        // now assume string 1 is greater because it's longer
  1275.         len = len2;
  1276.     }
  1277.     
  1278.     const unsigned char* s1 = (const unsigned char*) p1;
  1279.     const unsigned char* s2 = (const unsigned char*) p2;
  1280.     
  1281.     unsigned char c1 = *s1;
  1282.     unsigned char c2 = *s2;
  1283.  
  1284.     while (len-- > 0)
  1285.     {
  1286.         c1 = *s1++;
  1287.         c2 = *s2++;
  1288.         if (!c1)
  1289.             break;
  1290.         if (c1 != c2)
  1291.             break;
  1292.     }
  1293.     
  1294.     if (len > 0)
  1295.     {
  1296.         if (c1 < c2)
  1297.             result = -1;
  1298.         if (c1 > c2)
  1299.             result = 1;
  1300.     }
  1301.         
  1302.     return result;
  1303. }
  1304. #endif
  1305.  
  1306. //----------------------------------------------------------------------------------------
  1307. //    FW_PrivString_Compare
  1308. //----------------------------------------------------------------------------------------
  1309.  
  1310. FW_StringCompareResult FW_PrivString_Compare(FW_HString string1, FW_HString string2)
  1311. {
  1312. #ifdef FW_BUILD_MAC
  1313.     return ::TextOrder(string1->fParams.fTextStart, 
  1314.                          string2->fParams.fTextStart, 
  1315.                          string1->fParams.fTextByteLength, 
  1316.                          string2->fParams.fTextByteLength, 
  1317.                          string1->fParams.fTextLocale.fScriptCode, 
  1318.                          string2->fParams.fTextLocale.fScriptCode, 
  1319.                          string1->fParams.fTextLocale.fLangCode, 
  1320.                          string2->fParams.fTextLocale.fLangCode);
  1321. #else
  1322.     return ::FW_WinHackTextCompare(string1->fParams.fTextStart, 
  1323.                          string2->fParams.fTextStart, 
  1324.                          string1->fParams.fTextByteLength, 
  1325.                          string2->fParams.fTextByteLength);
  1326. #endif
  1327. }
  1328.  
  1329. //----------------------------------------------------------------------------------------
  1330. //    Number Conversion Functions
  1331. //----------------------------------------------------------------------------------------
  1332.  
  1333. //----------------------------------------------------------------------------------------
  1334. //    FW_PrivString_SignedIntegerToDecimalString
  1335. //----------------------------------------------------------------------------------------
  1336.  
  1337. FW_HString FW_PrivString_SignedIntegerToDecimalString(FW_HString self, 
  1338.                                                     long integer, 
  1339.                                                     FW_PlatformError* error)
  1340. {
  1341.     // we allow for the possiblity that longs are more than 32 bits
  1342.     const int kMaxDigits = 32;
  1343.     char string[kMaxDigits];
  1344.     FW_Boolean negative = integer < 0;
  1345.     if (negative) 
  1346.         integer = -integer;
  1347.     const char kZero = '0';
  1348.     const long int kBase = 10;
  1349.         
  1350.     int i = kMaxDigits;
  1351.  
  1352.     if (integer == 0)
  1353.     {
  1354.         --i;
  1355.         string[i] = kZero;
  1356.     }
  1357.     else
  1358.     {
  1359.         while (integer > 0)
  1360.         {
  1361.             --i;
  1362.             string[i] = (char) (integer % kBase) + kZero;
  1363.             integer = integer / kBase;
  1364.         }
  1365.     }
  1366.     
  1367.     if (negative)
  1368.     {
  1369.         --i;
  1370.         string[i] = '-';
  1371.     }
  1372.     
  1373.     return ::FW_PrivString_ReplaceAllBytes(self, string+i, kMaxDigits-i, error);
  1374. }
  1375.  
  1376. //----------------------------------------------------------------------------------------
  1377. //    FW_PrivString_UnsignedIntegerToDecimalString
  1378. //----------------------------------------------------------------------------------------
  1379.  
  1380. FW_HString FW_PrivString_UnsignedIntegerToDecimalString(FW_HString self, 
  1381.                                                     unsigned long integer, 
  1382.                                                     FW_PlatformError* error)
  1383. {
  1384.     // we allow for the possiblity that longs are more than 32 bits
  1385.     const int kMaxDigits = 32;
  1386.     char string[kMaxDigits];
  1387.     const char kZero = '0';
  1388.     const long int kBase = 10;
  1389.         
  1390.     int i = kMaxDigits;
  1391.  
  1392.     if (integer == 0)
  1393.     {
  1394.         --i;
  1395.         string[i] = kZero;
  1396.     }
  1397.     else
  1398.     {
  1399.         while (integer > 0)
  1400.         {
  1401.             --i;
  1402.             string[i] = (char) (integer % kBase) + kZero;
  1403.             integer = integer / kBase;
  1404.         }
  1405.     }
  1406.     
  1407.     return ::FW_PrivString_ReplaceAllBytes(self, string+i, kMaxDigits-i, error);
  1408. }
  1409.  
  1410. //----------------------------------------------------------------------------------------
  1411. //    FW_PrivString_UnsignedIntegerToHexadecimalString
  1412. //----------------------------------------------------------------------------------------
  1413.  
  1414. FW_HString FW_PrivString_UnsignedIntegerToHexadecimalString(FW_HString self, 
  1415.                                                     unsigned long integer, 
  1416.                                                     FW_PlatformError* error)
  1417. {
  1418.     // we allow for the possiblity that longs are more than 32 bits
  1419.     const int kMaxDigits = 32;
  1420.     char string[kMaxDigits];
  1421.     const char kZero = '0';
  1422.     const char kA = 'A';
  1423.     const long int kBase = 16;
  1424.         
  1425.     int i = kMaxDigits;
  1426.  
  1427.     if (integer == 0)
  1428.     {
  1429.         --i;
  1430.         string[i] = kZero;
  1431.     }
  1432.     else
  1433.     {
  1434.         while (integer > 0)
  1435.         {
  1436.             --i;
  1437.             unsigned long digit = (integer % kBase);
  1438.             if (digit < 10)
  1439.                 string[i] = (char) digit + kZero;
  1440.             else
  1441.                 string[i] = (char) digit + kA;
  1442.             integer = integer / kBase;
  1443.         }
  1444.     }
  1445.     
  1446.     return ::FW_PrivString_ReplaceAllBytes(self, string+i, kMaxDigits-i, error);
  1447. }
  1448.  
  1449. //----------------------------------------------------------------------------------------
  1450. //    FW_PrivString_DecimalStringToSignedInteger
  1451. //----------------------------------------------------------------------------------------
  1452.  
  1453. long FW_PrivString_DecimalStringToSignedInteger(FW_HString self)
  1454. {
  1455.     const char* string = self->fParams.fTextStart;
  1456.     const char* last = string + self->fParams.fTextByteLength;
  1457.     FW_Boolean negative = (*string == '-');
  1458.     const char kZero = '0';
  1459.     const char kNine = '9';
  1460.     const long int kBase = 10;
  1461.     long result = 0;
  1462.  
  1463.     if (negative)
  1464.         ++string;
  1465.     
  1466.     while ((string<last) && (*string >= kZero) && (*string <= kNine))
  1467.     {
  1468.         long digit = *string - kZero;
  1469.         result = result*kBase + digit;
  1470.         ++string;
  1471.     }
  1472.     
  1473.     if (negative)
  1474.         result = -result;
  1475.     
  1476.     return result;
  1477. }
  1478.  
  1479. //----------------------------------------------------------------------------------------
  1480. //    FW_PrivString_DecimalStringToUnsignedInteger
  1481. //----------------------------------------------------------------------------------------
  1482.  
  1483. unsigned long FW_PrivString_DecimalStringToUnsignedInteger(FW_HString self)
  1484. {
  1485.     const char* string = self->fParams.fTextStart;
  1486.     const char* last = string + self->fParams.fTextByteLength;
  1487.     const char kZero = '0';
  1488.     const char kNine = '9';
  1489.     const unsigned long int kBase = 10;
  1490.     unsigned long result = 0;
  1491.  
  1492.     while ((string<last) && (*string >= kZero) && (*string <= kNine))
  1493.     {
  1494.         unsigned long digit = *string - kZero;
  1495.         result = result*kBase + digit;
  1496.         ++string;
  1497.     }
  1498.     
  1499.     return result;
  1500. }
  1501.  
  1502. //----------------------------------------------------------------------------------------
  1503. //    IsHex
  1504. //----------------------------------------------------------------------------------------
  1505.  
  1506. static FW_Boolean IsHex(const char hexChar, unsigned long& digit)
  1507. {
  1508.     FW_Boolean result = false;
  1509.     if (hexChar>='0' && hexChar<='9')
  1510.     {
  1511.         result = true;
  1512.         digit = hexChar - '0';
  1513.     }
  1514.     else if (hexChar>='a' && hexChar<='f')
  1515.     {
  1516.         result = true;
  1517.         digit = hexChar - 'a';
  1518.     }
  1519.     else if (hexChar>='A' && hexChar<='F')
  1520.     {
  1521.         result = true;
  1522.         digit = hexChar - 'A';
  1523.     }
  1524.     return result;
  1525. }
  1526.  
  1527. //----------------------------------------------------------------------------------------
  1528. //    FW_PrivString_HexadecimalStringToUnsignedInteger
  1529. //----------------------------------------------------------------------------------------
  1530.  
  1531. unsigned long FW_PrivString_HexadecimalStringToUnsignedInteger(FW_HString self)
  1532. {
  1533.     const char* string = self->fParams.fTextStart;
  1534.     const char* last = string + self->fParams.fTextByteLength;
  1535.     const unsigned long int kBase = 16;
  1536.     unsigned long result = 0;
  1537.     unsigned long digit;
  1538.  
  1539.     while ((string<last) && IsHex(*string, digit))
  1540.     {
  1541.         result = result*kBase + digit;
  1542.         ++string;
  1543.     }
  1544.     
  1545.     return result;
  1546. }
  1547.  
  1548. //----------------------------------------------------------------------------------------
  1549. //    FW_PrivString_DoubleToString
  1550. //----------------------------------------------------------------------------------------
  1551.  
  1552. FW_HString FW_PrivString_DoubleToString(FW_HString self, 
  1553.                                         double value, 
  1554.                                         short fractionalDigits, 
  1555.                                         FW_PlatformError* error)
  1556. {
  1557. #ifdef FW_BUILD_MAC
  1558.     decform form = {FIXEDDECIMAL, 0, fractionalDigits};
  1559.     decimal intermediate;
  1560.     char buffer[DECSTROUTLEN];
  1561.     
  1562.     num2dec(&form, value, &intermediate);
  1563.     dec2str(&form, &intermediate, buffer);
  1564.     
  1565.     return ::FW_PrivString_ReplaceAllBytes(self, 
  1566.                                         buffer, 
  1567.                                         FW_PrimitiveStringLength(buffer), 
  1568.                                         error);
  1569. #elif defined FW_BUILD_WIN
  1570.     FW_PRIV_ASSERT(Not_Yet_Implemented);
  1571.     return (FW_HString) NULL;
  1572. #endif
  1573. }
  1574.  
  1575. //----------------------------------------------------------------------------------------
  1576. //    FW_PrivString_StringToDouble
  1577. //----------------------------------------------------------------------------------------
  1578.  
  1579. double FW_PrivString_StringToDouble(FW_HString self)
  1580. {
  1581.     double result = 0;
  1582.     
  1583. #if defined FW_BUILD_MAC
  1584.     // See IM-PPC Numerics for documentation on str2dec (chap 9, "Conversion Functions")
  1585.     decimal intermediate;        // On return, a pointer to the decimal structure containing the decimal number.
  1586.     short ix = 0;                // On entry, the starting position in the string. 
  1587.                                 // On return, one greater than the position of the last character in the 
  1588.                                 // string that was parsed if the entire string was not converted successfully.
  1589.     short vp;                    // On return, a Boolean argument indicating the success of the function. 
  1590.                                 // If the entire string was parsed, vp is true. If part of the string was parsed, 
  1591.                                 // vp is false and ix indicates where the function stopped parsing.
  1592.     char buffer[256];
  1593.     FW_PrivString_ExportCString(self, buffer);
  1594.     str2dec(buffer, &ix, &intermediate, &vp);
  1595.     result = dec2num(&intermediate);
  1596. #elif defined FW_BUILD_WIN
  1597.     FW_PRIV_ASSERT(Not_Yet_Implemented);
  1598. #endif
  1599.  
  1600.     return result;
  1601. }
  1602.  
  1603.