/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.open2jam.parsers;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.logging.Level;
import org.open2jam.parsers.utils.*;
/**
* This class let us parse a SNP file
*
* @author CdK
*/
public class SNPParser {
/** the signature, "VDISK1.0" in little endian */
private static final long SNP_SIGNATURE = 0x302E314B53494456L;
private static final int VDISK_HEADER = 24;
private static final int FILE_HEADER = 145;
public static class SNPFileHeader implements java.io.Serializable{
final byte isDir;
final String file_name;
final int size_original;
final int size_packed;
final long file_offset;
public SNPFileHeader(byte isDir, String name, int size_original, int size_packed, long file_offset) {
this.isDir = isDir;
this.file_name = name;
this.size_original = size_original;
this.size_packed = size_packed;
this.file_offset = file_offset;
}
public static SNPFileHeader readHeader(ByteBuffer buffer, long file_offset){
byte is_dir = buffer.get();
byte name[] = new byte[128];
buffer.get(name);
String fname = ByteHelper.toString(name).trim();
int sizeo = buffer.getInt();
int sizep = buffer.getInt();
return new SNPFileHeader(is_dir, fname, sizeo, sizep, file_offset);
}
}
public static boolean canRead(File file)
{
return file.getName().toLowerCase().endsWith(".snp");
}
public static ChartList parseFile(File file)
{
ByteBuffer buffer;
RandomAccessFile f;
HashMap<String, SNPFileHeader> file_index = new HashMap<String, SNPFileHeader>();
try{
f = new RandomAccessFile(file.getAbsolutePath(),"r");
buffer = f.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, VDISK_HEADER); //header 24
}catch(IOException e){
Logger.global.log(Level.WARNING, "IO exception on reading SNP file {0}", file.getName());
return null;
}
buffer.order(ByteOrder.LITTLE_ENDIAN);
if(buffer.getLong() != SNP_SIGNATURE)
{
Logger.global.log(Level.WARNING, "This isn't a snp file you! {0}", file.getName());
return null;
}
ChartList list = new ChartList();
try {
long pointer = VDISK_HEADER;
while(pointer < f.length())
{
buffer = f.getChannel().map(FileChannel.MapMode.READ_ONLY, pointer, FILE_HEADER);
buffer.order(ByteOrder.LITTLE_ENDIAN);
SNPFileHeader fh = SNPFileHeader.readHeader(buffer, pointer);
pointer += FILE_HEADER+fh.size_packed; //header + packed bits
if(fh.isDir < 1) //DO NOT WANT DIRS D:
file_index.put(fh.file_name, fh); //add the file
if(fh.size_packed > 0 && fh.file_name.trim().endsWith(".xnt"))
{
XNTChart chart = new XNTChart();
ArrayList<XNTChart> charts = KrazyRainDB.getInstance().getCharts(file.getName().toUpperCase());
if(charts != null) {
for(XNTChart c : charts)
{
if(c.getXNTFile().toUpperCase().equals(fh.file_name.trim().toUpperCase()))
chart = c;
}
}
else {
//so, the charts wheren't in the xml file D: Let's make a gracefully fallback xD
chart.title = file.getName().toUpperCase();
chart.artist = "KrazyRain";
chart.genre = "Unknown";
chart.level = 1;
chart.xnt_filename = fh.file_name.trim();
chart.xne_filename = fh.file_name.trim().substring(0, fh.file_name.trim().lastIndexOf("."))+".xne";
}
//Something weird happened and any of this files aren't in the chart so continue
if(chart.getXNEFile().isEmpty() || chart.getXNTFile().isEmpty()) {
Logger.global.log(Level.WARNING, "Something weird happened with this chart. XNT: {0}", fh.file_name);
continue;
}
list.add(chart);
}
}
} catch (IOException ex) {
Logger.global.log(Level.WARNING, "Fuck :_ {0}", file.getName());
return null;
}
//let's add the offsets of the files and forget about redo it later
for(int i = 0; i< list.size(); i++)
{
XNTChart chart = (XNTChart)list.get(i);
chart.file_index = file_index;
chart.source = file;
}
try {
f.close();
} catch (IOException ex) {
Logger.global.log(Level.WARNING, "Error closing the file (lol?) {0}", ex);
}
Collections.sort(list);
return list;
}
public static ByteBuffer extract(SNPFileHeader fh, RandomAccessFile f) throws IOException
{
ByteBuffer b =
f.getChannel().map(FileChannel.MapMode.READ_ONLY, fh.file_offset+FILE_HEADER, fh.size_packed);
b.order(ByteOrder.LITTLE_ENDIAN);
return Compressor.decompress(b);
}
public static HashMap<Integer, SampleData> getSamples(XNTChart chart)
{
HashMap<Integer, SampleData> samples = new HashMap<Integer, SampleData>();
ByteBuffer buffer;
RandomAccessFile f;
SNPFileHeader fh;
try{
f = new RandomAccessFile(chart.source.getAbsolutePath(),"r");
for(Entry<Integer, String> entry : chart.sample_index.entrySet())
{
int id = entry.getKey();
String fname = entry.getValue();
if(!chart.file_index.containsKey(fname))
{
Logger.global.log(Level.WARNING, "I can\'t find the file [{0}] in the snp :/", fname);
continue;
}
fh = chart.file_index.get(fname);
buffer = SNPParser.extract(fh, f);
buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
SampleData data = new SampleData(new ByteBufferInputStream(buffer), SampleData.Type.OGG, fname);
buffer.clear();
samples.put(id, data);
}
}catch(IOException e){
Logger.global.log(Level.WARNING, "IO exception on reading SNP file {0}", chart.source.getName());
return null;
}
return samples;
}
}