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 / IFC_112 / netscape / util / CompactOutputStream.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  8.6 KB  |  328 lines  |  [TEXT/CWIE]

  1. // CompactOutputStream.java
  2. // By Ned Etcode
  3. // Copyright 1995, 1996, 1997 Netscape Communications Corp.  All rights reserved.
  4.  
  5. package netscape.util;
  6.  
  7. import java.io.*;
  8.  
  9. /** Don't flush() in the middle of writing lots of booleans.  ALERT!
  10.   * @private
  11.   */
  12. public class CompactOutputStream extends OutputStream {
  13.     OutputStream out;
  14.     int booleanCount;
  15.     int booleanBuffer;
  16.     IdHashtable stringTable = new IdHashtable(true);
  17.     int stringCount = 2;
  18.  
  19.     public CompactOutputStream(OutputStream out) {
  20.         super();
  21.         this.out = out;
  22.     }
  23.  
  24.     private final void flushBooleanBuffer() throws IOException {
  25.         if (booleanCount > 0) {
  26.             out.write(booleanBuffer);
  27.             booleanCount = 0;
  28.             booleanBuffer = 0;
  29.         }
  30.     }
  31.  
  32.     public void write(int value) throws IOException {
  33.         flushBooleanBuffer();
  34.         out.write(value);
  35.     }
  36.  
  37.     public void write(byte value[]) throws IOException {
  38.         flushBooleanBuffer();
  39.         out.write(value, 0, value.length);
  40.     }
  41.  
  42.     public void write(byte value[], int offset, int length)
  43.         throws IOException {
  44.         flushBooleanBuffer();
  45.         out.write(value, offset, length);
  46.     }
  47.  
  48.     public void flush() throws IOException {
  49.         flushBooleanBuffer();
  50.         out.flush();
  51.     }
  52.  
  53.     public void close() throws IOException {
  54.         flushBooleanBuffer();
  55.         out.close();
  56.     }
  57.  
  58.     public void writeCompactBoolean(boolean value) throws IOException {
  59.         int buf, count;
  60.  
  61.         count = booleanCount;
  62.  
  63.         if (value) {
  64.             buf = booleanBuffer;
  65.             buf = buf | (1 << count);
  66.             count++;
  67.  
  68.             if (count >= 8) {
  69.                 out.write(buf);
  70.                 booleanCount = 0;
  71.                 booleanBuffer = 0;
  72.             } else {
  73.                 booleanCount = count;
  74.                 booleanBuffer = buf;
  75.             }
  76.         } else {
  77.             count++;
  78.  
  79.             if (count >= 8) {
  80.                 out.write(booleanBuffer);
  81.                 booleanCount = 0;
  82.                 booleanBuffer = 0;
  83.             } else {
  84.                 booleanCount = count;
  85.             }
  86.         }
  87.     }
  88.  
  89.     public void writeBoolean(boolean value) throws IOException {
  90.         if (value)
  91.             out.write(1);
  92.         else
  93.             out.write(0);
  94.     }
  95.  
  96.     public void writeByte(int value) throws IOException {
  97.         flushBooleanBuffer();
  98.         out.write(value);
  99.     }
  100.  
  101.     public void writeShort(int value) throws IOException {
  102.         OutputStream out = this.out;
  103.  
  104.         flushBooleanBuffer();
  105.         out.write((value >>> 8) & 0xff);
  106.         out.write((value >>> 0) & 0xff);
  107.     }
  108.  
  109.     public void writeChar(int value) throws IOException {
  110.         OutputStream out = this.out;
  111.  
  112.         flushBooleanBuffer();
  113.         out.write((value >>> 8) & 0xff);
  114.         out.write((value >>> 0) & 0xff);
  115.     }
  116.  
  117.     /** This writes out specially packed ints.
  118.       */
  119.     public void writeCompactInt(int value) throws IOException {
  120.         OutputStream out = this.out;
  121.  
  122.         flushBooleanBuffer();
  123.  
  124.         if (value < 0) {
  125.             if (value == Integer.MIN_VALUE) {
  126.                 out.write(0x40);
  127.                 return;
  128.             }
  129.  
  130.             value = -value;
  131.             if (value < 0x40) {
  132.                 out.write(value | 0x40);
  133.                 return;
  134.             } else {
  135.                 out.write((value & 0xff) | 0xc0);
  136.             }
  137.         } else {
  138.             if (value < 0x40) {
  139.                 out.write(value);
  140.                 return;
  141.             } else {
  142.                 out.write((value & 0x3f) | 0x80);
  143.             }
  144.         }
  145.  
  146.         value = value >>> 6;
  147.         if (value < 0x80) {
  148.             out.write(value);
  149.         } else {
  150.             out.write((value & 0xff) | 0x80);
  151.             value = value >>> 7;
  152.             if (value < 0x80) {
  153.                 out.write(value);
  154.             } else {
  155.                 out.write((value & 0xff) | 0x80);
  156.                 value = value >>> 7;
  157.                 if (value < 0x80) {
  158.                     out.write(value);
  159.                 } else {
  160.                     out.write((value & 0xff) | 0x80);
  161.                     value = value >>> 7;
  162.                     if (value > 0)
  163.                         out.write(value);
  164.                 }
  165.             }
  166.         }
  167.     }
  168.  
  169.     public void writeInt(int value) throws IOException {
  170.         OutputStream out = this.out;
  171.  
  172.         flushBooleanBuffer();
  173.         out.write((value >>> 24) & 0xff);
  174.         out.write((value >>> 16) & 0xff);
  175.         out.write((value >>>  8) & 0xff);
  176.         out.write((value >>>  0) & 0xff);
  177.     }
  178.  
  179.     public void writeLong(long value) throws IOException {
  180.         OutputStream out = this.out;
  181.  
  182.         flushBooleanBuffer();
  183.         out.write((int)(value >>> 56) & 0xff);
  184.         out.write((int)(value >>> 48) & 0xff);
  185.         out.write((int)(value >>> 40) & 0xff);
  186.         out.write((int)(value >>> 32) & 0xff);
  187.         out.write((int)(value >>> 24) & 0xff);
  188.         out.write((int)(value >>> 16) & 0xff);
  189.         out.write((int)(value >>>  8) & 0xff);
  190.         out.write((int)(value >>>  0) & 0xff);
  191.     }
  192.  
  193.     public void writeFloat(float value) throws IOException {
  194.         writeInt(Float.floatToIntBits(value));
  195.     }
  196.  
  197.     public void writeDouble(double value) throws IOException {
  198.         writeLong(Double.doubleToLongBits(value));
  199.     }
  200.  
  201.     public void writeBytes(String s) throws IOException {
  202.         int i, length;
  203.         OutputStream out = this.out;
  204.  
  205.         flushBooleanBuffer();
  206.         length = s.length();
  207.  
  208.         for (i = 0; i < length; i++) {
  209.             out.write((byte)s.charAt(i));
  210.         }
  211.     }
  212.  
  213.     public void writeChars(String s) throws IOException {
  214.         int i, length, value;
  215.         OutputStream out = this.out;
  216.  
  217.         flushBooleanBuffer();
  218.         length = s.length();
  219.  
  220.         for (i = 0; i < length; i++) {
  221.             value = s.charAt(i);
  222.             out.write((value >>> 8) & 0xff);
  223.             out.write((value >>> 0) & 0xff);
  224.         }
  225.     }
  226.  
  227.     /** Unlike DataOutputStream, this can take a null String.
  228.       */
  229.     public void writeCompactUTF(String str) throws IOException {
  230.         int id, length;
  231.  
  232.         // null and "" are handled specially.  They are assigned the
  233.         // ids 0 and 1 respectively.
  234.  
  235.         if (str == null) {
  236.             writeCompactInt(0);
  237.             return;
  238.         } else if (str.length() == 0) {
  239.             writeCompactInt(1);
  240.             return;
  241.         }
  242.  
  243.         // If we have already written out this String, then just write out the
  244.         // handle which is a positive int (not 0).
  245.  
  246.         id = stringTable.get(str);
  247.         if (id == IdHashtable.NOT_FOUND) {
  248.             id = stringCount++;
  249.             stringTable.putKnownAbsent(str, id);
  250.  
  251.             // The id of a string is determined by the order it appears in the
  252.             // stream.  They start at 2 and go up from there (null and "" are
  253.             // handled specially above).  To indicate that we are not writing
  254.             // an id, we write out the length as a negative number.
  255.  
  256.             length = utfLength(str);
  257.             writeCompactInt(-length);
  258.             writeUTFBytes(str);
  259.         } else {
  260.             writeCompactInt(id);
  261.         }
  262.     }
  263.  
  264.     public void writeUTF(String str) throws IOException {
  265.         int utflen;
  266.         OutputStream out = this.out;
  267.  
  268.         flushBooleanBuffer();
  269.  
  270.         if (str == null) {
  271.             out.write(0xff);
  272.             out.write(0xff);
  273.             return;
  274.         }
  275.  
  276.         utflen = utfLength(str);
  277.         if (utflen >= 0xffff) {
  278.             throw new IOException("string too long");
  279.         }
  280.  
  281.         out.write((utflen >>> 8) & 0xff);
  282.         out.write((utflen >>> 0) & 0xff);
  283.  
  284.         writeUTFBytes(str);
  285.     }
  286.  
  287.     private final int utfLength(String str) {
  288.         int i, c, strlen, utflen;
  289.  
  290.         strlen = str.length();
  291.         utflen = 0;
  292.  
  293.         for (i = 0; i < strlen ; i++) {
  294.             c = str.charAt(i);
  295.             if ((c >= 0x0001) && (c <= 0x007f)) {
  296.                 utflen++;
  297.             } else if (c > 0x07ff) {
  298.                 utflen += 3;
  299.             } else {
  300.                 utflen += 2;
  301.             }
  302.         }
  303.  
  304.         return utflen;
  305.     }
  306.  
  307.     private final void writeUTFBytes(String str) throws IOException {
  308.         int i, c, strlen;
  309.         OutputStream out = this.out;
  310.  
  311.         strlen = str.length();
  312.  
  313.         for (i = 0; i < strlen; i++) {
  314.             c = str.charAt(i);
  315.             if ((c >= 0x0001) && (c <= 0x007f)) {
  316.                 out.write(c);
  317.             } else if (c > 0x07ff) {
  318.                 out.write(0xe0 | ((c >> 12) & 0x0f));
  319.                 out.write(0x80 | ((c >>  6) & 0x3f));
  320.                 out.write(0x80 | ((c >>  0) & 0x3f));
  321.             } else {
  322.                 out.write(0xc0 | ((c >>  6) & 0x1f));
  323.                 out.write(0x80 | ((c >>  0) & 0x3f));
  324.             }
  325.         }
  326.     }
  327. }
  328.