home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / common / scsu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-19  |  43.9 KB  |  1,405 lines

  1. /*
  2. *******************************************************************************
  3. *                                                                             *
  4. * COPYRIGHT:                                                                  *
  5. *   (C) Copyright International Business Machines Corporation, 1998           *
  6. *   Licensed Material - Program-Property of IBM - All Rights Reserved.        *
  7. *   US Government Users Restricted Rights - Use, duplication, or disclosure   *
  8. *   restricted by GSA ADP Schedule Contract with IBM Corp.                    *
  9. *                                                                             *
  10. *******************************************************************************
  11. *
  12. * File scsu.c
  13. *
  14. * Modification History:
  15. *
  16. *   Date        Name        Description
  17. *   05/17/99    stephen        Creation (ported from java UnicodeCompressor.java)
  18. *   09/21/99    stephen     Updated to handle data splits on decompression.
  19. *******************************************************************************
  20. */
  21.  
  22. #include <limits.h>
  23.  
  24. #include "scsu.h"
  25.  
  26. #include "cmemory.h"
  27.  
  28. /* Generic window shift */
  29. #define COMPRESSIONOFFSET 0x80
  30.  
  31. /* Indicates a window index is invalid */
  32. #define INVALIDWINDOW -1
  33.  
  34. /* Indicates a character doesn't exist in input */
  35. #define INVALIDCHAR -1
  36.  
  37. /* Compression modes */
  38. #define SINGLEBYTEMODE 0
  39. #define UNICODEMODE 1
  40.  
  41. /* Reserved index value */
  42. #define RESERVEDINDEX 0x00
  43.  
  44. /* Indices for scripts which cross a half-block boundary */
  45. #define LATININDEX 0xF9
  46. #define IPAEXTENSIONINDEX 0xFA
  47. #define GREEKINDEX 0xFB
  48. #define ARMENIANINDEX 0xFC
  49. #define HIRAGANAINDEX 0xFD
  50. #define KATAKANAINDEX 0xFE
  51. #define HALFWIDTHKATAKANAINDEX 0xFF
  52.  
  53. /* Single-byte mode tags */
  54. #define SDEFINEX 0x0B
  55. /* 0x0C is a reserved value*/
  56. #define SRESERVED 0x0C
  57. #define SQUOTEU 0x0E
  58. #define SCHANGEU 0x0F
  59.  
  60. #define SQUOTE0 0x01
  61. #define SQUOTE1 0x02
  62. #define SQUOTE2 0x03
  63. #define SQUOTE3 0x04
  64. #define SQUOTE4 0x05
  65. #define SQUOTE5 0x06
  66. #define SQUOTE6 0x07
  67. #define SQUOTE7 0x08
  68.  
  69. #define SCHANGE0 0x10
  70. #define SCHANGE1 0x11
  71. #define SCHANGE2 0x12
  72. #define SCHANGE3 0x13
  73. #define SCHANGE4 0x14
  74. #define SCHANGE5 0x15
  75. #define SCHANGE6 0x16
  76. #define SCHANGE7 0x17
  77.  
  78. #define SDEFINE0 0x18
  79. #define SDEFINE1 0x19
  80. #define SDEFINE2 0x1A
  81. #define SDEFINE3 0x1B
  82. #define SDEFINE4 0x1C
  83. #define SDEFINE5 0x1D
  84. #define SDEFINE6 0x1E
  85. #define SDEFINE7 0x1F
  86.  
  87. /* Unicode mode tags */
  88. #define UCHANGE0 0xE0
  89. #define UCHANGE1 0xE1
  90. #define UCHANGE2 0xE2
  91. #define UCHANGE3 0xE3
  92. #define UCHANGE4 0xE4
  93. #define UCHANGE5 0xE5
  94. #define UCHANGE6 0xE6
  95. #define UCHANGE7 0xE7
  96.  
  97. #define UDEFINE0 0xE8
  98. #define UDEFINE1 0xE9
  99. #define UDEFINE2 0xEA
  100. #define UDEFINE3 0xEB
  101. #define UDEFINE4 0xEC
  102. #define UDEFINE5 0xED
  103. #define UDEFINE6 0xEE
  104. #define UDEFINE7 0xEF
  105.  
  106. #define UQUOTEU 0xF0
  107. #define UDEFINEX 0xF1
  108. /* 0xF2 is a reserved value*/
  109. #define URESERVED 0xF2
  110.  
  111. /* Local function prototypes */
  112. static int32_t scsu_makeIndex(int32_t c);
  113. static bool_t scsu_inDynamicWindow(const UnicodeCompressor *comp,
  114.                    int32_t c, 
  115.                    int32_t whichWindow);
  116. static bool_t scsu_inStaticWindow(int32_t c, 
  117.                   int32_t whichWindow);
  118. static bool_t scsu_isCompressible(int32_t c);
  119. static int32_t scsu_findDynamicWindow(const UnicodeCompressor *comp,
  120.                       int32_t c);
  121. static int32_t scsu_findStaticWindow(int32_t c);
  122. static int32_t scsu_getLRDefinedWindow(const UnicodeCompressor *comp);
  123.  
  124. /* Static tables generated by CompressionTableGenerator */
  125.  
  126. /** For window offset mapping */
  127. static int32_t sOffsetTable [] = { 
  128.   0x0, 0x80, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400, 0x480,
  129.   0x500, 0x580, 0x600, 0x680, 0x700, 0x780, 0x800, 0x880, 0x900,
  130.   0x980, 0xa00, 0xa80, 0xb00, 0xb80, 0xc00, 0xc80, 0xd00, 0xd80,
  131.   0xe00, 0xe80, 0xf00, 0xf80, 0x1000, 0x1080, 0x1100, 0x1180,
  132.   0x1200, 0x1280, 0x1300, 0x1380, 0x1400, 0x1480, 0x1500, 0x1580,
  133.   0x1600, 0x1680, 0x1700, 0x1780, 0x1800, 0x1880, 0x1900, 0x1980,
  134.   0x1a00, 0x1a80, 0x1b00, 0x1b80, 0x1c00, 0x1c80, 0x1d00, 0x1d80,
  135.   0x1e00, 0x1e80, 0x1f00, 0x1f80, 0x2000, 0x2080, 0x2100, 0x2180,
  136.   0x2200, 0x2280, 0x2300, 0x2380, 0x2400, 0x2480, 0x2500, 0x2580,
  137.   0x2600, 0x2680, 0x2700, 0x2780, 0x2800, 0x2880, 0x2900, 0x2980,
  138.   0x2a00, 0x2a80, 0x2b00, 0x2b80, 0x2c00, 0x2c80, 0x2d00, 0x2d80,
  139.   0x2e00, 0x2e80, 0x2f00, 0x2f80, 0x3000, 0x3080, 0x3100, 0x3180,
  140.   0x3200, 0x3280, 0x3300, 0x3380, 0xe000, 0xe080, 0xe100, 0xe180,
  141.   0xe200, 0xe280, 0xe300, 0xe380, 0xe400, 0xe480, 0xe500, 0xe580,
  142.   0xe600, 0xe680, 0xe700, 0xe780, 0xe800, 0xe880, 0xe900, 0xe980,
  143.   0xea00, 0xea80, 0xeb00, 0xeb80, 0xec00, 0xec80, 0xed00, 0xed80,
  144.   0xee00, 0xee80, 0xef00, 0xef80, 0xf000, 0xf080, 0xf100, 0xf180,
  145.   0xf200, 0xf280, 0xf300, 0xf380, 0xf400, 0xf480, 0xf500, 0xf580,
  146.   0xf600, 0xf680, 0xf700, 0xf780, 0xf800, 0xf880, 0xf900, 0xf980,
  147.   0xfa00, 0xfa80, 0xfb00, 0xfb80, 0xfc00, 0xfc80, 0xfd00, 0xfd80,
  148.   0xfe00, 0xfe80, 0xff00, 0xff80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  149.   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  150.   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  151.   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  152.   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  153.   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  154.   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0, 0x250, 0x370,
  155.   0x530, 0x3040, 0x30a0, 0xff60  
  156. };
  157.  
  158. /** For quick identification of a byte as a single-byte mode tag */
  159. static bool_t sSingleTagTable [] = {
  160.   FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE,
  161.   FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
  162.   TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
  163.   TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,FALSE, FALSE,
  164.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  165.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  166.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  167.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  168.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  169.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  170.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  171.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  172.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  173.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  174.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  175.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  176.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  177.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  178.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  179.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  180.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  181.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  182.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  183.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  184.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  185.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  186.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  187.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE 
  188. };
  189.  
  190. /** For quick identification of a byte as a unicode mode tag */
  191. static bool_t sUnicodeTagTable [] = {
  192.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  193.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  194.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  195.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  196.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  197.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  198.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  199.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  200.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  201.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  202.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  203.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  204.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  205.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  206.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  207.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  208.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  209.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  210.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  211.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  212.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  213.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  214.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  215.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  216.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,
  217.   TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
  218.   TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
  219.   FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  220.   FALSE
  221. };
  222.  
  223. /** Static compression window offsets */
  224. static int32_t sOffsets [] = {
  225.   0x0000,   /* for quoting single-byte mode tags*/
  226.   0x0080,   /* Latin-1 Supplement*/
  227.   0x0100,   /* Latin Extended-A*/
  228.   0x0300,   /* Combining Diacritical Marks*/
  229.   0x2000,   /* General Punctuation*/
  230.   0x2080,   /* Curency Symbols*/
  231.   0x2100,   /* Letterlike Symbols and Number Forms*/
  232.   0x3000    /* CJK Symbols and Punctuation*/
  233. };
  234.  
  235.  
  236. void
  237. scsu_init(UnicodeCompressor *comp)
  238. {
  239.   /* initialize to defaults*/
  240.   scsu_reset(comp);
  241. }
  242.  
  243. void
  244. scsu_compress(UnicodeCompressor *comp,
  245.           uint8_t           **target,
  246.           const uint8_t     *targetLimit,
  247.           const UChar       **source,
  248.           const UChar       *sourceLimit,
  249.           UErrorCode        *status)
  250. {
  251.   /* the current position in the source unichar buffer*/
  252.   const UChar *unicharBuffer = *source;
  253.  
  254.     /* the current position in the target byte buffer*/
  255.   uint8_t *byteBuffer = *target;
  256.     
  257.   /* the current unicode character from the source buffer*/
  258.   int32_t curUC = INVALIDCHAR;
  259.   
  260.   /* the index for the current character*/
  261.   int32_t curIndex = -1;
  262.         
  263.   /* look ahead*/
  264.   int32_t nextUC = INVALIDCHAR;
  265.   int32_t forwardUC = INVALIDCHAR;
  266.  
  267.     /* temporary for window searching*/
  268.   int32_t whichWindow = 0;
  269.       
  270.   /* high and low bytes of the current unicode character*/
  271.   int32_t hiByte = 0;
  272.   int32_t loByte = 0;
  273.  
  274.  
  275.     /* verify we weren't passed a failing error code */
  276.   if(U_FAILURE(*status)) {
  277.     return;
  278.   }
  279.   /* verify the target buffer can hold at least 4 bytes */
  280.   else if(targetLimit - byteBuffer < 4) {
  281.     *status = U_ILLEGAL_ARGUMENT_ERROR;
  282.     return;
  283.   }
  284.  
  285.  mainLoop:
  286.   while( unicharBuffer < sourceLimit && byteBuffer < targetLimit) {
  287.     switch( comp->fMode ) {
  288.         
  289.       /* main single byte mode compression loop*/
  290.     case SINGLEBYTEMODE:
  291.       while( unicharBuffer < sourceLimit && byteBuffer < targetLimit ) {
  292.  
  293.     /* get current char*/
  294.     curUC = *unicharBuffer++;
  295.         
  296.     /* get next char*/
  297.     if( unicharBuffer < sourceLimit ) 
  298.       nextUC = *unicharBuffer;
  299.     else
  300.       nextUC = INVALIDCHAR;
  301.         
  302.     /* chars less than 0x0080 (excluding tags) go straight in
  303.        stream */
  304.     if( curUC < 0x0080 ) {
  305.       loByte = curUC;
  306.             
  307.       /* we need to check and make sure we don't
  308.          accidentally write a single byte mode tag to
  309.          the stream unless it's quoted */
  310.       if(sSingleTagTable[loByte]) {
  311.         /* make sure there is enough room to write
  312.            both bytes and if not, rewind the source
  313.            stream and break out*/
  314.         if( (byteBuffer + 1) >= targetLimit) { 
  315.           --unicharBuffer; 
  316.           goto finish;
  317.         }
  318.             
  319.         /* since we know the byte is less than 0x80, SQUOTE0
  320.            will use static window 0, or Latin-1*/
  321.         *byteBuffer++ = (uint8_t) SQUOTE0;
  322.       }
  323.             
  324.       *byteBuffer++ = (uint8_t) loByte;
  325.     }
  326.         
  327.     /* if the char belongs to current window, convert it
  328.        to a byte by adding the generic compression offset
  329.        and subtracting the window's offset*/
  330.     else if(scsu_inDynamicWindow(comp, 
  331.                      curUC, comp->fCurrentWindow) ) {
  332.       *byteBuffer++ = (uint8_t) 
  333.         (curUC - comp->fOffsets[ comp->fCurrentWindow ] 
  334.          + COMPRESSIONOFFSET);
  335.     }
  336.         
  337.     /* if char is not in compressible range, either switch
  338.        to or quote from unicode*/
  339.     else if( ! scsu_isCompressible(curUC) ) {
  340.       /* only check next character if it is valid*/
  341.       if(nextUC != INVALIDCHAR && scsu_isCompressible(nextUC)) {
  342.         /* make sure there is enough room to write all
  343.            three bytes if not, rewind the source
  344.            stream and break out*/
  345.         if( (byteBuffer + 2) >= targetLimit) {
  346.           --unicharBuffer; 
  347.           goto finish;
  348.         }
  349.             
  350.         *byteBuffer++ = (uint8_t) SQUOTEU;
  351.         *byteBuffer++ = (uint8_t) (curUC >> 8);
  352.         *byteBuffer++ = (uint8_t) curUC;
  353.       }
  354.       else {
  355.         /* make sure there is enough room to write all
  356.            four bytes and if not, rewind the source
  357.            stream and break out*/
  358.         if( (byteBuffer + 3) >= targetLimit) { 
  359.           --unicharBuffer; 
  360.           goto finish;
  361.         }
  362.             
  363.         *byteBuffer++  = (uint8_t) SCHANGEU;
  364.             
  365.         hiByte = curUC >> 8;
  366.         loByte = curUC;
  367.             
  368.         /* add quote Unicode tag */
  369.         if( sUnicodeTagTable[hiByte] )
  370.           *byteBuffer++ = (uint8_t) UQUOTEU;  
  371.             
  372.         *byteBuffer++ = (uint8_t) hiByte;
  373.         *byteBuffer++ = (uint8_t) loByte;
  374.             
  375.         comp->fMode = UNICODEMODE;
  376.  
  377.         /* use a goto here for speed, to avoid having
  378.            to check fMode in the while loop at the top
  379.            of the case */
  380.         goto mainLoop;
  381.       }
  382.     }
  383.         
  384.     /* if the char is in a currently defined dynamic
  385.        window, figure out which one, and either switch to
  386.        it or quote from it*/
  387.     else if( (whichWindow = scsu_findDynamicWindow(comp, curUC)) 
  388.          != INVALIDWINDOW ) {
  389.       /* look ahead*/
  390.       if( (unicharBuffer + 1) < sourceLimit )
  391.         forwardUC = *(unicharBuffer + 1);
  392.       else
  393.         forwardUC = INVALIDCHAR;
  394.             
  395.       /* all three chars in same window, switch to that
  396.          window- inDynamicWindow will return FALSE for
  397.          INVALIDCHAR*/
  398.       if( scsu_inDynamicWindow(comp, nextUC, whichWindow) 
  399.           && scsu_inDynamicWindow(comp, forwardUC, whichWindow)){
  400.         /* make sure there is enough room to write
  401.            both bytes and if not, rewind the source
  402.            stream and break out*/
  403.         if( (byteBuffer + 1) >= targetLimit) { 
  404.           --unicharBuffer; 
  405.           goto finish;
  406.         }
  407.             
  408.         *byteBuffer++ = (uint8_t) (SCHANGE0 + whichWindow);
  409.         *byteBuffer++ = (uint8_t) 
  410.           (curUC - comp->fOffsets[whichWindow] 
  411.            + COMPRESSIONOFFSET);
  412.         comp->fTimeStamps [ whichWindow ] = ++(comp->fTimeStamp);
  413.         comp->fCurrentWindow  = whichWindow;
  414.       }
  415.             
  416.       /* either only next char or neither in same
  417.          window, so quote*/
  418.       else {
  419.         /* make sure there is enough room to write
  420.            both bytes and if not, rewind the source stream
  421.            and break out*/
  422.         if( (byteBuffer + 1) >= targetLimit) { 
  423.           --unicharBuffer; 
  424.           goto finish;
  425.         }
  426.             
  427.         *byteBuffer++ = (uint8_t) (SQUOTE0 + whichWindow);
  428.         *byteBuffer++ = (uint8_t) 
  429.           (curUC - comp->fOffsets[whichWindow] 
  430.            + COMPRESSIONOFFSET);
  431.       }
  432.     }
  433.         
  434.     /* if a static window is defined, and the following
  435.        character is not in that static window, quote from
  436.        the static window Note: to quote from a static
  437.        window, don't add 0x80*/
  438.     else if( (whichWindow = scsu_findStaticWindow(curUC)) 
  439.          != INVALIDWINDOW 
  440.          && ! scsu_inStaticWindow(nextUC, whichWindow) ) {
  441.       /* make sure there is enough room to write both
  442.          bytes if not, rewind the source stream and
  443.          break out*/
  444.       if( (byteBuffer + 1) >= targetLimit) { 
  445.         --unicharBuffer; 
  446.         goto finish;
  447.       }
  448.         
  449.       *byteBuffer++ = (uint8_t) (SQUOTE0 + whichWindow);
  450.       *byteBuffer++ = (uint8_t) (curUC - sOffsets[whichWindow]);
  451.     }
  452.         
  453.     /* if a window is not defined, decide if we want to
  454.        define a new one or switch to unicode mode*/
  455.     else {
  456.       /* determine index for current char (char is
  457.          compressible)*/
  458.       curIndex = scsu_makeIndex(curUC);
  459.       comp->fIndexCount[curIndex]++;
  460.             
  461.       /* look ahead*/
  462.       if( (unicharBuffer + 1) < sourceLimit )
  463.         forwardUC = *(unicharBuffer + 1);
  464.       else
  465.         forwardUC = INVALIDCHAR;
  466.             
  467.       /* if we have encountered this index at least once
  468.          before, define a new window*/
  469.       if( comp->fIndexCount[curIndex] > 1 ) {
  470.         /* make sure there is enough room to write all
  471.            three bytes and if not, rewind the source
  472.            stream and break out*/
  473.         if( (byteBuffer + 2) >= targetLimit) { 
  474.           --unicharBuffer; 
  475.           goto finish;
  476.         }
  477.  
  478.         /* get least recently defined window*/
  479.         whichWindow = scsu_getLRDefinedWindow(comp);
  480.             
  481.         *byteBuffer++ = (uint8_t) (SDEFINE0 + whichWindow);
  482.         *byteBuffer++ = (uint8_t) curIndex;
  483.         *byteBuffer++ = (uint8_t) 
  484.           (curUC - sOffsetTable[curIndex] 
  485.            + COMPRESSIONOFFSET);
  486.             
  487.         comp->fOffsets[whichWindow] = sOffsetTable[curIndex];
  488.         comp->fCurrentWindow = whichWindow;
  489.         comp->fTimeStamps [whichWindow] = ++(comp->fTimeStamp);
  490.       }
  491.         
  492.       /* three chars in a row with same index, define a
  493.          new window- makeIndex will return RESERVEDINDEX
  494.          for INVALIDCHAR*/
  495.       else if( curIndex == scsu_makeIndex(nextUC) 
  496.            && curIndex == scsu_makeIndex(forwardUC) ) {
  497.         /* make sure there is enough room to write all
  498.            three bytes if not, rewind the source
  499.            stream and break out*/
  500.         if( (byteBuffer + 2) >= targetLimit) { 
  501.           --unicharBuffer; 
  502.           goto finish;
  503.         }
  504.  
  505.         whichWindow = scsu_getLRDefinedWindow(comp);
  506.             
  507.         *byteBuffer++ = (uint8_t) (SDEFINE0 + whichWindow);
  508.         *byteBuffer++ = (uint8_t) curIndex;
  509.         *byteBuffer++ = (uint8_t) 
  510.           (curUC - sOffsetTable[curIndex] 
  511.            + COMPRESSIONOFFSET);
  512.             
  513.         comp->fOffsets[whichWindow] = sOffsetTable[curIndex];
  514.         comp->fCurrentWindow = whichWindow;
  515.         comp->fTimeStamps [whichWindow] = ++(comp->fTimeStamp);
  516.       }
  517.         
  518.       /* only two chars in a row with same index, so
  519.          switch to unicode mode makeIndex will return
  520.          RESERVEDINDEX for INVALIDCHAR*/
  521.       else if( curIndex == scsu_makeIndex(nextUC) 
  522.            && curIndex != scsu_makeIndex(forwardUC) ) {
  523.         /* make sure there is enough room to write all
  524.            four bytes if not, rewind the source stream
  525.            and break out*/
  526.         if( (byteBuffer + 3) >= targetLimit) { 
  527.           --unicharBuffer; 
  528.           goto finish;
  529.         }
  530.             
  531.         *byteBuffer++ = (uint8_t) SCHANGEU;
  532.             
  533.         hiByte = curUC >> 8;
  534.         loByte = curUC;
  535.             
  536.         /* add quote Unicode tag */
  537.         if( sUnicodeTagTable[hiByte] )
  538.           *byteBuffer++ = (uint8_t) UQUOTEU;
  539.             
  540.         *byteBuffer++ = (uint8_t) hiByte;
  541.         *byteBuffer++ = (uint8_t) loByte;
  542.             
  543.         comp->fMode = UNICODEMODE;
  544.  
  545.         /* use a goto here for speed, to avoid having
  546.            to check fMode in the while loop at the top
  547.            of the case */
  548.         goto mainLoop;
  549.       }
  550.             
  551.       /* three chars have different indices, so switch
  552.          to unicode mode*/
  553.       else {
  554.         /* make sure there is enough room to write all
  555.            four bytes and if not, rewind the source
  556.            stream and break out*/
  557.         if( (byteBuffer + 3) >= targetLimit) { 
  558.           --unicharBuffer; 
  559.           goto finish;
  560.         }
  561.             
  562.         *byteBuffer++ = (uint8_t) SCHANGEU;
  563.             
  564.         hiByte = curUC >> 8;
  565.         loByte = curUC;
  566.             
  567.         /* add quote Unicode tag*/
  568.         if( sUnicodeTagTable[ hiByte ] )
  569.           *byteBuffer++ = (uint8_t) UQUOTEU;
  570.             
  571.         *byteBuffer++ = (uint8_t) hiByte;
  572.         *byteBuffer++ = (uint8_t) loByte;
  573.             
  574.         comp->fMode = UNICODEMODE;
  575.  
  576.         /* use a goto here for speed, to avoid having
  577.            to check fMode in the while loop at the top
  578.            of the case */
  579.         goto mainLoop;
  580.       }
  581.     }
  582.       }
  583.       break;
  584.         
  585.       /* main unicode mode compression loop*/
  586.     case UNICODEMODE:
  587.       while(unicharBuffer < sourceLimit && byteBuffer < targetLimit) {
  588.  
  589.     /* get current char*/
  590.     curUC = *unicharBuffer++;  
  591.         
  592.     /* get next char*/
  593.     if( unicharBuffer < sourceLimit )
  594.       nextUC = *unicharBuffer;
  595.     else
  596.       nextUC = INVALIDCHAR;
  597.         
  598.     /* if we have two uncompressible unichars in a row,
  599.        put the current char's bytes in the stream*/
  600.     if( ! scsu_isCompressible(curUC) 
  601.         || (nextUC != INVALIDCHAR 
  602.         && ! scsu_isCompressible(nextUC)) ) {
  603.       /* make sure there is enough room to write all
  604.          three bytes and if not, rewind the source
  605.          stream and break out*/
  606.       if( (byteBuffer + 2) >= targetLimit) { 
  607.         --unicharBuffer; 
  608.         goto finish;
  609.       }
  610.             
  611.       hiByte = curUC >> 8;
  612.       loByte = curUC;
  613.             
  614.       /* add quote Unicode tag*/
  615.       if( sUnicodeTagTable[ hiByte ] )
  616.         *byteBuffer++   = (uint8_t) UQUOTEU;  
  617.             
  618.       *byteBuffer++ = (uint8_t) hiByte;
  619.       *byteBuffer++ = (uint8_t) loByte;
  620.     }
  621.         
  622.     /* bytes less than 0x80 can go straight in the stream,
  623.        but in single-byte mode*/
  624.     else if( curUC < 0x0080 ) {
  625.       loByte = curUC;
  626.             
  627.       /* if two chars in a row below 0x80 and the
  628.          current char is not a single-byte mode tag,
  629.          switch to single-byte mode*/
  630.       if(nextUC != INVALIDCHAR 
  631.          && nextUC < 0x0080 && ! sSingleTagTable[ loByte ] ) {
  632.         /* make sure there is enough room to write
  633.            both bytes and if not, rewind the source stream
  634.            and break out*/
  635.         if( (byteBuffer + 1) >= targetLimit) { 
  636.           --unicharBuffer; 
  637.           goto finish;
  638.         }
  639.             
  640.         /* use window 0, but any would work*/
  641.         *byteBuffer++ = (uint8_t) UCHANGE0;
  642.         *byteBuffer++ = (uint8_t) loByte;
  643.             
  644.         comp->fCurrentWindow = 0;
  645.         comp->fTimeStamps [0] = ++(comp->fTimeStamp);
  646.         comp->fMode = SINGLEBYTEMODE;
  647.  
  648.         /* use a goto here for speed, to avoid having
  649.            to check fMode in the while loop at the top
  650.            of the case */
  651.         goto mainLoop;
  652.       }
  653.             
  654.       /* otherwise, just write the bytes to the stream
  655.          (this will cover the case of only 1 char less
  656.          than 0x80 and single-byte mode tags)*/
  657.       else {
  658.         /* make sure there is enough room to write
  659.            both bytes and if not, rewind the source
  660.            stream and break out*/
  661.         if( (byteBuffer + 1) >= targetLimit) {
  662.           --unicharBuffer; 
  663.           goto finish;
  664.         }
  665.             
  666.         /* since the character is less than 0x80, the
  667.            high byte is always 0x00 - no need for
  668.            (curUC >> 8)*/
  669.         *byteBuffer++ = (uint8_t) 0x00;
  670.         *byteBuffer++ = (uint8_t) loByte;
  671.       }
  672.     }
  673.         
  674.     /* figure out if the current unichar is in a defined
  675.        window*/
  676.     else if( (whichWindow = scsu_findDynamicWindow(comp, curUC)) 
  677.          != INVALIDWINDOW ) {
  678.       /* if two chars in a row in the same window,
  679.          switch to that window and go to single-byte
  680.          mode inDynamicWindow will return FALSE for
  681.          INVALIDCHAR*/
  682.       if( scsu_inDynamicWindow(comp, nextUC, whichWindow) ) {
  683.         /* make sure there is enough room to write
  684.            both bytes if not, rewind the source stream
  685.            and break out*/
  686.         if( (byteBuffer + 1) >= targetLimit) { 
  687.           --unicharBuffer; 
  688.           goto finish;
  689.         }
  690.             
  691.         *byteBuffer++ = (uint8_t) (UCHANGE0 + whichWindow);
  692.         *byteBuffer++ = (uint8_t) 
  693.           (curUC - comp->fOffsets[whichWindow] 
  694.            + COMPRESSIONOFFSET);
  695.             
  696.         comp->fTimeStamps[whichWindow] = ++(comp->fTimeStamp);
  697.         comp->fCurrentWindow = whichWindow;
  698.         comp->fMode = SINGLEBYTEMODE;
  699.  
  700.         /* use a goto here for speed, to avoid having
  701.            to check fMode in the while loop at the top
  702.            of the case */
  703.         goto mainLoop;
  704.       }
  705.  
  706.       /* otherwise, just quote the unicode for the
  707.          char*/
  708.       else {
  709.         /* make sure there is enough room to write all
  710.            three bytes and if not, rewind the source
  711.            stream and break out*/
  712.         if( (byteBuffer + 2) >= targetLimit) { 
  713.           --unicharBuffer; 
  714.           goto finish;
  715.         }
  716.             
  717.         hiByte = curUC >> 8;
  718.         loByte = curUC;
  719.             
  720.         /* add quote Unicode tag*/
  721.         if( sUnicodeTagTable[ hiByte ] )
  722.           *byteBuffer++ = (uint8_t) UQUOTEU;
  723.             
  724.         *byteBuffer++ = (uint8_t) hiByte;
  725.         *byteBuffer++ = (uint8_t) loByte;
  726.       }
  727.     }
  728.         
  729.     /* char is not in a defined window*/
  730.     else {
  731.       /* determine index for current char (char is
  732.          compressible)*/
  733.       curIndex = scsu_makeIndex(curUC);
  734.       comp->fIndexCount[curIndex]++;
  735.             
  736.       /* look ahead*/
  737.       if( (unicharBuffer + 1) < sourceLimit )
  738.         forwardUC = *unicharBuffer;
  739.       else
  740.         forwardUC = INVALIDCHAR;
  741.             
  742.       /* if we have encountered this index at least once
  743.          before, define a new window for it that hasn't
  744.          previously been redefined*/
  745.       if( comp->fIndexCount[curIndex] > 1 ) {
  746.         /* make sure there is enough room to write all
  747.            three bytes if not, rewind the source
  748.            stream and break out*/
  749.         if( (byteBuffer + 2) >= targetLimit) { 
  750.           --unicharBuffer; 
  751.           goto finish;
  752.         }
  753.             
  754.         /* get least recently defined window*/
  755.         whichWindow = scsu_getLRDefinedWindow(comp);
  756.             
  757.         *byteBuffer++ = (uint8_t) (UDEFINE0 + whichWindow);
  758.         *byteBuffer++ = (uint8_t) curIndex;
  759.         *byteBuffer++ = (uint8_t) 
  760.           (curUC - sOffsetTable[curIndex] 
  761.            + COMPRESSIONOFFSET);
  762.             
  763.         comp->fOffsets[whichWindow] = sOffsetTable[curIndex];
  764.         comp->fCurrentWindow = whichWindow;
  765.         comp->fTimeStamps[whichWindow] = ++(comp->fTimeStamp);
  766.         comp->fMode = SINGLEBYTEMODE;
  767.  
  768.         /* use a goto here for speed, to avoid having
  769.            to check fMode in the while loop at the top
  770.            of the case */
  771.         goto mainLoop;
  772.       }
  773.         
  774.       /* if three chars in a row with the same index,
  775.          define a new window makeIndex will return
  776.          RESERVEDINDEX for INVALIDCHAR*/
  777.       else if( curIndex == scsu_makeIndex(nextUC) 
  778.            && curIndex == scsu_makeIndex(forwardUC) ) {
  779.         /* make sure there is enough room to write all
  780.            three bytes if not, rewind the source
  781.            stream and break out*/
  782.         if( (byteBuffer + 2) >= targetLimit) { 
  783.           --unicharBuffer; 
  784.           goto finish;
  785.         }
  786.             
  787.         whichWindow = scsu_getLRDefinedWindow(comp);
  788.             
  789.         *byteBuffer++ = (uint8_t) (UDEFINE0 + whichWindow);
  790.         *byteBuffer++ = (uint8_t) curIndex;
  791.         *byteBuffer++ = (uint8_t) 
  792.           (curUC - sOffsetTable[curIndex] 
  793.            + COMPRESSIONOFFSET);
  794.             
  795.         comp->fOffsets[whichWindow] = sOffsetTable[curIndex];
  796.         comp->fCurrentWindow = whichWindow;
  797.         comp->fTimeStamps[whichWindow] = ++(comp->fTimeStamp);
  798.         comp->fMode = SINGLEBYTEMODE;
  799.  
  800.         /* use a goto here for speed, to avoid having
  801.            to check fMode in the while loop at the top
  802.            of the case */
  803.         goto mainLoop;
  804.       }
  805.             
  806.       /* otherwise just quote the unicode, and save our
  807.          windows for longer runs*/
  808.       else {
  809.         /* make sure there is enough room to write all
  810.            three bytes and if not, rewind the source
  811.            stream and break out*/
  812.         if( (byteBuffer + 2) >= targetLimit) { 
  813.           --unicharBuffer; 
  814.           goto finish;
  815.         }
  816.             
  817.         hiByte = curUC >> 8;
  818.         loByte = curUC;
  819.             
  820.         /* add quote Unicode tag*/
  821.         if( sUnicodeTagTable[ hiByte ] )
  822.           *byteBuffer++ = (uint8_t) UQUOTEU;
  823.             
  824.         *byteBuffer++ = (uint8_t) hiByte;
  825.         *byteBuffer++ = (uint8_t) loByte;
  826.       }
  827.     }
  828.       }
  829.     }  /* end switch*/
  830.   }
  831.     
  832.  finish:
  833.     
  834.     /* fill in output parameters*/
  835.   *target = byteBuffer;
  836.   *source = unicharBuffer;
  837.  
  838.   if(unicharBuffer < sourceLimit)
  839.     *status = U_INDEX_OUTOFBOUNDS_ERROR;
  840. }
  841.  
  842. void 
  843. scsu_decompress(UnicodeCompressor *comp,
  844.         UChar             **target,
  845.         const UChar       *targetLimit,
  846.         const uint8_t     **source,
  847.         const uint8_t     *sourceLimit,
  848.         UErrorCode        *status)
  849. {
  850.   /* the current position in the source byte buffer*/
  851.   const uint8_t *byteBuffer = *source;
  852.  
  853.   /* the current position in the target unichar buffer*/
  854.   UChar *unicharBuffer = *target;
  855.  
  856.   /* the current byte from the source buffer*/
  857.   int32_t aByte  = 0x00;
  858.  
  859.   /* temporary for calculating surrogate pairs */
  860.   int32_t normalizedBase;
  861.    
  862.   /* temporary used for look-ahead */
  863.   int32_t dByte;
  864.  
  865.  
  866.   /* verify we weren't passed a failing error code */
  867.   if(U_FAILURE(*status)) {
  868.     return; 
  869.   }
  870.   /* verify the target buffer can hold at least 1 UChar */
  871.   else if(targetLimit - unicharBuffer < sizeof(UChar)) {
  872.     *status = U_ILLEGAL_ARGUMENT_ERROR;
  873.     return;
  874.   }
  875.  
  876.   /* if our internal buffer isn't empty, flush its contents
  877.        to the output buffer before doing any more decompression */
  878.   if(comp->fBufferLength > 0) {
  879.  
  880.     int32_t newBytes = 0;
  881.     const uint8_t *newSource = comp->fBuffer;
  882.     const uint8_t *newSourceLimit = comp->fBuffer + USCSU_BUFSIZE;
  883.  
  884.     /* fill the buffer completely, to guarantee one full character */
  885.     if(comp->fBufferLength != USCSU_BUFSIZE) {
  886.       newBytes = USCSU_BUFSIZE - comp->fBufferLength;
  887.  
  888.       /* verify there are newBytes bytes in byteBuffer */
  889.       if(sourceLimit - byteBuffer < newBytes)
  890.     newBytes = sourceLimit - byteBuffer;
  891.  
  892.       icu_memcpy(comp->fBuffer + comp->fBufferLength, byteBuffer, newBytes);
  893.     }
  894.  
  895.     /* reset buffer length to 0 before recursive call */
  896.     comp->fBufferLength = 0;
  897.  
  898.     /* call self recursively to decompress the buffer */
  899.     scsu_decompress(comp, &unicharBuffer, targetLimit,
  900.             &newSource, newSourceLimit, status);
  901.  
  902.     /* update the positions into the arrays */
  903.     /* unicharBuffer was updated by the call to decompress above */
  904.     byteBuffer += newBytes;
  905.   }
  906.  
  907.   /* the main decompression loop*/
  908.  mainLoop:
  909.   while(byteBuffer < sourceLimit && unicharBuffer < targetLimit) {
  910.  
  911.     switch(comp->fMode) {  
  912.  
  913.       /* single-byte mode decompression loop*/
  914.     case SINGLEBYTEMODE:
  915.       while(byteBuffer < sourceLimit && unicharBuffer < targetLimit) {
  916.         
  917.     /* get the next byte */
  918.     aByte = *byteBuffer++;
  919.         
  920.     switch(aByte) {
  921.       /* All bytes from 0x80 through 0xFF are remapped to
  922.          chars or surrogate pairs according to the currently
  923.          active window */
  924.     case 0x80: case 0x81: case 0x82: case 0x83: case 0x84:
  925.     case 0x85: case 0x86: case 0x87: case 0x88: case 0x89:
  926.     case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E:
  927.     case 0x8F: case 0x90: case 0x91: case 0x92: case 0x93:
  928.     case 0x94: case 0x95: case 0x96: case 0x97: case 0x98:
  929.     case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D:
  930.     case 0x9E: case 0x9F: case 0xA0: case 0xA1: case 0xA2:
  931.     case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7:
  932.     case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC:
  933.     case 0xAD: case 0xAE: case 0xAF: case 0xB0: case 0xB1:
  934.     case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6:
  935.     case 0xB7: case 0xB8: case 0xB9: case 0xBA: case 0xBB:
  936.     case 0xBC: case 0xBD: case 0xBE: case 0xBF: case 0xC0:
  937.     case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5:
  938.     case 0xC6: case 0xC7: case 0xC8: case 0xC9: case 0xCA:
  939.     case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF:
  940.     case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4:
  941.     case 0xD5: case 0xD6: case 0xD7: case 0xD8: case 0xD9:
  942.     case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE:
  943.     case 0xDF: case 0xE0: case 0xE1: case 0xE2: case 0xE3:
  944.     case 0xE4: case 0xE5: case 0xE6: case 0xE7:  case 0xE8:
  945.     case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED:
  946.     case 0xEE: case 0xEF: case 0xF0: case 0xF1: case 0xF2:
  947.     case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7:
  948.     case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC:
  949.     case 0xFD: case 0xFE: case 0xFF: 
  950.             
  951.       /* For offsets <= 0xFFFF, convert to a single char by
  952.          adding the window's offset and subtracting the
  953.          generic compression offset*/
  954.       if(comp->fOffsets[ comp->fCurrentWindow ] <= 0xFFFF) {
  955.         *unicharBuffer++ = (UChar) 
  956.           (aByte + comp->fOffsets[comp->fCurrentWindow] 
  957.            - COMPRESSIONOFFSET);
  958.       }
  959.       /* For offsets > 0x10000, convert to a surrogate pair by 
  960.          normBase = window's offset - 0x10000
  961.          high surrogate = 0xD800 + (normBase >> 10)
  962.          low  surrogate = 0xDC00 + (normBase & 0x3FF) 
  963.          + (byte & 0x7F) */
  964.       else {
  965.         /* make sure there is enough room to write
  966.            both characters 
  967.            if not, save state and break out */
  968.         if((unicharBuffer + 1) >= targetLimit) {
  969.           --byteBuffer;
  970.           icu_memcpy(comp->fBuffer, byteBuffer, 
  971.              sourceLimit - byteBuffer);
  972.           comp->fBufferLength = sourceLimit - byteBuffer;
  973.           byteBuffer += comp->fBufferLength;
  974.           goto finish;
  975.         }
  976.             
  977.         normalizedBase = comp->fOffsets[comp->fCurrentWindow] 
  978.           - 0x10000;
  979.         *unicharBuffer++ = 
  980.           (UChar) (0xD800 + (normalizedBase >> 10));
  981.         *unicharBuffer++ = (UChar) 
  982.           (0xDC00 + (normalizedBase & 0x3FF) 
  983.            + (aByte & 0x7F));
  984.       }
  985.       break;
  986.             
  987.       /* bytes from 0x20 through 0x7F are treated as ASCII
  988.          and are remapped to chars by padding the high byte
  989.          (this is the same as quoting from static window 0)
  990.          NUL (0x00), HT (0x09), CR (0x0A), LF (0x0D) are
  991.          treated as ASCII as well*/
  992.     case 0x00: case 0x09: case 0x0A: case 0x0D:
  993.     case 0x20: case 0x21: case 0x22: case 0x23: case 0x24:
  994.     case 0x25: case 0x26: case 0x27: case 0x28: case 0x29:
  995.     case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E:
  996.     case 0x2F: case 0x30: case 0x31: case 0x32: case 0x33:
  997.     case 0x34: case 0x35: case 0x36: case 0x37: case 0x38:
  998.     case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D:
  999.     case 0x3E: case 0x3F: case 0x40: case 0x41: case 0x42:
  1000.     case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
  1001.     case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C:
  1002.     case 0x4D: case 0x4E: case 0x4F: case 0x50: case 0x51:
  1003.     case 0x52: case 0x53: case 0x54: case 0x55: case 0x56:
  1004.     case 0x57: case 0x58: case 0x59: case 0x5A: case 0x5B:
  1005.     case 0x5C: case 0x5D: case 0x5E: case 0x5F: case 0x60:
  1006.     case 0x61: case 0x62: case 0x63: case 0x64: case 0x65:
  1007.     case 0x66: case 0x67: case 0x68: case 0x69: case 0x6A:
  1008.     case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F:
  1009.     case 0x70: case 0x71: case 0x72: case 0x73: case 0x74:
  1010.     case 0x75: case 0x76: case 0x77: case 0x78: case 0x79:
  1011.     case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E:
  1012.     case 0x7F: 
  1013.       *unicharBuffer++ = (UChar) aByte;
  1014.       break;
  1015.             
  1016.       /* quote unicode*/
  1017.     case SQUOTEU:
  1018.       /* verify we have two bytes following tag and if not,
  1019.          rewind the source stream and break out */
  1020.       if( (byteBuffer + 1) >= sourceLimit ) {
  1021.         --byteBuffer;
  1022.         icu_memcpy(comp->fBuffer, byteBuffer, 
  1023.                sourceLimit - byteBuffer);
  1024.         comp->fBufferLength = sourceLimit - byteBuffer;
  1025.         byteBuffer += comp->fBufferLength;
  1026.         goto finish;
  1027.       }
  1028.             
  1029.       aByte = *byteBuffer++;
  1030.       *unicharBuffer++ = 
  1031.         (UChar) (aByte << 8 | *byteBuffer++);
  1032.       break;
  1033.             
  1034.       /* switch to Unicode mode*/
  1035.     case SCHANGEU:
  1036.       comp->fMode = UNICODEMODE;
  1037.       /* use a goto here for speed, to avoid having to check
  1038.          fMode in the while loop at the top of the case */
  1039.       goto mainLoop;
  1040.       break;
  1041.             
  1042.       /* handle all quote tags*/
  1043.     case SQUOTE0:   case SQUOTE1:   case SQUOTE2:  case SQUOTE3:
  1044.     case SQUOTE4:   case SQUOTE5:   case SQUOTE6:  case SQUOTE7:
  1045.       /* verify there is a byte following the tag and if
  1046.          not, rewind the source stream and break out*/
  1047.       if( byteBuffer >= sourceLimit ) { 
  1048.         --byteBuffer;
  1049.         icu_memcpy(comp->fBuffer, byteBuffer, 
  1050.                sourceLimit - byteBuffer);
  1051.         comp->fBufferLength = sourceLimit - byteBuffer;
  1052.         byteBuffer += comp->fBufferLength;
  1053.         goto finish;
  1054.       }
  1055.             
  1056.       /* if the byte is in the range 0x00 - 0x7F, use static
  1057.          window n- otherwise, use dynamic window n */
  1058.       dByte = *byteBuffer++;
  1059.       *unicharBuffer++ = (UChar) 
  1060.         (dByte + (dByte >= 0x00 && dByte < 0x80 
  1061.               ? sOffsets[aByte - SQUOTE0] 
  1062.               : (comp->fOffsets[aByte - SQUOTE0] 
  1063.              - COMPRESSIONOFFSET))); 
  1064.       break;
  1065.             
  1066.       /* handle all change tags*/
  1067.     case SCHANGE0: case SCHANGE1: case SCHANGE2: case SCHANGE3: 
  1068.     case SCHANGE4: case SCHANGE5: case SCHANGE6: case SCHANGE7:
  1069.       comp->fCurrentWindow = (aByte - SCHANGE0);
  1070.       break;
  1071.             
  1072.       /* handle all define tags*/
  1073.     case SDEFINE0: case SDEFINE1: case SDEFINE2: case SDEFINE3:
  1074.     case SDEFINE4: case SDEFINE5: case SDEFINE6: case SDEFINE7:
  1075.       /* verify there is a byte following the tag and if
  1076.          not, rewind the source stream and break out*/
  1077.       if( byteBuffer >= sourceLimit ) {
  1078.         --byteBuffer;
  1079.         icu_memcpy(comp->fBuffer, byteBuffer, 
  1080.                sourceLimit - byteBuffer);
  1081.         comp->fBufferLength = sourceLimit - byteBuffer;
  1082.         byteBuffer += comp->fBufferLength;
  1083.         goto finish;
  1084.       }
  1085.             
  1086.       comp->fCurrentWindow = (aByte - SDEFINE0);
  1087.       comp->fOffsets[comp->fCurrentWindow] = 
  1088.         sOffsetTable[*byteBuffer++];
  1089.       break;
  1090.             
  1091.       /* handle define extended tag*/
  1092.     case SDEFINEX:
  1093.       /* verify we have two bytes following tag and if not,
  1094.          rewind the source stream and break out*/
  1095.       if( (byteBuffer + 1) >= sourceLimit ) {
  1096.         --byteBuffer;
  1097.         icu_memcpy(comp->fBuffer, byteBuffer, 
  1098.                sourceLimit - byteBuffer);
  1099.         comp->fBufferLength = sourceLimit - byteBuffer;
  1100.         byteBuffer += comp->fBufferLength;
  1101.         goto finish;
  1102.       }
  1103.             
  1104.       aByte = *byteBuffer++;
  1105.       comp->fCurrentWindow  = (aByte & 0xE0) >> 5;
  1106.       comp->fOffsets[comp->fCurrentWindow] = 0x10000 
  1107.         + (0x80 
  1108.            * (((aByte & 0x1F) << 8) | *byteBuffer++));
  1109.       break;
  1110.             
  1111.       /* reserved, shouldn't happen*/
  1112.     case SRESERVED:
  1113.       break;
  1114.             
  1115.     } /* end switch*/
  1116.       } /* end while*/
  1117.       break;
  1118.         
  1119.       /* unicode mode decompression loop*/
  1120.     case UNICODEMODE:
  1121.       while( byteBuffer < sourceLimit && unicharBuffer < targetLimit ) {
  1122.  
  1123.     /* get the next byte */
  1124.     aByte = *byteBuffer++;
  1125.         
  1126.     switch( aByte ) {
  1127.       /* handle all define tags*/
  1128.     case UDEFINE0: case UDEFINE1: case UDEFINE2: case UDEFINE3:
  1129.     case UDEFINE4: case UDEFINE5: case UDEFINE6: case UDEFINE7:
  1130.       /* verify there is a byte following tag and if not,
  1131.          rewind the source stream and break out*/
  1132.       if( byteBuffer >= sourceLimit ) { 
  1133.         --byteBuffer;
  1134.         icu_memcpy(comp->fBuffer, byteBuffer, 
  1135.                sourceLimit - byteBuffer);
  1136.         comp->fBufferLength = sourceLimit - byteBuffer;
  1137.         byteBuffer += comp->fBufferLength;
  1138.         goto finish;
  1139.       }
  1140.   
  1141.       comp->fCurrentWindow = (aByte - UDEFINE0);
  1142.       comp->fOffsets[comp->fCurrentWindow] = 
  1143.         sOffsetTable[*byteBuffer++];
  1144.       comp->fMode = SINGLEBYTEMODE;
  1145.       /* use a goto here for speed, to avoid having to check
  1146.          fMode in the while loop at the top of the case */
  1147.       goto mainLoop;
  1148.       break;
  1149.             
  1150.       /* handle define extended tag*/
  1151.     case UDEFINEX:
  1152.       /* verify we have two bytes following tag if not,
  1153.          rewind the source stream and break out*/
  1154.       if( (byteBuffer + 1) >= sourceLimit ) {
  1155.         --byteBuffer;
  1156.         icu_memcpy(comp->fBuffer, byteBuffer, 
  1157.                sourceLimit - byteBuffer);
  1158.         comp->fBufferLength = sourceLimit - byteBuffer;
  1159.         byteBuffer += comp->fBufferLength;
  1160.         goto finish;
  1161.       }
  1162.   
  1163.       aByte  = *byteBuffer++;
  1164.       comp->fCurrentWindow = (aByte & 0xE0) >> 5;
  1165.       comp->fOffsets[comp->fCurrentWindow] = 0x10000 
  1166.         + (0x80 
  1167.            * (((aByte & 0x1F) << 8) | *byteBuffer++));
  1168.       comp->fMode = SINGLEBYTEMODE;
  1169.       /* use a goto here for speed, to avoid having to check
  1170.          fMode in the while loop at the top of the case */
  1171.       goto mainLoop;
  1172.       break;
  1173.         
  1174.       /* handle all change tags*/
  1175.     case UCHANGE0: case UCHANGE1: case UCHANGE2: case UCHANGE3:
  1176.     case UCHANGE4: case UCHANGE5: case UCHANGE6: case UCHANGE7:
  1177.       comp->fCurrentWindow = (aByte - UCHANGE0);
  1178.       comp->fMode  = SINGLEBYTEMODE;
  1179.       /* use a goto here for speed, to avoid having to check
  1180.          fMode in the while loop at the top of the case */
  1181.       goto mainLoop;
  1182.       break;
  1183.             
  1184.       /* quote unicode*/
  1185.     case UQUOTEU:
  1186.       /* verify we have two bytes following tag if not,
  1187.          rewind the source stream and break out*/
  1188.       if( byteBuffer >= sourceLimit  - 1) { 
  1189.         --byteBuffer;
  1190.         icu_memcpy(comp->fBuffer, byteBuffer, 
  1191.                sourceLimit - byteBuffer);
  1192.         comp->fBufferLength = sourceLimit - byteBuffer;
  1193.         byteBuffer += comp->fBufferLength;
  1194.         goto finish;
  1195.       }
  1196.             
  1197.       aByte = *byteBuffer++;
  1198.       *unicharBuffer++ = (UChar) 
  1199.         (aByte << 8 | *byteBuffer++);
  1200.       break;
  1201.  
  1202.     default:
  1203.       /* verify there is a byte following tag if not, rewind
  1204.          the source stream and break out*/
  1205.       if( byteBuffer >= sourceLimit ) { 
  1206.         --byteBuffer;
  1207.         icu_memcpy(comp->fBuffer, byteBuffer, 
  1208.                sourceLimit - byteBuffer);
  1209.         comp->fBufferLength = sourceLimit - byteBuffer;
  1210.         byteBuffer += comp->fBufferLength;
  1211.         goto finish;
  1212.       }
  1213.  
  1214.       *unicharBuffer++ = (UChar) (aByte << 8 | *byteBuffer++);
  1215.       break;
  1216.         
  1217.     } /* end switch*/
  1218.       } /* end while*/
  1219.       break;
  1220.  
  1221.     } /* end switch( comp->fMode )*/
  1222.   } /* end while*/
  1223.  
  1224.     
  1225.  finish:
  1226.  
  1227.   /* fill in return values*/
  1228.   *target = unicharBuffer;
  1229.   *source = byteBuffer;
  1230.  
  1231.   if(byteBuffer < sourceLimit)
  1232.     *status = U_INDEX_OUTOFBOUNDS_ERROR;
  1233. }
  1234.  
  1235. /** Reset the compressor to its initial state. */
  1236. void 
  1237. scsu_reset(UnicodeCompressor *comp)
  1238. {
  1239.   int32_t i;
  1240.  
  1241.   /* reset dynamic windows*/
  1242.   comp->fOffsets[0] = 0x0080;  /* Latin-1*/
  1243.   comp->fOffsets[1] = 0x00C0;  /* Latin-1 Supplement + Latin Extended-A*/
  1244.   comp->fOffsets[2] = 0x0400;  /* Cyrillic*/
  1245.   comp->fOffsets[3] = 0x0600;  /* Arabic*/
  1246.   comp->fOffsets[4] = 0x0900;  /* Devanagari*/
  1247.   comp->fOffsets[5] = 0x3040;  /* Hiragana*/
  1248.   comp->fOffsets[6] = 0x30A0;  /* Katakana*/
  1249.   comp->fOffsets[7] = 0xFF00;  /* Fullwidth ASCII*/
  1250.     
  1251.   /* reset time stamps*/
  1252.   for(i = 0; i < USCSU_NUM_WINDOWS; i++) {
  1253.     comp->fTimeStamps[i]          = 0;
  1254.   }
  1255.     
  1256.   /* reset count of seen indices*/
  1257.   for( i = 0; i <= USCSU_MAX_INDEX; i++ ) {
  1258.     comp->fIndexCount[i] = 0;
  1259.   }
  1260.     
  1261.   comp->fTimeStamp      = 0;              /* Reset current time stamp*/
  1262.   comp->fCurrentWindow  = 0;              /* Make current window Latin-1*/
  1263.   comp->fMode           = SINGLEBYTEMODE; /* Start in single-byte mode*/
  1264.   comp->fBufferLength   = 0;              /* Empty buffer */
  1265. }
  1266.  
  1267. /**
  1268.  * Create the index value for a character.
  1269.  * For more information on this function, refer to table X-3
  1270.  * <A HREF="http://www.unicode.org/unicode/reports/tr6">UTR6</A>.
  1271.  * @param c The character in question.
  1272.  * @return An index for c
  1273.  */
  1274. static int32_t 
  1275. scsu_makeIndex(int32_t c)
  1276. {
  1277.   /* check the predefined indices*/
  1278.   if( c >= 0x00C0 && c < 0x0140)
  1279.     return LATININDEX;
  1280.   else if( c >= 0x0250 && c < 0x02D0 )
  1281.     return IPAEXTENSIONINDEX;
  1282.   else if( c >= 0x0370 && c < 0x03F0 )
  1283.     return GREEKINDEX;
  1284.   else if( c >= 0x0530 && c < 0x0590 )
  1285.     return ARMENIANINDEX;
  1286.   else if( c >= 0x3040 && c < 0x30A0 )
  1287.     return HIRAGANAINDEX;
  1288.   else if( c >= 0x30A0 && c < 0x3120)
  1289.     return KATAKANAINDEX;
  1290.   else if( c >= 0xFF60 && c < 0xFF9F )
  1291.     return HALFWIDTHKATAKANAINDEX;
  1292.     
  1293.     /* calculate index*/
  1294.   else if( c >= 0x0080 && c < 0x3400 )
  1295.     return (c / 0x80) & 0xFF;
  1296.   else if( c >= 0xE000 && c <= 0xFFFF )
  1297.     return ((c - 0xAC00) / 0x80) & 0xFF;
  1298.     
  1299.     /* should never happen*/
  1300.   else {
  1301.     return RESERVEDINDEX;
  1302.   }
  1303. }
  1304.  
  1305. /**
  1306.  * Determine if a character is in a dynamic window.  
  1307.  * @param c The character to test 
  1308.  * @param whichWindow The dynamic window the test
  1309.  * @return TRUE if <TT>c</TT> will fit in <TT>whichWindow</TT>, FALSE
  1310.  * otherwise.  
  1311.  */
  1312. static bool_t 
  1313. scsu_inDynamicWindow(const UnicodeCompressor *comp,
  1314.              int32_t c, 
  1315.              int32_t whichWindow)
  1316. {
  1317.   return (c >= comp->fOffsets[whichWindow] 
  1318.       && c < (comp->fOffsets[whichWindow] + 0x80));
  1319. }
  1320.  
  1321. /**
  1322.  * Determine if a character is in a static window.
  1323.  * @param c The character to test
  1324.  * @param whichWindow The static window the test
  1325.  * @return TRUE if <TT>c</TT> will fit in <TT>whichWindow</TT>, FALSE 
  1326.  * otherwise.
  1327.  */
  1328. static bool_t 
  1329. scsu_inStaticWindow(int32_t c, 
  1330.             int32_t whichWindow)
  1331. {
  1332.   return (c >= sOffsets[whichWindow] && c < (sOffsets[whichWindow] + 0x80));
  1333. }
  1334.  
  1335. /**
  1336.  * Determine if a character is compressible.
  1337.  * @param c The character to test.
  1338.  * @return TRUE if the <TT>c</TT> is compressible, FALSE otherwise.
  1339.  */
  1340. static bool_t 
  1341. scsu_isCompressible(int32_t c)
  1342. {
  1343.   return (c < 0x3400 || c >= 0xE000);
  1344. }
  1345.  
  1346. /**
  1347.  * Determine if a dynamic window for a certain character is defined
  1348.  * @param c The character in question
  1349.  * @return The dynamic window containing <TT>c</TT>, or INVALIDWINDOW if 
  1350.  * not defined.
  1351.  */
  1352. static int32_t 
  1353. scsu_findDynamicWindow(const UnicodeCompressor *comp,
  1354.                int32_t c)
  1355. {
  1356.   int32_t i;
  1357.     
  1358.   for(i = 0; i < USCSU_NUM_WINDOWS; i++) {
  1359.     if(scsu_inDynamicWindow(comp, c, i)) {
  1360.       return i;
  1361.     }
  1362.   }
  1363.     
  1364.   return INVALIDWINDOW;
  1365. }
  1366.  
  1367. /**
  1368.  * Determine if a static window for a certain character is defined
  1369.  * @param c The character in question
  1370.  * @return The static window containing <TT>c</TT>, or INVALIDWINDOW if 
  1371.  * not defined.
  1372.  */
  1373. static int32_t 
  1374. scsu_findStaticWindow(int32_t c)
  1375. {
  1376.   int32_t i;
  1377.     
  1378.   for(i = 0; i < USCSU_NUM_STATIC_WINDOWS; i++) {
  1379.     if(scsu_inStaticWindow(c, i)) {
  1380.       return i;
  1381.     }
  1382.   }
  1383.     
  1384.   return INVALIDWINDOW;
  1385. }
  1386.  
  1387. /** Find the least-recently defined window */
  1388. static int32_t 
  1389. scsu_getLRDefinedWindow(const UnicodeCompressor *comp)
  1390. {
  1391.   int32_t leastRU         = LONG_MAX;
  1392.   int32_t whichWindow     = INVALIDWINDOW;
  1393.   int32_t i;
  1394.   
  1395.   /* find least recently used window*/
  1396.   for(i = 0; i < USCSU_NUM_WINDOWS; i++ ) {
  1397.     if(comp->fTimeStamps[i] < leastRU) {
  1398.       leastRU = comp->fTimeStamps[i];
  1399.       whichWindow = i;
  1400.     }
  1401.   }
  1402.     
  1403.   return whichWindow;
  1404. }
  1405.