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 / SLCharIt.cpp < prev    next >
Encoding:
Text File  |  1996-09-17  |  24.3 KB  |  794 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                SLCharIt.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 SLCHARIT_H
  13. #include "SLCharIt.h"
  14. #endif
  15.  
  16. #ifndef PRCHARIT_H
  17. #include "PRCharIt.h"
  18. #endif
  19.  
  20. #ifndef PRSTRREP_H
  21. #include "PRStrRep.h"
  22. #endif
  23.  
  24. #ifndef SOM_FW_OTextRunReader_xh
  25. #include "SLTxtRun.xh"
  26. #endif
  27.  
  28. #ifdef FW_BUILD_MAC
  29. #pragma segment Strings
  30. #endif
  31.  
  32. //========================================================================================
  33. // Error handling strategy:
  34. //
  35. //    This unit provides interfaces that are exported from a shared library.
  36. //  As such, these interfaces must catch all exceptions and turn them into error codes.
  37. //
  38. //    Most functions in this unit only call functions that are known to not throw exceptions.
  39. //  For these functions, we do not use a try block, but instead simply check the error
  40. //  codes and return if any error is seen during the execution of the function. 
  41. //
  42. //    A few functions in this unit do call functions that can throw exceptions.  Two
  43. //    possibilities must be considered:
  44. //
  45. //    1) The function calls a SOM member function.  We assume that the SOM C++ binding will 
  46. //    invoke our SOMCHKEXCEPT which will throw an exception.
  47. //
  48. //    2) The function calls ::operator new.  We assume that operator new will throw an
  49. //    exception if the allocation fails.
  50. //
  51. //    There should be no other way for exceptions to be raised.  Functions defined here that
  52. //  can raise exceptions via 1) or 2) above must be enclosed in a try block.  We use the
  53. //    FW_SOM_TRY macros which will convert the exception into an Environment error.
  54. //========================================================================================
  55.  
  56. //----------------------------------------------------------------------------------------
  57. //    ByteInBlock
  58. //----------------------------------------------------------------------------------------
  59.  
  60. inline FW_ByteCount BytesInBlock(const char* last, const char* first)
  61. {
  62.     return last - first;
  63. }
  64.  
  65. //----------------------------------------------------------------------------------------
  66. //    PreviousByte
  67. //----------------------------------------------------------------------------------------
  68.  
  69. inline const char* PreviousByte(const char* current, FW_ByteCount delta)
  70. {
  71.     return current - delta;
  72. }
  73.  
  74. //----------------------------------------------------------------------------------------
  75. //    ClassInvariants
  76. //----------------------------------------------------------------------------------------
  77.  
  78. #ifdef FW_DEBUG
  79. static void ClassInvariants(FW_HTextReader self)
  80. {
  81.     if (self->fNext == 0)
  82.     {
  83.         // Must be in initial state, before first GetNextBuffer
  84.         FW_PRIV_ASSERT(self->fStart == 0);
  85.         FW_PRIV_ASSERT(self->fLimit == 0);
  86.         FW_PRIV_ASSERT(self->fBufferSum == 0);        
  87.     }
  88.     else if (self->fNext == self->fLimit)
  89.     {
  90.         // Must be at end of data structure
  91.         FW_PRIV_ASSERT(self->fBufferSum == self->fByteLength);
  92.     }
  93.     else
  94.     {
  95.         FW_PRIV_ASSERT(self->fBufferSum < self->fByteLength);
  96.         if (self->fNext < self->fStart)
  97.         {
  98.             // Must be at position -1 (backup past beginning)
  99.             FW_PRIV_ASSERT(self->fBufferSum == 0);
  100.             FW_PRIV_ASSERT(self->fNext == self->fStart-1); // may not be correct anymore
  101.         }
  102.         else
  103.         {
  104.             // Must be somewhere in middle of stream
  105.             FW_PRIV_ASSERT(self->fStart <= self->fNext);
  106.             FW_PRIV_ASSERT(self->fNext <= self->fLimit);
  107.         }
  108.     }
  109. }
  110. #else
  111. inline void ClassInvariants(FW_HTextReader) {}
  112.     // Let optimizer remove empty inline
  113. #endif
  114.  
  115. //----------------------------------------------------------------------------------------
  116. //    TextReader_Initialize
  117. //----------------------------------------------------------------------------------------
  118.  
  119. static void TextReader_Initialize(FW_HTextReader self, 
  120.                                 Environment* ev,
  121.                                 FW_OTextRunReader* adoptedReader)
  122. {
  123.     FW_SOM_TRY
  124.     {
  125.         FW_ByteCount length;
  126.         FW_Locale locale;
  127.         const char* start = adoptedReader->GetCurrentRun(ev, &length, &locale); // may throw
  128.         self->fLocale = locale;
  129.         self->fReader = adoptedReader;
  130.         self->fStart = start;
  131.         self->fLimit = self->fStart+length;
  132.         self->fNext = self->fStart;
  133.         self->fByteLength = self->fReader->GetTotalLength(ev); // may throw
  134.         ClassInvariants(self);
  135.     }
  136.     FW_SOM_CATCH
  137. }
  138.  
  139. //----------------------------------------------------------------------------------------
  140. //    FW_PrivTextReader_Initialize
  141. //----------------------------------------------------------------------------------------
  142.  
  143. FW_HTextReader FW_PrivTextReader_New(Environment* ev, FW_OTextRunReader* adoptedReader)
  144. {
  145.     FW_SOM_TRY
  146.     {
  147.         FW_HTextReader self = new FW_SPrivTextReader;    // may throw
  148.         self->fReader = 0;
  149.         self->fStart = 0;
  150.         self->fLimit = 0;
  151.         self->fNext = 0;
  152.         self->fByteLength = 0;
  153.         self->fBufferSum = 0;
  154. //        self->fLocale.fScriptCode = 0;
  155. //        self->fLocale.fLangCode = 0;
  156.         self->fLocale = FW_PrivGetDefaultLocale();
  157.         self->fRefCount = 0;
  158.         TextReader_Initialize(self, ev, adoptedReader);
  159.         return self;
  160.     }
  161.     FW_SOM_CATCH
  162.     return 0;
  163. }
  164.  
  165. //----------------------------------------------------------------------------------------
  166. //    FW_PrivTextReader_Acquire
  167. //----------------------------------------------------------------------------------------
  168.  
  169. void FW_PrivTextReader_Acquire(FW_HTextReader self, Environment* ev)
  170. {
  171. FW_UNUSED(ev);
  172.     // No FW_SOM_TRY necessary
  173.     ++self->fRefCount;
  174. }
  175.  
  176. //----------------------------------------------------------------------------------------
  177. //    FW_PrivTextReader_Delete
  178. //----------------------------------------------------------------------------------------
  179.  
  180. void FW_PrivTextReader_Release(FW_HTextReader self, Environment* ev)
  181. {
  182. FW_UNUSED(ev);
  183.     // No FW_SOM_TRY necessary
  184.     if (--self->fRefCount == 0)
  185.         delete self;
  186. }
  187.  
  188. //----------------------------------------------------------------------------------------
  189. //    FW_PrivTextReader_GetCharacterAndAdvance
  190. //----------------------------------------------------------------------------------------
  191.  
  192. FW_LChar FW_PrivTextReader_GetCharacterAndAdvance(FW_HTextReader self, Environment* ev, FW_ByteCount* bytesInChar)
  193. {
  194.     // No FW_SOM_TRY necessary
  195.     ClassInvariants(self);
  196.     FW_ByteCount b;
  197.     if (!bytesInChar)
  198.         bytesInChar = &b;
  199.     FW_LChar temp = FW_PrivTextReader_PeekCharacter(self, bytesInChar);
  200.     if (temp != FW_kNulCharacter)
  201.         FW_PrivTextReader_Advance(self, ev, *bytesInChar);
  202.     ClassInvariants(self);
  203.     return temp;
  204. }
  205.  
  206. //----------------------------------------------------------------------------------------
  207. //    FW_PrivTextReader_Advance
  208. //----------------------------------------------------------------------------------------
  209.  
  210. void FW_PrivTextReader_Advance(FW_HTextReader self, Environment* ev, FW_ByteCount delta)
  211. {
  212.     // No FW_SOM_TRY necessary
  213.     ClassInvariants(self);
  214.     FW_PRIV_ASSERT(delta>=0);
  215.     FW_PRIV_ASSERT(delta+FW_PrivTextReader_GetPosition(self) <= self->fByteLength);
  216.     FW_ByteCount inThisBuf = BytesInBlock(self->fLimit, self->fNext);
  217.     while (delta >= inThisBuf)
  218.     {
  219.         delta -= inThisBuf;
  220.         self->fNext += inThisBuf;
  221.         FW_PrivTextReader_GetNextBuffer(self, ev);
  222.         if (FW_GetEvError(ev))
  223.             return;
  224.         inThisBuf = BytesInBlock(self->fLimit, self->fStart);
  225.     }
  226.     self->fNext += delta;
  227.     ClassInvariants(self);
  228. }
  229.  
  230. //----------------------------------------------------------------------------------------
  231. //    FW_PrivTextReader_PeekCharacter
  232. //----------------------------------------------------------------------------------------
  233.  
  234. FW_LChar FW_PrivTextReader_PeekCharacter(FW_HTextReader self, FW_ByteCount* bytesInChar)
  235. {
  236.     // No FW_SOM_TRY necessary, no error possible
  237.     ClassInvariants(self);
  238.  
  239.     FW_Boolean singleByte = FW_LocaleIsSingleByte(self->fLocale);
  240.     if (bytesInChar)
  241.         *bytesInChar = 1;    // default to single byte characters
  242.  
  243.     if (self->fNext >= self->fStart && self->fNext < self->fLimit)
  244.     {
  245.         FW_LChar ch = *self->fNext;
  246.         if (singleByte)
  247.             return ch;
  248.  
  249.         // Check for double-byte
  250.         if (FW_CharIsDoubleByte(self->fNext, 0, self->fLocale))
  251.         {
  252.             ch = *((FW_LChar*)self->fNext);
  253.             if (bytesInChar)
  254.                 *bytesInChar = 2;
  255.         }
  256.         
  257.         return ch;
  258.     }
  259.     else
  260.         return FW_kNulCharacter;
  261. }
  262.  
  263. //----------------------------------------------------------------------------------------
  264. //    FW_PrivTextReader_GetPosition
  265. //----------------------------------------------------------------------------------------
  266.  
  267. FW_ByteCount FW_PrivTextReader_GetPosition(FW_HTextReader self)
  268. {
  269.     // No FW_SOM_TRY necessary, no error possible
  270.     ClassInvariants(self);
  271.     FW_ByteCount result;
  272.  
  273.     if (self->fNext == self->fLimit)
  274.         result = self->fBufferSum;
  275.     else
  276.         result = self->fBufferSum + (self->fNext - self->fStart);
  277.  
  278.     return result;
  279. }
  280.  
  281. //----------------------------------------------------------------------------------------
  282. //    DelegateGetNextBuffer
  283. //----------------------------------------------------------------------------------------
  284.  
  285. static void DelegateGetNextBuffer(FW_HTextReader self, Environment* ev)
  286. {
  287.     FW_SOM_TRY
  288.     {
  289.         FW_ByteCount length;
  290.         if (self->fReader->NextRun(ev))    // may throw
  291.         {
  292.             FW_Locale locale;
  293.             const char* start = self->fReader->GetCurrentRun(ev, &length, &locale); // may throw
  294.             self->fStart = start;
  295.             self->fLimit = start + length;
  296.             self->fLocale = locale;
  297.         }
  298.         else
  299.         {
  300.             self->fStart = 0;
  301.             self->fLimit = 0;
  302.         }
  303.     }
  304.     FW_SOM_CATCH
  305. }
  306.  
  307. //----------------------------------------------------------------------------------------
  308. //    FW_PrivTextReader_GetNextBuffer
  309. //----------------------------------------------------------------------------------------
  310.  
  311. void FW_PrivTextReader_GetNextBuffer(FW_HTextReader self, Environment* ev)
  312. {
  313.     // No FW_SOM_TRY necessary
  314.     // ClassInvariants won't hold here.
  315.     // This function is called to (among other things) restore class invariants.
  316.     FW_PRIV_ASSERT(self->fNext == self->fLimit);    // Must hold, but violates invariants
  317.     self->fBufferSum += BytesInBlock(self->fLimit, self->fStart);
  318.     if (self->fBufferSum < self->fByteLength)
  319.     {
  320.         DelegateGetNextBuffer(self, ev);
  321.         if (FW_GetEvError(ev))
  322.             return;
  323.         self->fNext = self->fStart;
  324.     }
  325.     else
  326.     {
  327.         FW_PRIV_ASSERT(self->fBufferSum == self->fByteLength);
  328.         self->fNext = self->fLimit;
  329.     }
  330.     ClassInvariants(self);
  331. }
  332.  
  333. //----------------------------------------------------------------------------------------
  334. //    FW_PrivTextReader_BackupAndGetCharacter
  335. //----------------------------------------------------------------------------------------
  336.  
  337. FW_LChar FW_PrivTextReader_BackupAndGetCharacter(FW_HTextReader self, Environment* ev, FW_ByteCount* bytesInChar)
  338. {
  339.     // No FW_SOM_TRY necessary
  340.     ClassInvariants(self);
  341.  
  342.     if (FW_LocaleIsSingleByte(self->fLocale))
  343.     {
  344.         FW_PrivTextReader_Backup(self, ev, 1);
  345.         if (FW_GetEvError(ev))
  346.             return 0;
  347.         ClassInvariants(self);
  348.         return FW_PrivTextReader_PeekCharacter(self, bytesInChar);
  349.     }
  350.     else
  351.     {
  352.         // probably double-byte, so back up 2 bytes
  353.         FW_PrivTextReader_Backup(self, ev, 2);
  354.         if (FW_GetEvError(ev))
  355.             return 0;
  356.  
  357.         // check the character
  358.         if (FW_PrivTextReader_PeekCharacterSize(self) == 2)
  359.             return FW_PrivTextReader_PeekCharacter(self, bytesInChar);
  360.  
  361.         // either single-byte or 2nd of double-byte
  362.         FW_PrivTextReader_Advance(self, ev, 1);
  363.         if (FW_GetEvError(ev))
  364.             return 0;
  365.         ClassInvariants(self);
  366.         return FW_PrivTextReader_PeekCharacter(self, bytesInChar);
  367.     }
  368. }
  369.  
  370. //----------------------------------------------------------------------------------------
  371. //    FW_PrivTextReader_Backup
  372. //----------------------------------------------------------------------------------------
  373.  
  374. void FW_PrivTextReader_Backup(FW_HTextReader self, Environment* ev, FW_ByteCount delta)
  375. {
  376.     // No FW_SOM_TRY necessary
  377.     ClassInvariants(self);
  378.     FW_PRIV_ASSERT(delta>=0);
  379. /*    FW_PRIV_ASSERT(delta<=GetPosition());    * doesn't allow backup at start */
  380.  
  381.     if (delta > 0)
  382.     {
  383.         if (self->fNext==self->fStart)    // at the start of a buffer
  384.         {
  385.             FW_PrivTextReader_GetPreviousBuffer(self, ev);
  386.             if (FW_GetEvError(ev))
  387.                 return;
  388.         }
  389.         else if (self->fNext == self->fLimit)    // at the end of the last buffer
  390.         {    // subtract bytes that were added by GetNextBuffer
  391.             self->fBufferSum -= BytesInBlock(self->fLimit, self->fStart);
  392.         }
  393.  
  394.         FW_ByteCount inThisBuf = BytesInBlock(self->fNext, self->fStart);
  395.         if (inThisBuf > 0)
  396.             while (delta > inThisBuf)
  397.             {
  398.                 delta -= inThisBuf;
  399.                 self->fNext = self->fStart;
  400.                 FW_PrivTextReader_GetPreviousBuffer(self, ev);
  401.                 if (FW_GetEvError(ev))
  402.                     return;
  403.                 inThisBuf = BytesInBlock(self->fNext, self->fStart);
  404.             }
  405.         self->fNext = PreviousByte(self->fNext, delta);    // may backup before fStart (-1)
  406.         ClassInvariants(self);
  407.     }
  408. }
  409.  
  410. //----------------------------------------------------------------------------------------
  411. //    DelegateGetPreviousBuffer
  412. //----------------------------------------------------------------------------------------
  413.  
  414. static void DelegateGetPreviousBuffer(FW_HTextReader self, Environment* ev)
  415. {
  416.     FW_SOM_TRY
  417.     {
  418.         FW_ByteCount length;
  419.         if (self->fReader->PreviousRun(ev)) // may throw
  420.         {
  421.             FW_Locale locale;
  422.             const char* start = self->fReader->GetCurrentRun(ev, &length, &locale); // may throw
  423.             self->fStart = start;
  424.             self->fLimit = start+length;
  425.             self->fLocale = locale;
  426.         }
  427.         else
  428.         {
  429.             self->fStart = 0;
  430.             self->fLimit = 0;
  431.         }
  432.     }
  433.     FW_SOM_CATCH
  434. }
  435.  
  436.  
  437. //----------------------------------------------------------------------------------------
  438. //    FW_PrivTextReader_GetPreviousBuffer
  439. //----------------------------------------------------------------------------------------
  440.  
  441. void FW_PrivTextReader_GetPreviousBuffer(FW_HTextReader self, Environment* ev)
  442. {
  443.     // No FW_SOM_TRY necessary
  444.     ClassInvariants(self);
  445.     if (self->fBufferSum == 0)
  446.     {
  447.         self->fNext = self->fStart;
  448.     }
  449.     else if (self->fBufferSum == self->fByteLength)
  450.     {
  451.         FW_PRIV_ASSERT(self->fLimit == self->fNext);
  452.         self->fBufferSum -= BytesInBlock(self->fLimit, self->fStart);
  453.     }
  454.     else
  455.     {
  456.         FW_PRIV_ASSERT(self->fStart == self->fNext);
  457.         DelegateGetPreviousBuffer(self, ev);
  458.         if (FW_GetEvError(ev))
  459.             return;
  460.         FW_PRIV_ASSERT(self->fStart < self->fLimit);
  461.         self->fBufferSum -= BytesInBlock(self->fLimit, self->fStart);
  462.         FW_PRIV_ASSERT(self->fBufferSum >= 0);
  463.         self->fNext = self->fLimit;
  464.     }
  465.     // Invariants won't hold here
  466.     // The calling function must modify fNext appropriately
  467.     // Note that GetPreviousBuffer is a protected method,
  468.     // so clients are not held responsible to restore invariants.
  469.     // Also, subclasses shouldn't need to call this function directly.
  470. }
  471.  
  472. //----------------------------------------------------------------------------------------
  473. //    FW_PrivTextReader_SetPosition
  474. //----------------------------------------------------------------------------------------
  475.  
  476. void FW_PrivTextReader_SetPosition(FW_HTextReader self, Environment* ev, FW_ByteCount position)
  477. {
  478.     // No FW_SOM_TRY necessary
  479.     ClassInvariants(self);
  480.     FW_PRIV_ASSERT(position>=0);
  481.     FW_PRIV_ASSERT(position<=self->fByteLength);
  482.     FW_ByteCount curPosition = FW_PrivTextReader_GetPosition(self);
  483.     if (position < curPosition)
  484.         FW_PrivTextReader_Backup(self, ev, curPosition-position);
  485.     else if (position > curPosition)
  486.         FW_PrivTextReader_Advance(self, ev, position-curPosition);
  487.     ClassInvariants(self);
  488. }
  489.  
  490. //----------------------------------------------------------------------------------------
  491. //    FW_PrivTextReader_GetByteLength
  492. //----------------------------------------------------------------------------------------
  493.  
  494. FW_ByteCount FW_PrivTextReader_GetByteLength(FW_HTextReader self)
  495. {
  496.     // No FW_SOM_TRY necessary
  497.     return self->fByteLength;
  498. }
  499.  
  500. //----------------------------------------------------------------------------------------
  501. //    FW_PrivTextReader_GetLocale
  502. //----------------------------------------------------------------------------------------
  503.  
  504. void FW_PrivTextReader_GetLocale(FW_HTextReader self, FW_Locale* locale)
  505. {
  506.     // No FW_SOM_TRY necessary
  507.     *locale = self->fLocale;
  508. }
  509.  
  510. //----------------------------------------------------------------------------------------
  511. //    FW_PrivTextReader_PeekRunAhead
  512. //----------------------------------------------------------------------------------------
  513.  
  514. void FW_PrivTextReader_PeekRunAhead(FW_HTextReader self, const char** start, FW_ByteCount* length)
  515. {
  516.     // No FW_SOM_TRY necessary, no error possible
  517.     *start = self->fNext;
  518.     *length = self->fLimit - self->fNext;
  519. }
  520.  
  521. //----------------------------------------------------------------------------------------
  522. //    FW_PrivTextReader_PeekRunBehind
  523. //----------------------------------------------------------------------------------------
  524.  
  525. void FW_PrivTextReader_PeekRunBehind(FW_HTextReader self, const char** end, FW_ByteCount* length)
  526. {
  527.     // No FW_SOM_TRY necessary, no error possible
  528.     *end = self->fNext;
  529.     *length = self->fNext - self->fStart;
  530. }
  531.  
  532. //----------------------------------------------------------------------------------------
  533. //    FW_PrivTextReader_PeekByte
  534. //----------------------------------------------------------------------------------------
  535.  
  536. const char* FW_PrivTextReader_PeekByte(FW_HTextReader self)
  537. {
  538.     // No FW_SOM_TRY necessary, no error possible
  539.     ClassInvariants(self);
  540.  
  541.     if (self->fNext>=self->fStart && self->fNext<self->fLimit)
  542.         return self->fNext;
  543.     else
  544.         return NULL;
  545. }
  546.  
  547. //----------------------------------------------------------------------------------------
  548. //    FW_PrivTextReader_PeekCharacterSize
  549. //----------------------------------------------------------------------------------------
  550.  
  551. FW_ByteCount FW_PrivTextReader_PeekCharacterSize(FW_HTextReader self)
  552. {
  553.     // No FW_SOM_TRY necessary, no error possible
  554.     ClassInvariants(self);
  555.  
  556.     if (self->fNext >= self->fStart && self->fNext < self->fLimit)
  557.     {
  558.         if (FW_LocaleIsSingleByte(self->fLocale))
  559.             return 1;
  560.  
  561.         // Check for double-byte character
  562.         if (FW_CharIsDoubleByte(self->fNext, 0, self->fLocale))
  563.             return 2;
  564.         
  565.         return 1;
  566.     }
  567.  
  568.     return 0;
  569. }
  570.  
  571. //========================================================================================
  572. //    FW_SPrivTextWriter Functions
  573. //========================================================================================
  574.  
  575. //----------------------------------------------------------------------------------------
  576. //    TextWriter_Initialize
  577. //----------------------------------------------------------------------------------------
  578.  
  579. static void TextWriter_Initialize(FW_HTextWriter self, Environment* ev, FW_OTextRunWriter* adoptedWriter)
  580. {
  581.     FW_SOM_TRY
  582.     {
  583.         FW_ByteCount length;
  584.         FW_Locale locale;
  585.         char* start = adoptedWriter->GetCurrentRun(ev, &length);    // may throw
  586.         self->fWriter = adoptedWriter;
  587.         adoptedWriter->GetLocale(ev, &locale);    // may throw
  588.         self->fLocale = locale;
  589.         self->fStart = start;
  590.         self->fLimit = start + length;
  591.         self->fNext = start;
  592.     }
  593.     FW_SOM_CATCH
  594. }
  595.  
  596. //----------------------------------------------------------------------------------------
  597. //    FW_SPrivTextWriter_New
  598. //----------------------------------------------------------------------------------------
  599.  
  600. FW_HTextWriter FW_PrivTextWriter_New(Environment* ev, FW_OTextRunWriter* adoptedWriter)
  601. {
  602.     FW_SOM_TRY
  603.     {
  604.         FW_HTextWriter self = new FW_SPrivTextWriter;    // may throw
  605.         self->fWriter = 0;
  606.         self->fStart = 0;
  607.         self->fLimit = 0;
  608.         self->fNext = 0;
  609.         self->fBufferSum = 0;
  610. //        self->fLocale.fScriptCode = 0;
  611. //        self->fLocale.fLangCode = 0;
  612.         self->fLocale = FW_PrivGetDefaultLocale();
  613.         self->fRefCount = 0;
  614.         TextWriter_Initialize(self, ev, adoptedWriter);
  615.         return self;
  616.     }
  617.     FW_SOM_CATCH
  618.     return 0;
  619. }
  620.  
  621. //----------------------------------------------------------------------------------------
  622. //    TextWriter_Delete
  623. //----------------------------------------------------------------------------------------
  624.  
  625. static void TextWriter_Delete(FW_HTextWriter self, Environment* ev)
  626. {
  627.     // No FW_SOM_TRY necessary
  628.     FW_PRIV_ASSERT(self->fNext <= self->fLimit);
  629.     if (self->fStart <  self->fNext)
  630.     {
  631.         FW_PrivTextWriter_FlushBuffer(self, ev);
  632.         if (FW_GetEvError(ev))
  633.             return;
  634.     }
  635.     FW_PRIV_ASSERT(self->fStart == self->fNext);
  636.     delete self;
  637. }
  638.  
  639. //----------------------------------------------------------------------------------------
  640. //    FW_PrivTextWriter_Acquire
  641. //----------------------------------------------------------------------------------------
  642.  
  643. void FW_PrivTextWriter_Acquire(FW_HTextWriter self)
  644. {
  645.     // No FW_SOM_TRY necessary, no error possible
  646.     ++self->fRefCount;
  647. }
  648.  
  649. //----------------------------------------------------------------------------------------
  650. //    FW_PrivTextWriter_Release
  651. //----------------------------------------------------------------------------------------
  652.  
  653. void FW_PrivTextWriter_Release(FW_HTextWriter self, Environment* ev)
  654. {
  655.     // No FW_SOM_TRY necessary
  656.     if (--self->fRefCount == 0)
  657.         TextWriter_Delete(self, ev);
  658. }
  659.  
  660. //----------------------------------------------------------------------------------------
  661. //    FW_PrivTextWriter_SetBufferSum
  662. //----------------------------------------------------------------------------------------
  663.  
  664. void FW_PrivTextWriter_SetBufferSum(FW_HTextWriter self, FW_ByteCount bufferSum)
  665. {
  666.     // No FW_SOM_TRY necessary, no error possible
  667.     self->fBufferSum = bufferSum;
  668. }
  669.     
  670. //----------------------------------------------------------------------------------------
  671. //    FW_PrivTextWriter_FlushBuffer
  672. //----------------------------------------------------------------------------------------
  673.  
  674. void FW_PrivTextWriter_FlushBuffer(FW_HTextWriter self, Environment* ev)
  675. {
  676.     FW_SOM_TRY
  677.     {
  678.         FW_PRIV_ASSERT(self->fNext <= self->fLimit);
  679.         FW_ByteCount bytesToFlush = self->fNext - self->fStart;
  680.         self->fWriter->FlushRun(ev, self->fStart, bytesToFlush);    // may throw
  681.         self->fBufferSum += bytesToFlush;
  682.         self->fStart = self->fNext;        // Mark the bytes as being written
  683.     }
  684.     FW_SOM_CATCH
  685. }
  686.  
  687. //----------------------------------------------------------------------------------------
  688. //    FW_PrivTextWriter_FlushAndGetNextBuffer
  689. //----------------------------------------------------------------------------------------
  690.  
  691. void FW_PrivTextWriter_FlushAndGetNextBuffer(FW_HTextWriter self, Environment* ev)
  692. {
  693.     FW_SOM_TRY
  694.     {
  695.         FW_ByteCount length;
  696.         FW_PrivTextWriter_FlushBuffer(self, ev);        // flush entire buffer
  697.         self->fWriter->FlushRun(ev, self->fStart, self->fNext - self->fStart);    // may throw
  698.         self->fWriter->NewRun(ev, &self->fLocale);    // may throw
  699.         self->fStart = self->fWriter->GetCurrentRun(ev, &length);    // may throw
  700.         self->fLimit = self->fStart + length;
  701.         self->fNext = self->fStart;
  702.     }
  703.     FW_SOM_CATCH
  704. }
  705.  
  706. //----------------------------------------------------------------------------------------
  707. //    FW_PrivTextWriter_PutCharacterAndAdvance
  708. //----------------------------------------------------------------------------------------
  709.  
  710. void FW_PrivTextWriter_PutCharacterAndAdvance(FW_HTextWriter self, 
  711.                                             Environment* ev, 
  712.                                             FW_LChar character, 
  713.                                             FW_ByteCount bytesInChar)
  714. {
  715.     // No FW_SOM_TRY necessary
  716.  
  717.     const FW_LChar kLowByteMask = 0x00FF;
  718.  
  719.     if (self->fNext >= self->fLimit)
  720.     {
  721.         FW_PrivTextWriter_FlushAndGetNextBuffer(self, ev);
  722.         if (FW_GetEvError(ev))
  723.             return;
  724.     }
  725.  
  726.     if (bytesInChar == 0)
  727.     {
  728.         bytesInChar = 1;
  729.         if (!FW_LocaleIsSingleByte(self->fLocale))
  730.         {    // probably a double-byte character; check for non-zero high byte
  731.             register FW_LChar ch = character >> 8;
  732.             if (ch != 0)
  733.                 bytesInChar = 2;
  734.         }
  735.     }
  736.  
  737.     if (bytesInChar == 1)
  738.         *self->fNext = (FW_Char) character;
  739.     else
  740.     {
  741.         *self->fNext = character >> 8;
  742.         *(self->fNext+1) = character & kLowByteMask;
  743.     }
  744.  
  745.     self->fNext += bytesInChar;
  746. }
  747.  
  748. //----------------------------------------------------------------------------------------
  749. //    FW_PrivTextWriter_GetPosition
  750. //----------------------------------------------------------------------------------------
  751.  
  752. FW_ByteCount FW_PrivTextWriter_GetPosition(FW_HTextWriter self, Environment* ev)
  753. {
  754. FW_UNUSED(ev);
  755.     // No FW_SOM_TRY necessary, no error possible
  756.     return self->fBufferSum + (self->fNext - self->fStart);
  757. }
  758.  
  759. //----------------------------------------------------------------------------------------
  760. //    FW_PrivTextWriter_WritePeek
  761. //----------------------------------------------------------------------------------------
  762.  
  763. void FW_PrivTextWriter_WritePeek(FW_HTextWriter self, Environment* ev, char** start, FW_ByteCount* length)
  764. {
  765.     // No FW_SOM_TRY necessary
  766.     FW_PRIV_ASSERT(self->fNext <= self->fLimit);
  767.     if (self->fNext == self->fLimit)
  768.     {
  769.         FW_PrivTextWriter_FlushAndGetNextBuffer(self, ev);
  770.         if (FW_GetEvError(ev))
  771.             return;
  772.     }
  773.  
  774.     *start = self->fNext;
  775.     *length = self->fLimit - self->fNext;
  776. }
  777.  
  778. //----------------------------------------------------------------------------------------
  779. //    FW_PrivTextWriter_WritePeekAdvance
  780. //----------------------------------------------------------------------------------------
  781.  
  782. void FW_PrivTextWriter_WritePeekAdvance(FW_HTextWriter self, char* start, FW_ByteCount bytesWritten)
  783. {
  784. #ifndef FW_DEBUG
  785.     FW_UNUSED(start);
  786. #endif
  787.     // No FW_SOM_TRY necessary, no error possible
  788.     FW_PRIV_ASSERT(start == self->fNext);
  789.     FW_PRIV_ASSERT(bytesWritten <= self->fLimit - self->fNext);
  790.     self->fNext += bytesWritten;
  791. }
  792.  
  793.  
  794.