|
import java.io.ByteArrayInputStream; |
|
import java.io.ByteArrayOutputStream; |
|
import java.io.DataInputStream; |
|
import java.io.File; |
|
import java.io.FileInputStream; |
|
import java.io.IOException; |
|
import java.io.UnsupportedEncodingException; |
|
import java.math.BigDecimal; |
|
import java.util.ArrayList; |
|
import java.util.List; |
|
|
|
public class VMDFile { |
|
private byte[] bin; |
|
private String header = null; |
|
private String name = null; |
|
private long size = 0l; |
|
private List<VMDFrame> frames = new ArrayList<VMDFrame>(); |
|
public VMDFile(File file) { |
|
this.bin = VMDReadUtil.convertBinary(file); |
|
if(this.bin == null) return; |
|
this.header = VMDReadUtil.parseString(bin, 0, 30, "Null"); |
|
this.name = VMDReadUtil.parseString(bin, 30, 20, "Null"); |
|
this.size = VMDReadUtil.parseLong(bin, 50, 0); |
|
for(int i = 0; i < size; i++) { |
|
VMDFrame frame = new VMDFrame(this.bin, i); |
|
if(frame.getName() != null) this.frames.add(frame); |
|
} |
|
} |
|
public byte[] getBinary() { |
|
return this.bin; |
|
} |
|
public String getHeader() { |
|
return this.header; |
|
} |
|
public String getName() { |
|
return this.name; |
|
} |
|
public long getSize() { |
|
return this.size; |
|
} |
|
public List<VMDFrame> getFrames() { |
|
return this.frames; |
|
} |
|
public String[] toStrings() { |
|
List<String> args = new ArrayList<String>(); |
|
args.add(this.header); |
|
if(this.name != null) args.add("Name: "+this.name); |
|
else args.add("Name: Null"); |
|
args.add("Size: "+this.size); |
|
for(VMDFrame frame : this.frames) { |
|
args.add(frame.toString()); |
|
} |
|
return args.toArray(new String[0]); |
|
} |
|
public static class VMDFrame { |
|
private String name = null; |
|
private long number = 0l; |
|
private float[] pos = new float[3]; |
|
private float[] ang = new float[4]; |
|
private float[] degAng = new float[4]; |
|
private byte[] ip = null; |
|
public VMDFrame(byte[] bin, int index) { |
|
int offset = 54+(index*111); |
|
this.name = VMDReadUtil.parseString(bin, offset+0, 15, null); |
|
if(this.name == null) return; |
|
this.number = VMDReadUtil.parseLong(bin, offset+15, 0); |
|
this.pos[0] = VMDReadUtil.parsePosition(bin, offset+19); |
|
this.pos[1] = VMDReadUtil.parsePosition(bin, offset+23); |
|
this.pos[2] = VMDReadUtil.parsePosition(bin, offset+27); |
|
float[][] angs = new float[4][2]; |
|
angs[0] = VMDReadUtil.parseAngle(bin, offset+31); |
|
angs[1] = VMDReadUtil.parseAngle(bin, offset+35); |
|
angs[2] = VMDReadUtil.parseAngle(bin, offset+39); |
|
angs[3] = VMDReadUtil.parseAngle(bin, offset+43); |
|
for(int i = 0; i < 4; i++) { |
|
degAng[i] = angs[i][0]; |
|
ang[i] = angs[i][1]; |
|
} |
|
this.ip = VMDReadUtil.subBytes(bin, offset+47, 64, false); |
|
} |
|
public String getName() { |
|
return this.name; |
|
} |
|
public long getNumber() { |
|
return this.number; |
|
} |
|
public float[] getPositions() { |
|
return this.pos; |
|
} |
|
public float[] getAngles() { |
|
return this.ang; |
|
} |
|
@Deprecated |
|
public byte[] getInterpolationParameter() { |
|
return this.ip; |
|
} |
|
public String toString() { |
|
StringBuilder sb = new StringBuilder(); |
|
sb.append(this.number); |
|
sb.append(": Name:"); |
|
if(this.name != null) sb.append(this.name); |
|
else sb.append("Null"); |
|
sb.append(",{Pos:["); |
|
sb.append(this.pos[0]); sb.append(','); |
|
sb.append(this.pos[1]); sb.append(','); |
|
sb.append(this.pos[2]); |
|
sb.append("],Ang:["); |
|
sb.append(this.ang[0]); sb.append(','); |
|
sb.append(this.ang[1]); sb.append(','); |
|
sb.append(this.ang[2]); sb.append(','); |
|
sb.append(this.ang[3]); sb.append("]}"); |
|
return sb.toString(); |
|
} |
|
} |
|
public static class VMDReadUtil { |
|
public static byte[] convertBinary(File file) { |
|
byte[] bin = null; |
|
FileInputStream fis = null; |
|
ByteArrayOutputStream baos = null; |
|
try { |
|
if(file.exists()) { |
|
bin = new byte[1]; |
|
fis = new FileInputStream(file); |
|
baos = new ByteArrayOutputStream(); |
|
while (fis.read(bin) > 0) { |
|
baos.write(bin); |
|
} |
|
bin = baos.toByteArray(); |
|
} |
|
} catch (IOException e){ |
|
} finally { |
|
if(baos != null) { |
|
try { |
|
baos.close(); |
|
} catch (IOException e) {} |
|
} |
|
if(fis != null) { |
|
try { |
|
fis.close(); |
|
} catch (IOException e) {} |
|
} |
|
} |
|
return bin; |
|
} |
|
public static String parseString(byte[] bin, int offset, int length, String def) { |
|
byte[] data = subBytes(bin, offset, length, true); |
|
try { |
|
if(data != null) return new String(data, "Shift-JIS"); |
|
} catch (UnsupportedEncodingException e) {} |
|
return def; |
|
} |
|
public static int parseInt(byte[] bin, int offset, int def) { |
|
byte[] data = subBytes(bin, offset, 4, false); |
|
if(data != null) { |
|
String bis = ""; |
|
for(int i = data.length; i > 0; i--) { |
|
bis += String.format("%02X", data[i-1]); |
|
} |
|
return Integer.parseInt(bis, 16); |
|
} |
|
return def; |
|
} |
|
public static long parseLong(byte[] bin, int offset, long def) { |
|
byte[] data = subBytes(bin, offset, 4, false); |
|
if(data != null) { |
|
String bis = ""; |
|
for(int i = data.length; i > 0; i--) { |
|
bis += String.format("%02X", data[i-1]); |
|
} |
|
return Long.parseLong(bis, 16); |
|
} |
|
return def; |
|
} |
|
public static float parseFloat(byte[] bin, int offset, float def) { |
|
byte[] data = subBytes(bin, offset, 4, false); |
|
if(data != null) { |
|
int len = data.length; |
|
byte[] buf = new byte[len]; |
|
for(int i = 0; i < len; i++) { |
|
buf[i] = data[len-1-i]; |
|
} |
|
DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf)); |
|
float f; |
|
try { |
|
f = in.readFloat(); |
|
} catch (IOException e) { |
|
f = def; |
|
} finally { |
|
try { |
|
in.close(); |
|
} catch (IOException e) {} |
|
} |
|
return f; |
|
} |
|
return def; |
|
} |
|
public static float parsePosition(byte[] bin, int offset) { |
|
float f = parseFloat(bin, offset, 0f); |
|
float a = new BigDecimal(f).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue(); |
|
return a; |
|
} |
|
public static float[] parseAngle(byte[] bin, int offset) { |
|
float f = parseFloat(bin, offset, 0f); |
|
double d = Math.toDegrees(f)*-2.0d; |
|
float a = new BigDecimal(d).setScale(1, BigDecimal.ROUND_HALF_UP).floatValue(); |
|
return new float[]{f, a}; |
|
} |
|
public static byte[] subBytes(byte[] bin, int offset, int length, boolean cut) { |
|
byte[] data = new byte[length]; |
|
int end = offset+length; |
|
if(bin != null && bin.length >= end) { |
|
int index = 0; |
|
for(int i = offset; i < end; i++) { |
|
byte b = bin[i]; |
|
if(cut && b == (byte)0) break; |
|
data[index] = b; |
|
index++; |
|
} |
|
byte[] ba = new byte[index]; |
|
for(int i = 0; i < index; i++) { |
|
ba[i] = data[i]; |
|
} |
|
return ba; |
|
} else { |
|
return null; |
|
} |
|
} |
|
} |
|
} |