content: /**
   * Copyright 2009 DFKI GmbH.
   * All Rights Reserved.  Use is subject to license terms.
   * <p/>
   * This file is part of MARY TTS.
   * <p/>
   * MARY TTS is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation, version 3 of the License.
   * <p/>
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU Lesser General Public License for more details.
   * <p/>
   * You should have received a copy of the GNU Lesser General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  package marytts.util.io;
  
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.DataInput;
  import java.io.DataInputStream;
  import java.io.DataOutput;
  import java.io.DataOutputStream;
  import java.io.EOFException;
  import java.io.IOException;
  import java.io.UTFDataFormatException;
  import java.nio.BufferUnderflowException;
  import java.nio.ByteBuffer;
  
  /**
   * @author marc
   */
  public class StreamUtils {
  
      public static double[] readDoubleArray(DataInput stream, int len)
              throws IOException {
          byte[] raw = new byte[len * Double.SIZE / 8];
          stream.readFully(raw);
          DataInputStream in = new DataInputStream(new ByteArrayInputStream(raw));
          double[] data = new double[len];
          for (int i = 0; i < len; i++) {
              data[i] = in.readDouble();
          }
          return data;
      }
  
  
      public static void writeDoubleArray(DataOutput stream, double[] data)
              throws IOException {
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          DataOutputStream out = new DataOutputStream(baos);
          for (int i = 0; i < data.length; i++) {
              out.writeDouble(data[i]);
          }
          out.close();
          byte[] raw = baos.toByteArray();
          assert raw.length == data.length * Double.SIZE / 8;
          stream.write(raw);
      }
  
      /**
       * Reads from the
       * bytebuffer <code>bb</code> a representation
       * of a Unicode  character string encoded in
       * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> format;
       * this string of characters is then returned as a <code>String</code>.
       * The details of the modified UTF-8 representation
       * are  exactly the same as for the <code>readUTF</code>
       * method of <code>DataInput</code>.
       *
       * @param in a byte buffer.
       * @return a Unicode string.
       * @throws BufferUnderflowException if the input stream reaches the end
       *                                  before all the bytes.
       * @throws UTFDataFormatException   if the bytes do not represent a
       *                                  valid modified UTF-8 encoding of a Unicode string.
       * @see java.io.DataInputStream#readUnsignedShort()
       */
      public static String readUTF(ByteBuffer bb) throws BufferUnderflowException, UTFDataFormatException {
          int utflen = readUnsignedShort(bb);
          byte[] bytearr = new byte[utflen];
          char[] chararr = new char[utflen];
  
          int c, char2, char3;
          int count = 0;
          int chararr_count = 0;
  
          bb.get(bytearr);
  
          while (count < utflen) {
              c = bytearr[count] & 0xff;
              if (c > 127) break;
              count++;
              chararr[chararr_count++] = (char) c;
          }
  
          while (count < utflen) {
              c = bytearr[count] & 0xff;
              switch (c >> 4) {
                  case 0:
                  case 1:
                  case 2:
                  case 3:
                  case 4:
                  case 5:
                  case 6:
                  case 7:
                      /* 0xxxxxxx*/
                      count++;
                      chararr[chararr_count++] = (char) c;
                      break;
                  case 12:
                  case 13:
                      /* 110x xxxx   10xx xxxx*/
                      count += 2;
                      if (count > utflen)
                          throw new UTFDataFormatException(
                                  "malformed input: partial character at end");
                      char2 = bytearr[count - 1];
                      if ((char2 & 0xC0) != 0x80)
                          throw new UTFDataFormatException(
                                  "malformed input around byte " + count);
                      chararr[chararr_count++] = (char) (((c & 0x1F) << 6) |
                              (char2 & 0x3F));
                      break;
                  case 14:
                      /* 1110 xxxx  10xx xxxx  10xx xxxx */
                      count += 3;
                      if (count > utflen)
                          throw new UTFDataFormatException(
                                  "malformed input: partial character at end");
                      char2 = bytearr[count - 2];
                      char3 = bytearr[count - 1];
                      if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
                          throw new UTFDataFormatException(
                                  "malformed input around byte " + (count - 1));
                      chararr[chararr_count++] = (char) (((c & 0x0F) << 12) |
                              ((char2 & 0x3F) << 6) |
                              ((char3 & 0x3F) << 0));
                      break;
                  default:
                      /* 10xx xxxx,  1111 xxxx */
                      throw new UTFDataFormatException(
                              "malformed input around byte " + count);
              }
          }
          // The number of chars produced may be less than utflen
          return new String(chararr, 0, chararr_count);
      }
  
      /**
       * See the general contract of the <code>readUnsignedShort</code>
       * method of <code>DataInput</code>.
       * <p/>
       * Bytes
       * for this operation are read from the given byte buffer
       *
       * @return the next two bytes of this input stream, interpreted as an
       * unsigned 16-bit integer.
       * @throws EOFException if this input stream reaches the end before
       *                      reading two bytes.
       * @throws IOException  the stream has been closed and the contained
       *                      input stream does not support reading after close, or
       *                      another I/O error occurs.
       * @see java.io.FilterInputStream#in
       */
      public static int readUnsignedShort(ByteBuffer bb) throws BufferUnderflowException {
          int ch1 = bb.get() & 0xFF; // convert byte to unsigned byte
          int ch2 = bb.get() & 0xFF; // convert byte to unsigned byte
          return (ch1 << 8) + (ch2 << 0);
      }
  }
  