/** * 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. * * 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: * * 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. * * 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 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; /** * Common helper class to read/write a standard Mary header to/from the various Mary data files. * * @author sacha * */ public class MaryHeader { /* Global constants */ private final static int MAGIC = 0x4d415259; // "MARY" private final static int VERSION = 40; // 4.0 /* 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; /* Private fields */ private int magic = MAGIC; private int version = VERSION; private int type = UNKNOWN; // STATIC CODE /** * For the given file, look inside and determine the file type. * * @param fileName * file name * @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(); } } /****************/ /* CONSTRUCTORS */ /****************/ /** * Consruct a MaryHeader from scratch. * * 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(); } /** * 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) { throw new MaryConfigurationException("Cannot load mary header", e); } if (!hasLegalMagic() || !hasLegalType()) { 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) { throw new MaryConfigurationException("Cannot load mary header", e); } if (!hasLegalMagic() || !hasLegalType()) { throw new MaryConfigurationException("Ill-formed Mary header!"); } // post-conditions: assert hasLegalMagic(); assert hasLegalType(); } /*****************/ /* 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); } }