content: /**
   * Portions Copyright 2006 DFKI GmbH.
   * Portions Copyright 2001 Sun Microsystems, Inc.
   * Portions Copyright 1999-2001 Language Technologies Institute,
   * Carnegie Mellon University.
   * All Rights Reserved.  Use is subject to license terms.
   * <p/>
   * Permission is hereby granted, free of charge, to use and distribute
   * this software and its documentation without restriction, including
   * without limitation the rights to use, copy, modify, merge, publish,
   * distribute, sublicense, and/or sell copies of this work, and to
   * permit persons to whom this work is furnished to do so, subject to
   * the following conditions:
   * <p/>
   * 1. The code must retain the above copyright notice, this list of
   * conditions and the following disclaimer.
   * 2. Any modifications must be clearly marked as such.
   * 3. Original authors' names are not deleted.
   * 4. The authors' names are not used to endorse or promote products
   * derived from this software without specific prior written
   * permission.
   * <p/>
   * DFKI GMBH AND THE CONTRIBUTORS TO THIS WORK DISCLAIM ALL WARRANTIES WITH
   * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
   * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DFKI GMBH NOR THE
   * CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
   * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
   * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
   * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
   * THIS SOFTWARE.
   */
  package marytts.util.data;
  
  import android.util.Log;
  
  import java.io.BufferedInputStream;
  import java.io.DataInput;
  import java.io.DataInputStream;
  import java.io.DataOutput;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.nio.BufferUnderflowException;
  import java.nio.ByteBuffer;
  
  import marytts.exceptions.MaryConfigurationException;
  import marytts.server.Mary;
  
  /**
   * Common helper class to read/write a standard Mary header to/from the various
   * Mary data files.
   *
   * @author sacha
   */
  public class MaryHeader {
      /* List of authorized file type identifier constants */
      public final static int UNKNOWN = 0;
      public final static int CARTS = 100;
      public final static int DIRECTED_GRAPH = 110;
      public final static int UNITS = 200;
      public final static int LISTENERUNITS = 225;
      public final static int UNITFEATS = 300;
      public final static int LISTENERFEATS = 325;
      public final static int HALFPHONE_UNITFEATS = 301;
      public final static int JOINFEATS = 400;
      public final static int SCOST = 445;
      public final static int PRECOMPUTED_JOINCOSTS = 450;
      public final static int TIMELINE = 500;
      /* Global constants */
      private final static int MAGIC = 0x4d415259; // "MARY"
      private final static int VERSION = 40; // 4.0
      /* Private fields */
      private int magic = MAGIC;
      private int version = VERSION;
      private int type = UNKNOWN;
  
  
      // STATIC CODE
  
      /**
       * Consruct a MaryHeader from scratch.
       * <p/>
       * Fundamental guarantee: after construction, the MaryHeader has a valid magic number and a valid type.
       *
       * @param newType The type of MaryHeader to create. See public final constants in this class.
       * @throws IllegalArgumentException if the input type is unknown.
       */
      public MaryHeader(int newType) {
          if ((newType > TIMELINE) || (newType < UNKNOWN)) {
              throw new IllegalArgumentException("Unauthorized Mary file type [" + type + "].");
          }
          type = newType;
  
          // post-conditions:
          assert version == VERSION;
          assert hasLegalMagic();
          assert hasLegalType();
      }
  
  
      /****************/
      /* CONSTRUCTORS */
      /****************/
  
      /**
       * Construct a MaryHeader by reading from a file.
       * Fundamental guarantee: after construction, the MaryHeader has a valid magic number and a valid type.
       *
       * @param input a DataInputStream or RandomAccessFile to read the header from.
       * @throws MaryConfigurationException if no mary header can be read from input.
       */
      public MaryHeader(DataInput input) throws MaryConfigurationException {
          try {
              this.load(input);
          } catch (IOException e) {
              Log.d(Mary.LOG, "Cannot load mary header" + e);
              throw new MaryConfigurationException("Cannot load mary header", e);
          }
          if (!hasLegalMagic() || !hasLegalType()) {
              Log.d(Mary.LOG, "Ill-formed Mary header!");
              throw new MaryConfigurationException("Ill-formed Mary header!");
          }
  
          // post-conditions:
          assert hasLegalMagic();
          assert hasLegalType();
      }
  
      /**
       * Construct a MaryHeader by reading from a file.
       * Fundamental guarantee: after construction, the MaryHeader has a valid magic number and a valid type.
       *
       * @param input a byte buffer to read the header from.
       * @throws MaryConfigurationException if no mary header can be read from input.
       */
      public MaryHeader(ByteBuffer input) throws MaryConfigurationException {
          try {
              this.load(input);
          } catch (BufferUnderflowException e) {
              Log.d(Mary.LOG, "Cannot load mary header" + e);
              throw new MaryConfigurationException("Cannot load mary header", e);
          }
          if (!hasLegalMagic() || !hasLegalType()) {
              throw new MaryConfigurationException("Ill-formed Mary header!");
          }
  
          // post-conditions:
          assert hasLegalMagic();
          assert hasLegalType();
      }
  
      /**
       * For the given file, look inside and determine the file type.
       *
       * @param fileName
       * @return the file type, or -1 if the file does not have a valid MARY header.
       * @throws IOException if the file cannot be read
       */
      public static int peekFileType(String fileName) throws IOException {
          DataInputStream dis = null;
          dis = new DataInputStream(new BufferedInputStream(new FileInputStream(fileName)));
          /* Load the Mary header */
          try {
              MaryHeader hdr = new MaryHeader(dis);
              int type = hdr.getType();
              return type;
          } catch (MaryConfigurationException e) {
              // not a valid MARY header
              return -1;
          } finally {
              dis.close();
          }
  
      }
  
      /*****************/
      /* OTHER METHODS */
      /*****************/
  
      /**
       * Mary header writer
       *
       * @param output The DataOutputStream or RandomAccessFile to write to
       * @return the number of written bytes.
       * @throws IOException if the file type is unknown.
       */
      public long writeTo(DataOutput output) throws IOException {
  
          long nBytes = 0;
  
          assert this.hasLegalType() : "Unknown Mary file type [" + type + "].";
  
          output.writeInt(magic);
          nBytes += 4;
          output.writeInt(version);
          nBytes += 4;
          output.writeInt(type);
          nBytes += 4;
  
          return (nBytes);
      }
  
      /**
       * Load a mary header.
       *
       * @param input The data input (DataInputStream or RandomAccessFile) to read from.
       * @throws IOException if the header data cannot be read
       */
      private void load(DataInput input) throws IOException {
  
          magic = input.readInt();
          version = input.readInt();
          type = input.readInt();
      }
  
      /**
       * Load a mary header.
       *
       * @param input the byte buffer from which to read the mary header.
       * @throws BufferUnderflowException if the header data cannot be read
       */
      private void load(ByteBuffer input) {
          magic = input.getInt();
          version = input.getInt();
          type = input.getInt();
      }
  
      /* Accessors */
      public int getMagic() {
          return (magic);
      }
  
      public int getVersion() {
          return (version);
      }
  
      public int getType() {
          return (type);
      }
  
      /* Checkers */
      public boolean hasCurrentVersion() {
          return (version == VERSION);
      }
  
      private boolean hasLegalType() {
          return (type <= TIMELINE) && (type > UNKNOWN);
      }
  
      private boolean hasLegalMagic() {
          return (magic == MAGIC);
      }
  
  }
  