rockbox/songdbj/javazoom/jl/converter/RiffFile.java

496 lines
12 KiB
Java
Raw Normal View History

/*
* 11/19/04 1.0 moved to LGPL.
* 02/23/99 JavaConversion by E.B
* Don Cross, April 1993.
* RIFF file format classes.
* See Chapter 8 of "Multimedia Programmer's Reference" in
* the Microsoft Windows SDK.
*
*-----------------------------------------------------------------------
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*----------------------------------------------------------------------
*/
package javazoom.jl.converter;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* Class to manage RIFF files
*/
public class RiffFile
{
class RiffChunkHeader
{
public int ckID = 0; // Four-character chunk ID
public int ckSize = 0; // Length of data in chunk
public RiffChunkHeader()
{}
}
// DDCRET
public static final int DDC_SUCCESS = 0; // The operation succeded
public static final int DDC_FAILURE = 1; // The operation failed for unspecified reasons
public static final int DDC_OUT_OF_MEMORY = 2; // Operation failed due to running out of memory
public static final int DDC_FILE_ERROR = 3; // Operation encountered file I/O error
public static final int DDC_INVALID_CALL = 4; // Operation was called with invalid parameters
public static final int DDC_USER_ABORT = 5; // Operation was aborted by the user
public static final int DDC_INVALID_FILE = 6; // File format does not match
// RiffFileMode
public static final int RFM_UNKNOWN = 0; // undefined type (can use to mean "N/A" or "not open")
public static final int RFM_WRITE = 1; // open for write
public static final int RFM_READ = 2; // open for read
private RiffChunkHeader riff_header; // header for whole file
protected int fmode; // current file I/O mode
protected RandomAccessFile file; // I/O stream to use
/**
* Dummy Constructor
*/
public RiffFile()
{
file = null;
fmode = RFM_UNKNOWN;
riff_header = new RiffChunkHeader();
riff_header.ckID = FourCC("RIFF");
riff_header.ckSize = 0;
}
/**
* Return File Mode.
*/
public int CurrentFileMode()
{return fmode;}
/**
* Open a RIFF file.
*/
public int Open(String Filename, int NewMode)
{
int retcode = DDC_SUCCESS;
if ( fmode != RFM_UNKNOWN )
{
retcode = Close();
}
if ( retcode == DDC_SUCCESS )
{
switch ( NewMode )
{
case RFM_WRITE:
try
{
file = new RandomAccessFile(Filename,"rw");
try
{
// Write the RIFF header...
// We will have to come back later and patch it!
byte[] br = new byte[8];
br[0] = (byte) ((riff_header.ckID >>> 24) & 0x000000FF);
br[1] = (byte) ((riff_header.ckID >>> 16) & 0x000000FF);
br[2] = (byte) ((riff_header.ckID >>> 8) & 0x000000FF);
br[3] = (byte) (riff_header.ckID & 0x000000FF);
byte br4 = (byte) ((riff_header.ckSize >>> 24)& 0x000000FF);
byte br5 = (byte) ((riff_header.ckSize >>> 16)& 0x000000FF);
byte br6 = (byte) ((riff_header.ckSize >>> 8)& 0x000000FF);
byte br7 = (byte) (riff_header.ckSize & 0x000000FF);
br[4] = br7;
br[5] = br6;
br[6] = br5;
br[7] = br4;
file.write(br,0,8);
fmode = RFM_WRITE;
} catch (IOException ioe)
{
file.close();
fmode = RFM_UNKNOWN;
}
} catch (IOException ioe)
{
fmode = RFM_UNKNOWN;
retcode = DDC_FILE_ERROR;
}
break;
case RFM_READ:
try
{
file = new RandomAccessFile(Filename,"r");
try
{
// Try to read the RIFF header...
byte[] br = new byte[8];
file.read(br,0,8);
fmode = RFM_READ;
riff_header.ckID = ((br[0]<<24)& 0xFF000000) | ((br[1]<<16)&0x00FF0000) | ((br[2]<<8)&0x0000FF00) | (br[3]&0x000000FF);
riff_header.ckSize = ((br[4]<<24)& 0xFF000000) | ((br[5]<<16)&0x00FF0000) | ((br[6]<<8)&0x0000FF00) | (br[7]&0x000000FF);
} catch (IOException ioe)
{
file.close();
fmode = RFM_UNKNOWN;
}
} catch (IOException ioe)
{
fmode = RFM_UNKNOWN;
retcode = DDC_FILE_ERROR;
}
break;
default:
retcode = DDC_INVALID_CALL;
}
}
return retcode;
}
/**
* Write NumBytes data.
*/
public int Write(byte[] Data, int NumBytes )
{
if ( fmode != RFM_WRITE )
{
return DDC_INVALID_CALL;
}
try
{
file.write(Data,0,NumBytes);
fmode = RFM_WRITE;
}
catch (IOException ioe)
{
return DDC_FILE_ERROR;
}
riff_header.ckSize += NumBytes;
return DDC_SUCCESS;
}
/**
* Write NumBytes data.
*/
public int Write(short[] Data, int NumBytes )
{
byte[] theData = new byte[NumBytes];
int yc = 0;
for (int y = 0;y<NumBytes;y=y+2)
{
theData[y] = (byte) (Data[yc] & 0x00FF);
theData[y+1] =(byte) ((Data[yc++] >>> 8) & 0x00FF);
}
if ( fmode != RFM_WRITE )
{
return DDC_INVALID_CALL;
}
try
{
file.write(theData,0,NumBytes);
fmode = RFM_WRITE;
}
catch (IOException ioe)
{
return DDC_FILE_ERROR;
}
riff_header.ckSize += NumBytes;
return DDC_SUCCESS;
}
/**
* Write NumBytes data.
*/
public int Write(RiffChunkHeader Triff_header, int NumBytes )
{
byte[] br = new byte[8];
br[0] = (byte) ((Triff_header.ckID >>> 24) & 0x000000FF);
br[1] = (byte) ((Triff_header.ckID >>> 16) & 0x000000FF);
br[2] = (byte) ((Triff_header.ckID >>> 8) & 0x000000FF);
br[3] = (byte) (Triff_header.ckID & 0x000000FF);
byte br4 = (byte) ((Triff_header.ckSize >>> 24)& 0x000000FF);
byte br5 = (byte) ((Triff_header.ckSize >>> 16)& 0x000000FF);
byte br6 = (byte) ((Triff_header.ckSize >>> 8)& 0x000000FF);
byte br7 = (byte) (Triff_header.ckSize & 0x000000FF);
br[4] = br7;
br[5] = br6;
br[6] = br5;
br[7] = br4;
if ( fmode != RFM_WRITE )
{
return DDC_INVALID_CALL;
}
try
{
file.write(br,0,NumBytes);
fmode = RFM_WRITE;
} catch (IOException ioe)
{
return DDC_FILE_ERROR;
}
riff_header.ckSize += NumBytes;
return DDC_SUCCESS;
}
/**
* Write NumBytes data.
*/
public int Write(short Data, int NumBytes )
{
short theData = (short) ( ((Data>>>8)&0x00FF) | ((Data<<8)&0xFF00) );
if ( fmode != RFM_WRITE )
{
return DDC_INVALID_CALL;
}
try
{
file.writeShort(theData);
fmode = RFM_WRITE;
} catch (IOException ioe)
{
return DDC_FILE_ERROR;
}
riff_header.ckSize += NumBytes;
return DDC_SUCCESS;
}
/**
* Write NumBytes data.
*/
public int Write(int Data, int NumBytes )
{
short theDataL = (short) ((Data>>>16)&0x0000FFFF);
short theDataR = (short) (Data&0x0000FFFF);
short theDataLI = (short) ( ((theDataL>>>8)&0x00FF) | ((theDataL<<8)&0xFF00) );
short theDataRI = (short) ( ((theDataR>>>8)&0x00FF) | ((theDataR<<8)&0xFF00) );
int theData = ((theDataRI<<16)&0xFFFF0000) | (theDataLI&0x0000FFFF);
if ( fmode != RFM_WRITE )
{
return DDC_INVALID_CALL;
}
try
{
file.writeInt(theData);
fmode = RFM_WRITE;
} catch (IOException ioe)
{
return DDC_FILE_ERROR;
}
riff_header.ckSize += NumBytes;
return DDC_SUCCESS;
}
/**
* Read NumBytes data.
*/
public int Read (byte[] Data, int NumBytes)
{
int retcode = DDC_SUCCESS;
try
{
file.read(Data,0,NumBytes);
} catch (IOException ioe)
{
retcode = DDC_FILE_ERROR;
}
return retcode;
}
/**
* Expect NumBytes data.
*/
public int Expect(String Data, int NumBytes )
{
byte target = 0;
int cnt = 0;
try
{
while ((NumBytes--) != 0)
{
target = file.readByte();
if (target != Data.charAt(cnt++)) return DDC_FILE_ERROR;
}
} catch (IOException ioe)
{
return DDC_FILE_ERROR;
}
return DDC_SUCCESS;
}
/**
* Close Riff File.
* Length is written too.
*/
public int Close()
{
int retcode = DDC_SUCCESS;
switch ( fmode )
{
case RFM_WRITE:
try
{
file.seek(0);
try
{
byte[] br = new byte[8];
br[0] = (byte) ((riff_header.ckID >>> 24) & 0x000000FF);
br[1] = (byte) ((riff_header.ckID >>> 16) & 0x000000FF);
br[2] = (byte) ((riff_header.ckID >>> 8) & 0x000000FF);
br[3] = (byte) (riff_header.ckID & 0x000000FF);
br[7] = (byte) ((riff_header.ckSize >>> 24)& 0x000000FF);
br[6] = (byte) ((riff_header.ckSize >>> 16)& 0x000000FF);
br[5] = (byte) ((riff_header.ckSize >>> 8)& 0x000000FF);
br[4] = (byte) (riff_header.ckSize & 0x000000FF);
file.write(br,0,8);
file.close();
} catch (IOException ioe)
{
retcode = DDC_FILE_ERROR;
}
} catch (IOException ioe)
{
retcode = DDC_FILE_ERROR;
}
break;
case RFM_READ:
try
{
file.close();
} catch (IOException ioe)
{
retcode = DDC_FILE_ERROR;
}
break;
}
file = null;
fmode = RFM_UNKNOWN;
return retcode;
}
/**
* Return File Position.
*/
public long CurrentFilePosition()
{
long position;
try
{
position = file.getFilePointer();
} catch (IOException ioe)
{
position = -1;
}
return position;
}
/**
* Write Data to specified offset.
*/
public int Backpatch (long FileOffset, RiffChunkHeader Data, int NumBytes )
{
if (file == null)
{
return DDC_INVALID_CALL;
}
try
{
file.seek(FileOffset);
} catch (IOException ioe)
{
return DDC_FILE_ERROR;
}
return Write ( Data, NumBytes );
}
public int Backpatch (long FileOffset, byte[] Data, int NumBytes )
{
if (file == null)
{
return DDC_INVALID_CALL;
}
try
{
file.seek(FileOffset);
} catch (IOException ioe)
{
return DDC_FILE_ERROR;
}
return Write ( Data, NumBytes );
}
/**
* Seek in the File.
*/
protected int Seek(long offset)
{
int rc;
try
{
file.seek(offset);
rc = DDC_SUCCESS;
} catch (IOException ioe)
{
rc = DDC_FILE_ERROR;
}
return rc;
}
/**
* Error Messages.
*/
private String DDCRET_String(int retcode)
{
switch ( retcode )
{
case DDC_SUCCESS: return "DDC_SUCCESS";
case DDC_FAILURE: return "DDC_FAILURE";
case DDC_OUT_OF_MEMORY: return "DDC_OUT_OF_MEMORY";
case DDC_FILE_ERROR: return "DDC_FILE_ERROR";
case DDC_INVALID_CALL: return "DDC_INVALID_CALL";
case DDC_USER_ABORT: return "DDC_USER_ABORT";
case DDC_INVALID_FILE: return "DDC_INVALID_FILE";
}
return "Unknown Error";
}
/**
* Fill the header.
*/
public static int FourCC(String ChunkName)
{
byte[] p = {0x20,0x20,0x20,0x20};
ChunkName.getBytes(0,4,p,0);
int ret = (((p[0] << 24)& 0xFF000000) | ((p[1] << 16)&0x00FF0000) | ((p[2] << 8)&0x0000FF00) | (p[3]&0x000000FF));
return ret;
}
}