package jp.sourceforge.mikutoga.pmd.parser;
import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.Arrays;
import jp.sourceforge.mikutoga.parser.CommonParser;
+import jp.sourceforge.mikutoga.parser.MmdEofException;
import jp.sourceforge.mikutoga.parser.MmdFormatException;
-import jp.sourceforge.mikutoga.parser.MmdSource;
+import jp.sourceforge.mikutoga.parser.TextDecoder;
/**
* PMDモデルファイルのパーサ基本部。
*/
public class PmdParserBase extends CommonParser {
+ /**
+ * PMDで用いられる文字エンコーディング(windows-31j)。
+ * ほぼShift_JISのスーパーセットと思ってよい。
+ * デコード結果はUCS-2集合に収まるはず。
+ */
+ public static final Charset CS_WIN31J = Charset.forName("windows-31j");
+
/** 改行文字列 CR。 */
protected static final String CR = "\r"; // 0x0d
/** 改行文字列 LF。 */
}
+ private final TextDecoder decoderWin31j = new TextDecoder(CS_WIN31J);
+
private PmdBasicHandler basicHandler = null;
private PmdShapeHandler shapeHandler = null;
private PmdMaterialHandler materialHandler = null;
* コンストラクタ。
* @param source 入力ソース
*/
- public PmdParserBase(MmdSource source){
+ public PmdParserBase(InputStream source){
super(source);
+ this.decoderWin31j.setZeroChopMode(true);
return;
}
}
/**
+ * 指定されたバイト長に収まるゼロ終端(0x00)文字列を読み込む。
+ * 入力バイト列はwindows-31jエンコーディングとして解釈される。
+ * ゼロ終端以降のデータは無視されるが、
+ * IO入力は指定バイト数だけ読み進められる。
+ * ゼロ終端が見つからないまま指定バイト数が読み込み終わった場合、
+ * そこまでのデータから文字列を構成する。
+ * @param byteLen 読み込みバイト数
+ * @return デコードされた文字列
+ * @throws IOException IOエラー
+ * @throws MmdEofException 読み込む途中でストリーム終端に達した。
+ * @throws MmdFormatException 不正な文字エンコーディングが検出された。
+ */
+ protected String parsePmdText(int byteLen)
+ throws IOException,
+ MmdEofException,
+ MmdFormatException {
+ String result = parseString(this.decoderWin31j, byteLen);
+ return result;
+ }
+
+ /**
* PMDファイルのパースを開始する。
* @throws IOException IOエラー
* @throws MmdFormatException フォーマットエラー
byte[] header = new byte[HEADER_LENGTH];
parseByteArray(header);
- for(int idx = 0; idx < MAGIC_BYTES.length; idx++){
- if(header[idx] != MAGIC_BYTES[idx]){
- throw new MmdFormatException("unknown PMD-header type");
- }
+ if( ! Arrays.equals(header, MAGIC_BYTES) ){
+ throw new MmdFormatException("unknown PMD-header type");
}
String modelName =
- parseZeroTermWin31J(PmdLimits.MAXBYTES_MODELNAME);
+ parsePmdText(PmdLimits.MAXBYTES_MODELNAME);
String description =
- parseZeroTermWin31J(PmdLimits.MAXBYTES_MODELDESC);
+ parsePmdText(PmdLimits.MAXBYTES_MODELDESC);
description = description.replace(CRLF, LF);
if(this.basicHandler != null){
* @throws MmdFormatException フォーマットエラー
*/
private void parseVertexList() throws IOException, MmdFormatException{
- int vertexNum = parseInteger();
+ int vertexNum = parseLeInt();
if(this.shapeHandler == null){
skip(VERTEX_DATA_SZ * vertexNum);
this.shapeHandler.loopStart(PmdShapeHandler.VERTEX_LIST, vertexNum);
for(int ct = 0; ct < vertexNum; ct++){
- float xPos = parseFloat();
- float yPos = parseFloat();
- float zPos = parseFloat();
+ float xPos = parseLeFloat();
+ float yPos = parseLeFloat();
+ float zPos = parseLeFloat();
this.shapeHandler.pmdVertexPosition(xPos, yPos, zPos);
- float xVec = parseFloat();
- float yVec = parseFloat();
- float zVec = parseFloat();
+ float xVec = parseLeFloat();
+ float yVec = parseLeFloat();
+ float zVec = parseLeFloat();
this.shapeHandler.pmdVertexNormal(xVec, yVec, zVec);
- float uVal = parseFloat();
- float vVal = parseFloat();
+ float uVal = parseLeFloat();
+ float vVal = parseLeFloat();
this.shapeHandler.pmdVertexUV(uVal, vVal);
- int boneId1 = parseUShortAsInteger();
- int boneId2 = parseUShortAsInteger();
- int weightForB1 = parseUByteAsInteger();
+ int boneId1 = parseLeUShortAsInt();
+ int boneId2 = parseLeUShortAsInt();
+ int weightForB1 = parseUByteAsInt();
this.shapeHandler.pmdVertexWeight(boneId1, boneId2, weightForB1);
boolean hideEdge = parseBoolean();
* @throws MmdFormatException フォーマットエラー
*/
private void parseSurfaceList() throws IOException, MmdFormatException{
- int vertexNum = parseInteger();
+ int vertexNum = parseLeInt();
if(vertexNum % 3 != 0) throw new MmdFormatException();
int surfaceNum = vertexNum / 3;
this.shapeHandler.loopStart(PmdShapeHandler.SURFACE_LIST, surfaceNum);
for(int ct = 0; ct < surfaceNum; ct++){
- int vertexId1 = parseUShortAsInteger();
- int vertexId2 = parseUShortAsInteger();
- int vertexId3 = parseUShortAsInteger();
+ int vertexId1 = parseLeUShortAsInt();
+ int vertexId2 = parseLeUShortAsInt();
+ int vertexId3 = parseLeUShortAsInt();
this.shapeHandler.pmdSurfaceTriangle(vertexId1,
vertexId2,
vertexId3 );
* @throws MmdFormatException フォーマットエラー
*/
private void parseMaterialList() throws IOException, MmdFormatException{
- int materialNum = parseInteger();
+ int materialNum = parseLeInt();
if(this.materialHandler == null){
skip(MATERIAL_DATA_SZ * materialNum);
float green;
float blue;
- red = parseFloat();
- green = parseFloat();
- blue = parseFloat();
- float alpha = parseFloat();
+ red = parseLeFloat();
+ green = parseLeFloat();
+ blue = parseLeFloat();
+ float alpha = parseLeFloat();
this.materialHandler.pmdMaterialDiffuse(red, green, blue, alpha);
- float shininess = parseFloat();
- red = parseFloat();
- green = parseFloat();
- blue = parseFloat();
+ float shininess = parseLeFloat();
+ red = parseLeFloat();
+ green = parseLeFloat();
+ blue = parseLeFloat();
this.materialHandler.pmdMaterialSpecular(red, green, blue,
shininess);
- red = parseFloat();
- green = parseFloat();
- blue = parseFloat();
+ red = parseLeFloat();
+ green = parseLeFloat();
+ blue = parseLeFloat();
this.materialHandler.pmdMaterialAmbient(red, green, blue);
- int toonidx = parseUByteAsInteger();
+ int toonidx = parseUByteAsInt();
boolean hasEdge = parseBoolean();
- int surfaceCount = parseInteger();
+ int surfaceCount = parseLeInt();
String shadingFile =
- parseZeroTermWin31J(PmdLimits.MAXBYTES_TEXTUREFILENAME);
+ parsePmdText(PmdLimits.MAXBYTES_TEXTUREFILENAME);
String[] splitted = splitShadingFileInfo(shadingFile);
String textureFile = splitted[0];
String sphereFile = splitted[1];
* @throws MmdFormatException フォーマットエラー
*/
private void parseBoneList() throws IOException, MmdFormatException{
- this.boneCount = parseUShortAsInteger();
+ this.boneCount = parseLeUShortAsInt();
if(this.boneHandler == null){
skip(BONE_DATA_SZ * this.boneCount);
for(int ct = 0; ct < this.boneCount; ct++){
String boneName =
- parseZeroTermWin31J(PmdLimits.MAXBYTES_BONENAME);
- int parentId = parseUShortAsInteger();
- int tailId = parseUShortAsInteger();
+ parsePmdText(PmdLimits.MAXBYTES_BONENAME);
+ int parentId = parseLeUShortAsInt();
+ int tailId = parseLeUShortAsInt();
byte boneKind = parseByte();
- int ikId = parseUShortAsInteger();
+ int srcId = parseLeUShortAsInt();
this.boneHandler.pmdBoneInfo(boneName, boneKind);
- this.boneHandler.pmdBoneLink(parentId, tailId, ikId);
+ this.boneHandler.pmdBoneLink(parentId, tailId, srcId);
- float xPos = parseFloat();
- float yPos = parseFloat();
- float zPos = parseFloat();
+ float xPos = parseLeFloat();
+ float yPos = parseLeFloat();
+ float zPos = parseLeFloat();
this.boneHandler.pmdBonePosition(xPos, yPos, zPos);
* @throws MmdFormatException フォーマットエラー
*/
private void parseIKList() throws IOException, MmdFormatException{
- int ikCount = parseUShortAsInteger();
+ int ikCount = parseLeUShortAsInt();
if(this.boneHandler != null){
this.boneHandler.loopStart(PmdBoneHandler.IK_LIST, ikCount);
}
for(int ct = 0; ct < ikCount; ct++){
- int boneId = parseUShortAsInteger();
- int targetId = parseUShortAsInteger();
- int chainLength = parseUByteAsInteger();
- int depth = parseUShortAsInteger();
- float weight = parseFloat();
+ int boneId = parseLeUShortAsInt();
+ int targetId = parseLeUShortAsInt();
+ int chainLength = parseUByteAsInt();
+ int depth = parseLeUShortAsInt();
+ float weight = parseLeFloat();
parseIKChainList(chainLength);
}
for(int ct = 0; ct < chainLength; ct++){
- int childId = parseUShortAsInteger();
+ int childId = parseLeUShortAsInt();
if(this.boneHandler != null){
this.boneHandler.pmdIKChainInfo(childId);
this.boneHandler.loopNext(PmdBoneHandler.IKCHAIN_LIST);
* @throws MmdFormatException フォーマットエラー
*/
private void parseMorphList() throws IOException, MmdFormatException{
- this.morphCount = parseUShortAsInteger();
+ this.morphCount = parseLeUShortAsInt();
if(this.morphHandler != null){
this.morphHandler.loopStart(PmdMorphHandler.MORPH_LIST,
for(int ct = 0; ct < this.morphCount; ct++){
String morphName =
- parseZeroTermWin31J(PmdLimits.MAXBYTES_MORPHNAME);
- int vertexCount = parseInteger();
+ parsePmdText(PmdLimits.MAXBYTES_MORPHNAME);
+ int vertexCount = parseLeInt();
byte morphType = parseByte();
if(this.morphHandler != null){
vertexCount );
for(int ct = 0; ct < vertexCount; ct++){
- int vertexId = parseInteger();
- float xPos = parseFloat();
- float yPos = parseFloat();
- float zPos = parseFloat();
+ int vertexId = parseLeInt();
+ float xPos = parseLeFloat();
+ float yPos = parseLeFloat();
+ float zPos = parseLeFloat();
this.morphHandler.pmdMorphVertexInfo(vertexId, xPos, yPos, zPos);
this.morphHandler.loopNext(PmdMorphHandler.MORPHVERTEX_LIST);
}
*/
private void parseMorphOrderList()
throws IOException, MmdFormatException{
- int morphOrderCount = parseUByteAsInteger();
+ int morphOrderCount = parseUByteAsInt();
if(this.morphHandler == null){
skip(MORPHORDER_DATA_SZ * morphOrderCount);
morphOrderCount );
for(int ct = 0; ct < morphOrderCount; ct++){
- int morphId = parseUShortAsInteger();
+ int morphId = parseLeUShortAsInt();
this.morphHandler.pmdMorphOrderInfo(morphId);
this.morphHandler.loopNext(PmdMorphHandler.MORPHORDER_LIST);
*/
private void parseBoneGroupList()
throws IOException, MmdFormatException{
- this.boneGroupCount = parseUByteAsInteger();
+ this.boneGroupCount = parseUByteAsInt();
if(this.boneHandler == null){
skip(BONEGROUP_DATA_SZ * this.boneGroupCount);
for(int ct = 0; ct < this.boneGroupCount; ct++){
String groupName =
- parseZeroTermWin31J(PmdLimits.MAXBYTES_BONEGROUPNAME);
+ parsePmdText(PmdLimits.MAXBYTES_BONEGROUPNAME);
groupName = chopLastLF(groupName);
this.boneHandler.pmdBoneGroupInfo(groupName);
*/
private void parseGroupedBoneList()
throws IOException, MmdFormatException{
- int groupedBoneCount = parseInteger();
+ int groupedBoneCount = parseLeInt();
if(this.boneHandler == null){
skip(GROUPEDBONE_DATA_SZ * groupedBoneCount);
groupedBoneCount);
for(int ct = 0; ct < groupedBoneCount; ct++){
- int boneId = parseUShortAsInteger();
- int groupId = parseUByteAsInteger();
+ int boneId = parseLeUShortAsInt();
+ int groupId = parseUByteAsInt();
this.boneHandler.pmdGroupedBoneInfo(boneId, groupId);
this.boneHandler.loopNext(PmdBoneHandler.GROUPEDBONE_LIST);