OSDN Git Service

2.102.2版リリース準備
[mikutoga/TogaGem.git] / src / main / java / jp / sourceforge / mikutoga / pmd / parser / PmdParserBase.java
index 1bf7f97..a0eb060 100644 (file)
@@ -8,16 +8,25 @@
 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 {
 
-    public static final int HEADER_LENGTH = 7;
+    /**
+     * 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
@@ -26,6 +35,8 @@ public class PmdParserBase extends CommonParser {
     /** 改行文字列 CRLF。 */
     protected static final String CRLF = CR + LF;  // 0x0d, 0x0a
 
+    private static final int HEADER_LENGTH = 7;
+
     private static final byte[] MAGIC_BYTES = {
         (byte)0x50, (byte)0x6d, (byte)0x64,               // "Pmd"
         (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x3f,   // 1.0f
@@ -46,6 +57,8 @@ public class PmdParserBase extends CommonParser {
     }
 
 
+    private final TextDecoder decoderWin31j  = new TextDecoder(CS_WIN31J);
+
     private PmdBasicHandler basicHandler = null;
     private PmdShapeHandler shapeHandler = null;
     private PmdMaterialHandler materialHandler = null;
@@ -61,8 +74,9 @@ public class PmdParserBase extends CommonParser {
      * コンストラクタ。
      * @param source 入力ソース
      */
-    public PmdParserBase(MmdSource source){
+    public PmdParserBase(InputStream source){
         super(source);
+        this.decoderWin31j.setZeroChopMode(true);
         return;
     }
 
@@ -183,6 +197,27 @@ public class PmdParserBase extends CommonParser {
     }
 
     /**
+     * 指定されたバイト長に収まるゼロ終端(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 フォーマットエラー
@@ -234,16 +269,14 @@ public class PmdParserBase extends CommonParser {
         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){
@@ -260,7 +293,7 @@ public class PmdParserBase extends CommonParser {
      * @throws MmdFormatException フォーマットエラー
      */
     private void parseVertexList() throws IOException, MmdFormatException{
-        int vertexNum = parseInteger();
+        int vertexNum = parseLeInt();
 
         if(this.shapeHandler == null){
             skip(VERTEX_DATA_SZ * vertexNum);
@@ -270,23 +303,23 @@ public class PmdParserBase extends CommonParser {
         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();
@@ -306,7 +339,7 @@ public class PmdParserBase extends CommonParser {
      * @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;
 
@@ -318,9 +351,9 @@ public class PmdParserBase extends CommonParser {
         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 );
@@ -338,7 +371,7 @@ public class PmdParserBase extends CommonParser {
      * @throws MmdFormatException フォーマットエラー
      */
     private void parseMaterialList() throws IOException, MmdFormatException{
-        int materialNum = parseInteger();
+        int materialNum = parseLeInt();
 
         if(this.materialHandler == null){
             skip(MATERIAL_DATA_SZ * materialNum);
@@ -353,29 +386,29 @@ public class PmdParserBase extends CommonParser {
             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];
@@ -398,7 +431,7 @@ public class PmdParserBase extends CommonParser {
      * @throws MmdFormatException フォーマットエラー
      */
     private void parseBoneList() throws IOException, MmdFormatException{
-        this.boneCount = parseUShortAsInteger();
+        this.boneCount = parseLeUShortAsInt();
 
         if(this.boneHandler == null){
             skip(BONE_DATA_SZ * this.boneCount);
@@ -409,18 +442,18 @@ public class PmdParserBase extends CommonParser {
 
         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);
 
@@ -438,18 +471,18 @@ public class PmdParserBase extends CommonParser {
      * @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);
 
@@ -480,7 +513,7 @@ public class PmdParserBase extends CommonParser {
         }
 
         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);
@@ -500,7 +533,7 @@ public class PmdParserBase extends CommonParser {
      * @throws MmdFormatException フォーマットエラー
      */
     private void parseMorphList() throws IOException, MmdFormatException{
-        this.morphCount = parseUShortAsInteger();
+        this.morphCount = parseLeUShortAsInt();
 
         if(this.morphHandler != null){
             this.morphHandler.loopStart(PmdMorphHandler.MORPH_LIST,
@@ -509,8 +542,8 @@ public class PmdParserBase extends CommonParser {
 
         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){
@@ -548,10 +581,10 @@ public class PmdParserBase extends CommonParser {
                                     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);
         }
@@ -568,7 +601,7 @@ public class PmdParserBase extends CommonParser {
      */
     private void parseMorphOrderList()
             throws IOException, MmdFormatException{
-        int morphOrderCount = parseUByteAsInteger();
+        int morphOrderCount = parseUByteAsInt();
 
         if(this.morphHandler == null){
             skip(MORPHORDER_DATA_SZ * morphOrderCount);
@@ -579,7 +612,7 @@ public class PmdParserBase extends CommonParser {
                                     morphOrderCount );
 
         for(int ct = 0; ct < morphOrderCount; ct++){
-            int morphId = parseUShortAsInteger();
+            int morphId = parseLeUShortAsInt();
             this.morphHandler.pmdMorphOrderInfo(morphId);
 
             this.morphHandler.loopNext(PmdMorphHandler.MORPHORDER_LIST);
@@ -597,7 +630,7 @@ public class PmdParserBase extends CommonParser {
      */
     private void parseBoneGroupList()
             throws IOException, MmdFormatException{
-        this.boneGroupCount = parseUByteAsInteger();
+        this.boneGroupCount = parseUByteAsInt();
 
         if(this.boneHandler == null){
             skip(BONEGROUP_DATA_SZ * this.boneGroupCount);
@@ -609,7 +642,7 @@ public class PmdParserBase extends CommonParser {
 
         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);
 
@@ -628,7 +661,7 @@ public class PmdParserBase extends CommonParser {
      */
     private void parseGroupedBoneList()
             throws IOException, MmdFormatException{
-        int groupedBoneCount = parseInteger();
+        int groupedBoneCount = parseLeInt();
 
         if(this.boneHandler == null){
             skip(GROUPEDBONE_DATA_SZ * groupedBoneCount);
@@ -639,8 +672,8 @@ public class PmdParserBase extends CommonParser {
                                    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);