home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / text / Utility.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  15.6 KB  |  457 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)Utility.java    1.9 98/06/29
  3.  *
  4.  * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  5.  * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  6.  *
  7.  * Portions copyright (c) 1997, 1998 Sun Microsystems, Inc.
  8.  * All Rights Reserved.
  9.  *
  10.  * The original version of this source code and documentation
  11.  * is copyrighted and owned by Taligent, Inc., a wholly-owned
  12.  * subsidiary of IBM. These materials are provided under terms
  13.  * of a License Agreement between Taligent and Sun. This technology
  14.  * is protected by multiple US and International patents.
  15.  *
  16.  * This notice and attribution to Taligent may not be removed.
  17.  * Taligent is a registered trademark of Taligent, Inc.
  18.  *
  19.  * Permission to use, copy, modify, and distribute this software
  20.  * and its documentation for NON-COMMERCIAL purposes and without
  21.  * fee is hereby granted provided that this copyright notice
  22.  * appears in all copies. Please refer to the file "copyright.html"
  23.  * for further important copyright and licensing information.
  24.  *
  25.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  26.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  27.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  28.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  29.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  30.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  31.  *
  32.  */
  33. package java.text;
  34.  
  35. final class Utility {
  36.  
  37.     /**
  38.      * Convenience utility to compare two Object[]s.
  39.      * Ought to be in System
  40.      */
  41.     final static boolean arrayEquals(Object[] source, Object target) {
  42.         if (source == null) return (target == null);
  43.         if (!(target instanceof Object[])) return false;
  44.         Object[] targ = (Object[]) target;
  45.         return (source.length == targ.length
  46.                 && arrayRegionMatches(source, 0, targ, 0, source.length));
  47.     }
  48.  
  49.     /**
  50.      * Convenience utility to compare two int[]s
  51.      * Ought to be in System
  52.      */
  53.     final static boolean arrayEquals(int[] source, Object target) {
  54.         if (source == null) return (target == null);
  55.         if (!(target instanceof int[])) return false;
  56.         int[] targ = (int[]) target;
  57.         return (source.length == targ.length
  58.                 && arrayRegionMatches(source, 0, targ, 0, source.length));
  59.     }
  60.  
  61.     /**
  62.      * Convenience utility to compare two double[]s
  63.      * Ought to be in System
  64.      */
  65.     final static boolean arrayEquals(double[] source, Object target) {
  66.         if (source == null) return (target == null);
  67.         if (!(target instanceof double[])) return false;
  68.         double[] targ = (double[]) target;
  69.         return (source.length == targ.length
  70.                 && arrayRegionMatches(source, 0, targ, 0, source.length));
  71.     }
  72.  
  73.     /**
  74.      * Convenience utility to compare two Object[]s
  75.      * Ought to be in System
  76.      */
  77.     final static boolean arrayEquals(Object source, Object target) {
  78.         if (source == null) return (target == null);
  79.         // for some reason, the correct arrayEquals is not being called
  80.         // so do it by hand for now.
  81.         if (source instanceof Object[])
  82.             return(arrayEquals((Object[]) source,target));
  83.         if (source instanceof int[])
  84.             return(arrayEquals((int[]) source,target));
  85.         if (source instanceof double[])
  86.             return(arrayEquals((int[]) source,target));
  87.         return source.equals(target);
  88.     }
  89.  
  90.     /**
  91.      * Convenience utility to compare two Object[]s
  92.      * Ought to be in System.
  93.      * @param len the length to compare.
  94.      * The start indices and start+len must be valid.
  95.      */
  96.     final static boolean arrayRegionMatches(Object[] source, int sourceStart,
  97.                                             Object[] target, int targetStart,
  98.                                             int len)
  99.     {
  100.         int sourceEnd = sourceStart + len;
  101.         int delta = targetStart - sourceStart;
  102.         for (int i = sourceStart; i < sourceEnd; i++) {
  103.             if (!arrayEquals(source[i],target[i + delta]))
  104.             return false;
  105.         }
  106.         return true;
  107.     }
  108.  
  109.     /**
  110.      * Convenience utility to compare two int[]s.
  111.      * @param len the length to compare.
  112.      * The start indices and start+len must be valid.
  113.      * Ought to be in System
  114.      */
  115.     final static boolean arrayRegionMatches(int[] source, int sourceStart,
  116.                                             int[] target, int targetStart,
  117.                                             int len)
  118.     {
  119.         int sourceEnd = sourceStart + len;
  120.         int delta = targetStart - sourceStart;
  121.         for (int i = sourceStart; i < sourceEnd; i++) {
  122.             if (source[i] != target[i + delta])
  123.             return false;
  124.         }
  125.         return true;
  126.     }
  127.  
  128.     /**
  129.      * Convenience utility to compare two arrays of doubles.
  130.      * @param len the length to compare.
  131.      * The start indices and start+len must be valid.
  132.      * Ought to be in System
  133.      */
  134.     final static boolean arrayRegionMatches(double[] source, int sourceStart,
  135.                                             double[] target, int targetStart,
  136.                                             int len)
  137.     {
  138.         int sourceEnd = sourceStart + len;
  139.         int delta = targetStart - sourceStart;
  140.         for (int i = sourceStart; i < sourceEnd; i++) {
  141.             if (source[i] != target[i + delta])
  142.             return false;
  143.         }
  144.         return true;
  145.     }
  146.  
  147.     /**
  148.      * Convenience utility. Does null checks on objects, then calls equals.
  149.      */
  150.     final static boolean objectEquals(Object source, Object target) {
  151.     if (source == null)
  152.             return (target == null);
  153.     else
  154.             return source.equals(target);
  155.     }
  156.  
  157.     /**
  158.      * The ESCAPE character is used during run-length encoding.  It signals
  159.      * a run of identical chars.
  160.      */
  161.     static final char ESCAPE = '\uA5A5';
  162.  
  163.     /**
  164.      * The ESCAPE_BYTE character is used during run-length encoding.  It signals
  165.      * a run of identical bytes.
  166.      */
  167.     static final byte ESCAPE_BYTE = (byte)0xA5;
  168.  
  169.     /**
  170.      * Construct a string representing a short array.  Use run-length encoding.
  171.      * A character represents itself, unless it is the ESCAPE character.  Then
  172.      * the following notations are possible:
  173.      *   ESCAPE ESCAPE   ESCAPE literal
  174.      *   ESCAPE n c      n instances of character c
  175.      * Since an encoded run occupies 3 characters, we only encode runs of 4 or
  176.      * more characters.  Thus we have n > 0 and n != ESCAPE and n <= 0xFFFF.
  177.      * If we encounter a run where n == ESCAPE, we represent this as:
  178.      *   c ESCAPE n-1 c
  179.      * The ESCAPE value is chosen so as not to collide with commonly
  180.      * seen values.
  181.      */
  182.     static final String arrayToRLEString(short[] a) {
  183.     StringBuffer buffer = new StringBuffer();
  184.     // for (int i=0; i<a.length; ++i) buffer.append((char) a[i]);
  185.     buffer.append((char) (a.length >> 16));
  186.     buffer.append((char) a.length);
  187.     short runValue = a[0];
  188.     int runLength = 1;
  189.     for (int i=1; i<a.length; ++i) {
  190.         short s = a[i];
  191.         if (s == runValue && runLength < 0xFFFF) ++runLength;
  192.         else {
  193.         encodeRun(buffer, runValue, runLength);
  194.         runValue = s;
  195.         runLength = 1;
  196.         }
  197.     }
  198.     encodeRun(buffer, runValue, runLength);
  199.     return buffer.toString();
  200.     }
  201.  
  202.     /**
  203.      * Construct a string representing a byte array.  Use run-length encoding.
  204.      * Two bytes are packed into a single char, with a single extra zero byte at
  205.      * the end if needed.  A byte represents itself, unless it is the
  206.      * ESCAPE_BYTE.  Then the following notations are possible:
  207.      *   ESCAPE_BYTE ESCAPE_BYTE   ESCAPE_BYTE literal
  208.      *   ESCAPE_BYTE n b           n instances of byte b
  209.      * Since an encoded run occupies 3 bytes, we only encode runs of 4 or
  210.      * more bytes.  Thus we have n > 0 and n != ESCAPE_BYTE and n <= 0xFF.
  211.      * If we encounter a run where n == ESCAPE_BYTE, we represent this as:
  212.      *   b ESCAPE_BYTE n-1 b
  213.      * The ESCAPE_BYTE value is chosen so as not to collide with commonly
  214.      * seen values.
  215.      */
  216.     static final String arrayToRLEString(byte[] a) {
  217.     StringBuffer buffer = new StringBuffer();
  218.     buffer.append((char) (a.length >> 16));
  219.     buffer.append((char) a.length);
  220.     byte runValue = a[0];
  221.     int runLength = 1;
  222.     byte[] state = new byte[2];
  223.     for (int i=1; i<a.length; ++i) {
  224.         byte b = a[i];
  225.         if (b == runValue && runLength < 0xFF) ++runLength;
  226.         else {
  227.         encodeRun(buffer, runValue, runLength, state);
  228.         runValue = b;
  229.         runLength = 1;
  230.         }
  231.     }
  232.     encodeRun(buffer, runValue, runLength, state);
  233.  
  234.     // We must save the final byte, if there is one, by padding
  235.     // an extra zero.
  236.     if (state[0] != 0) appendEncodedByte(buffer, (byte)0, state);
  237.  
  238.     return buffer.toString();
  239.     }
  240.  
  241.     /**
  242.      * Encode a run, possibly a degenerate run (of < 4 values).
  243.      * @param length The length of the run; must be > 0 && <= 0xFFFF.
  244.      */
  245.     private static final void encodeRun(StringBuffer buffer, short value, int length) {
  246.     if (length < 4) {
  247.         for (int j=0; j<length; ++j) {
  248.         if (value == (int) ESCAPE) buffer.append(ESCAPE);
  249.         buffer.append((char) value);
  250.         }
  251.     }
  252.     else {
  253.         if (length == (int) ESCAPE) {
  254.         if (value == (int) ESCAPE) buffer.append(ESCAPE);
  255.         buffer.append((char) value);
  256.         --length;
  257.         }
  258.         buffer.append(ESCAPE);
  259.         buffer.append((char) length);
  260.         buffer.append((char) value); // Don't need to escape this value
  261.     }
  262.     }
  263.  
  264.     /**
  265.      * Encode a run, possibly a degenerate run (of < 4 values).
  266.      * @param length The length of the run; must be > 0 && <= 0xFF.
  267.      */
  268.     private static final void encodeRun(StringBuffer buffer, byte value, int length,
  269.                     byte[] state) {
  270.     if (length < 4) {
  271.         for (int j=0; j<length; ++j) {
  272.         if (value == ESCAPE_BYTE) appendEncodedByte(buffer, ESCAPE_BYTE, state);
  273.         appendEncodedByte(buffer, value, state);
  274.         }
  275.     }
  276.     else {
  277.         if (length == ESCAPE_BYTE) {
  278.         if (value == ESCAPE_BYTE) appendEncodedByte(buffer, ESCAPE_BYTE, state);
  279.         appendEncodedByte(buffer, value, state);
  280.         --length;
  281.         }
  282.         appendEncodedByte(buffer, ESCAPE_BYTE, state);
  283.         appendEncodedByte(buffer, (byte)length, state);
  284.         appendEncodedByte(buffer, value, state); // Don't need to escape this value
  285.     }
  286.     }
  287.  
  288.     /**
  289.      * Append a byte to the given StringBuffer, packing two bytes into each
  290.      * character.  The state parameter maintains intermediary data between
  291.      * calls.
  292.      * @param state A two-element array, with state[0] == 0 if this is the
  293.      * first byte of a pair, or state[0] != 0 if this is the second byte
  294.      * of a pair, in which case state[1] is the first byte.
  295.      */
  296.     private static final void appendEncodedByte(StringBuffer buffer, byte value,
  297.                         byte[] state) {
  298.     if (state[0] != 0) {
  299.         char c = (char) ((state[1] << 8) | (((int) value) & 0xFF));
  300.         buffer.append(c);
  301.         state[0] = 0;
  302.     }
  303.     else {
  304.         state[0] = 1;
  305.         state[1] = value;
  306.     }
  307.     }
  308.  
  309.     /**
  310.      * Construct an array of shorts from a run-length encoded string.
  311.      */
  312.     static final short[] RLEStringToShortArray(String s) {
  313.     int length = (((int) s.charAt(0)) << 16) | ((int) s.charAt(1));
  314.     short[] array = new short[length];
  315.     int ai = 0;
  316.     for (int i=2; i<s.length(); ++i) {
  317.         char c = s.charAt(i);
  318.         if (c == ESCAPE) {
  319.         c = s.charAt(++i);
  320.         if (c == ESCAPE) array[ai++] = (short) c;
  321.         else {
  322.             int runLength = (int) c;
  323.             short runValue = (short) s.charAt(++i);
  324.             for (int j=0; j<runLength; ++j) array[ai++] = runValue;
  325.         }
  326.         }
  327.         else {
  328.         array[ai++] = (short) c;
  329.         }
  330.     }
  331.  
  332.     if (ai != length)
  333.         throw new InternalError("Bad run-length encoded short array");
  334.  
  335.     return array;
  336.     }
  337.  
  338.     /**
  339.      * Construct an array of bytes from a run-length encoded string.
  340.      */
  341.     static final byte[] RLEStringToByteArray(String s) {
  342.     int length = (((int) s.charAt(0)) << 16) | ((int) s.charAt(1));
  343.     byte[] array = new byte[length];
  344.     boolean nextChar = true;
  345.     char c = 0;
  346.     int node = 0;
  347.     int runLength = 0;
  348.     int i = 2;
  349.     for (int ai=0; ai<length; ) {
  350.         // This part of the loop places the next byte into the local
  351.         // variable 'b' each time through the loop.  It keeps the
  352.         // current character in 'c' and uses the boolean 'nextChar'
  353.         // to see if we've taken both bytes out of 'c' yet.
  354.         byte b;
  355.         if (nextChar) {
  356.         c = s.charAt(i++);
  357.         b = (byte) (c >> 8);
  358.         nextChar = false;
  359.         }
  360.         else {
  361.         b = (byte) (c & 0xFF);
  362.         nextChar = true;
  363.         }
  364.  
  365.         // This part of the loop is a tiny state machine which handles
  366.         // the parsing of the run-length encoding.  This would be simpler
  367.         // if we could look ahead, but we can't, so we use 'node' to
  368.         // move between three nodes in the state machine.
  369.         switch (node) {
  370.         case 0:
  371.         // Normal idle node
  372.         if (b == ESCAPE_BYTE) {
  373.             node = 1;
  374.         }
  375.         else {
  376.             array[ai++] = b;
  377.         }
  378.         break;
  379.         case 1:
  380.         // We have seen one ESCAPE_BYTE; we expect either a second
  381.         // one, or a run length and value.
  382.         if (b == ESCAPE_BYTE) {
  383.             array[ai++] = ESCAPE_BYTE;
  384.             node = 0;
  385.         }
  386.         else {
  387.             runLength = b;
  388.             // Interpret signed byte as unsigned
  389.             if (runLength < 0) runLength += 0x100;
  390.             node = 2;
  391.         }
  392.         break;
  393.         case 2:
  394.         // We have seen an ESCAPE_BYTE and length byte.  We interpret
  395.         // the next byte as the value to be repeated.
  396.         for (int j=0; j<runLength; ++j) array[ai++] = b;
  397.         node = 0;
  398.         break;
  399.         }
  400.     }
  401.  
  402.     if (node != 0)
  403.         throw new InternalError("Bad run-length encoded byte array");
  404.  
  405.     if (i != s.length())
  406.         throw new InternalError("Excess data in RLE byte array string");
  407.  
  408.     return array;
  409.     }
  410.  
  411.     /**
  412.      * Format a String for representation in a source file.  This includes
  413.      * breaking it into lines escaping characters using octal notation
  414.      * when necessary (control characters and double quotes).
  415.      */
  416.     static final String formatForSource(String s) {
  417.     StringBuffer buffer = new StringBuffer();
  418.     for (int i=0; i<s.length();) {
  419.         if (i > 0) buffer.append("+\n");
  420.         buffer.append("        \"");
  421.         int count = 11;
  422.         while (i<s.length() && count<80) {
  423.         char c = s.charAt(i++);
  424.         if (c < '\u0020' || c == '"') {
  425.             // Represent control characters and the double quote
  426.             // using octal notation; otherwise the string we form
  427.             // won't compile, since Unicode escape sequences are
  428.             // processed before tokenization.
  429.             buffer.append('\\');
  430.             buffer.append(HEX_DIGIT[(c & 0700) >> 6]); // HEX_DIGIT works for octal
  431.             buffer.append(HEX_DIGIT[(c & 0070) >> 3]);
  432.             buffer.append(HEX_DIGIT[(c & 0007)]);
  433.             count += 4;
  434.         }
  435.         else if (c <= '\u007E') {
  436.             buffer.append(c);
  437.             count += 1;
  438.         }
  439.         else {
  440.             buffer.append("\\u");
  441.             buffer.append(HEX_DIGIT[(c & 0xF000) >> 12]);
  442.             buffer.append(HEX_DIGIT[(c & 0x0F00) >> 8]);
  443.             buffer.append(HEX_DIGIT[(c & 0x00F0) >> 4]);
  444.             buffer.append(HEX_DIGIT[(c & 0x000F)]);
  445.             count += 6;
  446.         }
  447.         }
  448.         buffer.append('"');
  449.     }
  450.     return buffer.toString();
  451.     }
  452.  
  453.     static final char[] HEX_DIGIT = {'0','1','2','3','4','5','6','7',
  454.                      '8','9','A','B','C','D','E','F'};
  455. }
  456.  
  457.