OSDN Git Service

TogaGem1.103.2版より移行。
authorOlyutorskii <olyutorskii@users.osdn.me>
Wed, 6 Oct 2010 12:17:37 +0000 (21:17 +0900)
committerOlyutorskii <olyutorskii@users.osdn.me>
Wed, 6 Oct 2010 12:17:37 +0000 (21:17 +0900)
34 files changed:
CHANGELOG.txt [new file with mode: 0644]
LICENSE.txt [new file with mode: 0644]
README.txt [new file with mode: 0644]
build.xml [new file with mode: 0644]
pom.xml [new file with mode: 0644]
src/main/assembly/descriptor.xml [new file with mode: 0644]
src/main/config/checks.xml [new file with mode: 0644]
src/main/config/pmdrules.xml [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/CommonParser.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/LoopHandler.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/MmdEofException.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/MmdFormatException.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/MmdSource.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/ParseStage.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/package-info.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdBasicHandler.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdBoneHandler.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdEngHandler.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdJointHandler.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdLimits.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdMaterialHandler.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdMorphHandler.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParser.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserBase.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserExt1.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserExt2.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserExt3.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdRigidHandler.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdShapeHandler.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdToonHandler.java [new file with mode: 0644]
src/main/java/jp/sourceforge/mikutoga/parser/pmd/package-info.java [new file with mode: 0644]
src/test/java/jp/sourceforge/mikutoga/parser/ParseStageTest.java [new file with mode: 0644]
src/test/java/sample/pmd/DummyHandler.java [new file with mode: 0644]
src/test/java/sample/pmd/DummyMain.java [new file with mode: 0644]

diff --git a/CHANGELOG.txt b/CHANGELOG.txt
new file mode 100644 (file)
index 0000000..d90cb85
--- /dev/null
@@ -0,0 +1,11 @@
+[UTF-8 Japanese]\r
+\r
+\r
+TogaGem 変更履歴\r
+\r
+\r
+1.104-SNAPSHOT (2010-10-06)\r
+    ・TogaParser1.103.2版を吸収する形で開発をスタート。\r
+\r
+\r
+--- EOF ---\r
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644 (file)
index 0000000..225e3e3
--- /dev/null
@@ -0,0 +1,34 @@
+[UTF-8 English & Japanese]\r
+\r
+The MIT License\r
+\r
+\r
+Copyright(c) 2010 olyutorskii\r
+\r
+\r
+Permission is hereby granted, free of charge, to any person obtaining a copy\r
+of this software and associated documentation files (the "Software"), to deal\r
+in the Software without restriction, including without limitation the rights\r
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
+copies of the Software, and to permit persons to whom the Software is\r
+furnished to do so, subject to the following conditions:\r
+\r
+The above copyright notice and this permission notice shall be included in\r
+all copies or substantial portions of the Software.\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
+THE SOFTWARE.\r
+\r
+\r
+TogaGemオリジナル制作者自身からのコメント:\r
+\r
+  ※ 少なくともこのソフトウェアの実行、複製、配布、改造は自由です。\r
+  ※ 少なくともこのソフトウェアは無保証です。\r
+\r
+\r
+--- EOF ---\r
diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..1672527
--- /dev/null
@@ -0,0 +1,96 @@
+[UTF-8 Japanese]\r
+\r
+                              T o g a G e m\r
+                                  Readme\r
+\r
+                                              Copyright(c) 2010 olyutorskii\r
+\r
+\r
+=== TogaGemとは ===\r
+\r
+TogaGemは、3D動画制作ツール、MikuMikuDance(MMD)で用いられる\r
+各種データファイルを読み書きするためのJavaライブラリです。\r
+TogaGemは、MikuTogaプロジェクトの派生ライブラリとして、\r
+TogaParserライブラリの1.103.2版を引き継ぐ形で誕生しました。\r
+\r
+MikuTogaプロジェクトは、MMDによる3Dアニメーション制作を支援するプログラムの\r
+整備のために発足した、オープンソースプロジェクトです。\r
+\r
+現時点では、PMDモデルファイル(*.pmd)の読み書きが可能です。\r
+\r
+※ MMD開発者の樋口M氏は、MikuTogaの開発活動に一切関与していません。\r
+  TogaGemに関する問い合わせをを樋口M氏へ投げかけないように!約束だよ!\r
+\r
+\r
+=== 実行環境 ===\r
+\r
+ - TogaGemはJava言語(JLS3)で記述されたプログラムです。\r
+ - TogaGemはJRE1.6に準拠したJava実行環境で利用できるように作られています。\r
+   原則として、JRE1.6に準拠した実行系であれば、プラットフォームを選びません。\r
+\r
+\r
+=== アーカイブ管理体制 ===\r
+\r
+  このアーカイブは、UTF-8による開発環境を前提として構成されています。\r
+  このアーカイブの原本となる開発資産は、\r
+      http://hg.sourceforge.jp/view/mikutoga/TogaGem\r
+  を上位に持つMercurialリポジトリで管理されています。\r
+  アーカイブの代わりにMercurialを通じての開発資産へのアクセスが可能です。\r
+  # hg clone http://hg.sourceforge.jp/view/mikutoga/TogaGem\r
+\r
+\r
+=== 開発プロジェクト運営元 ===\r
+\r
+  http://sourceforge.jp/projects/mikutoga/ まで。\r
+\r
+\r
+=== ディレクトリ内訳構成 ===\r
+\r
+基本的にはMaven2のmaven-archetype-quickstart構成に準じます。\r
+\r
+./README.txt\r
+    あなたが今見てるこれ。\r
+\r
+./CHANGELOG.txt\r
+    変更履歴。\r
+\r
+./LICENSE.txt\r
+    ライセンスに関して。\r
+\r
+./pom.xml\r
+    Maven2用プロジェクト構成定義ファイル。\r
+\r
+./src/main/java/\r
+    Javaのソースコード。\r
+\r
+./src/test/java/\r
+    JUnit 4.* 用のユニットテストコード。\r
+\r
+./src/test/java/sample/\r
+    パーサ利用のサンプルプログラム。\r
+\r
+./src/main/config/\r
+    各種ビルド・構成管理に必要なファイル群。\r
+\r
+./src/main/config/checks.xml\r
+    Checkstyle用configファイル。\r
+\r
+./src/main/config/pmdrules.xml\r
+    PMD用ルール定義ファイル。\r
+\r
+\r
+=== 謝辞 ===\r
+\r
+このライブラリを制作するにあたって、以下の情報を参考にしました。\r
+\r
+\r
+通りすがりの記憶 (T.Tetosuki氏ブログ)\r
+「MMD のモデルデータ(PMD)形式 めも (まとめ)」\r
+http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4\r
+\r
+\r
+PMDエディタver0.0.6.3(極北P氏制作)\r
+同梱readme.txt\r
+\r
+\r
+--- EOF ---\r
diff --git a/build.xml b/build.xml
new file mode 100644 (file)
index 0000000..233a6e0
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ====================================================================== -->
+<!-- Ant build file (http://ant.apache.org/) for Ant 1.6.2 or above.        -->
+<!-- ====================================================================== -->
+
+<project name="togagem" default="package" basedir=".">
+
+<!-- ====================================================================== -->
+<!-- Import maven-build.xml into the current project                        -->
+<!-- Maven2 command "mvn ant:ant" will put maven-build.xml                  -->
+<!-- ====================================================================== -->
+
+    <import optional="true" file="maven-build.xml"/>
+
+<!-- ====================================================================== -->
+<!-- Help target                                                            -->
+<!-- ====================================================================== -->
+
+    <target name="help">
+        <echo message="Please run: $ant -projecthelp"/>
+    </target>
+
+<!-- ====================================================================== -->
+<!-- sanitize files for native environment                                  -->
+<!-- ====================================================================== -->
+
+    <target description="sanitize files" name="sanitize" >
+        <echo message="sanitize files..." />
+
+        <fixcrlf
+            srcDir="./src/" includes="**/*.java"
+            encoding="UTF-8" outputencoding="UTF-8"
+            tablength="4" tab="remove" javafiles="true"
+            eof="remove"
+        />
+
+        <fixcrlf
+            srcDir="./src/" includes="**/*.xml,**/*.xsd"
+            encoding="UTF-8" outputencoding="UTF-8"
+            tablength="8" tab="remove"
+            eol="lf"
+            eof="remove"
+        />
+
+        <fixcrlf
+            srcDir="./src/" includes="**/*.properties"
+            encoding="ISO-8859-1" outputencoding="ISO-8859-1"
+            eol="lf"
+            eof="remove"
+        />
+
+        <fixcrlf
+            srcDir="." includes="*.txt"
+            encoding="UTF-8" outputencoding="UTF-8"
+            tablength="8" tab="remove"
+            eof="remove"
+        />
+
+        <chmod type="file" perm="a-x">
+            <fileset dir="." includes="**/*" excludes="**/*.sh" />
+        </chmod>
+
+    </target>
+
+</project>
+
+<!-- EOF -->
diff --git a/pom.xml b/pom.xml
new file mode 100644 (file)
index 0000000..943fe0d
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    TogaGemライブラリ
+    Maven2用プロジェクト構成定義ファイル
+-->
+
+<project
+  xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+  http://maven.apache.org/maven-v4_0_0.xsd"
+>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>jp.sourceforge.mikutoga</groupId>
+    <artifactId>togagem</artifactId>
+
+    <version>1.104-SNAPSHOT</version>
+
+    <packaging>jar</packaging>
+    <name>TogaGem</name>
+
+    <description><!--
+-->TogaGem is a file reader/writer library for MikuMikuDance(MMD) with Java. <!--
+-->TogaGem is a sub-project of MikuToga project. <!--
+--></description>
+
+    <url>http://sourceforge.jp/projects/mikutoga/</url>
+    <inceptionYear>2010</inceptionYear>
+
+    <organization>
+        <name>MikuToga Partners</name>
+        <url>http://sourceforge.jp/projects/mikutoga/</url>
+    </organization>
+
+    <licenses>
+        <license>
+            <name>The MIT License</name>
+            <url>http://www.opensource.org/licenses/mit-license.php</url>
+            <distribution>manual</distribution>
+        </license>
+    </licenses>
+
+    <developers>
+        <developer>
+            <id>olyutorskii</id>
+            <url>http://sites.google.com/site/olyutorskiipit/</url>
+            <organization>MikuToga Partners</organization>
+            <organizationUrl>http://sourceforge.jp/projects/mikutoga/devel/</organizationUrl>
+            <roles>
+                <role>Project Founder</role>
+                <role>Java Developer</role>
+            </roles>
+        </developer>
+    </developers>
+
+    <contributors/>
+    <mailingLists/>
+
+    <prerequisites>
+        <maven>2.1</maven>
+    </prerequisites>
+
+    <modules/>
+
+    <scm>
+        <connection>scm:hg:http://hg.sourceforge.jp/view/mikutoga/TogaGem</connection>
+        <developerConnection>scm:hg:ssh://hg.sourceforge.jp//hgroot/mikutoga/TogaGem</developerConnection>
+        <url>http://hg.sourceforge.jp/view/mikutoga/TogaGem</url>
+    </scm>
+
+    <issueManagement>
+        <system>SourceForge.JP</system>
+        <url>http://sourceforge.jp/projects/mikutoga/ticket/</url>
+    </issueManagement>
+
+    <ciManagement/>
+    <distributionManagement/>
+
+    <properties>
+        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
+
+        <maven.compiler.source>1.6</maven.compiler.source>
+        <maven.compiler.target>1.6</maven.compiler.target>
+
+        <maven.compiler.showDeprecation>true</maven.compiler.showDeprecation>
+        <maven.compiler.showWarnings>true</maven.compiler.showWarnings>
+
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+
+        <project.myrepoconf>${project.basedir}/src/main/config</project.myrepoconf>
+    </properties>
+
+    <dependencyManagement/>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>[4,)</version>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <repositories/>
+    <pluginRepositories/>
+
+    <build>
+        <pluginManagement/>
+
+        <plugins>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.6</source>  <!-- for NetBeans IDE -->
+                    <target>1.6</target>
+                    <showDeprecation>true</showDeprecation>
+                    <showWarnings>true</showWarnings>
+                    <compilerArguments>
+                        <Xlint/>
+                    </compilerArguments>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-clean-plugin</artifactId>
+                <configuration>
+                    <filesets>
+                        <fileset>
+                            <directory>${project.basedir}</directory>
+                            <includes>
+                                <include>**/.DS_Store</include>
+                                <include>**/Thumbs.db</include>
+                                <include>**/core</include>
+                            </includes>
+                        </fileset>
+                    </filesets>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifestEntries>
+                            <Built-By>${project.organization.name}</Built-By>
+                        </manifestEntries>
+                    </archive>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <descriptors>
+                        <descriptor>src/main/assembly/descriptor.xml</descriptor>
+                    </descriptors>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <configuration>
+                    <rules>
+                        <requireMavenVersion>
+                            <version>[2.1,3)</version>
+                        </requireMavenVersion>
+                        <requireJavaVersion>
+                            <version>[1.6,)</version>
+                        </requireJavaVersion>
+                    </rules>
+                </configuration>
+            </plugin>
+
+        </plugins>
+
+        <resources>
+
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/version.properties</include>
+                </includes>
+            </resource>
+
+        </resources>
+
+    </build>
+
+    <reporting>
+        <plugins>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.7</version>
+                <configuration>
+                    <show>protected</show>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <artifactId>maven-site-plugin</artifactId>
+                <version>2.1.1</version>
+                <configuration>
+                    <locales>ja</locales>
+                    <inputEncoding>${project.build.sourceEncoding}</inputEncoding>
+                    <outputEncoding>${project.reporting.outputEncoding}</outputEncoding>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-checkstyle-plugin</artifactId>
+                <version>2.5</version>
+                <configuration>
+                    <configLocation>${project.myrepoconf}/checks.xml</configLocation>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-pmd-plugin</artifactId>
+                <version>2.5</version>
+                <configuration>
+                    <sourceEncoding>UTF-8</sourceEncoding>
+                    <targetJdk>1.6</targetJdk>
+                    <rulesets>
+                        <ruleset>${project.myrepoconf}/pmdrules.xml</ruleset>
+                    </rulesets>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>findbugs-maven-plugin</artifactId>
+                <version>2.3.1</version>
+                <configuration>
+                    <effort>Max</effort>
+                    <threshold>Low</threshold>
+                    <inputEncoding>${project.build.sourceEncoding}</inputEncoding>
+                    <outputEncoding>${project.reporting.outputEncoding}</outputEncoding>
+                    <!--excludeFilterFile/-->
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>cobertura-maven-plugin</artifactId>
+                <version>2.4</version>
+            </plugin>
+
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>javancss-maven-plugin</artifactId>
+                <version>2.0</version>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jxr-plugin</artifactId>
+                <version>2.2</version>
+            </plugin>
+
+        </plugins>
+    </reporting>
+
+</project>
+
+<!-- EOF -->
diff --git a/src/main/assembly/descriptor.xml b/src/main/assembly/descriptor.xml
new file mode 100644 (file)
index 0000000..b744cbd
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<assembly
+  xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0
+  http://maven.apache.org/xsd/assembly-1.1.0.xsd"
+>
+
+<!--
+    SourceForge.JP用リリースファイル構成定義ファイル
+    Maven2 assembly用
+-->
+
+    <id>src</id>
+
+    <formats>
+        <format>zip</format>
+    </formats>
+
+    <fileSets>
+        <fileSet>
+            <includes>
+                <include>*.txt</include>
+                <include>pom.xml</include>
+                <include>build.xml</include>
+            </includes>
+            <useDefaultExcludes>true</useDefaultExcludes>
+        </fileSet>
+        <fileSet>
+            <directory>src/</directory>
+            <useDefaultExcludes>true</useDefaultExcludes>
+        </fileSet>
+    </fileSets>
+
+</assembly>
+
+<!-- EOF -->
diff --git a/src/main/config/checks.xml b/src/main/config/checks.xml
new file mode 100644 (file)
index 0000000..67da074
--- /dev/null
@@ -0,0 +1,367 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE module PUBLIC
+    "-//Puppy Crawl//DTD Check Configuration 1.2//EN"
+    "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
+
+<!--
+    Checkstyle用チェック項目定義。
+
+    Checkstyle5.1以降向けに記述。
+
+    [ http://checkstyle.sourceforge.net/ ]
+
+    Copyright(c) 2010 olyutorskii
+-->
+
+
+<module name="Checker">
+
+    <property name="charset" value="UTF-8" />
+    <property name="severity" value="error" />
+
+
+    <!-- Duplicate Code -->
+    <module name="StrictDuplicateCode">
+        <property name="min" value="20" />
+    </module>
+
+
+    <!-- Headers -->
+    <module name="RegexpHeader">
+        <property name="header" value="^/\*$\n^ \*( .*)?$\n^ \*/$\n" />
+        <property name="multiLines" value="2" />
+    </module>
+
+
+    <!-- Javadoc Comments -->
+    <module name="JavadocPackage" />
+
+
+    <!-- Miscellaneous -->
+    <module name="NewlineAtEndOfFile" />
+    <module name="Translation" />
+
+
+    <!-- Regexp -->
+    <module name="RegexpSingleline">
+        <property name="format" value="\s+$" />
+        <property name="minimum" value="0" />
+        <property name="maximum" value="0" />
+    </module>
+
+
+    <!-- Size Violations -->
+    <module name="FileLength" />
+
+
+    <!-- Whitespace -->
+    <module name="FileTabCharacter" />
+
+
+<!-- Filters
+    <module name="SeverityMatchFilter" />
+    <module name="SuppressionFilter" />
+    <module name="SuppressionCommentFilter" />
+    <module name="SuppressWithNearbyCommentFilter" />
+-->
+
+
+    <module name="TreeWalker">
+
+        <property name="tabWidth" value="4" />
+
+
+    <!-- Annotations -->
+
+        <module name="AnnotationUseStyle" />
+        <module name="MissingDeprecated" />
+        <module name="MissingOverride" />
+        <module name="PackageAnnotation" />
+        <module name="SuppressWarnings" />
+
+
+    <!-- Block Checks -->
+
+        <module name="EmptyBlock" />
+        <module name="LeftCurly" />
+        <module name="NeedBraces">
+            <property name="tokens" value="LITERAL_DO" />
+        </module>
+        <module name="RightCurly" />
+        <module name="AvoidNestedBlocks" />
+
+
+    <!-- Class Design -->
+
+        <module name="VisibilityModifier" />
+        <module name="FinalClass" />
+        <module name="InterfaceIsType" />
+        <module name="HideUtilityClassConstructor" />
+<!--    <module name="DesignForExtension" />  -->
+        <module name="MutableException" />
+        <module name="ThrowsCount">
+            <property name="max" value="4" />
+        </module>
+
+
+    <!-- Coding -->
+
+        <module name="ArrayTrailingComma" />
+        <module name="AvoidInlineConditionals" />
+        <module name="CovariantEquals" />
+        <module name="DoubleCheckedLocking" />
+        <module name="EmptyStatement" />
+        <module name="EqualsAvoidNull" />
+        <module name="EqualsHashCode" />
+<!--    <module name="FinalLocalVariable" />  -->
+        <module name="HiddenField">
+            <property name="ignoreConstructorParameter" value="true" />
+            <property name="ignoreSetter" value="true" />
+            <property name="ignoreAbstractMethods" value="true" />
+        </module>
+        <module name="IllegalInstantiation">
+            <property
+                name="classes"
+                value="java.lang.Boolean, java.lang.Integer" />
+        </module>
+        <module name="IllegalToken">
+            <property name="tokens" value="LITERAL_NATIVE, STATIC_IMPORT" />
+        </module>
+        <module name="IllegalTokenText">
+            <property name="tokens" value="NUM_INT, NUM_LONG" />
+            <property name="format" value="^0[^lx]" />
+            <property name="ignoreCase" value="true" />
+        </module>
+        <module name="InnerAssignment" />
+        <module name="MagicNumber" />
+        <module name="MissingSwitchDefault" />
+        <module name="ModifiedControlVariable" />
+        <module name="RedundantThrows">
+            <property name="allowUnchecked" value="true" />
+            <property name="allowSubclasses" value="true" />
+        </module>
+        <module name="SimplifyBooleanExpression" />
+        <module name="SimplifyBooleanReturn" />
+        <module name="StringLiteralEquality" />
+        <module name="NestedIfDepth" />
+        <module name="NestedTryDepth" />
+        <module name="NoClone" />
+        <module name="NoFinalizer" />
+        <module name="SuperClone" />
+        <module name="SuperFinalize" />
+        <module name="IllegalCatch" />
+        <module name="IllegalThrows" />
+        <module name="PackageDeclaration" />
+        <module name="JUnitTestCase" />
+        <module name="ReturnCount">
+            <property name="max" value="3" />
+        </module>
+        <module name="IllegalType" />
+        <module name="DeclarationOrder" />
+        <module name="ParameterAssignment" />
+<!--    <module name="ExplicitInitialization" />  -->
+        <module name="DefaultComesLast" />
+        <module name="MissingCtor" />
+        <module name="FallThrough" />
+        <module name="MultipleStringLiterals" />
+        <module name="MultipleVariableDeclarations" />
+        <module name="UnnecessaryParentheses" />
+
+
+    <!-- Imports -->
+
+        <module name="AvoidStarImport" />
+        <module name="AvoidStaticImport" />
+        <module name="IllegalImport" />
+        <module name="RedundantImport" />
+        <module name="UnusedImports" />
+        <module name="ImportOrder" />
+<!--    <module name="ImportControl" />  -->
+
+
+    <!-- Javadoc Comments -->
+
+        <module name="JavadocType" />
+        <module name="JavadocMethod" />
+        <module name="JavadocVariable">
+            <property name="scope" value="protected" />
+        </module>
+        <module name="JavadocStyle">
+            <property
+                name="endOfSentenceFormat"
+                value="([。.?!][ \t\n\r\f&lt;])|([。.?!]$)" />
+            <property name="checkEmptyJavadoc" value="true" />
+            <property name="checkHtml" value="true" />
+        </module>
+<!--    <module name="WriteTag" />  -->
+
+
+    <!-- Metrics -->
+
+        <module name="BooleanExpressionComplexity" />
+        <module name="ClassDataAbstractionCoupling" />
+        <module name="ClassFanOutComplexity" />
+        <module name="CyclomaticComplexity" />
+        <module name="NPathComplexity" />
+        <module name="JavaNCSS" />
+
+
+    <!-- Miscellaneous -->
+
+        <module name="TodoComment">
+            <property name="format" value="TODO" />
+        </module>
+        <module name="UncommentedMain" />
+        <module name="UpperEll" />
+        <module name="ArrayTypeStyle" />
+<!--    <module name="FinalParameters" />  -->
+        <module name="DescendantToken" />
+<!--
+        <module name="Indentation">
+            <property name="basicOffset" value="4" />
+            <property name="caseIndent" value="0" />
+        </module>
+-->
+<!--    <module name="TrailingComment" />  -->
+        <module name="Regexp">
+            <property name="format" value="@author" />
+            <property name="illegalPattern" value="true" />
+        </module>
+        <module name="Regexp">
+            <property name="format" value="^ \* Copyright\(c\)" />
+        </module>
+        <module name="Regexp">
+            <property name="format" value="^ \* License : The MIT License" />
+            <property name="duplicateLimit" value="1" />
+        </module>
+
+    <!-- Modifiers -->
+
+        <module name="ModifierOrder" />
+        <module name="RedundantModifier" />
+
+
+    <!-- Naming Conventions -->
+
+        <module name="AbstractClassName" />
+        <module name="ClassTypeParameterName" />
+        <module name="ConstantName" />
+        <module name="LocalFinalVariableName">
+            <property name="format" value="^[a-z][_a-zA-Z0-9]*$" />
+        </module>
+        <module name="LocalVariableName">
+            <property name="format" value="^[a-z][_a-zA-Z0-9]*$" />
+        </module>
+        <module name="MemberName">
+            <property name="format" value="^[a-z][_a-zA-Z0-9]*$" />
+        </module>
+        <module name="MethodName" />
+        <module name="MethodTypeParameterName" />
+        <module name="PackageName" />
+        <module name="ParameterName">
+            <property name="format" value="^[a-z][_a-zA-Z0-9]*$" />
+        </module>
+        <module name="StaticVariableName">
+            <property name="format" value="^[a-z][_a-zA-Z0-9]*$" />
+        </module>
+        <module name="TypeName" />
+
+
+    <!-- Size Violations -->
+
+        <module name="ExecutableStatementCount" />
+        <module name="LineLength">
+            <property name="max" value="78" />
+        </module>
+        <module name="MethodLength" />
+        <module name="AnonInnerLength" />
+        <module name="ParameterNumber" />
+        <module name="OuterTypeNumber" />
+
+
+    <!-- Whitespace -->
+
+        <module name="GenericWhitespace" />
+        <module name="EmptyForInitializerPad" />
+        <module name="EmptyForIteratorPad" />
+        <module name="MethodParamPad">
+            <property name="tokens" value="CTOR_DEF, LITERAL_NEW, METHOD_DEF, SUPER_CTOR_CALL" />
+        </module>
+        <module name="NoWhitespaceAfter">
+            <property name="allowLineBreaks" value="false" />
+            <property name="tokens" value="DEC, DOT, INC" />
+        </module>
+        <module name="NoWhitespaceBefore">
+            <property name="allowLineBreaks" value="false" />
+            <property name="tokens" value="POST_DEC, POST_INC" />
+        </module>
+        <module name="NoWhitespaceBefore">
+            <property name="allowLineBreaks" value="true" />
+            <property name="tokens" value="SEMI" />
+        </module>
+        <module name="OperatorWrap">
+            <property name="option" value="eol" />
+            <property
+                name="tokens"
+                value="ASSIGN,
+                       BAND_ASSIGN, BOR_ASSIGN, BXOR_ASSIGN,
+                       PLUS_ASSIGN, MINUS_ASSIGN,
+                       STAR_ASSIGN, DIV_ASSIGN, MOD_ASSIGN,
+                       SL_ASSIGN, SR_ASSIGN"
+            />
+        </module>
+        <module name="OperatorWrap">
+            <property name="option" value="nl" />
+            <property
+                name="tokens"
+                value="BAND, BOR, BXOR,
+                       MINUS, STAR, DIV, MOD,
+                       LAND, LOR,
+                       EQUAL"
+            />
+        </module>
+        <module name="ParenPad">
+            <property name="option" value="nospace" />
+            <property name="tokens" value="CTOR_CALL, METHOD_CALL, SUPER_CTOR_CALL" />
+        </module>
+        <module name="TypecastParenPad" />
+        <module name="WhitespaceAfter">
+            <property name="tokens" value="COMMA, SEMI" />
+        </module>
+        <module name="WhitespaceAround">
+            <property
+                name="tokens"
+                value="ASSIGN,
+                       LAND, LOR,
+                       BAND, BOR, BXOR, BSR,
+                       BAND_ASSIGN, BOR_ASSIGN, BXOR_ASSIGN, BSR_ASSIGN,
+                       SL, SR,
+                       SL_ASSIGN, SR_ASSIGN,
+                       MINUS, STAR, DIV, MOD,
+                       PLUS_ASSIGN, MINUS_ASSIGN, STAR_ASSIGN, DIV_ASSIGN, MOD_ASSIGN,
+                       EQUAL, NOT_EQUAL, GT, GE, LT, LE,
+                       "
+            />
+        </module>
+
+
+<!-- 代用品で解決
+        <module name="Header" />
+        <module name="RegexpSingleline" />
+        <module name="RegexpMultiline" />
+        <module name="RegexpSinglelineJava" />
+-->
+
+<!-- バグ?
+        <module name="RequireThis" />
+-->
+
+<!-- Obsolated
+        <module name="TabCharacter" />
+-->
+
+    </module>
+</module>
+
+<!-- EOF -->
diff --git a/src/main/config/pmdrules.xml b/src/main/config/pmdrules.xml
new file mode 100644 (file)
index 0000000..1b5fcf2
--- /dev/null
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    PMD用ルールセット定義
+
+    PMD [ http://pmd.sourceforge.net/ ] 4.2.5 以降用に記述されています。
+
+    Copyright(c) 2010 olyutorskii
+-->
+
+<ruleset
+  name="Custom ruleset"
+  xmlns="http://pmd.sf.net/ruleset/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
+  http://pmd.sf.net/ruleset_xml_schema.xsd"
+  xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"
+>
+
+    <rule ref="rulesets/basic.xml">
+        <exclude name="UnnecessaryReturn" />
+    </rule>
+
+    <rule ref="rulesets/braces.xml">
+        <exclude name="IfElseStmtsMustUseBraces" />
+        <exclude name="IfStmtsMustUseBraces" />
+    </rule>
+
+    <rule ref="rulesets/codesize.xml">
+        <exclude name="TooManyMethods" />
+    </rule>
+
+    <rule ref="rulesets/clone.xml" />
+
+    <rule ref="rulesets/controversial.xml">
+        <exclude name="DataflowAnomalyAnalysis" />
+        <exclude name="OnlyOneReturn" />
+        <exclude name="DefaultPackage" />
+    </rule>
+
+    <rule ref="rulesets/coupling.xml" />
+
+    <rule ref="rulesets/design.xml">
+        <exclude name="UnnecessaryLocalBeforeReturn" />
+    </rule>
+
+    <rule ref="rulesets/finalizers.xml" />
+
+    <rule ref="rulesets/imports.xml" />
+
+    <rule ref="rulesets/logging-java.xml" />
+
+    <rule ref="rulesets/migrating.xml" />
+    <rule ref="rulesets/migrating_to_15.xml" />
+
+    <rule ref="rulesets/naming.xml">
+        <exclude name="LongVariable" />
+        <exclude name="ShortVariable" />
+    </rule>
+
+    <rule ref="rulesets/optimizations.xml">
+        <exclude name="LocalVariableCouldBeFinal" />
+        <exclude name="MethodArgumentCouldBeFinal" />
+    </rule>
+
+    <rule ref="rulesets/strictexception.xml">
+        <exclude name="AvoidThrowingNullPointerException" />
+    </rule>
+
+    <rule ref="rulesets/strings.xml" />
+
+    <rule ref="rulesets/sunsecure.xml" />
+
+    <rule ref="rulesets/typeresolution.xml" />
+
+    <rule ref="rulesets/unusedcode.xml" />
+
+</ruleset>
+
+<!-- EOF -->
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/CommonParser.java b/src/main/java/jp/sourceforge/mikutoga/parser/CommonParser.java
new file mode 100644 (file)
index 0000000..443c86a
--- /dev/null
@@ -0,0 +1,327 @@
+/*\r
+ * common MMD parser\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser;\r
+\r
+import java.io.IOException;\r
+import java.nio.ByteBuffer;\r
+import java.nio.CharBuffer;\r
+import java.nio.charset.Charset;\r
+import java.nio.charset.CharsetDecoder;\r
+import java.nio.charset.CoderResult;\r
+import java.nio.charset.CodingErrorAction;\r
+\r
+/**\r
+ * 各種パーサの共通実装。\r
+ */\r
+public class CommonParser {\r
+\r
+    /** 日本語デコード作業用入力バッファ長。バイト単位。 */\r
+    public static final int TEXTBUF_SZ = 512;\r
+\r
+    /**\r
+     * MMD各種ファイルで用いられる日本語エンコーディング。(windows-31j)\r
+     * ほぼShift_JISのスーパーセットと思ってよい。\r
+     * デコード結果はUCS-2集合に収まるはず。\r
+     */\r
+    protected static final Charset CS_WIN31J = Charset.forName("windows-31j");\r
+\r
+    private static final byte TERMINATOR = (byte) '\0';  // 0x00\r
+    private static final char UCSYEN = '\u00a5';\r
+    private static final char SJISYEN = (char) 0x005c;  // '\u005c\u005c';\r
+\r
+    private final MmdSource source;\r
+    private final CharsetDecoder decoder;\r
+    private final byte[] textArray;\r
+    private final ByteBuffer textBuffer;  // textArrayの別ビュー\r
+    private final CharBuffer charBuffer;\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param source 入力ソース\r
+     */\r
+    public CommonParser(MmdSource source){\r
+        super();\r
+\r
+        this.source = source;\r
+        this.decoder = CS_WIN31J.newDecoder();\r
+        this.textArray = new byte[TEXTBUF_SZ];\r
+        this.textBuffer = ByteBuffer.wrap(this.textArray);\r
+        int maxChars =\r
+                (int)(TEXTBUF_SZ * (this.decoder.maxCharsPerByte())) + 1;\r
+        this.charBuffer = CharBuffer.allocate(maxChars);\r
+\r
+        this.decoder.onMalformedInput(CodingErrorAction.REPORT);\r
+        this.decoder.onUnmappableCharacter(CodingErrorAction.REPORT);\r
+        this.textBuffer.clear();\r
+        this.charBuffer.clear();\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 入力ソースにまだデータが残っているか判定する。\r
+     * @return まだ読み込んでいないデータが残っていればtrue\r
+     * @throws IOException IOエラー\r
+     * @see MmdSource#hasMore()\r
+     */\r
+    protected boolean hasMore() throws IOException{\r
+        boolean result = this.source.hasMore();\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * 入力ソースを読み飛ばす。\r
+     * @param skipLength 読み飛ばすバイト数。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み飛ばす途中でストリーム終端に達した。\r
+     * @see MmdSource#skip(long)\r
+     */\r
+    protected void skip(long skipLength)\r
+            throws IOException, MmdEofException {\r
+        long result = this.source.skip(skipLength);\r
+        if(result != skipLength){\r
+            throw new MmdEofException(this.source.getPosition());\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 入力ソースを読み飛ばす。\r
+     * @param skipLength 読み飛ばすバイト数。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み飛ばす途中でストリーム終端に達した。\r
+     * @see MmdSource#skip(long)\r
+     */\r
+    protected void skip(int skipLength)\r
+            throws IOException, MmdEofException {\r
+        skip((long) skipLength);\r
+    }\r
+\r
+    /**\r
+     * byte値を読み込む。\r
+     * @return 読み込んだbyte値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see MmdSource#parseByte()\r
+     */\r
+    protected byte parseByte()\r
+            throws IOException, MmdEofException{\r
+        return this.source.parseByte();\r
+    }\r
+\r
+    /**\r
+     * 符号無し値としてbyte値を読み込み、int型に変換して返す。\r
+     * 符号は拡張されない。(0xffは0x000000ffとなる)\r
+     * @return 読み込まれた値のint値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see MmdSource#parseUByteAsInteger()\r
+     */\r
+    protected int parseUByteAsInteger()\r
+            throws IOException, MmdEofException{\r
+        return this.source.parseUByteAsInteger();\r
+    }\r
+\r
+    /**\r
+     * byte値を読み込み、boolean型に変換して返す。\r
+     * 0x00は偽、それ以外は真と解釈される。\r
+     * @return 読み込まれた値のboolean値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see MmdSource#parseBoolean()\r
+     */\r
+    protected boolean parseBoolean()\r
+            throws IOException, MmdEofException{\r
+        return this.source.parseBoolean();\r
+    }\r
+\r
+    /**\r
+     * short値を読み込む。\r
+     * short値はリトルエンディアンで格納されていると仮定される。\r
+     * @return 読み込んだshort値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see MmdSource#parseShort()\r
+     */\r
+    protected short parseShort()\r
+            throws IOException, MmdEofException{\r
+        return this.source.parseShort();\r
+    }\r
+\r
+    /**\r
+     * 符号無し値としてshort値を読み込み、int型に変換して返す。\r
+     * 符号は拡張されない。(0xffffは0x0000ffffとなる)\r
+     * short値はリトルエンディアンで格納されていると仮定される。\r
+     * @return 読み込まれた値のint値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see MmdSource#parseUShortAsInteger()\r
+     */\r
+    protected int parseUShortAsInteger()\r
+            throws IOException, MmdEofException{\r
+        return this.source.parseUShortAsInteger();\r
+    }\r
+\r
+    /**\r
+     * int値を読み込む。\r
+     * int値はリトルエンディアンで格納されていると仮定される。\r
+     * @return 読み込んだint値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see MmdSource#parseInteger()\r
+     */\r
+    protected int parseInteger()\r
+            throws IOException, MmdEofException{\r
+        return this.source.parseInteger();\r
+    }\r
+\r
+    /**\r
+     * float値を読み込む。\r
+     * float値はリトルエンディアンで格納されていると仮定される。\r
+     * @return 読み込んだfloat値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see MmdSource#parseFloat()\r
+     */\r
+    protected float parseFloat()\r
+            throws IOException, MmdEofException{\r
+        return this.source.parseFloat();\r
+    }\r
+\r
+    /**\r
+     * byte配列を読み込む。\r
+     * @param dst 格納先配列\r
+     * @param offset 読み込み開始オフセット\r
+     * @param length 読み込みバイト数\r
+     * @throws IOException IOエラー\r
+     * @throws NullPointerException 配列がnull\r
+     * @throws IndexOutOfBoundsException 引数が配列属性と矛盾\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see MmdSource#parseByteArray(byte[], int, int)\r
+     */\r
+    protected void parseByteArray(byte[] dst, int offset, int length)\r
+            throws IOException,\r
+                   NullPointerException,\r
+                   IndexOutOfBoundsException,\r
+                   MmdEofException {\r
+        this.source.parseByteArray(dst, offset, length);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * byte配列を読み込む。\r
+     * 配列要素全ての読み込みが試みられる。\r
+     * @param dst 格納先配列\r
+     * @throws IOException IOエラー\r
+     * @throws NullPointerException 配列がnull\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see MmdSource#parseByteArray(byte[])\r
+     */\r
+    protected void parseByteArray(byte[] dst)\r
+            throws IOException, NullPointerException, MmdEofException{\r
+        this.source.parseByteArray(dst);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * float配列を読み込む。\r
+     * @param dst 格納先配列\r
+     * @param offset 読み込み開始オフセット\r
+     * @param length 読み込みfloat要素数\r
+     * @throws IOException IOエラー\r
+     * @throws NullPointerException 配列がnull\r
+     * @throws IndexOutOfBoundsException 引数が配列属性と矛盾\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see MmdSource#parseFloatArray(float[], int, int)\r
+     */\r
+    protected void parseFloatArray(float[] dst, int offset, int length)\r
+            throws IOException,\r
+                   NullPointerException,\r
+                   IndexOutOfBoundsException,\r
+                   MmdEofException {\r
+        this.source.parseFloatArray(dst, offset, length);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * float配列を読み込む。\r
+     * 配列要素全ての読み込みが試みられる。\r
+     * @param dst 格納先配列\r
+     * @throws IOException IOエラー\r
+     * @throws NullPointerException 配列がnull\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see MmdSource#parseFloatArray(float[])\r
+     */\r
+    protected void parseFloatArray(float[] dst)\r
+            throws IOException, NullPointerException, MmdEofException{\r
+        this.source.parseFloatArray(dst);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 指定された最大バイト長に収まるゼロ終端(0x00)文字列を読み込む。\r
+     * 入力バイト列はwindows-31jエンコーディングとして解釈される。\r
+     * ゼロ終端以降のデータは無視されるが、\r
+     * IO入力は指定バイト数だけ読み進められる。\r
+     * ゼロ終端が見つからないまま指定バイト数が読み込み終わった場合、\r
+     * そこまでのデータから文字列を構成する。\r
+     * <p>\r
+     * 戻り結果にはU+00A5(UCS円通貨記号)が含まれないことが保証される。\r
+     * ※0x5c(Win31J円通貨)はU+005C(UCSバックスラッシュ)にデコードされる。\r
+     *\r
+     * @param maxlen 読み込みバイト数\r
+     * @return デコードされた文字列\r
+     * @throws IOException IOエラー\r
+     * @throws IllegalArgumentException 読み込みバイト数が負であるか、\r
+     * または内部バッファに対し大きすぎる。\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @throws MmdFormatException 不正な文字エンコーディングが検出された。\r
+     */\r
+    protected String parseZeroTermString(int maxlen)\r
+            throws IOException,\r
+                   IllegalArgumentException,\r
+                   MmdEofException,\r
+                   MmdFormatException {\r
+        if(this.textArray.length < maxlen || maxlen < 0){\r
+            throw new IllegalArgumentException();\r
+        }\r
+\r
+        this.source.parseByteArray(this.textArray, 0, maxlen);\r
+\r
+        int length = -1;\r
+        for(int pos = 0; pos < maxlen; pos++){\r
+            byte ch = this.textArray[pos];\r
+            if(ch == TERMINATOR){\r
+                length = pos;\r
+                break;\r
+            }\r
+        }\r
+        if(length < 0) length = maxlen;\r
+\r
+        this.textBuffer.rewind();\r
+        this.textBuffer.limit(length);\r
+        this.charBuffer.clear();\r
+        CoderResult decResult =\r
+                this.decoder.decode(this.textBuffer, this.charBuffer, true);\r
+        if( ! decResult.isUnderflow() || decResult.isError()){\r
+            throw new MmdFormatException("illegal character encoding",\r
+                                         this.source.getPosition() );\r
+        }\r
+\r
+        this.charBuffer.flip();\r
+        String result = this.charBuffer.toString();\r
+\r
+        if(result.indexOf(UCSYEN) >= 0){\r
+            result = result.replace(UCSYEN, SJISYEN);\r
+        }\r
+\r
+        return result;\r
+    }\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/LoopHandler.java b/src/main/java/jp/sourceforge/mikutoga/parser/LoopHandler.java
new file mode 100644 (file)
index 0000000..5183ede
--- /dev/null
@@ -0,0 +1,44 @@
+/*\r
+ * loop handler\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser;\r
+\r
+/**\r
+ * ループ構造の通知用ハンドラ。\r
+ * ステージ指定により、多重ネストループをもサポートする。\r
+ */\r
+public interface LoopHandler {\r
+\r
+    /**\r
+     * ループ構造開始の通知を受け取る。\r
+     * 0回ループの場合も含め一度呼ばれる。\r
+     * @param stage ループ種別\r
+     * @param loops ループ回数。未知の場合は負の値。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void loopStart(ParseStage stage, int loops) throws MmdFormatException;\r
+\r
+    /**\r
+     * ループ構造の1イテレーション終了の通知を受け取る。\r
+     * 1度しか回らないループでも呼ばれる。0回ループでは決して呼ばれない。\r
+     * @param stage ループ種別\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void loopNext(ParseStage stage) throws MmdFormatException;\r
+\r
+    /**\r
+     * ループ構造終了の通知を受け取る。\r
+     * 0回ループの場合も含め一度呼ばれる。\r
+     * @param stage ループ種別\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void loopEnd(ParseStage stage) throws MmdFormatException;\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/MmdEofException.java b/src/main/java/jp/sourceforge/mikutoga/parser/MmdEofException.java
new file mode 100644 (file)
index 0000000..fac9deb
--- /dev/null
@@ -0,0 +1,54 @@
+/*\r
+ * unexpected file EOF founded exception\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser;\r
+\r
+/**\r
+ * 入力ソースが予期せずに終了した異常系。\r
+ */\r
+@SuppressWarnings("serial")\r
+public class MmdEofException extends MmdFormatException {\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     */\r
+    public MmdEofException(){\r
+        this(null);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param message エラーメッセージ\r
+     */\r
+    public MmdEofException(String message){\r
+        this(message, -1L);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param position 入力ソース先頭からのエラー位置。(バイト単位)\r
+     * 負の値を与えると、エラー位置は無効と解釈される。\r
+     */\r
+    public MmdEofException(long position){\r
+        this(null, position);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param message エラーメッセージ\r
+     * @param position 入力ソース先頭からのエラー位置。(バイト単位)\r
+     * 負の値を与えると、エラー位置は無効と解釈される。\r
+     */\r
+    public MmdEofException(String message, long position){\r
+        super(message, position);\r
+        return;\r
+    }\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/MmdFormatException.java b/src/main/java/jp/sourceforge/mikutoga/parser/MmdFormatException.java
new file mode 100644 (file)
index 0000000..a56822c
--- /dev/null
@@ -0,0 +1,100 @@
+/*\r
+ * unexpected file format founded exception\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser;\r
+\r
+/**\r
+ * MMD関連ファイルのパース異常系。\r
+ * 必要に応じて、パースに失敗した位置を保持する。\r
+ */\r
+@SuppressWarnings("serial")\r
+public class MmdFormatException extends Exception {\r
+\r
+    private final long position;\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     */\r
+    public MmdFormatException(){\r
+        this(null);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param message エラーメッセージ\r
+     */\r
+    public MmdFormatException(String message){\r
+        this(message, -1L);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param position 入力ソース先頭から数えたエラー位置。(バイト単位)\r
+     * 負の値を与えると、エラー位置は無効と解釈される。\r
+     */\r
+    public MmdFormatException(long position){\r
+        this(null, position);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param message エラーメッセージ\r
+     * @param position 入力ソース先頭から数えたエラー位置。(バイト単位)\r
+     * 負の値を与えると、エラー位置は無効と解釈される。\r
+     */\r
+    public MmdFormatException(String message, long position){\r
+        super(message);\r
+        this.position = position;\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * {@inheritDoc}\r
+     * 有効なエラー発生位置を保持している場合、追加出力される。\r
+     * @return {@inheritDoc}\r
+     */\r
+    @Override\r
+    public String getMessage(){\r
+        StringBuilder result = new StringBuilder();\r
+\r
+        String msg = super.getMessage();\r
+        if(msg != null) result.append(msg);\r
+\r
+        if(hasPosition()){\r
+            result.append('(')\r
+                  .append("position:")\r
+                  .append(this.position)\r
+                  .append(')');\r
+        }\r
+\r
+        if(result.length() <= 0) return null;\r
+\r
+        return result.toString();\r
+    }\r
+\r
+    /**\r
+     * エラー位置を取得する。\r
+     * @return 入力ソース先頭からのバイト数で表されるエラー位置。\r
+     * 負なら無効なエラー位置。\r
+     */\r
+    public long getPosition(){\r
+        return this.position;\r
+    }\r
+\r
+    /**\r
+     * 有効なエラー位置が設定されているか判定する。\r
+     * @return エラー位置が有効(非負)ならtrue\r
+     */\r
+    public boolean hasPosition(){\r
+        if(this.position < 0L) return false;\r
+        return true;\r
+    }\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/MmdSource.java b/src/main/java/jp/sourceforge/mikutoga/parser/MmdSource.java
new file mode 100644 (file)
index 0000000..051660f
--- /dev/null
@@ -0,0 +1,328 @@
+/*\r
+ * MMD file input source\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser;\r
+\r
+import java.io.Closeable;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.PushbackInputStream;\r
+import java.nio.ByteBuffer;\r
+import java.nio.ByteOrder;\r
+\r
+/**\r
+ * MMD各種ファイルの入力ソース。\r
+ * 入力ソース終端の判定が可能。\r
+ * パースエラー発生位置(バイト単位)の取得が可能。\r
+ * リトルエンディアン形式で格納された各種プリミティブ型値の解決を行う。\r
+ */\r
+public class MmdSource implements Closeable {\r
+\r
+    private static final int BYTES_SHORT = Short  .SIZE / Byte.SIZE;\r
+    private static final int BYTES_INT   = Integer.SIZE / Byte.SIZE;\r
+    private static final int BYTES_FLOAT = Float  .SIZE / Byte.SIZE;\r
+    private static final int BUF_SZ = 4;\r
+\r
+    private static final int MASK_8BIT = 0xff;\r
+    private static final int MASK_16BIT = 0xffff;\r
+\r
+    static{\r
+        assert BUF_SZ >= BYTES_SHORT;\r
+        assert BUF_SZ >= BYTES_INT;\r
+        assert BUF_SZ >= BYTES_FLOAT;\r
+    }\r
+\r
+    private final PushbackInputStream istream;\r
+    private final byte[] readArray;       // 読み込みバッファ\r
+    private final ByteBuffer readBuffer;  // 読み込みバッファの別ビュー\r
+    private long position;                // 読み込み位置\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param is 入力ストリーム。\r
+     * I/O効率が考慮されたバッファリングを行うストリームを渡すのが望ましい。\r
+     * @throws NullPointerException ストリーム引数がnull。\r
+     */\r
+    public MmdSource(InputStream is)\r
+            throws NullPointerException {\r
+        super();\r
+\r
+        if(is == null) throw new NullPointerException();\r
+\r
+        // 読み戻しバッファは1byte確保\r
+        this.istream = new PushbackInputStream(is);\r
+\r
+        this.readArray = new byte[BUF_SZ];\r
+        this.readBuffer = ByteBuffer.wrap(this.readArray);\r
+        this.readBuffer.order(ByteOrder.LITTLE_ENDIAN);\r
+        this.readBuffer.clear();\r
+\r
+        this.position = 0L;\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 今までに読み込みに成功したバイト数を返す。\r
+     * @return 読み込みに成功したバイト数。\r
+     */\r
+    public long getPosition(){\r
+        return this.position;\r
+    }\r
+\r
+    /**\r
+     * 入力ソースを読み飛ばす。\r
+     * 入力ソースがディスクファイルに由来する場合、\r
+     * 空読みするより早くなるかも。\r
+     * @param skipLength 読み飛ばすバイト数。\r
+     * @return 実際に読み飛ばしたバイト数。\r
+     * @throws IOException IOエラー\r
+     * @see java.io.InputStream#skip(long)\r
+     */\r
+    public long skip(long skipLength)\r
+            throws IOException{\r
+        if(skipLength <= 0L) return 0L;\r
+\r
+        long remain = skipLength;\r
+        while(remain > 0L){      // BufferedInputStream対策\r
+            long result = this.istream.skip(remain);\r
+            if(result <= 0L) break;\r
+            this.position += result;\r
+            remain -= result;\r
+        }\r
+\r
+        return skipLength - remain;\r
+    }\r
+\r
+    /**\r
+     * 入力ソースにまだデータが残っているか判定する。\r
+     * @return まだ読み込んでいないデータが残っていればtrue\r
+     * @throws IOException IOエラー\r
+     */\r
+    public boolean hasMore() throws IOException{\r
+        int bData = this.istream.read();\r
+        if(bData < 0){\r
+            return false;\r
+        }\r
+\r
+        this.istream.unread(bData);\r
+\r
+        return true;\r
+    }\r
+\r
+    /**\r
+     * 入力ソースを閉じる。\r
+     * 読み込み済みバイト数の情報は保持される。\r
+     * @throws IOException IOエラー\r
+     * @see java.io.InputStream#close()\r
+     */\r
+    public void close() throws IOException{\r
+        this.istream.close();\r
+        this.readBuffer.clear();\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 指定したバイト数だけ内部バッファに読み込む。\r
+     * @param fillSize 読み込むバイト数\r
+     * @throws IOException IOエラー\r
+     * @throws IndexOutOfBoundsException 引数がバッファサイズと矛盾。\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     */\r
+    protected void fillBuffer(int fillSize)\r
+            throws IOException, IndexOutOfBoundsException, MmdEofException{\r
+        int result = this.istream.read(this.readArray, 0, fillSize);\r
+        if(result >= 0){\r
+            this.position += result;\r
+        }\r
+\r
+        if(result != fillSize){\r
+            throw new MmdEofException(this.position);\r
+        }\r
+\r
+        this.readBuffer.rewind();\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * byte値を読み込む。\r
+     * @return 読み込んだbyte値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     */\r
+    public byte parseByte() throws IOException, MmdEofException{\r
+        int bData = this.istream.read();\r
+        if(bData < 0){\r
+            throw new MmdEofException(this.position);\r
+        }else{\r
+            this.position++;\r
+        }\r
+\r
+        byte result = (byte) bData;\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * 符号無し値としてbyte値を読み込み、int型に変換して返す。\r
+     * 符号は拡張されない。(0xffは0x000000ffとなる)\r
+     * @return 読み込まれた値のint値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     */\r
+    public int parseUByteAsInteger()\r
+            throws IOException, MmdEofException{\r
+        return ((int) parseByte()) & MASK_8BIT;\r
+    }\r
+\r
+    /**\r
+     * byte値を読み込み、boolean型に変換して返す。\r
+     * 0x00は偽、それ以外は真と解釈される。\r
+     * @return 読み込まれた値のboolean値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     */\r
+    public boolean parseBoolean() throws IOException, MmdEofException{\r
+        byte result = parseByte();\r
+        if(result == 0x00) return false;\r
+        return true;\r
+    }\r
+\r
+    /**\r
+     * short値を読み込む。\r
+     * short値はリトルエンディアンで格納されていると仮定される。\r
+     * @return 読み込んだshort値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     */\r
+    public short parseShort() throws IOException, MmdEofException{\r
+        fillBuffer(BYTES_SHORT);\r
+        short result = this.readBuffer.getShort();\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * 符号無し値としてshort値を読み込み、int型に変換して返す。\r
+     * 符号は拡張されない。(0xffffは0x0000ffffとなる)\r
+     * short値はリトルエンディアンで格納されていると仮定される。\r
+     * @return 読み込まれた値のint値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     */\r
+    public int parseUShortAsInteger()\r
+            throws IOException, MmdEofException{\r
+        return ((int) parseShort()) & MASK_16BIT;\r
+    }\r
+\r
+    /**\r
+     * int値を読み込む。\r
+     * int値はリトルエンディアンで格納されていると仮定される。\r
+     * @return 読み込んだint値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     */\r
+    public int parseInteger() throws IOException, MmdEofException{\r
+        fillBuffer(BYTES_INT);\r
+        int result = this.readBuffer.getInt();\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * float値を読み込む。\r
+     * float値はリトルエンディアンで格納されていると仮定される。\r
+     * @return 読み込んだfloat値\r
+     * @throws IOException IOエラー\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     */\r
+    public float parseFloat() throws IOException, MmdEofException{\r
+        fillBuffer(BYTES_FLOAT);\r
+        float result = this.readBuffer.getFloat();\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * byte配列を読み込む。\r
+     * @param dst 格納先配列\r
+     * @param offset 読み込み開始オフセット\r
+     * @param length 読み込みバイト数\r
+     * @throws IOException IOエラー\r
+     * @throws NullPointerException 配列がnull\r
+     * @throws IndexOutOfBoundsException 引数が配列属性と矛盾\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     * @see java.io.InputStream#read(byte[], int, int)\r
+     */\r
+    public void parseByteArray(byte[] dst, int offset, int length)\r
+            throws IOException,\r
+                   NullPointerException,\r
+                   IndexOutOfBoundsException,\r
+                   MmdEofException {\r
+        int result = this.istream.read(dst, offset, length);\r
+        if(result >= 0){\r
+            this.position += result;\r
+        }\r
+\r
+        if(result != length){\r
+            throw new MmdEofException(this.position);\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * byte配列を読み込む。\r
+     * @param dst 格納先配列\r
+     * @throws IOException IOエラー\r
+     * @throws NullPointerException 配列がnull\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     */\r
+    public void parseByteArray(byte[] dst)\r
+            throws IOException, NullPointerException, MmdEofException{\r
+        parseByteArray(dst, 0, dst.length);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * float配列を読み込む。\r
+     * @param dst 格納先配列\r
+     * @param offset 読み込み開始オフセット\r
+     * @param length 読み込みfloat要素数\r
+     * @throws IOException IOエラー\r
+     * @throws NullPointerException 配列がnull\r
+     * @throws IndexOutOfBoundsException 引数が配列属性と矛盾\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     */\r
+    public void parseFloatArray(float[] dst, int offset, int length)\r
+            throws IOException,\r
+                   NullPointerException,\r
+                   IndexOutOfBoundsException,\r
+                   MmdEofException {\r
+        if(offset < 0 || length < 0 || dst.length - offset < length){\r
+            throw new IndexOutOfBoundsException();\r
+        }\r
+\r
+        for(int idx = 0; idx < length; idx++){\r
+            dst[offset+idx] = parseFloat();\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * float配列を読み込む。\r
+     * @param dst 格納先配列\r
+     * @throws IOException IOエラー\r
+     * @throws NullPointerException 配列がnull\r
+     * @throws MmdEofException 読み込む途中でストリーム終端に達した。\r
+     */\r
+    public void parseFloatArray(float[] dst)\r
+            throws IOException, NullPointerException, MmdEofException{\r
+        parseFloatArray(dst, 0, dst.length);\r
+        return;\r
+    }\r
+\r
+    // TODO ビッグエンディアン対応が今後必要になる状況はありうるか?\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/ParseStage.java b/src/main/java/jp/sourceforge/mikutoga/parser/ParseStage.java
new file mode 100644 (file)
index 0000000..ea04c7d
--- /dev/null
@@ -0,0 +1,47 @@
+/*\r
+ * parse-processing stage\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser;\r
+\r
+/**\r
+ * パース処理の進行ステージ種別を表す。\r
+ * ループ構造の識別に用いられる。\r
+ */\r
+public class ParseStage {\r
+\r
+    private final String name;\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * 進行ステージ名は空文字列が指定される。\r
+     */\r
+    public ParseStage(){\r
+        this("");\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param name 進行ステージ名\r
+     */\r
+    public ParseStage(String name){\r
+        super();\r
+        this.name = name;\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * {@inheritDoc}\r
+     * 進行ステージ名を返す。\r
+     * @return {@inheritDoc} 進行ステージ名\r
+     */\r
+    @Override\r
+    public String toString(){\r
+        return this.name;\r
+    }\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/package-info.java b/src/main/java/jp/sourceforge/mikutoga/parser/package-info.java
new file mode 100644 (file)
index 0000000..e01d5f6
--- /dev/null
@@ -0,0 +1,17 @@
+/*\r
+ * package information for Javadoc\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+/**\r
+ * MMD用各種パーサ共通ライブラリ。\r
+ * <p>\r
+ * PMDモデルファイルやVMDモーションファイルなどの個別のパーサは\r
+ * 別パッケージにより提供される。\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser;\r
+\r
+/* EOF */\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdBasicHandler.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdBasicHandler.java
new file mode 100644 (file)
index 0000000..dccc41c
--- /dev/null
@@ -0,0 +1,54 @@
+/*\r
+ * PMD basic information handler\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+\r
+/**\r
+ * PMDモデル情報ファイルの基本情報の通知用ハンドラ。\r
+ */\r
+public interface PmdBasicHandler {\r
+\r
+    /**\r
+     * PMDファイルのパース処理開始の通知を受け取る。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdParseStart()\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * PMDファイルのパース処理終了の通知を受け取る。\r
+     * @param hasMoreData 入力ソースに\r
+     * まだ読み込まれていないデータがあればtrue\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdParseEnd(boolean hasMoreData)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * PMDファイルのヘッダ情報の通知を受け取る。\r
+     * @param ver ヘッダ情報の版数。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdHeaderInfo(float ver)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * PMDファイルのモデル基本情報の通知を受け取る。\r
+     * @param modelName モデル名\r
+     * @param description モデルの説明文。改行CRLFは"\n"に変換される。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdModelInfo(String modelName, String description)\r
+            throws MmdFormatException;\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdBoneHandler.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdBoneHandler.java
new file mode 100644 (file)
index 0000000..5cbdf38
--- /dev/null
@@ -0,0 +1,137 @@
+/*\r
+ * PMD bone information handler\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.LoopHandler;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.ParseStage;\r
+\r
+/**\r
+ * PMDモデルの各種ボーン情報の通知用ハンドラ。\r
+ * ボーン定義の出現順と、0から始まるボーンIDは対応する。\r
+ */\r
+public interface PmdBoneHandler extends LoopHandler {\r
+\r
+    /**\r
+     * ボーン情報パースステージ。\r
+     */\r
+    class PmdBoneStage extends ParseStage{\r
+        /** コンストラクタ。 */\r
+        PmdBoneStage(){ super(); return; }\r
+    }\r
+\r
+    /** ボーン定義抽出ループ。 */\r
+    PmdBoneStage BONE_LIST = new PmdBoneStage();\r
+\r
+    /** IKリスト抽出ループ。 */\r
+    PmdBoneStage IK_LIST = new PmdBoneStage();\r
+\r
+    /** IKチェーンリスト抽出ループ。 */\r
+    PmdBoneStage IKCHAIN_LIST = new PmdBoneStage();\r
+\r
+    /** ボーングループ名抽出ループ。 */\r
+    PmdBoneStage BONEGROUP_LIST = new PmdBoneStage();\r
+\r
+    /** ボーングループ内訳抽出ループ。 */\r
+    PmdBoneStage GROUPEDBONE_LIST = new PmdBoneStage();\r
+\r
+    /**\r
+     * ボーン定義情報の通知を受け取る。\r
+     * {@link #BONE_LIST}ループの構成要素。\r
+     * @param boneName ボーン名\r
+     * @param boneKind ボーン種別。\r
+     * <ul>\r
+     * <li>0:回転\r
+     * <li>1:回転/移動\r
+     * <li>2:IK\r
+     * <li>3:不明\r
+     * <li>4:IK影響下(回転)\r
+     * <li>5:回転影響下\r
+     * <li>6:IK接続先\r
+     * <li>7:非表示\r
+     * <li>8:捩り\r
+     * <li>9:回転連動\r
+     * </ul>\r
+     * ※8,9はMMD4.0から?\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdBoneInfo(String boneName, byte boneKind)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * ボーン間接続情報の通知を受け取る。\r
+     * {@link #BONE_LIST}ループの構成要素。\r
+     * @param parentId 親(前)ボーンID。無い場合は0xffff。\r
+     * @param tailId 子(次)ボーンID。末端の場合は0。\r
+     * 捩りボーンの場合は軸方向のボーンID、\r
+     * 回転連動ボーンの場合は影響元ボーンID\r
+     * @param ikId 影響IKボーンID。未指定の場合は0。\r
+     * ※回転連動では影響度(0-100)、負や100以上もOK!\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdBoneLink(int parentId, int tailId, int ikId)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * ボーン位置情報の通知を受け取る。\r
+     * {@link #BONE_LIST}ループの構成要素。\r
+     * @param xPos X座標\r
+     * @param yPos Y座標\r
+     * @param zPos Z座標\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdBonePosition(float xPos, float yPos, float zPos)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * IKボーン情報の通知を受け取る。\r
+     * {@link #IK_LIST}ループの構成要素。\r
+     * @param boneId IKボーンID\r
+     * @param targetId IKボーンが最初に接続するIK接続先ボーンID\r
+     * @param depth 再帰演算の深さ\r
+     * @param weight 制限角度強度\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdIKInfo(int boneId, int targetId, int depth, float weight)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * IKチェイン要素の通知を受け取る。\r
+     * {@link #IK_LIST}ループの下位{@link #IKCHAIN_LIST}ループの構成要素。\r
+     * @param childId IK影響下ボーンID\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdIKChainInfo(int childId)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * ボーングループ名定義の通知を受け取る。\r
+     * {@link #BONEGROUP_LIST}ループの構成要素。\r
+     * @param groupName ボーングループ名。末尾のLF(0x0a)は削除される。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdBoneGroupInfo(String groupName) throws MmdFormatException;\r
+\r
+    /**\r
+     * ボーングループ内訳の通知を受け取る。\r
+     * {@link #GROUPEDBONE_LIST}ループの構成要素。\r
+     * @param boneId グループに所属するボーンのID\r
+     * @param groupId ボーンが所属するボーングループIDに1を足した数\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdGroupedBoneInfo(int boneId, int groupId)\r
+            throws MmdFormatException;\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdEngHandler.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdEngHandler.java
new file mode 100644 (file)
index 0000000..0a26bc9
--- /dev/null
@@ -0,0 +1,82 @@
+/*\r
+ * PMD english information handler\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.LoopHandler;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.ParseStage;\r
+\r
+/**\r
+ * PMDモデルの英語情報の通知用ハンドラ。\r
+ */\r
+public interface PmdEngHandler extends LoopHandler {\r
+\r
+    /**\r
+     * 英語情報パースステージ。\r
+     */\r
+    class PmdEngStage extends ParseStage{\r
+        /** コンストラクタ。 */\r
+        PmdEngStage(){ super(); return; }\r
+    }\r
+\r
+    /** ボーン英語名抽出ループ。 */\r
+    ParseStage ENGBONE_LIST = new PmdEngStage();\r
+\r
+    /** モーフ英語名抽出ループ。 */\r
+    ParseStage ENGMORPH_LIST = new PmdEngStage();\r
+\r
+    /** ボーングループ英語名抽出グループ。 */\r
+    ParseStage ENGBONEGROUP_LIST = new PmdEngStage();\r
+\r
+    /**\r
+     * PMD英語情報の有無の通知を受け取る。\r
+     * @param hasEnglishInfo 英語情報が含まれればtrue\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdEngEnabled(boolean hasEnglishInfo) throws MmdFormatException;\r
+\r
+    /**\r
+     * PMD英語基本情報の通知を受け取る。\r
+     * @param modelName モデル名\r
+     * @param description モデルの説明文。改行CRLFは"\n"に変換される。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdEngModelInfo(String modelName, String description)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * 英語ボーン名の通知を受け取る。\r
+     * {@link #ENGBONE_LIST}ループの構成要素\r
+     * @param boneName 英語ボーン名\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdEngBoneInfo(String boneName) throws MmdFormatException;\r
+\r
+    /**\r
+     * 英語モーフ名の通知を受け取る。\r
+     * モーフ名「base」に対応する英語名は通知されない。\r
+     * {@link #ENGMORPH_LIST}ループの構成要素\r
+     * @param morphName 英語モーフ名\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdEngMorphInfo(String morphName) throws MmdFormatException;\r
+\r
+    /**\r
+     * 英語ボーングループ名の通知を受け取る。\r
+     * {@link #ENGBONEGROUP_LIST}ループの構成要素\r
+     * @param groupName 英語ボーングループ名\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdEngBoneGroupInfo(String groupName) throws MmdFormatException;\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdJointHandler.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdJointHandler.java
new file mode 100644 (file)
index 0000000..70567f9
--- /dev/null
@@ -0,0 +1,139 @@
+/*\r
+ * PMD joint information handler\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.LoopHandler;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.ParseStage;\r
+\r
+/**\r
+ * PMDモデルの各種剛体間ジョイント情報の通知用ハンドラ。\r
+ */\r
+public interface PmdJointHandler extends LoopHandler {\r
+\r
+    /**\r
+     * ジョイント情報パースステージ。\r
+     */\r
+    class PmdJointStage extends ParseStage{\r
+        /** コンストラクタ。 */\r
+        PmdJointStage(){ super(); return; }\r
+    }\r
+\r
+    /** ジョイント情報抽出ループ。 */\r
+    PmdJointStage JOINT_LIST = new PmdJointStage();\r
+\r
+    /**\r
+     * ジョイント名の通知を受け取る。\r
+     * {@link #JOINT_LIST}ループの構成要素。\r
+     * @param jointName ジョイント名\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示。\r
+     */\r
+    void pmdJointName(String jointName)\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * ジョイントが繋ぐ接続剛体IDの通知を受け取る。\r
+     * {@link #JOINT_LIST}ループの構成要素。\r
+     * @param rigidIdA 接続剛体AのID\r
+     * @param rigidIdB 接続剛体BのID\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示。\r
+     */\r
+    void pmdJointLink(int rigidIdA, int rigidIdB)\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * ジョイント位置の通知を受け取る。\r
+     * {@link #JOINT_LIST}ループの構成要素。\r
+     * @param posX X座標\r
+     * @param posY Y座標\r
+     * @param posZ Z座標\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示。\r
+     */\r
+    void pmdJointPosition(float posX, float posY, float posZ)\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * ジョイント回転姿勢の通知を受け取る。\r
+     * {@link #JOINT_LIST}ループの構成要素。\r
+     * @param radX X軸回転量(radian)\r
+     * @param radY Y軸回転量(radian)\r
+     * @param radZ Z軸回転量(radian)\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示。\r
+     */\r
+    void pmdJointRotation(float radX, float radY, float radZ)\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * ジョイント移動制限の通知を受け取る。\r
+     * {@link #JOINT_LIST}ループの構成要素。\r
+     * ※(制限端その1<=その2)条件を満たす必要はあるか?\r
+     * @param posXlim1 X座標制限端その1\r
+     * @param posXlim2 X座標制限端その2\r
+     * @param posYlim1 Y座標制限端その1\r
+     * @param posYlim2 Y座標制限端その2\r
+     * @param posZlim1 Z座標制限端その1\r
+     * @param posZlim2 Z座標制限端その2\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示。\r
+     */\r
+    void pmdPositionLimit(float posXlim1, float posXlim2,\r
+                            float posYlim1, float posYlim2,\r
+                            float posZlim1, float posZlim2 )\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * ジョイント回転制限の通知を受け取る。\r
+     * {@link #JOINT_LIST}ループの構成要素。\r
+     * ※(制限端その1<=その2)条件を満たす必要はあるか?\r
+     * @param radXlim1 X軸制限端その1(radian)\r
+     * @param radXlim2 X軸制限端その2(radian)\r
+     * @param radYlim1 Y軸制限端その1(radian)\r
+     * @param radYlim2 Y軸制限端その2(radian)\r
+     * @param radZlim1 Z軸制限端その1(radian)\r
+     * @param radZlim2 Z軸制限端その2(radian)\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示。\r
+     */\r
+    void pmdRotationLimit(float radXlim1, float radXlim2,\r
+                            float radYlim1, float radYlim2,\r
+                            float radZlim1, float radZlim2 )\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * ジョイントのばね移動情報の通知を受け取る。\r
+     * {@link #JOINT_LIST}ループの構成要素。\r
+     * @param elasticPosX X座標\r
+     * @param elasticPosY Y座標\r
+     * @param elasticPosZ Z座標\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示。\r
+     */\r
+    void pmdElasticPosition(float elasticPosX,\r
+                               float elasticPosY,\r
+                               float elasticPosZ )\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * ジョイントのばね回転情報の通知を受け取る。\r
+     * {@link #JOINT_LIST}ループの構成要素。\r
+     * @param elasticDegX X軸変量(degree)\r
+     * @param elasticDegY Y軸変量(degree)\r
+     * @param elasticDegZ Z軸変量(degree)\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示。\r
+     */\r
+    void pmdElasticRotation(float elasticDegX,\r
+                               float elasticDegY,\r
+                               float elasticDegZ )\r
+        throws MmdFormatException;\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdLimits.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdLimits.java
new file mode 100644 (file)
index 0000000..09daa2b
--- /dev/null
@@ -0,0 +1,81 @@
+/*\r
+ * pmd limit numbers\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.CommonParser;\r
+\r
+/**\r
+ * PMDファイルフォーマットの各種リミット値その他定数。\r
+ */\r
+public final class PmdLimits {\r
+\r
+    /** モデル名最大長。バイト単位。 */\r
+    public static final int MAXBYTES_MODELNAME = 20;\r
+\r
+    /** モデル説明文最大長。バイト単位。 */\r
+    public static final int MAXBYTES_MODELDESC = 256;\r
+\r
+    /** ボーン名最大長。バイト単位。 */\r
+    public static final int MAXBYTES_BONENAME = 20;\r
+\r
+    /** モーフ名最大長。バイト単位。 */\r
+    public static final int MAXBYTES_MORPHNAME = 20;\r
+\r
+    /** ボーングループ名最大長。バイト単位。 */\r
+    public static final int MAXBYTES_BONEGROUPNAME = 50;\r
+\r
+    /** テクスチャファイル名最大長。バイト単位。 */\r
+    public static final int MAXBYTES_TEXTUREFILENAME = 20;\r
+\r
+    /** 独自トゥーンテクスチャファイル名の最大長。バイト単位。 */\r
+    public static final int MAXBYTES_TOONFILENAME = 100;\r
+\r
+    /** 剛体名最大長。バイト単位。 */\r
+    public static final int MAXBYTES_RIGIDNAME = 20;\r
+\r
+    /** ジョイント名最大長。バイト単位。 */\r
+    public static final int MAXBYTES_JOINTNAME = 20;\r
+\r
+\r
+    /**\r
+     * ボーン最大数。\r
+     * (Id : 0 - 0xfffe)\r
+     * MMDがいくつまで受け入れるかはまた別の話だよ。\r
+     */\r
+    public static final int MAX_BONE = 65535;\r
+\r
+    /** 剛体衝突グループ総数。 */\r
+    public static final int RIGIDGROUP_FIXEDNUM = 16;\r
+\r
+    /** 独自トゥーンテクスチャファイル名テーブルの固定数。 */\r
+    public static final int TOON_FIXEDNUM = 10;\r
+\r
+\r
+    static{\r
+        assert CommonParser.TEXTBUF_SZ >= MAXBYTES_MODELNAME;\r
+        assert CommonParser.TEXTBUF_SZ >= MAXBYTES_MODELDESC;\r
+        assert CommonParser.TEXTBUF_SZ >= MAXBYTES_BONENAME;\r
+        assert CommonParser.TEXTBUF_SZ >= MAXBYTES_MORPHNAME;\r
+        assert CommonParser.TEXTBUF_SZ >= MAXBYTES_BONEGROUPNAME;\r
+        assert CommonParser.TEXTBUF_SZ >= MAXBYTES_TEXTUREFILENAME;\r
+        assert CommonParser.TEXTBUF_SZ >= MAXBYTES_TOONFILENAME;\r
+        assert CommonParser.TEXTBUF_SZ >= MAXBYTES_RIGIDNAME;\r
+        assert CommonParser.TEXTBUF_SZ >= MAXBYTES_JOINTNAME;\r
+    }\r
+\r
+\r
+    /**\r
+     * 隠しコンストラクタ。\r
+     */\r
+    private PmdLimits(){\r
+        super();\r
+        assert false;\r
+        throw new AssertionError();\r
+    }\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdMaterialHandler.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdMaterialHandler.java
new file mode 100644 (file)
index 0000000..f0d51f7
--- /dev/null
@@ -0,0 +1,100 @@
+/*\r
+ * PMD material information handler\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.LoopHandler;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.ParseStage;\r
+\r
+/**\r
+ * PMDモデルの各種材質情報の通知用ハンドラ。\r
+ * 色空間はsRGB?\r
+ */\r
+public interface PmdMaterialHandler extends LoopHandler {\r
+\r
+    /**\r
+     * モデル材質パースステージ。\r
+     */\r
+    class PmdMaterialStage extends ParseStage{\r
+        /** コンストラクタ。 */\r
+        PmdMaterialStage(){ super(); return; }\r
+    }\r
+\r
+    /** 材質抽出ループ。 */\r
+    PmdMaterialStage MATERIAL_LIST = new PmdMaterialStage();\r
+\r
+    /**\r
+     * 材質の拡散光成分の通知を受け取る。\r
+     * {@link #MATERIAL_LIST}ループの構成要素。\r
+     * @param red 0.0~1.0の範囲の赤成分\r
+     * @param green 0.0~1.0の範囲の緑成分\r
+     * @param blue 0.0~1.0の範囲の青成分\r
+     * @param alpha 0.0(透明)~1.0(不透明)のアルファ値。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdMaterialDiffuse(float red, float green, float blue,\r
+                               float alpha )\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * 材質の反射光成分の通知を受け取る。\r
+     * {@link #MATERIAL_LIST}ループの構成要素。\r
+     * @param red 0.0~1.0の範囲の赤成分\r
+     * @param green 0.0~1.0の範囲の緑成分\r
+     * @param blue 0.0~1.0の範囲の青成分\r
+     * @param shininess 光沢強度(1~15ぐらい)\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdMaterialSpecular(float red, float green, float blue,\r
+                                float shininess)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * 材質の環境色成分の通知を受け取る。\r
+     * {@link #MATERIAL_LIST}ループの構成要素。\r
+     * @param red 0.0~1.0の範囲の赤成分\r
+     * @param green 0.0~1.0の範囲の緑成分\r
+     * @param blue 0.0~1.0の範囲の青成分\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdMaterialAmbient(float red, float green, float blue)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * シェーディング情報の通知を受け取る。\r
+     * {@link #MATERIAL_LIST}ループの構成要素。\r
+     * @param toonIdx トゥーンファイル番号。\r
+     * 0ならtoon01.bmp。9ならtoon10.bmp。0xffならtoon0.bmp。\r
+     * @param textureFile テクスチャファイル名。\r
+     * 無ければ空文字。\r
+     * @param sphereFile スフィアマップファイル名。\r
+     * 無ければ空文字。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdMaterialShading(int toonIdx,\r
+                               String textureFile, String sphereFile )\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * 材質情報の通知を受け取る。\r
+     * {@link #MATERIAL_LIST}ループの構成要素。\r
+     * @param hasEdge エッジを表示するならtrue\r
+     * @param vertexNum 面頂点数。\r
+     * 3の倍数のはず。\r
+     * 3で割ると積算で表される面IDの範囲を表す。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdMaterialInfo(boolean hasEdge, int vertexNum)\r
+            throws MmdFormatException;\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdMorphHandler.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdMorphHandler.java
new file mode 100644 (file)
index 0000000..eb36cd3
--- /dev/null
@@ -0,0 +1,77 @@
+/*\r
+ * PMD morph information handler\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.LoopHandler;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.ParseStage;\r
+\r
+/**\r
+ * PMDモデルのモーフ情報の通知用ハンドラ。\r
+ */\r
+public interface PmdMorphHandler extends LoopHandler {\r
+\r
+    /**\r
+     * モーフ情報パースステージ。\r
+     */\r
+    class PmdMorphStage extends ParseStage{\r
+        /** コンストラクタ。 */\r
+        PmdMorphStage(){ super(); return; }\r
+    }\r
+\r
+    /** モーフ抽出ループ。 */\r
+    PmdMorphStage MORPH_LIST = new PmdMorphStage();\r
+\r
+    /** モーフ頂点抽出ループ。 */\r
+    PmdMorphStage MORPHVERTEX_LIST = new PmdMorphStage();\r
+\r
+    /** モーフ出現順抽出ループ。 */\r
+    PmdMorphStage MORPHORDER_LIST = new PmdMorphStage();\r
+\r
+    /**\r
+     * モーフ情報の通知を受け取る。\r
+     * {@link #MORPH_LIST}ループの構成要素\r
+     * @param morphName モーフ名\r
+     * @param morphType モーフ種別。\r
+     * <ul>\r
+     * <li>0:base\r
+     * <li>1:まゆ\r
+     * <li>2:目\r
+     * <li>3:リップ\r
+     * <li>4:その他\r
+     * </ul>\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdMorphInfo(String morphName, byte morphType)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * モーフ形状の通知を受け取る。\r
+     * {@link #MORPH_LIST}ループの下位{@link #MORPHVERTEX_LIST}の構成要素\r
+     * @param serialId base型の場合は頂点ID、それ以外はモーフ頂点ID\r
+     * @param xPos base型の場合はX座標、それ以外はX軸変位\r
+     * @param yPos base型の場合はY座標、それ以外はY軸変位\r
+     * @param zPos base型の場合はZ座標、それ以外はZ軸変位\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdMorphVertexInfo(int serialId,\r
+                               float xPos, float yPos, float zPos)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * 各モーフ種別内のGUI表示順の通知を受け取る。\r
+     * {@link #MORPHORDER_LIST}ループの構成要素\r
+     * @param morphId モーフ通し番号。同一種別内の大小関係のみ意味がある。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdMorphOrderInfo(int morphId) throws MmdFormatException;\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParser.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParser.java
new file mode 100644 (file)
index 0000000..ca77571
--- /dev/null
@@ -0,0 +1,29 @@
+/*\r
+ * pmd file parser (up to date)\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.MmdSource;\r
+\r
+/**\r
+ * PMDモデルファイルのパーサ最新版。\r
+ * 将来のリリースにおいて、\r
+ * 常に最新のPMDモデルファイルフォーマットに対応したパーサの\r
+ * 別名であることが保証される。つもり。\r
+ */\r
+public class PmdParser extends PmdParserExt3{\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param source 入力ソース\r
+     */\r
+    public PmdParser(MmdSource source){\r
+        super(source);\r
+        return;\r
+    }\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserBase.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserBase.java
new file mode 100644 (file)
index 0000000..8a45f6b
--- /dev/null
@@ -0,0 +1,642 @@
+/*\r
+ * pmd file parser\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import java.io.IOException;\r
+import jp.sourceforge.mikutoga.parser.CommonParser;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.MmdSource;\r
+\r
+/**\r
+ * PMDモデルファイルのパーサ基本部。\r
+ */\r
+public class PmdParserBase extends CommonParser {\r
+\r
+    /** 改行文字列 CR。 */\r
+    protected static final String CR = "\r";       // 0x0d\r
+    /** 改行文字列 LF。 */\r
+    protected static final String LF = "\n";       // 0x0a\r
+    /** 改行文字列 CRLF。 */\r
+    protected static final String CRLF = CR + LF;  // 0x0d, 0x0a\r
+\r
+    private static final String MAGIC = "Pmd";\r
+    private static final int MAGIC_SZ = MAGIC.getBytes(CS_WIN31J).length;\r
+\r
+    private static final int VERTEX_DATA_SZ      = 38;\r
+    private static final int SURFACE_DATA_SZ     =  6;\r
+    private static final int MATERIAL_DATA_SZ    = 70;\r
+    private static final int BONE_DATA_SZ        = 39;\r
+    private static final int MORPHVERTEX_DATA_SZ = 16;\r
+    private static final int MORPHORDER_DATA_SZ  =  2;\r
+    private static final int BONEGROUP_DATA_SZ   = 50;\r
+    private static final int GROUPEDBONE_DATA_SZ =  3;\r
+\r
+\r
+    private PmdBasicHandler basicHandler = null;\r
+    private PmdShapeHandler shapeHandler = null;\r
+    private PmdMaterialHandler materialHandler = null;\r
+    private PmdBoneHandler boneHandler = null;\r
+    private PmdMorphHandler morphHandler = null;\r
+\r
+    private int boneCount      = -1;\r
+    private int morphCount     = -1;\r
+    private int boneGroupCount = -1;\r
+\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param source 入力ソース\r
+     */\r
+    public PmdParserBase(MmdSource source){\r
+        super(source);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 文字列の最後がLF(0x0a)の場合削除する。\r
+     * @param name 文字列\r
+     * @return 末尾LFが削除された文字列\r
+     */\r
+    public static String chopLastLF(String name){\r
+        String result;\r
+\r
+        if(name.endsWith(LF)){\r
+            result = name.substring(0, name.length() - 1);\r
+        }else{\r
+            result = name;\r
+        }\r
+\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * シェーディング用ファイル情報から\r
+     * テクスチャファイル名とスフィアマップファイル名を分離する。\r
+     * @param shadingFile シェーディング用ファイル情報\r
+     * @return [0]:テクスチャファイル名 [1]:スフィアマップファイル名。\r
+     * 該当ファイル名が無い場合は空文字列。\r
+     */\r
+    public static String[] splitShadingFileInfo(String shadingFile){\r
+        String[] result;\r
+\r
+        result = shadingFile.split('\\'+"*", 2);\r
+        assert result.length == 1 || result.length == 2;\r
+\r
+        if(result.length == 1){\r
+            String onlyFile = result[0];\r
+            result = new String[2];\r
+            result[0] = "";\r
+            result[1] = "";\r
+            if(onlyFile.endsWith(".sph") || onlyFile.endsWith(".spa")){\r
+                result[1] = onlyFile;\r
+            }else{\r
+                result[0] = onlyFile;\r
+            }\r
+        }\r
+\r
+        assert result.length == 2;\r
+\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * 基本情報通知ハンドラを登録する。\r
+     * @param handler ハンドラ\r
+     */\r
+    public void setBasicHandler(PmdBasicHandler handler){\r
+        this.basicHandler = handler;\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 形状情報通知ハンドラを登録する。\r
+     * @param handler ハンドラ\r
+     */\r
+    public void setShapeHandler(PmdShapeHandler handler){\r
+        this.shapeHandler = handler;\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 材質情報通知ハンドラを登録する。\r
+     * @param handler ハンドラ\r
+     */\r
+    public void setMaterialHandler(PmdMaterialHandler handler){\r
+        this.materialHandler = handler;\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * ボーン情報通知ハンドラを登録する。\r
+     * @param handler ハンドラ\r
+     */\r
+    public void setBoneHandler(PmdBoneHandler handler){\r
+        this.boneHandler = handler;\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * モーフ情報通知ハンドラを登録する。\r
+     * @param handler ハンドラ\r
+     */\r
+    public void setMorphHandler(PmdMorphHandler handler){\r
+        this.morphHandler = handler;\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * パースによって得られたボーン数を返す。\r
+     * @return ボーン数\r
+     */\r
+    protected int getBoneCount(){\r
+        return this.boneCount;\r
+    }\r
+\r
+    /**\r
+     * パースによって得られたモーフ数を返す。\r
+     * @return モーフ数\r
+     */\r
+    protected int getMorphCount(){\r
+        return this.morphCount;\r
+    }\r
+\r
+    /**\r
+     * パースによって得られたボーングループ数を返す。\r
+     * @return ボーングループ数\r
+     */\r
+    protected int getBoneGroupCount(){\r
+        return this.boneGroupCount;\r
+    }\r
+\r
+    /**\r
+     * PMDファイルのパースを開始する。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    public void parsePmd()\r
+            throws IOException, MmdFormatException {\r
+        if(this.basicHandler != null){\r
+            this.basicHandler.pmdParseStart();\r
+        }\r
+\r
+        parseBody();\r
+\r
+        boolean hasMoreData = hasMore();\r
+        if(this.basicHandler != null){\r
+            this.basicHandler.pmdParseEnd(hasMoreData);\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * PMDファイル本体のパースを開始する。\r
+     * パーサを拡張する場合はこのメソッドをオーバーライドする。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    protected void parseBody() throws IOException, MmdFormatException{\r
+        parsePmdHeader();\r
+\r
+        parseVertexList();\r
+        parseSurfaceList();\r
+        parseMaterialList();\r
+        parseBoneList();\r
+        parseIKList();\r
+        parseMorphList();\r
+        parseMorphOrderList();\r
+        parseBoneGroupList();\r
+        parseGroupedBoneList();\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * PMDファイルヘッダ部のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parsePmdHeader() throws IOException, MmdFormatException{\r
+        String magic = parseZeroTermString(MAGIC_SZ);\r
+        if( ! magic.equals(MAGIC) ){\r
+            throw new MmdFormatException("unrecognized magic data");\r
+        }\r
+\r
+        float ver = parseFloat();\r
+        String modelName   =\r
+                parseZeroTermString(PmdLimits.MAXBYTES_MODELNAME);\r
+        String description =\r
+                parseZeroTermString(PmdLimits.MAXBYTES_MODELDESC);\r
+        description = description.replace(CRLF, LF);\r
+\r
+        if(this.basicHandler != null){\r
+            this.basicHandler.pmdHeaderInfo(ver);\r
+            this.basicHandler.pmdModelInfo(modelName, description);\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 頂点情報のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseVertexList() throws IOException, MmdFormatException{\r
+        int vertexNum = parseInteger();\r
+\r
+        if(this.shapeHandler == null){\r
+            skip(VERTEX_DATA_SZ * vertexNum);\r
+            return;\r
+        }\r
+\r
+        this.shapeHandler.loopStart(PmdShapeHandler.VERTEX_LIST, vertexNum);\r
+\r
+        for(int ct = 0; ct < vertexNum; ct++){\r
+            float xPos = parseFloat();\r
+            float yPos = parseFloat();\r
+            float zPos = parseFloat();\r
+            this.shapeHandler.pmdVertexPosition(xPos, yPos, zPos);\r
+\r
+            float xVec = parseFloat();\r
+            float yVec = parseFloat();\r
+            float zVec = parseFloat();\r
+            this.shapeHandler.pmdVertexNormal(xVec, yVec, zVec);\r
+\r
+            float uVal = parseFloat();\r
+            float vVal = parseFloat();\r
+            this.shapeHandler.pmdVertexUV(uVal, vVal);\r
+\r
+            int boneId1 = parseUShortAsInteger();\r
+            int boneId2 = parseUShortAsInteger();\r
+            int weightForB1 = parseUByteAsInteger();\r
+            this.shapeHandler.pmdVertexWeight(boneId1, boneId2, weightForB1);\r
+\r
+            boolean hideEdge = parseBoolean();\r
+            this.shapeHandler.pmdVertexEdge(hideEdge);\r
+\r
+            this.shapeHandler.loopNext(PmdShapeHandler.VERTEX_LIST);\r
+        }\r
+\r
+        this.shapeHandler.loopEnd(PmdShapeHandler.VERTEX_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 面情報のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseSurfaceList() throws IOException, MmdFormatException{\r
+        int vertexNum = parseInteger();\r
+        if(vertexNum % 3 != 0) throw new MmdFormatException();\r
+        int surfaceNum = vertexNum / 3;\r
+\r
+        if(this.shapeHandler == null){\r
+            skip(SURFACE_DATA_SZ * surfaceNum);\r
+            return;\r
+        }\r
+\r
+        this.shapeHandler.loopStart(PmdShapeHandler.SURFACE_LIST, surfaceNum);\r
+\r
+        for(int ct = 0; ct < surfaceNum; ct++){\r
+            int vertexId1 = parseUShortAsInteger();\r
+            int vertexId2 = parseUShortAsInteger();\r
+            int vertexId3 = parseUShortAsInteger();\r
+            this.shapeHandler.pmdSurfaceTriangle(vertexId1,\r
+                                                 vertexId2,\r
+                                                 vertexId3 );\r
+            this.shapeHandler.loopNext(PmdShapeHandler.SURFACE_LIST);\r
+        }\r
+\r
+        this.shapeHandler.loopEnd(PmdShapeHandler.SURFACE_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 材質情報のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseMaterialList() throws IOException, MmdFormatException{\r
+        int materialNum = parseInteger();\r
+\r
+        if(this.materialHandler == null){\r
+            skip(MATERIAL_DATA_SZ * materialNum);\r
+            return;\r
+        }\r
+\r
+        this.materialHandler.loopStart(PmdMaterialHandler.MATERIAL_LIST,\r
+                                       materialNum );\r
+\r
+        for(int ct = 0; ct < materialNum; ct++){\r
+            float red;\r
+            float green;\r
+            float blue;\r
+\r
+            red   = parseFloat();\r
+            green = parseFloat();\r
+            blue  = parseFloat();\r
+            float alpha = parseFloat();\r
+            this.materialHandler.pmdMaterialDiffuse(red, green, blue, alpha);\r
+\r
+            float shininess = parseFloat();\r
+            red   = parseFloat();\r
+            green = parseFloat();\r
+            blue  = parseFloat();\r
+            this.materialHandler.pmdMaterialSpecular(red, green, blue,\r
+                                                     shininess);\r
+\r
+            red   = parseFloat();\r
+            green = parseFloat();\r
+            blue  = parseFloat();\r
+            this.materialHandler.pmdMaterialAmbient(red, green, blue);\r
+\r
+            int toonidx = parseUByteAsInteger();\r
+            boolean hasEdge = parseBoolean();\r
+            int surfaceCount = parseInteger();\r
+            String shadingFile =\r
+                    parseZeroTermString(PmdLimits.MAXBYTES_TEXTUREFILENAME);\r
+            String[] splitted = splitShadingFileInfo(shadingFile);\r
+            String textureFile = splitted[0];\r
+            String sphereFile = splitted[1];\r
+\r
+            this.materialHandler.pmdMaterialShading(toonidx,\r
+                                                    textureFile, sphereFile );\r
+            this.materialHandler.pmdMaterialInfo(hasEdge, surfaceCount);\r
+\r
+            this.materialHandler.loopNext(PmdMaterialHandler.MATERIAL_LIST);\r
+        }\r
+\r
+        this.materialHandler.loopEnd(PmdMaterialHandler.MATERIAL_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * ボーン情報のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseBoneList() throws IOException, MmdFormatException{\r
+        this.boneCount = parseUShortAsInteger();\r
+\r
+        if(this.boneHandler == null){\r
+            skip(BONE_DATA_SZ * this.boneCount);\r
+            return;\r
+        }\r
+\r
+        this.boneHandler.loopStart(PmdBoneHandler.BONE_LIST, this.boneCount);\r
+\r
+        for(int ct = 0; ct < this.boneCount; ct++){\r
+            String boneName =\r
+                    parseZeroTermString(PmdLimits.MAXBYTES_BONENAME);\r
+            int parentId = parseUShortAsInteger();\r
+            int tailId = parseUShortAsInteger();\r
+            byte boneKind = parseByte();\r
+            int ikId = parseUShortAsInteger();\r
+\r
+            this.boneHandler.pmdBoneInfo(boneName, boneKind);\r
+            this.boneHandler.pmdBoneLink(parentId, tailId, ikId);\r
+\r
+            float xPos = parseFloat();\r
+            float yPos = parseFloat();\r
+            float zPos = parseFloat();\r
+\r
+            this.boneHandler.pmdBonePosition(xPos, yPos, zPos);\r
+\r
+            this.boneHandler.loopNext(PmdBoneHandler.BONE_LIST);\r
+        }\r
+\r
+        this.boneHandler.loopEnd(PmdBoneHandler.BONE_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * IKリスト情報のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseIKList() throws IOException, MmdFormatException{\r
+        int ikCount = parseUShortAsInteger();\r
+\r
+        if(this.boneHandler != null){\r
+            this.boneHandler.loopStart(PmdBoneHandler.IK_LIST, ikCount);\r
+        }\r
+\r
+        for(int ct = 0; ct < ikCount; ct++){\r
+            int boneId = parseUShortAsInteger();\r
+            int targetId = parseUShortAsInteger();\r
+            int chainLength = parseUByteAsInteger();\r
+            int depth = parseUShortAsInteger();\r
+            float weight = parseFloat();\r
+\r
+            parseIKChainList(chainLength);\r
+\r
+            if(this.boneHandler != null){\r
+                this.boneHandler.pmdIKInfo(boneId, targetId, depth, weight);\r
+                this.boneHandler.loopNext(PmdBoneHandler.IK_LIST);\r
+            }\r
+        }\r
+\r
+        if(this.boneHandler != null){\r
+            this.boneHandler.loopEnd(PmdBoneHandler.IK_LIST);\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * IKチェーン情報のパースと通知。\r
+     * @param chainLength チェーン長\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseIKChainList(int chainLength)\r
+            throws IOException, MmdFormatException{\r
+        if(this.boneHandler != null){\r
+            this.boneHandler.loopStart(PmdBoneHandler.IKCHAIN_LIST,\r
+                                       chainLength);\r
+        }\r
+\r
+        for(int ct = 0; ct < chainLength; ct++){\r
+            int childId = parseUShortAsInteger();\r
+            if(this.boneHandler != null){\r
+                this.boneHandler.pmdIKChainInfo(childId);\r
+                this.boneHandler.loopNext(PmdBoneHandler.IKCHAIN_LIST);\r
+            }\r
+        }\r
+\r
+        if(this.boneHandler != null){\r
+            this.boneHandler.loopEnd(PmdBoneHandler.IKCHAIN_LIST);\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * モーフ情報のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseMorphList() throws IOException, MmdFormatException{\r
+        this.morphCount = parseUShortAsInteger();\r
+\r
+        if(this.morphHandler != null){\r
+            this.morphHandler.loopStart(PmdMorphHandler.MORPH_LIST,\r
+                                        this.morphCount );\r
+        }\r
+\r
+        for(int ct = 0; ct < this.morphCount; ct++){\r
+            String morphName =\r
+                    parseZeroTermString(PmdLimits.MAXBYTES_MORPHNAME);\r
+            int vertexCount = parseInteger();\r
+            byte morphType = parseByte();\r
+\r
+            if(this.morphHandler != null){\r
+                this.morphHandler.pmdMorphInfo(morphName, morphType);\r
+            }\r
+\r
+            parseMorphVertexList(vertexCount);\r
+\r
+            if(this.morphHandler != null){\r
+                this.morphHandler.loopNext(PmdMorphHandler.MORPH_LIST);\r
+            }\r
+        }\r
+\r
+        if(this.morphHandler != null){\r
+            this.morphHandler.loopEnd(PmdMorphHandler.MORPH_LIST);\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * モーフ形状のパースと通知。\r
+     * @param vertexCount 頂点数\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseMorphVertexList(int vertexCount)\r
+            throws IOException, MmdFormatException{\r
+        if(this.morphHandler == null){\r
+            skip(MORPHVERTEX_DATA_SZ * vertexCount);\r
+            return;\r
+        }\r
+\r
+        this.morphHandler.loopStart(PmdMorphHandler.MORPHVERTEX_LIST,\r
+                                    vertexCount );\r
+\r
+        for(int ct = 0; ct < vertexCount; ct++){\r
+            int vertexId = parseInteger();\r
+            float xPos = parseFloat();\r
+            float yPos = parseFloat();\r
+            float zPos = parseFloat();\r
+            this.morphHandler.pmdMorphVertexInfo(vertexId, xPos, yPos, zPos);\r
+            this.morphHandler.loopNext(PmdMorphHandler.MORPHVERTEX_LIST);\r
+        }\r
+\r
+        this.morphHandler.loopEnd(PmdMorphHandler.MORPHVERTEX_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * モーフGUI表示順のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseMorphOrderList()\r
+            throws IOException, MmdFormatException{\r
+        int morphOrderCount = parseUByteAsInteger();\r
+\r
+        if(this.morphHandler == null){\r
+            skip(MORPHORDER_DATA_SZ * morphOrderCount);\r
+            return;\r
+        }\r
+\r
+        this.morphHandler.loopStart(PmdMorphHandler.MORPHORDER_LIST,\r
+                                    morphOrderCount );\r
+\r
+        for(int ct = 0; ct < morphOrderCount; ct++){\r
+            int morphId = parseUShortAsInteger();\r
+            this.morphHandler.pmdMorphOrderInfo(morphId);\r
+\r
+            this.morphHandler.loopNext(PmdMorphHandler.MORPHORDER_LIST);\r
+        }\r
+\r
+        this.morphHandler.loopEnd(PmdMorphHandler.MORPHORDER_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * ボーングループ名のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseBoneGroupList()\r
+            throws IOException, MmdFormatException{\r
+        this.boneGroupCount = parseUByteAsInteger();\r
+\r
+        if(this.boneHandler == null){\r
+            skip(BONEGROUP_DATA_SZ * this.boneGroupCount);\r
+            return;\r
+        }\r
+\r
+        this.boneHandler.loopStart(PmdBoneHandler.BONEGROUP_LIST,\r
+                                   this.boneGroupCount);\r
+\r
+        for(int ct = 0; ct < this.boneGroupCount; ct++){\r
+            String groupName =\r
+                    parseZeroTermString(PmdLimits.MAXBYTES_BONEGROUPNAME);\r
+            groupName = chopLastLF(groupName);\r
+            this.boneHandler.pmdBoneGroupInfo(groupName);\r
+\r
+            this.boneHandler.loopNext(PmdBoneHandler.BONEGROUP_LIST);\r
+        }\r
+\r
+        this.boneHandler.loopEnd(PmdBoneHandler.BONEGROUP_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * ボーングループ内訳のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseGroupedBoneList()\r
+            throws IOException, MmdFormatException{\r
+        int groupedBoneCount = parseInteger();\r
+\r
+        if(this.boneHandler == null){\r
+            skip(GROUPEDBONE_DATA_SZ * groupedBoneCount);\r
+            return;\r
+        }\r
+\r
+        this.boneHandler.loopStart(PmdBoneHandler.GROUPEDBONE_LIST,\r
+                                   groupedBoneCount);\r
+\r
+        for(int ct = 0; ct < groupedBoneCount; ct++){\r
+            int boneId = parseUShortAsInteger();\r
+            int groupId = parseUByteAsInteger();\r
+            this.boneHandler.pmdGroupedBoneInfo(boneId, groupId);\r
+\r
+            this.boneHandler.loopNext(PmdBoneHandler.GROUPEDBONE_LIST);\r
+        }\r
+\r
+        this.boneHandler.loopEnd(PmdBoneHandler.GROUPEDBONE_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserExt1.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserExt1.java
new file mode 100644 (file)
index 0000000..cffe8d9
--- /dev/null
@@ -0,0 +1,177 @@
+/*\r
+ * pmd parser extension 1\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import java.io.IOException;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.MmdSource;\r
+\r
+/**\r
+ * PMDモデルファイルのパーサ拡張その1。\r
+ * ※英名対応\r
+ */\r
+public class PmdParserExt1 extends PmdParserBase {\r
+\r
+    private PmdEngHandler engHandler = null;\r
+    private boolean hasEnglishInfo = true;\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param source 入力ソース\r
+     */\r
+    public PmdParserExt1(MmdSource source){\r
+        super(source);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 英語ハンドラを登録する。\r
+     * @param handler ハンドラ\r
+     */\r
+    public void setEngHandler(PmdEngHandler handler){\r
+        this.engHandler = handler;\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * {@inheritDoc}\r
+     * @throws IOException {@inheritDoc}\r
+     * @throws MmdFormatException {@inheritDoc}\r
+     */\r
+    @Override\r
+    protected void parseBody()\r
+            throws IOException, MmdFormatException{\r
+        super.parseBody();\r
+\r
+        if(hasMore()){\r
+            parseEngHeader();\r
+            if(this.hasEnglishInfo){\r
+                parseEngBoneList();\r
+                parseEngMorphName();\r
+                parseEngBoneGroupName();\r
+            }\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * PMDモデル英語基本情報のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseEngHeader()\r
+            throws IOException, MmdFormatException{\r
+        this.hasEnglishInfo = parseBoolean();\r
+\r
+        if(this.engHandler != null){\r
+            this.engHandler.pmdEngEnabled(this.hasEnglishInfo);\r
+        }\r
+        if( ! this.hasEnglishInfo ) return;\r
+\r
+        String modelName =\r
+                parseZeroTermString(PmdLimits.MAXBYTES_MODELNAME);\r
+        String description =\r
+                parseZeroTermString(PmdLimits.MAXBYTES_MODELDESC);\r
+        description = description.replace(CRLF, LF);\r
+\r
+        if(this.engHandler != null){\r
+            this.engHandler.pmdEngModelInfo(modelName, description);\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * PMDモデル英語ボーン名のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseEngBoneList()\r
+            throws IOException, MmdFormatException{\r
+        int boneNum = getBoneCount();\r
+\r
+        if(this.engHandler == null){\r
+            skip(PmdLimits.MAXBYTES_BONENAME * boneNum);\r
+            return;\r
+        }\r
+\r
+        this.engHandler.loopStart(PmdEngHandler.ENGBONE_LIST, boneNum);\r
+\r
+        for(int ct = 0; ct < boneNum; ct++){\r
+            String boneName =\r
+                    parseZeroTermString(PmdLimits.MAXBYTES_BONENAME);\r
+            this.engHandler.pmdEngBoneInfo(boneName);\r
+\r
+            this.engHandler.loopNext(PmdEngHandler.ENGBONE_LIST);\r
+        }\r
+\r
+        this.engHandler.loopEnd(PmdEngHandler.ENGBONE_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * PMDモデル英語モーフ名のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseEngMorphName()\r
+            throws IOException, MmdFormatException{\r
+        int morphNum = getMorphCount() - 1;  // base は英名なし\r
+\r
+        if(this.engHandler == null){\r
+            skip(PmdLimits.MAXBYTES_MORPHNAME * morphNum);\r
+            return;\r
+        }\r
+\r
+        this.engHandler.loopStart(PmdEngHandler.ENGMORPH_LIST, morphNum);\r
+\r
+        for(int ct = 0; ct < morphNum; ct++){\r
+            String morphName =\r
+                    parseZeroTermString(PmdLimits.MAXBYTES_MORPHNAME);\r
+            this.engHandler.pmdEngMorphInfo(morphName);\r
+\r
+            this.engHandler.loopNext(PmdEngHandler.ENGMORPH_LIST);\r
+        }\r
+\r
+        this.engHandler.loopEnd(PmdEngHandler.ENGMORPH_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * PMDモデル英語ボーングループ名のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseEngBoneGroupName()\r
+            throws IOException, MmdFormatException{\r
+        int groupNum = getBoneGroupCount();\r
+\r
+        if(this.engHandler == null){\r
+            skip(PmdLimits.MAXBYTES_BONEGROUPNAME * groupNum);\r
+            return;\r
+        }\r
+\r
+        this.engHandler.loopStart(PmdEngHandler.ENGBONEGROUP_LIST, groupNum);\r
+\r
+        for(int ct = 0; ct < groupNum; ct++){\r
+            String boneGroupName =\r
+                    parseZeroTermString(PmdLimits.MAXBYTES_BONEGROUPNAME);\r
+            this.engHandler.pmdEngBoneGroupInfo(boneGroupName);\r
+\r
+            this.engHandler.loopNext(PmdEngHandler.ENGBONEGROUP_LIST);\r
+        }\r
+\r
+        this.engHandler.loopEnd(PmdEngHandler.ENGBONEGROUP_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserExt2.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserExt2.java
new file mode 100644 (file)
index 0000000..3088b63
--- /dev/null
@@ -0,0 +1,84 @@
+/*\r
+ * pmd parser extensin 2\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import java.io.IOException;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.MmdSource;\r
+\r
+/**\r
+ * PMDモデルファイルのパーサ拡張その2。\r
+ * ※独自トゥーンテクスチャファイル名対応\r
+ */\r
+public class PmdParserExt2 extends PmdParserExt1 {\r
+\r
+    private PmdToonHandler toonHandler = null;\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param source 入力ソース\r
+     */\r
+    public PmdParserExt2(MmdSource source){\r
+        super(source);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * トゥーンテクスチャファイルハンドラを登録する。\r
+     * @param handler ハンドラ\r
+     */\r
+    public void setToonHandler(PmdToonHandler handler){\r
+        this.toonHandler = handler;\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * {@inheritDoc}\r
+     * @throws IOException {@inheritDoc}\r
+     * @throws MmdFormatException {@inheritDoc}\r
+     */\r
+    @Override\r
+    protected void parseBody()\r
+            throws IOException, MmdFormatException{\r
+        super.parseBody();\r
+\r
+        if(hasMore()){\r
+            parseToonName();\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 独自トゥーンテクスチャファイル名のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseToonName() throws IOException, MmdFormatException{\r
+        if(this.toonHandler == null){\r
+            skip(PmdLimits.MAXBYTES_TOONFILENAME * PmdLimits.TOON_FIXEDNUM);\r
+            return;\r
+        }\r
+\r
+        this.toonHandler.loopStart(PmdToonHandler.TOON_LIST,\r
+                                   PmdLimits.TOON_FIXEDNUM );\r
+\r
+        for(int ct = 0; ct < PmdLimits.TOON_FIXEDNUM; ct++){\r
+            String toonName =\r
+                    parseZeroTermString(PmdLimits.MAXBYTES_TOONFILENAME);\r
+            this.toonHandler.pmdToonFileInfo(toonName);\r
+\r
+            this.toonHandler.loopNext(PmdToonHandler.TOON_LIST);\r
+        }\r
+\r
+        this.toonHandler.loopEnd(PmdToonHandler.TOON_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserExt3.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdParserExt3.java
new file mode 100644 (file)
index 0000000..a34272b
--- /dev/null
@@ -0,0 +1,208 @@
+/*\r
+ * pmd parser extension 3\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import java.io.IOException;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.MmdSource;\r
+\r
+/**\r
+ * PMDモデルファイルのパーサ拡張その3。\r
+ * ※剛体情報対応\r
+ */\r
+public class PmdParserExt3 extends PmdParserExt2 {\r
+\r
+    private static final int RIGID_DATA_SZ = 83;\r
+    private static final int JOINT_DATA_SZ = 124;\r
+\r
+    private PmdRigidHandler rigidHandler = null;\r
+    private PmdJointHandler jointHandler = null;\r
+\r
+    /**\r
+     * コンストラクタ。\r
+     * @param source 入力ソース\r
+     */\r
+    public PmdParserExt3(MmdSource source){\r
+        super(source);\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 剛体ハンドラを登録する。\r
+     * @param handler 剛体ハンドラ\r
+     */\r
+    public void setRigidHandler(PmdRigidHandler handler){\r
+        this.rigidHandler = handler;\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * ジョイントハンドラを登録する。\r
+     * @param handler ジョイントハンドラ\r
+     */\r
+    public void setJointHandler(PmdJointHandler handler){\r
+        this.jointHandler = handler;\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * {@inheritDoc}\r
+     * @throws IOException {@inheritDoc}\r
+     * @throws MmdFormatException {@inheritDoc}\r
+     */\r
+    @Override\r
+    protected void parseBody()\r
+            throws IOException, MmdFormatException {\r
+        super.parseBody();\r
+\r
+        if(hasMore()){\r
+            parseRigidList();\r
+            parseJointList();\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * 剛体情報のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseRigidList() throws IOException, MmdFormatException{\r
+        int rigidNum = parseInteger();\r
+\r
+        if(this.rigidHandler == null){\r
+            skip(RIGID_DATA_SZ * rigidNum);\r
+            return;\r
+        }\r
+\r
+        this.rigidHandler.loopStart(PmdRigidHandler.RIGID_LIST, rigidNum);\r
+\r
+        for(int ct = 0; ct < rigidNum; ct++){\r
+            String rigidName =\r
+                    parseZeroTermString(PmdLimits.MAXBYTES_RIGIDNAME);\r
+            this.rigidHandler.pmdRigidName(rigidName);\r
+\r
+            int linkedBoneId = parseUShortAsInteger();\r
+            int rigidGroupId = parseUByteAsInteger();\r
+            short collisionMap = parseShort();\r
+            this.rigidHandler.pmdRigidInfo(rigidGroupId, linkedBoneId);\r
+\r
+            byte shapeType = parseByte();\r
+            float width = parseFloat();\r
+            float height = parseFloat();\r
+            float depth = parseFloat();\r
+            this.rigidHandler.pmdRigidShape(shapeType, width, height, depth);\r
+\r
+            float posX = parseFloat();\r
+            float posY = parseFloat();\r
+            float posZ = parseFloat();\r
+            this.rigidHandler.pmdRigidPosition(posX, posY, posZ);\r
+\r
+            float rotX = parseFloat();\r
+            float rotY = parseFloat();\r
+            float rotZ = parseFloat();\r
+            this.rigidHandler.pmdRigidRotation(rotX, rotY, rotZ);\r
+\r
+            float mass = parseFloat();\r
+            float dampingPos = parseFloat();\r
+            float dampingRot = parseFloat();\r
+            float restitution = parseFloat();\r
+            float friction = parseFloat();\r
+            this.rigidHandler.pmdRigidPhysics(mass,\r
+                                              dampingPos, dampingRot,\r
+                                              restitution, friction );\r
+\r
+            byte behaveType = parseByte();\r
+            this.rigidHandler.pmdRigidBehavior(behaveType, collisionMap);\r
+\r
+            this.rigidHandler.loopNext(PmdRigidHandler.RIGID_LIST);\r
+        }\r
+\r
+        this.rigidHandler.loopEnd(PmdRigidHandler.RIGID_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * ジョイント情報のパースと通知。\r
+     * @throws IOException IOエラー\r
+     * @throws MmdFormatException フォーマットエラー\r
+     */\r
+    private void parseJointList() throws IOException, MmdFormatException{\r
+        int jointNum = parseInteger();\r
+\r
+        if(this.jointHandler == null){\r
+            skip(JOINT_DATA_SZ * jointNum);\r
+            return;\r
+        }\r
+\r
+        this.jointHandler.loopStart(PmdJointHandler.JOINT_LIST, jointNum);\r
+\r
+        for(int ct = 0; ct < jointNum; ct++){\r
+            String jointName =\r
+                    parseZeroTermString(PmdLimits.MAXBYTES_JOINTNAME);\r
+            this.jointHandler.pmdJointName(jointName);\r
+\r
+            int rigidIdA = parseInteger();\r
+            int rigidIdB = parseInteger();\r
+            this.jointHandler.pmdJointLink(rigidIdA, rigidIdB);\r
+\r
+            float posX = parseFloat();\r
+            float posY = parseFloat();\r
+            float posZ = parseFloat();\r
+            this.jointHandler.pmdJointPosition(posX, posY, posZ);\r
+\r
+            float rotX = parseFloat();\r
+            float rotY = parseFloat();\r
+            float rotZ = parseFloat();\r
+            this.jointHandler.pmdJointRotation(rotX, rotY, rotZ);\r
+\r
+            float posXlim1 = parseFloat();\r
+            float posYlim1 = parseFloat();\r
+            float posZlim1 = parseFloat();\r
+            float posXlim2 = parseFloat();\r
+            float posYlim2 = parseFloat();\r
+            float posZlim2 = parseFloat();\r
+            this.jointHandler.pmdPositionLimit(posXlim1, posXlim2,\r
+                                               posYlim1, posYlim2,\r
+                                               posZlim1, posZlim2 );\r
+\r
+            float rotXlim1 = parseFloat();\r
+            float rotYlim1 = parseFloat();\r
+            float rotZlim1 = parseFloat();\r
+            float rotXlim2 = parseFloat();\r
+            float rotYlim2 = parseFloat();\r
+            float rotZlim2 = parseFloat();\r
+            this.jointHandler.pmdRotationLimit(rotXlim1, rotXlim2,\r
+                                               rotYlim1, rotYlim2,\r
+                                               rotZlim1, rotZlim2 );\r
+\r
+            float elasticPosX = parseFloat();\r
+            float elasticPosY = parseFloat();\r
+            float elasticPosZ = parseFloat();\r
+            this.jointHandler.pmdElasticPosition(elasticPosX,\r
+                                                 elasticPosY,\r
+                                                 elasticPosZ );\r
+\r
+            float elasticRotX = parseFloat();\r
+            float elasticRotY = parseFloat();\r
+            float elasticRotZ = parseFloat();\r
+            this.jointHandler.pmdElasticRotation(elasticRotX,\r
+                                                 elasticRotY,\r
+                                                 elasticRotZ );\r
+\r
+            this.jointHandler.loopNext(PmdJointHandler.JOINT_LIST);\r
+        }\r
+\r
+        this.jointHandler.loopEnd(PmdJointHandler.JOINT_LIST);\r
+\r
+        return;\r
+    }\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdRigidHandler.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdRigidHandler.java
new file mode 100644 (file)
index 0000000..98ee70c
--- /dev/null
@@ -0,0 +1,130 @@
+/*\r
+ * PMD rigid information handler\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.LoopHandler;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.ParseStage;\r
+\r
+/**\r
+ * PMDモデルの各種剛体情報の通知用ハンドラ。\r
+ */\r
+public interface PmdRigidHandler extends LoopHandler {\r
+\r
+    /**\r
+     * 剛体情報パースステージ。\r
+     */\r
+    class PmdRigidStage extends ParseStage{\r
+        /** コンストラクタ。 */\r
+        PmdRigidStage(){ super(); return; }\r
+    }\r
+\r
+    /** 剛体情報抽出ループ。 */\r
+    PmdRigidStage RIGID_LIST = new PmdRigidStage();\r
+\r
+    /**\r
+     * 剛体名の通知を受け取る。\r
+     * {@link #RIGID_LIST}ループの構成要素。\r
+     * @param rigidName 剛体名\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdRigidName(String rigidName)\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * 剛体基本情報の通知を受け取る。\r
+     * {@link #RIGID_LIST}ループの構成要素。\r
+     * @param rigidGroupId 剛体グループ番号から1引いた数。(0-15)\r
+     * @param linkedBoneId 接続先ボーンID\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdRigidInfo(int rigidGroupId,\r
+                        int linkedBoneId)\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * 剛体形状の通知を受け取る。\r
+     * {@link #RIGID_LIST}ループの構成要素。\r
+     * @param shapeType 形状種別。\r
+     * <ul>\r
+     * <li>0x00:球\r
+     * <li>0x01:箱\r
+     * <li>0x02:カプセル\r
+     * </ul>\r
+     * @param width 球orカプセル半径。箱の幅。\r
+     * @param height 箱orカプセルの高さ\r
+     * @param depth 箱の奥行き\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdRigidShape(byte shapeType,\r
+                         float width, float height, float depth)\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * 剛体位置の通知を受け取る。\r
+     * {@link #RIGID_LIST}ループの構成要素。\r
+     * @param posX X座標\r
+     * @param posY Y座標\r
+     * @param posZ Z座標\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdRigidPosition(float posX, float posY, float posZ)\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * 剛体姿勢の通知を受け取る。\r
+     * {@link #RIGID_LIST}ループの構成要素。\r
+     * @param radX X軸回転量(radian)\r
+     * @param radY Y軸回転量(radian)\r
+     * @param radZ Z軸回転量(radian)\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdRigidRotation(float radX, float radY, float radZ)\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * 剛体物理系数の通知を受け取る。\r
+     * {@link #RIGID_LIST}ループの構成要素。\r
+     * @param mass 質量\r
+     * @param dampingPos 移動減衰率\r
+     * @param dampingRot 回転減衰率\r
+     * @param restitution 反発力\r
+     * @param friction 摩擦力\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdRigidPhysics(float mass,\r
+                           float dampingPos, float dampingRot,\r
+                           float restitution, float friction )\r
+        throws MmdFormatException;\r
+\r
+    /**\r
+     * 剛体の振る舞い情報の通知を受け取る。\r
+     * {@link #RIGID_LIST}ループの構成要素。\r
+     * @param behaveType 剛体タイプ。\r
+     * <ul>\r
+     * <li>0:ボーン追従\r
+     * <li>1:物理演算\r
+     * <li>2:物理演算+ボーン位置合わせ\r
+     * </ul>\r
+     * @param collisionMap 非衝突剛体グループビットマップ。\r
+     * (衝突グループ番号-1)位置のビット位置は1に、\r
+     * (非衝突グループ番号-1)位置のビット位置は0になる。\r
+     * 例)グループ1と8のみが非衝突指定の場合、0xff7eになる。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdRigidBehavior(byte behaveType, short collisionMap)\r
+        throws MmdFormatException;\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdShapeHandler.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdShapeHandler.java
new file mode 100644 (file)
index 0000000..9d4f591
--- /dev/null
@@ -0,0 +1,107 @@
+/*\r
+ * PMD shape information handler\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.LoopHandler;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.ParseStage;\r
+\r
+/**\r
+ * PMDモデルの各種形状(頂点、面)の通知用ハンドラ。\r
+ * 0から始まる頂点ID順に頂点は出現する。\r
+ * 0から始まる面ID順に面は出現する。\r
+ */\r
+public interface PmdShapeHandler extends LoopHandler {\r
+\r
+    /**\r
+     * モデル形状パースステージ。\r
+     */\r
+    class PmdShapeStage extends ParseStage{\r
+        /** コンストラクタ。 */\r
+        PmdShapeStage(){ super(); return; }\r
+    }\r
+\r
+    /** 頂点抽出ループ。 */\r
+    PmdShapeStage VERTEX_LIST = new PmdShapeStage();\r
+    /** 面抽出ループ。 */\r
+    PmdShapeStage SURFACE_LIST = new PmdShapeStage();\r
+\r
+    /**\r
+     * 頂点の座標の通知を受け取る。\r
+     * {@link #VERTEX_LIST}ループの構成要素\r
+     * @param xPos X座標\r
+     * @param yPos Y座標\r
+     * @param zPos Z座標\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdVertexPosition(float xPos, float yPos, float zPos)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * 頂点の法線情報の通知を受け取る。\r
+     * {@link #VERTEX_LIST}ループの構成要素\r
+     * ※単位ベクトル化必須?\r
+     * @param xVec 法線ベクトルX成分\r
+     * @param yVec 法線ベクトルY成分\r
+     * @param zVec 法線ベクトルZ成分\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdVertexNormal(float xVec, float yVec, float zVec)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * 頂点のUVマッピング情報の通知を受け取る。\r
+     * (頂点UV)\r
+     * {@link #VERTEX_LIST}ループの構成要素\r
+     * @param uVal テクスチャのU座標\r
+     * @param vVal テクスチャのV座標\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdVertexUV(float uVal, float vVal )\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * 頂点のボーン間ウェイトバランス情報の通知を受け取る。\r
+     * {@link #VERTEX_LIST}ループの構成要素\r
+     * @param boneId1 ボーンその1識別ID\r
+     * @param boneId2 ボーンその2識別ID\r
+     * @param weightForB1 ボーンその1への影響度。0(min)~100(max)\r
+     * ボーンその2への影響度は100からの引き算で求める。\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdVertexWeight(int boneId1, int boneId2, int weightForB1)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * 頂点のエッジ表現情報の通知を受け取る。\r
+     * 材質単位でのエッジ表現指定に優先される。\r
+     * {@link #VERTEX_LIST}ループの構成要素\r
+     * @param hideEdge エッジ無効ならtrue\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdVertexEdge(boolean hideEdge)\r
+            throws MmdFormatException;\r
+\r
+    /**\r
+     * 3つの頂点から構成される面情報の通知を受け取る。\r
+     * {@link #SURFACE_LIST}ループの構成要素\r
+     * @param vertexId1 頂点IDその1\r
+     * @param vertexId2 頂点IDその1\r
+     * @param vertexId3 頂点IDその1\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdSurfaceTriangle(int vertexId1, int vertexId2, int vertexId3)\r
+            throws MmdFormatException;\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdToonHandler.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/PmdToonHandler.java
new file mode 100644 (file)
index 0000000..8d285f8
--- /dev/null
@@ -0,0 +1,39 @@
+/*\r
+ * PMD toon texture file information handler\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.LoopHandler;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.ParseStage;\r
+\r
+/**\r
+ * PMDモデルの独自トゥーンテクスチャファイル名の通知用ハンドラ。\r
+ */\r
+public interface PmdToonHandler extends LoopHandler {\r
+\r
+    /**\r
+     * 独自トゥーンテクスチャファイル名パースステージ。\r
+     */\r
+    class PmdToonStage extends ParseStage{\r
+        /** コンストラクタ。 */\r
+        PmdToonStage(){ super(); return; }\r
+    }\r
+\r
+    /** トゥーンテクスチャファイル名抽出ループ。 */\r
+    PmdToonStage TOON_LIST = new PmdToonStage();\r
+\r
+    /**\r
+     * 独自トゥーンテクスチャファイル名の通知を受け取る。\r
+     * {@link #TOON_LIST}ループの構成要素\r
+     * @param toonName 独自トゥーンテクスチャファイル名\r
+     * @throws MmdFormatException 不正フォーマットによる\r
+     * パース処理の中断をパーサに指示\r
+     */\r
+    void pmdToonFileInfo(String toonName) throws MmdFormatException;\r
+\r
+}\r
diff --git a/src/main/java/jp/sourceforge/mikutoga/parser/pmd/package-info.java b/src/main/java/jp/sourceforge/mikutoga/parser/pmd/package-info.java
new file mode 100644 (file)
index 0000000..cf9ed5d
--- /dev/null
@@ -0,0 +1,14 @@
+/*\r
+ * package information for Javadoc\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+/**\r
+ * PMDモデルファイル用パーサライブラリ。\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser.pmd;\r
+\r
+/* EOF */\r
diff --git a/src/test/java/jp/sourceforge/mikutoga/parser/ParseStageTest.java b/src/test/java/jp/sourceforge/mikutoga/parser/ParseStageTest.java
new file mode 100644 (file)
index 0000000..a135013
--- /dev/null
@@ -0,0 +1,47 @@
+/*\r
+ *\r
+ */\r
+\r
+package jp.sourceforge.mikutoga.parser;\r
+\r
+import junit.framework.TestCase;\r
+import org.junit.Test;\r
+\r
+/**\r
+ *\r
+ */\r
+public class ParseStageTest extends TestCase {\r
+\r
+    public ParseStageTest(String testName) {\r
+        super(testName);\r
+    }\r
+\r
+    @Override\r
+    protected void setUp() throws Exception {\r
+        super.setUp();\r
+    }\r
+\r
+    @Override\r
+    protected void tearDown() throws Exception {\r
+        super.tearDown();\r
+    }\r
+\r
+    /**\r
+     * Test of toString method, of class ParseStage.\r
+     */\r
+    @Test\r
+    public void testToString(){\r
+        System.out.println("toString");\r
+\r
+        ParseStage instance;\r
+\r
+        instance = new ParseStage();\r
+        assertEquals("", instance.toString());\r
+\r
+        instance = new ParseStage("ABC");\r
+        assertEquals("ABC", instance.toString());\r
+\r
+        return;\r
+    }\r
+\r
+}\r
diff --git a/src/test/java/sample/pmd/DummyHandler.java b/src/test/java/sample/pmd/DummyHandler.java
new file mode 100644 (file)
index 0000000..5caead7
--- /dev/null
@@ -0,0 +1,336 @@
+/*\r
+ * sample handler\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package sample.pmd;\r
+\r
+import jp.sourceforge.mikutoga.parser.ParseStage;\r
+import jp.sourceforge.mikutoga.parser.pmd.PmdBasicHandler;\r
+import jp.sourceforge.mikutoga.parser.pmd.PmdBoneHandler;\r
+import jp.sourceforge.mikutoga.parser.pmd.PmdEngHandler;\r
+import jp.sourceforge.mikutoga.parser.pmd.PmdJointHandler;\r
+import jp.sourceforge.mikutoga.parser.pmd.PmdMaterialHandler;\r
+import jp.sourceforge.mikutoga.parser.pmd.PmdMorphHandler;\r
+import jp.sourceforge.mikutoga.parser.pmd.PmdRigidHandler;\r
+import jp.sourceforge.mikutoga.parser.pmd.PmdShapeHandler;\r
+import jp.sourceforge.mikutoga.parser.pmd.PmdToonHandler;\r
+\r
+/**\r
+ * サンプルのハンドラ。\r
+ */\r
+public class DummyHandler\r
+        implements PmdBasicHandler,\r
+                   PmdBoneHandler,\r
+                   PmdShapeHandler,\r
+                   PmdMorphHandler,\r
+                   PmdMaterialHandler,\r
+                   PmdEngHandler,\r
+                   PmdToonHandler,\r
+                   PmdRigidHandler,\r
+                   PmdJointHandler {\r
+\r
+    public DummyHandler(){\r
+        super();\r
+        return;\r
+    }\r
+\r
+    public void pmdParseStart(){\r
+        System.out.println("PMD parse start");\r
+        return;\r
+    }\r
+\r
+    public void pmdParseEnd(boolean hasMoreData){\r
+        System.out.println("PMD parse end");\r
+        if(hasMoreData){\r
+            System.out.println("thre is unknown data below");\r
+        }\r
+        return;\r
+    }\r
+\r
+    public void loopStart(ParseStage stage, int loops){\r
+        System.out.println("===== Loop start ===== * " + loops);\r
+        return;\r
+    }\r
+\r
+    public void loopNext(ParseStage stage){\r
+        return;\r
+    }\r
+\r
+    public void loopEnd(ParseStage stage){\r
+        System.out.println("===== Loop end =====");\r
+        return;\r
+    }\r
+\r
+    public void pmdHeaderInfo(float ver){\r
+        System.out.println("ver=" + ver);\r
+        return;\r
+    }\r
+\r
+    public void pmdModelInfo(String modelName, String description){\r
+        System.out.println("modelName=" + modelName);\r
+        System.out.println("comment=" + description);\r
+        return;\r
+    }\r
+\r
+    public void pmdVertexPosition(float xPos, float yPos, float zPos){\r
+//        System.out.println("x,y,z = " + xPos + "," + yPos + "," + zPos);\r
+        return;\r
+    }\r
+\r
+    public void pmdVertexNormal(float xVec, float yVec, float zVec){\r
+//        System.out.println("x,y,z = " + xVec + "," + yVec + "," + zVec);\r
+    }\r
+\r
+    public void pmdVertexUV(float uVal, float vVal){\r
+        return;\r
+    }\r
+\r
+    public void pmdVertexWeight(int boneId_1, int boneId_2,\r
+                                  int weightForB1){\r
+//        System.out.println("x,y,z = "\r
+//        + boneId_1 + "," + boneId_2 + "," + weightForB1);\r
+        return;\r
+    }\r
+\r
+    public void pmdVertexEdge(boolean hideEdge){\r
+//        System.out.println("x,y,z = " + hideEdge);\r
+        return;\r
+    }\r
+\r
+    public void pmdSurfaceTriangle(int vertexId_1,\r
+                                      int vertexId_2,\r
+                                      int vertexId_3){\r
+//        System.out.println("v1,v2,v3 = "\r
+//                + vertexId_1 + "," + vertexId_2 + "," + vertexId_3);\r
+    }\r
+\r
+    public void pmdMaterialDiffuse(float red, float green, float blue,\r
+                                      float alpha ){\r
+//        System.out.println("diffuse rgba="\r
+//        + red + "," + green + "," + blue + "," + alpha);\r
+        return;\r
+    }\r
+\r
+    public void pmdMaterialSpecular(float red, float green, float blue,\r
+                                       float shininess){\r
+//        System.out.println("specular rgbs="\r
+//        + red + "," + green + "," + blue + "," + shininess);\r
+        return;\r
+    }\r
+\r
+    public void pmdMaterialAmbient(float red, float green, float blue){\r
+//        System.out.println("ambient rgb=" + red + "," + green + "," + blue);\r
+        return;\r
+    }\r
+\r
+    public void pmdMaterialShading(int toon_idx,\r
+                                      String textureFile, String sphereFile){\r
+//        System.out.println("toon idx=" + toon_idx);\r
+//        System.out.println("texfile=" + textureFile);\r
+//        System.out.println("spherefile=" + sphereFile);\r
+        return;\r
+    }\r
+\r
+    public void pmdMaterialInfo(boolean hasEdge, int surfaceNum){\r
+//        System.out.println("surfaces=" + surfaceNum);\r
+        return;\r
+    }\r
+\r
+    public void pmdBoneInfo(String boneName, byte boneKind){\r
+//        System.out.println("bonename = " + boneName);\r
+//        System.out.println("kind = " + boneKind);\r
+        return;\r
+    }\r
+\r
+    public void pmdBoneLink(int parentId, int tailId, int ikId){\r
+//        System.out.println("parent = " + parentId);\r
+//        System.out.println("tail = " + tailId);\r
+//        System.out.println("ik = " + ikId);\r
+        return;\r
+    }\r
+\r
+    public void pmdBonePosition(float xPos, float yPos, float zPos){\r
+//        System.out.println("x="+xPos+" y="+yPos+" z="+zPos);\r
+        return;\r
+    }\r
+\r
+    public void pmdIKInfo(int boneId, int targetId,\r
+                           int depth, float weight ){\r
+        return;\r
+    }\r
+\r
+    public void pmdIKChainInfo(int childId){\r
+//        System.out.println("chained bone = " + childId);\r
+        return;\r
+    }\r
+\r
+    public void pmdMorphInfo(String morphName, byte morphType){\r
+//        System.out.println("morph name = " + morphName);\r
+        return;\r
+    }\r
+\r
+    public void pmdMorphVertexInfo(int vertexId,\r
+                                 float xPos, float yPos, float zPos){\r
+//        System.out.println("id="+vertexId+",x="+xPos+",y="+yPos+",z="+zPos);\r
+        return;\r
+    }\r
+\r
+    public void pmdMorphOrderInfo(int morphId){\r
+//        System.out.println("morph idx = " + morphId);\r
+        return;\r
+    }\r
+\r
+    public void pmdBoneGroupInfo(String groupName){\r
+//        System.out.println("group name = " + groupName);\r
+        return;\r
+    }\r
+\r
+    public void pmdGroupedBoneInfo(int boneId, int groupId){\r
+//        System.out.println("bone index="\r
+//        + boneId + " groupIndex=" + groupId);\r
+        return;\r
+    }\r
+\r
+    public void pmdEngEnabled(boolean hasEnglishInfo){\r
+        return;\r
+    }\r
+\r
+    public void pmdEngModelInfo(String modelName, String description){\r
+        return;\r
+    }\r
+\r
+    public void pmdEngBoneInfo(String boneName){\r
+//        System.out.println("bone eng name = " + boneName);\r
+        return;\r
+    }\r
+\r
+    public void pmdEngMorphInfo(String morphName){\r
+//        System.out.println("morph eng name = " + morphName);\r
+        return;\r
+    }\r
+\r
+    public void pmdEngBoneGroupInfo(String groupName){\r
+//        System.out.println("group eng name = " + groupName);\r
+        return;\r
+    }\r
+\r
+    public void pmdToonFileInfo(String toonName){\r
+//        System.out.println("toon file name = " + toonName);\r
+        return;\r
+    }\r
+\r
+    public void pmdRigidName(String rigidName){\r
+//        System.out.println("rigid name = " + rigidName);\r
+        return;\r
+    }\r
+\r
+    public void pmdRigidInfo(int rigidGroupId, int linkedBoneId){\r
+//        System.out.println("rigid group = "\r
+//        + rigidGroupId + ",linked Bone =" + linkedBoneId);\r
+        return;\r
+    }\r
+\r
+    public void pmdRigidShape(byte shapeType,\r
+                                float width, float height, float depth){\r
+//        System.out.println("type="+shapeType);\r
+//        System.out.println("w="+width);\r
+//        System.out.println("h="+height);\r
+//        System.out.println("d="+depth);\r
+        return;\r
+    }\r
+\r
+    public void pmdRigidPosition(float posX, float posY, float posZ){\r
+//        System.out.println("x="+posX);\r
+//        System.out.println("y="+posY);\r
+//        System.out.println("z="+posZ);\r
+        return;\r
+    }\r
+\r
+    public void pmdRigidRotation(float rotX, float rotY, float rotZ){\r
+//        System.out.println("x="+rotX);\r
+//        System.out.println("y="+rotY);\r
+//        System.out.println("z="+rotZ);\r
+        return;\r
+    }\r
+\r
+    public void pmdRigidPhysics(float mass,\r
+                                  float fadePos, float fadeRot,\r
+                                  float restitution, float friction ){\r
+//        System.out.println("mass="+mass);\r
+//        System.out.println("fadePos="+fadePos);\r
+//        System.out.println("fadeRot="+fadeRot);\r
+//        System.out.println("recoil="+restitution);\r
+//        System.out.println("friction="+friction);\r
+        return;\r
+    }\r
+\r
+    public void pmdRigidBehavior(byte behaveType, short collisionMap){\r
+//      System.out.println("type="+behaveType);\r
+//        System.out.println("map="+collisionMap);\r
+        return;\r
+    }\r
+\r
+    public void pmdJointName(String jointName){\r
+//        System.out.println("joint name = " + jointName);\r
+        return;\r
+    }\r
+\r
+    public void pmdJointLink(int rigidId_A, int rigidId_B){\r
+//        System.out.println("rigid1 = " + rigidId_A+",rigidB = " + rigidId_B);\r
+        return;\r
+    }\r
+\r
+    public void pmdJointPosition(float posX, float posY, float posZ){\r
+//        System.out.println("posX = " + posX);\r
+//        System.out.println("posY = " + posY);\r
+//        System.out.println("posZ = " + posZ);\r
+        return;\r
+    }\r
+\r
+    public void pmdJointRotation(float rotX, float rotY, float rotZ){\r
+//        System.out.println("rotX = " + rotX);\r
+//        System.out.println("rotY = " + rotY);\r
+//        System.out.println("rotZ = " + rotZ);\r
+        return;\r
+    }\r
+\r
+    public void pmdPositionLimit(float posX_lim1, float posX_lim2,\r
+                                   float posY_lim1, float posY_lim2,\r
+                                   float posZ_lim1, float posZ_lim2 ){\r
+//        System.out.println("limX = " + posX_lim1+"-"+posX_lim2);\r
+//        System.out.println("limY = " + posY_lim1+"-"+posY_lim2);\r
+//        System.out.println("limZ = " + posZ_lim1+"-"+posZ_lim2);\r
+        return;\r
+    }\r
+\r
+    public void pmdRotationLimit(float rotX_lim1, float rotX_lim2,\r
+                                   float rotY_lim1, float rotY_lim2,\r
+                                   float rotZ_lim1, float rotZ_lim2 ){\r
+//        System.out.println("limX = " + rotX_lim1+"-"+rotX_lim2);\r
+//        System.out.println("limY = " + rotY_lim1+"-"+rotY_lim2);\r
+//        System.out.println("limZ = " + rotZ_lim1+"-"+rotZ_lim2);\r
+        return;\r
+    }\r
+\r
+    public void pmdElasticPosition(float elasticPosX,\r
+                                  float elasticPosY,\r
+                                  float elasticPosZ ){\r
+//        System.out.println("posX="+elasticPosX);\r
+//        System.out.println("posY="+elasticPosY);\r
+//        System.out.println("posZ="+elasticPosZ);\r
+        return;\r
+    }\r
+\r
+    public void pmdElasticRotation(float elasticRotX,\r
+                                  float elasticRotY,\r
+                                  float elasticRotZ ){\r
+//        System.out.println("posX="+elasticRotX);\r
+//        System.out.println("posY="+elasticRotY);\r
+//        System.out.println("posZ="+elasticRotZ);\r
+        return;\r
+    }\r
+\r
+}\r
diff --git a/src/test/java/sample/pmd/DummyMain.java b/src/test/java/sample/pmd/DummyMain.java
new file mode 100644 (file)
index 0000000..ed4d624
--- /dev/null
@@ -0,0 +1,104 @@
+/*\r
+ * sample parser\r
+ *\r
+ * License : The MIT License\r
+ * Copyright(c) 2010 MikuToga Partners\r
+ */\r
+\r
+package sample.pmd;\r
+\r
+import java.io.BufferedInputStream;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import jp.sourceforge.mikutoga.parser.MmdFormatException;\r
+import jp.sourceforge.mikutoga.parser.MmdSource;\r
+import jp.sourceforge.mikutoga.parser.pmd.PmdParser;\r
+\r
+/**\r
+ * パーサ利用のサンプルプログラム。\r
+ */\r
+public class DummyMain {\r
+\r
+    private static final String PMDFILE;\r
+    private static final int BUF_SZ = 4086;\r
+    private static final DummyHandler handler = new DummyHandler();\r
+\r
+    static{\r
+        PMDFILE = "D:\\Test\\test.pmd";\r
+    }\r
+\r
+    /**\r
+     * 入力ソースを準備する。\r
+     * @param fname ファイル名\r
+     * @return 入力ソース\r
+     */\r
+    private static MmdSource buildSource(String fname){\r
+        File file = new File(fname);\r
+\r
+        InputStream is;\r
+        try{\r
+            is = new FileInputStream(file);\r
+        }catch(FileNotFoundException e){\r
+            System.err.println(e);\r
+            System.exit(1);\r
+            return null;\r
+        }\r
+        is = new BufferedInputStream(is, BUF_SZ);\r
+\r
+        MmdSource source = new MmdSource(is);\r
+\r
+        return source;\r
+    }\r
+\r
+    /**\r
+     * 各種ハンドラをパーサにセットアップする。\r
+     * @param parser パーサ\r
+     */\r
+    private static void setupHandler(PmdParser parser){\r
+        parser.setBasicHandler(handler);\r
+        parser.setShapeHandler(handler);\r
+        parser.setMaterialHandler(handler);\r
+        parser.setBoneHandler(handler);\r
+        parser.setMorphHandler(handler);\r
+        parser.setEngHandler(handler);\r
+        parser.setToonHandler(handler);\r
+        parser.setRigidHandler(handler);\r
+        parser.setJointHandler(handler);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * Java実行エントリ\r
+     * @param args 起動引数\r
+     */\r
+    public static void main(String[] args){\r
+        String fname;\r
+        if(args.length == 1) fname = args[0];\r
+        else                 fname = PMDFILE;\r
+\r
+        MmdSource source = buildSource(fname);\r
+\r
+        PmdParser parser = new PmdParser(source);\r
+\r
+        setupHandler(parser);\r
+\r
+        try{\r
+            parser.parsePmd();\r
+        }catch(IOException e){\r
+            System.err.println(e);\r
+            System.exit(1);\r
+        }catch(MmdFormatException e){\r
+            System.err.println(e);\r
+            System.exit(1);\r
+        }\r
+\r
+        System.exit(0);\r
+\r
+        return;\r
+    }\r
+\r
+}\r