/*
* Copyright (c) 2005 (Mike) Maurice Kienenberger (mkienenb@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.gamenet.application.mm8leveleditor.mm6;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import org.gamenet.application.mm8leveleditor.converter.FormatConverter;
import org.gamenet.application.mm8leveleditor.lod.LodEntry;
import org.gamenet.application.mm8leveleditor.lod.LodResource;
import org.gamenet.util.ByteConversions;
import com.mmbreakfast.unlod.lod.LodFile;
import com.mmbreakfast.unlod.lod.Extractor;
public class MM6SndEntry extends LodEntry
{
protected Extractor theLodFileExtractor = new Extractor();
// entry header
protected static final int ENTRY_NAME__ENTRY_HEADER_OFFSET = 0x00;
protected static final int ENTRY_NAME__ENTRY_HEADER_MAX_LENGTH = 0x28;
protected static final int DATA_SEGMENT_OFFSET__ENTRY_HEADER_OFFSET = 0x28;
protected static final int DATA_CONTENT_COMPRESSED_SIZE__ENTRY_HEADER_OFFSET = 0x2C;
protected static final int DATA_CONTENT_UNCOMPRESSED_SIZE__ENTRY_HEADER_OFFSET = 0x30;
// data header
protected static final int DATA_HEADER_LENGTH = 0x0;
protected Extractor theFileExtractor = new Extractor();
public MM6SndEntry(LodFile lodFile, long headerOffset)
throws IOException
{
super(lodFile, headerOffset);
}
public String getTextDescription()
{
return "Name: "
+ getName()
+ "\n"
+ "EntryName: "
+ getEntryName()
+ "\n"
+ "FileType: "
+ getFileType()
+ "\n"
+ "Data Length: "
+ getDataLength()
+ "\n"
+ "Decompressed Size: "
+ getDecompressedSize()
+ "\n"
+ "Data Offset: "
+ getDataOffset()
;
}
protected void computeEntryBasedOffsets()
{
}
protected void computeDataBasedOffsets()
{
}
public long getDataOffset()
{
return ByteConversions.getIntegerInByteArrayAtPosition(entryHeader, getOffsetInEntryHeaderForDataSegmentOffset());
}
protected int getDataLength()
{
return ByteConversions.getIntegerInByteArrayAtPosition(entryHeader, DATA_CONTENT_COMPRESSED_SIZE__ENTRY_HEADER_OFFSET);
}
protected void readDataHeader() throws IOException
{
}
public byte[] getData() throws IOException
{
byte[] rawData = readRawData();
if (0 == getDecompressedSize())
return rawData;
else
{
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
theLodFileExtractor.decompress(null, rawData, byteStream, null, true);
return byteStream.toByteArray();
}
}
public String getResourceType()
{
return getFileType();
}
protected int getOffsetInEntryHeaderForDataSegmentOffset()
{
return DATA_SEGMENT_OFFSET__ENTRY_HEADER_OFFSET;
}
protected int getOffsetInEntryHeaderForDataSegmentLength()
{
return DATA_CONTENT_COMPRESSED_SIZE__ENTRY_HEADER_OFFSET;
}
protected long getOffsetInEntryHeaderFortDataContentCompressedLength()
{
return DATA_CONTENT_COMPRESSED_SIZE__ENTRY_HEADER_OFFSET;
}
protected long getOffsetInEntryHeaderFortDataContentUncompressedLength()
{
return DATA_CONTENT_UNCOMPRESSED_SIZE__ENTRY_HEADER_OFFSET;
}
public String getFileName()
{
String baseName = getEntryName();
String fileName = null;
if (baseName.toLowerCase().endsWith("." + getFileType().toLowerCase()))
{
fileName = baseName;
}
else
{
fileName = baseName + "." + getFileType();
}
String converterFileType = getFormatConverterFileType();
if (null != converterFileType)
{
if (false == fileName.toLowerCase().endsWith("." + converterFileType.toLowerCase()))
{
fileName = fileName + "." + converterFileType;
}
}
return fileName;
}
protected String getFileType()
{
return "wav";
}
public String getEntryName()
{
int offset = ENTRY_NAME__ENTRY_HEADER_OFFSET;
int maxLength = ENTRY_NAME__ENTRY_HEADER_MAX_LENGTH;
int length = 0;
while ( (0 != entryHeader[offset + length]) && (length < maxLength) )
length++;
return new String(entryHeader, offset, length);
}
protected long getDecompressedSize()
{
int index = (int)getOffsetInEntryHeaderFortDataContentUncompressedLength();
if (-1 == index) return -1;
return ByteConversions.getIntegerInByteArrayAtPosition(entryHeader, index);
}
public FormatConverter getFormatConverter()
{
return super.getFormatConverter();
}
public String getFormatConverterFileType()
{
return super.getFormatConverterFileType();
}
protected class NullOutputStream extends OutputStream
{
public void write(int b) throws IOException
{
}
}
protected int getNewCompressedDataLength(LodResource lodResourceDataSource)
{
try
{
return (int)writeNewData(lodResourceDataSource, new NullOutputStream(), 0);
}
catch (IOException exception)
{
// Doesn't throw exceptions
exception.printStackTrace();
return -1;
}
}
protected int getUpdatedCompressedDataLength(LodResource lodResourceDataSource)
{
try
{
return (int)updateData(lodResourceDataSource, new NullOutputStream(), 0);
}
catch (IOException exception)
{
// Doesn't throw exceptions
exception.printStackTrace();
return -1;
}
}
protected int getNewUncompressedDataLength(LodResource lodResourceDataSource) throws IOException
{
try
{
return lodResourceDataSource.getData().length;
}
catch (IOException exception)
{
// Doesn't throw exceptions
exception.printStackTrace();
return -1;
}
}
protected int getUpdatedUncompressedDataLength(LodResource lodResourceDataSource) throws IOException
{
try
{
return lodResourceDataSource.getData().length;
}
catch (IOException exception)
{
// Doesn't throw exceptions
exception.printStackTrace();
return -1;
}
}
private long writeEntry(String name, long compressedDataLength, long uncompressedDataLength, OutputStream outputStream, long entryListOffset, long entryOffset, long dataOffset) throws IOException
{
byte originalEntryHeader[] = getEntryHeader();
byte newEntryHeader[] = new byte[originalEntryHeader.length];
System.arraycopy(originalEntryHeader, 0, newEntryHeader, 0, originalEntryHeader.length);
if (null != name)
{
// update name
Arrays.fill(newEntryHeader, 0, ENTRY_NAME__ENTRY_HEADER_MAX_LENGTH, (byte)0);
byte[] entryNameBytes = name.getBytes();
System.arraycopy(entryNameBytes, 0, newEntryHeader, 0, Math.min(ENTRY_NAME__ENTRY_HEADER_MAX_LENGTH, entryNameBytes.length));
if (entryNameBytes.length < ENTRY_NAME__ENTRY_HEADER_MAX_LENGTH) newEntryHeader[entryNameBytes.length] = 0;
}
// update data offset
ByteConversions.setIntegerInByteArrayAtPosition(dataOffset, newEntryHeader, getOffsetInEntryHeaderForDataSegmentOffset());
// System.out.println(getName() + "- storing " + String.valueOf(dataOffset) + " in entry.dataoffset");
// System.out.println(getName() + "- datacontentlength: " + compressedDataLength);
// update data compressed length
ByteConversions.setIntegerInByteArrayAtPosition(compressedDataLength, newEntryHeader, (int)this.getOffsetInEntryHeaderFortDataContentCompressedLength());
// System.out.println(getName() + "- storing " + String.valueOf(compressedDataLength) + " in entry.compressedDataLength");
// System.out.println(getName() + "- datacontentlength: " + uncompressedDataLength);
// update data decompressed length
ByteConversions.setIntegerInByteArrayAtPosition(uncompressedDataLength, newEntryHeader, (int)this.getOffsetInEntryHeaderFortDataContentUncompressedLength());
// System.out.println(getName() + "- storing " + String.valueOf(uncompressedDataLength) + " in entry.uncompressedDataLength");
outputStream.write(newEntryHeader);
return dataOffset + compressedDataLength;
}
public long rewriteEntry(OutputStream outputStream, long entryListOffset, long entryOffset, long dataOffset) throws IOException
{
byte[] rawData = readRawData();
return writeEntry(null, rawData.length, getDecompressedSize(), outputStream, entryListOffset, entryOffset, dataOffset);
}
public long writeNewEntry(LodResource lodResourceDataSource, OutputStream outputStream, long entryListOffset, long entryOffset, long dataOffset) throws IOException
{
return writeEntry(this.getEntryName(), getNewCompressedDataLength(lodResourceDataSource), getNewUncompressedDataLength(lodResourceDataSource), outputStream, entryListOffset, entryOffset, dataOffset);
}
public long updateEntry(LodResource lodResourceDataSource, OutputStream outputStream, long entryListOffset, long entryOffset, long dataOffset) throws IOException
{
return writeEntry(null, getUpdatedCompressedDataLength(lodResourceDataSource), getNewUncompressedDataLength(lodResourceDataSource), outputStream, entryListOffset, entryOffset, dataOffset);
}
public long writeNewData(LodResource lodResourceDataSource, OutputStream outputStream, long dataOffset)
throws IOException
{
byte uncompressedData[] = lodResourceDataSource.getData();
// System.out.println(getName() + "- DS data size: " + uncompressedData.length);
byte compressedData[] = theLodFileExtractor.compress(uncompressedData);
int uncompressedDataLengthSpecifier;
// System.out.println(getName() + "- rawdataLength: " + compressedData.length);
outputStream.write(compressedData);
long newOffset = dataOffset + compressedData.length;
// System.out.println(getName() + " - nextoffset: " + newOffset);
return newOffset;
}
public long updateData(LodResource lodResourceDataSource, OutputStream outputStream, long dataOffset)
throws IOException
{
byte uncompressedData[] = lodResourceDataSource.getData();
// System.out.println(getName() + "- DS data size: " + uncompressedData.length);
byte compressedData[] = theLodFileExtractor.compress(uncompressedData);
// System.out.println(getName() + "- rawdataLength: " + compressedData.length);
outputStream.write(compressedData);
long newOffset = dataOffset + compressedData.length;
// System.out.println(getName() + " - nextoffset: " + newOffset);
return newOffset;
}
public long rewriteData(OutputStream outputStream, long dataOffset)
throws IOException
{
byte[] rawData = readRawData();
outputStream.write(rawData);
long newOffset = dataOffset + rawData.length;
// System.out.println(getName() + " - nextoffset: " + newOffset);
return newOffset;
}
protected long getDataHeaderOffset()
{
return 0;
}
public String getDataName()
{
return null;
}
}