package org.jaudiotagger.audio.aiff;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.audio.generic.AudioFileReader;
import org.jaudiotagger.audio.generic.GenericAudioHeader;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.aiff.AiffTag;
public class AiffFileReader extends AudioFileReader {
/* Fixed value for first 4 bytes */
private static final int[] sigByte =
{ 0X46, 0X4F, 0X52, 0X4D };
/* AIFF-specific information which isn'timer "tag" information */
private AiffAudioHeader aiffHeader;
/* "Tag" information */
private AiffTag aiffTag;
/* InputStream that reads the file sequentially */
// private DataInputStream inStream;
public AiffFileReader () {
aiffHeader = new AiffAudioHeader();
aiffTag = new AiffTag ();
}
public AiffFileReader (RandomAccessFile raf) {
aiffHeader = new AiffAudioHeader();
aiffTag = new AiffTag ();
}
/** Reads the file and fills in the audio header and tag information.
* Holds the tag information for later and returns the audio header. */
@Override
protected GenericAudioHeader getEncodingInfo(RandomAccessFile raf)
throws CannotReadException, IOException {
logger.finest("Reading AIFF file ");
byte sigBuf[] = new byte[4];
raf.read(sigBuf);
for (int i = 0; i < 4; i++) {
if (sigBuf[i] != sigByte[i]) {
logger.finest ("AIFF file has incorrect signature");
throw new CannotReadException ("Not an AIFF file: incorrect signature");
}
}
long bytesRemaining = AiffUtil.readUINT32(raf);
// Read the file type.
if (!readFileType (raf)) {
throw new CannotReadException ("Invalid AIFF file: Incorrect file type info");
}
bytesRemaining -= 4;
while (bytesRemaining > 0) {
if (!readChunk (raf, bytesRemaining)) {
break;
}
}
return aiffHeader;
}
@Override
protected Tag getTag(RandomAccessFile raf) throws CannotReadException,
IOException {
logger.info("getTag called");
// TODO fill out stub code
return aiffTag;
}
/* Reads the file type.
* Broken out from parse().
* If it is not a valid file type, returns false.
*/
private boolean readFileType (RandomAccessFile raf) throws IOException
{
String typ = AiffUtil.read4Chars (raf);
if ("AIFF".equals (typ)) {
aiffHeader.setFileType (AiffAudioHeader.FileType.AIFFTYPE);
return true;
}
else if ("AIFC".equals (typ)) {
aiffHeader.setFileType (AiffAudioHeader.FileType.AIFCTYPE);
return true;
}
else {
return false;
}
}
/** Reads an AIFF Chunk.
*
*/
protected boolean readChunk
(RandomAccessFile raf, long bytesRemaining)
throws IOException
{
Chunk chunk = null;
ChunkHeader chunkh = new ChunkHeader ();
if (!chunkh.readHeader(raf)) {
return false;
}
int chunkSize = (int) chunkh.getSize ();
bytesRemaining -= chunkSize + 8;
String id = chunkh.getID ();
if ("FVER".equals (id)) {
chunk = new FormatVersionChunk (chunkh, raf, aiffHeader);
}
else if ("APPL".equals (id)) {
chunk = new ApplicationChunk (chunkh, raf, aiffHeader);
// Any number of application chunks is ok
}
else if ("COMM".equals (id)) {
// There should be no more than one of these
chunk = new CommonChunk (chunkh, raf, aiffHeader);
}
else if ("COMT".equals (id)) {
chunk = new CommentsChunk (chunkh, raf, aiffHeader);
}
else if ("NAME".equals (id)) {
chunk = new NameChunk (chunkh, raf, aiffHeader);
}
else if ("AUTH".equals (id)) {
chunk = new AuthorChunk (chunkh, raf, aiffHeader);
}
else if ("(c) ".equals (id)) {
chunk = new CopyrightChunk (chunkh, raf, aiffHeader);
}
else if ("ANNO".equals (id)) {
chunk = new AnnotationChunk (chunkh, raf, aiffHeader);
}
else if ("ID3 ".equals (id)) {
chunk = new ID3Chunk (chunkh, raf, aiffTag);
}
if (chunk != null) {
if (!chunk.readChunk ()) {
return false;
}
}
else {
// Other chunk types are legal, just skip over them
raf.skipBytes (chunkSize);
}
if ((chunkSize & 1) != 0) {
// Must come out to an even byte boundary
raf.skipBytes(1);
--bytesRemaining;
}
return true;
}
}