X.XXX.X (20XX-XX-XX)
・Maven3対応。
+ ・JRE版数によって"0.001"や"0.0010"になるXML上の実数表記揺れを吸収。
2.101.2 (2011-08-24)
・VMDファイルの読み込みに対応。
* @return 読み込んだbyte値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
- * @see MmdInputStream#parseByte()
*/
protected byte parseByte()
throws IOException, MmdEofException{
* @return 読み込まれた値のint値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
- * @see MmdInputStream#parseUByteAsInt()
*/
protected int parseUByteAsInt()
throws IOException, MmdEofException{
* @return 読み込まれた値のboolean値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
- * @see MmdInputStream#parseBoolean()
*/
protected boolean parseBoolean()
throws IOException, MmdEofException{
* @return 読み込んだshort値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
- * @see MmdInputStream#parseShort()
*/
protected short parseLeShort()
throws IOException, MmdEofException{
* @return 読み込まれた値のint値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
- * @see MmdInputStream#parseUShortAsInteger()
*/
protected int parseLeUShortAsInt()
throws IOException, MmdEofException{
* @return 読み込んだint値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
- * @see MmdInputStream#parseInteger()
*/
protected int parseLeInt()
throws IOException, MmdEofException{
* @return 読み込んだfloat値
* @throws IOException IOエラー
* @throws MmdEofException 読み込む途中でストリーム終端に達した。
- * @see MmdInputStream#parseFloat()
*/
protected float parseLeFloat()
throws IOException, MmdEofException{
/**
* 各インスタンスに割り当てられたユニークな通し番号を返す。
- * @return
+ * @return 通し番号
*/
public int getNo(){
return this.no;
--- /dev/null
+/*
+ * MMD model file types.
+ *
+ * License : The MIT License
+ * Copyright(c) 2012 MikuToga Partners
+ */
+
+package jp.sourceforge.mikutoga.pmd;
+
+/**
+ * モデルファイル種別。
+ */
+public enum ModelFileType {
+
+ /** 不明。 */
+ NONE,
+
+ /** MikuMikuDance ver7 前後で読み書きが可能なPMDファイル。 */
+ PMD,
+
+ /**
+ * スキーマ
+ * http://mikutoga.sourceforge.jp/xml/xsd/pmdxml-101009.xsd
+ * で定義されたXMLファイル。
+ */
+ XML_101009,
+
+ ;
+
+}
/*
- * typical object information
+ * internationalization name alias
*
* License : The MIT License
* Copyright(c) 2011 MikuToga Partners
import java.io.IOException;
import java.io.InputStream;
+import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import org.xml.sax.SAXException;
/**
- * å\90\84種æ¨\99æº\96オブジェクトの実装基板。
+ * å\9b½é\9a\9bå\8c\96&å\88¥å\90\8d管ç\90\86オブジェクトの実装基板。
* <p>国産モデルではプライマリ名に日本語名が収められることが多い。
* プライマリ名は必ず一つ以上なければならない。
* <p>国産モデルではグローバル名に英語名が収められることが多いが、
* プライマリ名と同一の日本語名が収められている場合も多い。
*/
-class TypicalObject {
+class I18nAlias {
/** オーダ番号によるコンパレータ。 */
- public static final Comparator<TypicalObject> ORDER_COMPARATOR =
+ public static final Comparator<I18nAlias> ORDER_COMPARATOR =
new OrderComparator();
- protected final List<String> primaryList;
- protected final List<String> globalList;
- protected final List<String> umodPrimaryList;
- protected final List<String> umodGlobalList;
+ private int orderNo;
- protected int orderNo;
+ private final List<String> primaryList;
+ private final List<String> globalList;
+
+ private final List<String> umodPrimaryList;
+ private final List<String> umodGlobalList;
/**
* コンストラクタ。
- * <p>各初期数が0以下の場合は、状況に応じて伸長する連結リストが用意される。
+ * <p>各初期数が0以下の場合は、
+ * 状況に応じて伸長する連結リストが用意される。
* @param primaryNo プライマリ名初期数。
* @param globalNo グローバル名初期数。
*/
- protected TypicalObject(int primaryNo, int globalNo){
+ protected I18nAlias(int primaryNo, int globalNo){
super();
if(primaryNo <= 0){
/**
* コンストラクタ。
- * <p>プライマリ名、グローバル名共、状況に応じて伸長する連結リストが用意される。
+ * <p>プライマリ名、グローバル名共、
+ * 状況に応じて伸長する連結リストが用意される。
*/
- protected TypicalObject(){
+ protected I18nAlias(){
this(0, 0);
return;
}
return top;
}
+ /**
+ * NFKC正規化された文字列を返す。
+ * <ul>
+ * <li>「ボーン」は「ボーン」になる
+ * <li>「ホ゛ーン9」は「ボーン9」になる
+ * </ul>
+ * @param name
+ * @return
+ */
+ protected static String normalize(CharSequence name){
+ String result;
+ result = Normalizer.normalize(name, Normalizer.Form.NFKC);
+ return result;
+ }
+
+
+ /**
+ * オーダー番号を返す。
+ * @return
+ */
+ protected int getOrderNo(){
+ return this.orderNo;
+ }
+
+ /**
+ * オーダー番号を設定する。
+ * @param orderNo
+ */
+ protected void setOrderNo(int orderNo){
+ this.orderNo = orderNo;
+ return;
+ }
/**
- * プライマリ名をひとつ返す。
+ * ã\83\97ã\83©ã\82¤ã\83\9eã\83ªå\90\8dã\81®ä»£è¡¨ã\82\92ã\81²ã\81¨ã\81¤è¿\94ã\81\99ã\80\82
* @return 最初のプライマリ名
*/
public String getTopPrimaryName(){
}
/**
- * グローバル名をひとつ返す。
+ * ã\82°ã\83ã\83¼ã\83\90ã\83«å\90\8dã\81®ä»£è¡¨ã\82\92ã\81²ã\81¨ã\81¤è¿\94ã\81\99ã\80\82
* @return 最初のグローバル名。ひとつもなければnull
*/
public String getTopGlobalName(){
}
/**
- * 全プライマリ名を返す。
+ * プライマリ名の全エイリアス文字列リストを返す。
* @return 全プライマリ名リスト。(不可変)
*/
public List<String> getPrimaryList(){
}
/**
- * 全グローバル名を返す。
+ * プライマリ名を追加。
+ * @param name プライマリ名
+ */
+ protected void addPrimaryName(String name){
+ this.primaryList.add(name);
+ return;
+ }
+
+ /**
+ * グローバル名の全エイリアス文字列リストを返す。
* @return 全グローバル名リスト。(不可変)
*/
public List<String> getGlobalList(){
}
/**
+ * グローバル名を追加。
+ * @param name グローバル名
+ */
+ protected void addGlobalName(String name){
+ this.globalList.add(name);
+ return;
+ }
+
+ /**
* オーダ番号によるコンパレータ。
*/
+ @SuppressWarnings("serial")
private static class OrderComparator
- implements Comparator<TypicalObject> {
+ implements Comparator<I18nAlias> {
/**
* コンストラクタ。
* @return {@inheritDoc}
*/
@Override
- public int compare(TypicalObject o1, TypicalObject o2){
- int result = o1.orderNo - o2.orderNo;
+ public int compare(I18nAlias o1, I18nAlias o2){
+ int result = o1.getOrderNo() - o2.getOrderNo();
return result;
}
import java.io.IOException;
import java.io.InputStream;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
* <p>選択基準は独断。
* <p>和英対訳はMMD Ver7.39の同梱モデルにほぼ準拠。
*/
-public final class TypicalBone extends TypicalObject {
+public final class TypicalBone extends I18nAlias {
private static final Class<?> THISCLASS = TypicalBone.class;
private static final String BONE_XML = "resources/typicalBone.xml";
private static final Map<String, TypicalBone> GLOBAL_MAP =
new HashMap<String, TypicalBone>();
+ private static final List<TypicalBone> TYP_BONE_UNMODLIST =
+ Collections.unmodifiableList(TYP_BONE_LIST);
static{
InputStream is = THISCLASS.getResourceAsStream(BONE_XML);
Element top;
try{
- top = TypicalObject.loadXml(is);
+ top = I18nAlias.loadXml(is);
}catch(ParserConfigurationException e){
throw new ExceptionInInitializerError(e);
}catch(SAXException e){
/**
* コンストラクタ。
- * <p>各初期数が0以下の場合は、状況に応じて伸長する連結リストが用意される。
+ * <p>各初期数が0以下の場合は、
+ * 状況に応じて伸長する連結リストが用意される。
* @param primaryNo プライマリ名初期数。
* @param globalNo グローバル名初期数。
*/
for(int idx = 0; idx < primaryNo; idx++){
Element primary = (Element) primaryNodes.item(idx);
String name = primary.getAttribute("name");
- typBone.primaryList.add(name);
+ typBone.addPrimaryName(name);
}
for(int idx = 0; idx < globalNo; idx++){
Element global = (Element) globalNodes.item(idx);
String name = global.getAttribute("name");
- typBone.globalList.add(name);
+ typBone.addGlobalName(name);
}
- for(String primaryName : typBone.primaryList){
- PRIMARY_MAP.put(primaryName, typBone);
+ for(String primaryName : typBone.getPrimaryList()){
+ String key = normalize(primaryName).intern();
+ PRIMARY_MAP.put(key, typBone);
}
- for(String globalName : typBone.globalList){
- GLOBAL_MAP.put(globalName, typBone);
+ for(String globalName : typBone.getGlobalList()){
+ String key = normalize(globalName).intern();
+ GLOBAL_MAP.put(key, typBone);
}
return typBone;
private static void numbering(){
int order = 0;
for(TypicalBone bone : TYP_BONE_LIST){
- bone.orderNo = order++;
+ bone.setOrderNo(order++);
}
return;
}
/**
+ * 全ボーンの不変リストを返す。
+ * @return 全ボーンのリスト
+ */
+ public static List<TypicalBone> getBoneList(){
+ return TYP_BONE_UNMODLIST;
+ }
+
+ /**
* プライマリ名の合致するボーン情報を返す。
+ * NFKCで正規化されたプライマリ名で検索される。
* @param primaryName プライマリ名
* @return モーフ情報。見つからなければnull
*/
public static TypicalBone findWithPrimary(String primaryName){
- TypicalBone result = PRIMARY_MAP.get(primaryName);
+ String key = normalize(primaryName);
+ TypicalBone result = PRIMARY_MAP.get(key);
return result;
}
/**
* グローバル名の合致するボーン情報を返す。
+ * NFKCで正規化されたグローバル名で検索される。
* @param globalName グローバル名
* @return モーフ情報。見つからなければnull
*/
public static TypicalBone findWithGlobal(String globalName){
- TypicalBone result = GLOBAL_MAP.get(globalName);
+ String key = normalize(globalName);
+ TypicalBone result = GLOBAL_MAP.get(key);
return result;
}
* <p>選択基準は独断。
* <p>和英対訳はMMD Ver7.39の同梱モデルにほぼ準拠。
*/
-public final class TypicalMorph extends TypicalObject {
+public final class TypicalMorph extends I18nAlias {
private static final Class<?> THISCLASS = TypicalMorph.class;
private static final String MORPH_XML = "resources/typicalMorph.xml";
InputStream is = THISCLASS.getResourceAsStream(MORPH_XML);
Element top;
try{
- top = TypicalObject.loadXml(is);
+ top = I18nAlias.loadXml(is);
}catch(ParserConfigurationException e){
throw new ExceptionInInitializerError(e);
}catch(SAXException e){
/**
* コンストラクタ。
- * <p>各初期数が0以下の場合は、状況に応じて伸長する連結リストが用意される。
+ * <p>各初期数が0以下の場合は、
+ * 状況に応じて伸長する連結リストが用意される。
* @param type モーフ種別
* @param primaryNo プライマリ名初期数。
* @param globalNo グローバル名初期数。
parseGroup(group);
}
- // 空リスト登録
+ // 必要に応じモーフ枠に不変空リスト登録
for(MorphType morphType : MorphType.values()){
if( ! TYPED_MAP.containsKey(morphType) ){
TYPED_MAP.put(morphType, EMPTY);
NodeList morphList = group.getElementsByTagName("morph");
int morphNo = morphList.getLength();
- List<TypicalMorph> groupedList = new ArrayList<TypicalMorph>(morphNo);
+ List<TypicalMorph> groupedList =
+ new ArrayList<TypicalMorph>(morphNo);
for(int idx = 0; idx < morphNo; idx++){
Element morph = (Element) morphList.item(idx);
groupedList.add(common);
}
- TYPED_MAP.put(morphType, Collections.unmodifiableList(groupedList));
+ groupedList = Collections.unmodifiableList(groupedList);
+ TYPED_MAP.put(morphType, groupedList);
return;
}
for(int idx = 0; idx < primaryNo; idx++){
Element primary = (Element) primaryNodes.item(idx);
String name = primary.getAttribute("name");
- typMorph.primaryList.add(name);
+ typMorph.addPrimaryName(name);
}
for(int idx = 0; idx < globalNo; idx++){
Element global = (Element) globalNodes.item(idx);
String name = global.getAttribute("name");
- typMorph.globalList.add(name);
+ typMorph.addGlobalName(name);
}
- for(String primaryName : typMorph.primaryList){
- PRIMARY_MAP.put(primaryName, typMorph);
+ for(String primaryName : typMorph.getPrimaryList()){
+ String key = normalize(primaryName).intern();
+ PRIMARY_MAP.put(key, typMorph);
}
- for(String globalName : typMorph.globalList){
- GLOBAL_MAP.put(globalName, typMorph);
+ for(String globalName : typMorph.getGlobalList()){
+ String key = normalize(globalName).intern();
+ GLOBAL_MAP.put(key, typMorph);
}
return typMorph;
int order = 0;
for(MorphType morphType : MorphType.values()){
for(TypicalMorph common : TYPED_MAP.get(morphType)){
- common.orderNo = order++;
+ common.setOrderNo(order++);
}
}
/**
* プライマリ名の合致するモーフ情報を返す。
+ * NFKCで正規化されたプライマリ名で検索される。
* @param primaryName プライマリ名
* @return モーフ情報。見つからなければnull
*/
public static TypicalMorph findWithPrimary(String primaryName){
- TypicalMorph result = PRIMARY_MAP.get(primaryName);
+ String key = normalize(primaryName);
+ TypicalMorph result = PRIMARY_MAP.get(key);
return result;
}
/**
* グローバル名の合致するモーフ情報を返す。
+ * NFKCで正規化されたグローバル名で検索される。
* @param globalName グローバル名
* @return モーフ情報。見つからなければnull
*/
public static TypicalMorph findWithGlobal(String globalName){
- TypicalMorph result = GLOBAL_MAP.get(globalName);
+ String key = normalize(globalName);
+ TypicalMorph result = GLOBAL_MAP.get(key);
return result;
}
return primary;
}
+
/**
* モーフ種別を返す。
* @return モーフ種別
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.xml.bind.DatatypeConverter;
/**
private static final Charset CS_UTF8 = Charset.forName("UTF-8");
/** デフォルトの改行文字列。 */
- private static final String LF = "\n"; // 0x0a
+ private static final String DEF_NL = "\n"; // 0x0a(LF)
/** デフォルトのインデント単位。 */
- private static final String DEFAULT_INDENT_UNIT = "\u0020\u0020";
+ private static final String DEF_INDENT_UNIT = "\u0020\u0020"; // ␣␣
- private static final char CH_SP = '\u0020'; //
- private static final char CH_YEN = '\u00a5'; // ¥
- private static final char CH_BSLASH = '\u005c\u005c'; // \
+ private static final char CH_SP = '\u0020'; // ␣
+ private static final char CH_YEN = '\u00a5'; // ¥
+ private static final char CH_BSLASH = (char)0x005c; // \
+ private static final char CH_DQ = '\u0022'; // "
+ private static final char CH_SQ = (char)0x0027; // '
+ private static final String COMM_START = "<!--";
+ private static final String COMM_END = "-->";
+ private static final String REF_HEX = "&#x";
+
+ private static final Pattern NUM_FUZZY =
+ Pattern.compile("([^.]*\\.[0-9][0-9]*?)0+");
+
+ private static final int HEX_EXP = 4; // 2 ** 4 == 16
+ private static final int MASK_1HEX = (1 << HEX_EXP) - 1; // 0b00001111
+ private static final int MAX_OCTET = (1 << Byte.SIZE) - 1; // 0xff
private static final char[] HEXCHAR_TABLE = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F',
};
- private static final String COMM_START = "<!--";
- private static final String COMM_END = "-->";
-
- private static final int MASK_BIT8 = 0x000f;
- private static final int MASK_BIT16 = 0x00ff;
static{
- assert HEXCHAR_TABLE.length == 16;
+ assert HEX_EXP * 2 == Byte.SIZE;
+ assert HEXCHAR_TABLE.length == (1 << HEX_EXP);
}
private final Appendable appendable;
- private String newline = LF;
- private String indentUnit = DEFAULT_INDENT_UNIT;
+ private String newline = DEF_NL;
+ private String indentUnit = DEF_INDENT_UNIT;
private int indentNest = 0;
private boolean basicLatinOnlyOut = true;
return;
}
+
/**
* ASCIIコード相当(UCS:Basic-Latin)の文字か否か判定する。
+ * <p>※ Basic-Latinには各種制御文字も含まれる。
* @param ch 判定対象文字
* @return Basic-Latin文字ならtrue
*/
public static boolean isBasicLatin(char ch){
- Character.UnicodeBlock block = Character.UnicodeBlock.of(ch);
- if(block == Character.UnicodeBlock.BASIC_LATIN) return true;
+ if('\u0000' <= ch && ch <= '\u007f'){
+ return true;
+ }
return false;
}
/**
- * 改行文字列を設定する。
- * @param newLine 改行文字列
- * @throws NullPointerException 引数がnull
+ * 冗長な実数出力を抑止する。
+ * <p>DatatypeConverterにおけるJDK1.6系と1.7系の仕様変更を吸収する。
+ * <p>0.001fは"0.0010"ではなく"0.001"と出力される。
+ * <p>指数表記での冗長桁は無視する。
+ * @param numTxt 実数表記
+ * @return 冗長桁が抑止された実数表記
*/
- public void setNewLine(String newLine) throws NullPointerException{
- if(newLine == null) throw new NullPointerException();
- this.newline = newLine;
- return;
+ public static String chopFuzzyZero(String numTxt){
+ String result;
+
+ Matcher matcher = NUM_FUZZY.matcher(numTxt);
+ if(matcher.matches()){
+ result = matcher.group(1);
+ }else{
+ result = numTxt;
+ }
+
+ return result;
}
+
/**
* BasicLatin文字だけで出力するか設定する。
- * BasicLatin以外の文字(≒日本語)をそのまま出力するか
- * 文字参照で出力するかの設定が可能。
- * コメント部中身は対象外。
+ * <p>BasicLatin以外の文字(≒日本語)を、そのまま出力するか、
+ * æ\96\87å\97å\8f\82ç\85§ã\81§å\87ºå\8a\9bã\81\99ã\82\8bã\81\8bã\80\81ã\81®è¨å®\9aã\81\8cå\8f¯è\83½ã\80\82
+ * <p>コメント部中身は対象外。
* @param bool BasicLatin文字だけで出力するならtrue
*/
public void setBasicLatinOnlyOut(boolean bool){
/**
* BasicLatin文字だけを出力する状態か判定する。
- * コメント部中身は対象外。
+ * <p>コメント部中身は対象外。
* @return BasicLatin文字だけで出力するならtrue
*/
public boolean isBasicLatinOnlyOut(){
/**
* 改行文字列を設定する。
- * デフォルトではLF(0x0a)\nが用いられる。
- * @param seq 改行文字列。nullは空文字列""と解釈される。
+ * @param newLine 改行文字列
+ * @throws NullPointerException 引数がnull
*/
- public void setNewLine(CharSequence seq){
- if(seq == null) this.newline = "";
- else this.newline = seq.toString();
+ public void setNewLine(String newLine) throws NullPointerException{
+ if(newLine == null) throw new NullPointerException();
+ this.newline = newLine;
return;
}
/**
+ * 改行文字列を返す。
+ * @return 改行文字列
+ */
+ public String getNewLine(){
+ return this.newline;
+ }
+
+ /**
* インデント単位文字列を設定する。
- * デフォルトでは空白2個。
- * @param seq インデント単位文字列。nullは空文字列""と解釈される。
+ * <p>デフォルトでは空白2個。
+ * @param indUnit インデント単位文字列。
+ * @throws NullPointerException 引数がnull
+ */
+ public void setIndentUnit(String indUnit) throws NullPointerException{
+ if(indUnit == null) throw new NullPointerException();
+ this.indentUnit = indUnit;
+ return;
+ }
+
+ /**
+ * インデント単位文字列を返す。
+ * @return インデント単位文字列
*/
- public void setIndentUnit(CharSequence seq){
- if(seq == null) this.indentUnit = "";
- else this.indentUnit = seq.toString();
+ public String getIndentUnit(){
+ return this.indentUnit;
}
/**
* @return this本体
* @throws IOException 出力エラー
*/
- public BasicXmlExporter put(char ch) throws IOException{
+ public BasicXmlExporter putRawCh(char ch) throws IOException{
this.appendable.append(ch);
return this;
}
* @return this本体
* @throws IOException 出力エラー
*/
- public BasicXmlExporter put(CharSequence seq) throws IOException{
+ public BasicXmlExporter putRawText(CharSequence seq) throws IOException{
this.appendable.append(seq);
return this;
}
/**
- * int値を出力する。
- * @param iVal int値
+ * 指定された文字を16進2桁の文字参照形式で出力する。
+ * 2桁で出力できない場合(>0x00ff)は4桁で出力する。
+ * @param ch 文字
* @return this本体
* @throws IOException 出力エラー
- * @see java.lang.Integer#toString(int)
*/
- public BasicXmlExporter put(int iVal) throws IOException{
- String value = DatatypeConverter.printInt(iVal);
- this.appendable.append(value);
+ public BasicXmlExporter putCharRef2Hex(char ch) throws IOException{
+ if(ch > MAX_OCTET) return putCharRef4Hex(ch);
+
+ int ibits = ch; // 常に正なので符号拡張なし
+
+ int idx4 = ibits & MASK_1HEX;
+ ibits >>= HEX_EXP;
+ int idx3 = ibits & MASK_1HEX;
+
+ char hex3 = HEXCHAR_TABLE[idx3];
+ char hex4 = HEXCHAR_TABLE[idx4];
+
+ putRawText(REF_HEX).putRawCh(hex3).putRawCh(hex4)
+ .putRawCh(';');
+
return this;
}
/**
- * float値を出力する。
- * @param fVal float値
+ * 指定された文字を16進4桁の文字参照形式で出力する。
+ * UCS4に伴うサロゲートペアは未サポート
+ * @param ch 文字
* @return this本体
* @throws IOException 出力エラー
- * @see java.lang.Float#toString(float)
*/
- public BasicXmlExporter put(float fVal) throws IOException{
- String value = DatatypeConverter.printFloat(fVal);
- this.appendable.append(value);
+ public BasicXmlExporter putCharRef4Hex(char ch) throws IOException{
+ int ibits = ch; // 常に正なので符号拡張なし
+
+ int idx4 = ibits & MASK_1HEX;
+ ibits >>= HEX_EXP;
+ int idx3 = ibits & MASK_1HEX;
+ ibits >>= HEX_EXP;
+ int idx2 = ibits & MASK_1HEX;
+ ibits >>= HEX_EXP;
+ int idx1 = ibits & MASK_1HEX;
+
+ char hex1 = HEXCHAR_TABLE[idx1];
+ char hex2 = HEXCHAR_TABLE[idx2];
+ char hex3 = HEXCHAR_TABLE[idx3];
+ char hex4 = HEXCHAR_TABLE[idx4];
+
+ putRawText(REF_HEX).putRawCh(hex1).putRawCh(hex2)
+ .putRawCh(hex3).putRawCh(hex4)
+ .putRawCh(';');
+
+ return this;
+ }
+
+ /**
+ * 要素の中身および属性値中身を出力する。
+ * <p>XMLの構文規則を守る上で必要な各種エスケープ処理が行われる。
+ * @param ch 文字
+ * @return this本体
+ * @throws IOException 出力エラー
+ */
+ public BasicXmlExporter putCh(char ch) throws IOException{
+ if(Character.isISOControl(ch)){
+ putCharRef2Hex(ch);
+ return this;
+ }
+
+ String escTxt;
+ switch(ch){
+ case '&': escTxt = "&"; break;
+ case '<': escTxt = "<"; break;
+ case '>': escTxt = ">"; break;
+ case CH_DQ: escTxt = """; break;
+ case CH_SQ: escTxt = "'"; break;
+ default: escTxt = null; break;
+ }
+
+ if(escTxt != null){
+ putRawText(escTxt);
+ }else{
+ putRawCh(ch);
+ }
+
+ return this;
+ }
+
+ /**
+ * 要素の中身および属性値中身を出力する。
+ * <p>必要に応じてXML定義済み実体文字が割り振られた文字、
+ * コントロールコード、および非BasicLatin文字がエスケープされる。
+ * <p>半角通貨記号U+00A5はバックスラッシュU+005Cに置換される。
+ * <p>連続するスペースU+0020の2文字目以降は文字参照化される。
+ * <p>全角スペースその他空白文字は無条件に文字参照化される。
+ * @param content 内容
+ * @return this本体
+ * @throws IOException 出力エラー
+ */
+ public BasicXmlExporter putContent(CharSequence content)
+ throws IOException{
+ int length = content.length();
+
+ char prev = '\0';
+ for(int pos = 0; pos < length; pos++){
+ char ch = content.charAt(pos);
+
+ if( isBasicLatinOnlyOut() && ! isBasicLatin(ch) ){
+ putCharRef4Hex(ch);
+ }else if(ch == CH_YEN){
+ putRawCh(CH_BSLASH);
+ }else if(Character.isSpaceChar(ch)){
+ if(ch == CH_SP && prev != CH_SP){
+ putRawCh(ch);
+ }else{
+ putCharRef2Hex(ch);
+ }
+ }else{
+ putCh(ch);
+ }
+
+ prev = ch;
+ }
+
return this;
}
*/
public BasicXmlExporter ind() throws IOException{
for(int ct = 1; ct <= this.indentNest; ct++){
- put(this.indentUnit);
+ putRawText(this.indentUnit);
}
return this;
}
}
/**
- * 指定された文字を16進2桁の文字参照形式で出力する。
- * 2桁で出力できない場合は4桁で出力する。
- * @param ch 文字
- * @return this本体
- * @throws IOException 出力エラー
- */
- public BasicXmlExporter putCharRef2Hex(char ch) throws IOException{
- if(ch > MASK_BIT16) return putCharRef4Hex(ch);
-
- char hex3 = HEXCHAR_TABLE[(ch >> 4) & MASK_BIT8];
- char hex4 = HEXCHAR_TABLE[(ch >> 0) & MASK_BIT8];
-
- put("&#x").put(hex3).put(hex4).put(';');
-
- return this;
- }
-
- /**
- * 指定された文字を16進4桁の文字参照形式で出力する。
- * UCS4に伴うサロゲートペアは未サポート
- * @param ch 文字
+ * int値をXMLスキーマ準拠の形式で出力する。
+ * @param iVal int値
* @return this本体
* @throws IOException 出力エラー
+ * @see java.lang.Integer#toString(int)
*/
- public BasicXmlExporter putCharRef4Hex(char ch) throws IOException{
- char hex1 = HEXCHAR_TABLE[(ch >> 12) & MASK_BIT8];
- char hex2 = HEXCHAR_TABLE[(ch >> 8) & MASK_BIT8];
- char hex3 = HEXCHAR_TABLE[(ch >> 4) & MASK_BIT8];
- char hex4 = HEXCHAR_TABLE[(ch >> 0) & MASK_BIT8];
-
- put("&#x").put(hex1).put(hex2).put(hex3).put(hex4).put(';');
-
+ public BasicXmlExporter putXsdInt(int iVal) throws IOException{
+ String value = DatatypeConverter.printInt(iVal);
+ this.appendable.append(value);
return this;
}
/**
- * 要素の中身および属性値中身を出力する。
- * <p>必要に応じてXML定義済み実体文字が割り振られた文字、
- * コントロールコード、および非BasicLatin文字がエスケープされる。
- * <p>半角通貨記号U+00A5はバックスラッシュU+005Cに置換される。
- * @param content 内容
+ * float値をXMLスキーマ準拠の形式で出力する。
+ * @param fVal float値
* @return this本体
* @throws IOException 出力エラー
+ * @see java.lang.Float#toString(float)
*/
- public BasicXmlExporter putContent(CharSequence content)
- throws IOException{
- int length = content.length();
-
- char prev = '\0';
- for(int pos = 0; pos < length; pos++){
- char ch = content.charAt(pos);
-
- if(Character.isISOControl(ch)){
- putCharRef2Hex(ch);
- }else if( ! isBasicLatin(ch) && isBasicLatinOnlyOut()){
- putCharRef4Hex(ch);
- }else if(ch == CH_SP){
- if(prev == CH_SP){
- putCharRef2Hex(ch);
- }else{
- put(ch);
- }
- }else if(Character.isSpaceChar(ch)){
- // 全角スペースその他
- putCharRef2Hex(ch);
- }else if(ch == CH_YEN){
- put(CH_BSLASH);
- }else{
- switch(ch){
- case '&': put("&"); break;
- case '<': put("<"); break;
- case '>': put(">"); break;
- case '"': put("""); break;
- case '\'': put("'"); break;
- default: put(ch); break;
- }
- }
-
- prev = ch;
- }
-
+ public BasicXmlExporter putXsdFloat(float fVal) throws IOException{
+ String value = DatatypeConverter.printFloat(fVal);
+ this.appendable.append(value);
return this;
}
public BasicXmlExporter putAttr(CharSequence attrName,
CharSequence content)
throws IOException{
- put(attrName).put('=').put('"').putContent(content).put('"');
+ putRawText(attrName).putRawCh('=');
+
+ putRawCh('"');
+ putContent(content);
+ putRawCh('"');
+
return this;
}
* @throws IOException 出力エラー
*/
public BasicXmlExporter putIntAttr(CharSequence attrName,
- int iVal)
+ int iVal)
throws IOException{
- put(attrName).put('=').put('"').put(iVal).put('"');
+ String attrValue = DatatypeConverter.printInt(iVal);
+ putAttr(attrName, attrValue);
return this;
}
* @throws IOException 出力エラー
*/
public BasicXmlExporter putFloatAttr(CharSequence attrName,
- float fVal)
+ float fVal)
throws IOException{
- put(attrName).put('=').put('"').put(fVal).put('"');
+ String attrValue = DatatypeConverter.printFloat(fVal);
+ attrValue = chopFuzzyZero(attrValue);
+ putAttr(attrName, attrValue);
return this;
}
if(ch == '\n'){
ln();
}else if('\u0000' <= ch && ch <= '\u001f'){
- put((char)('\u2400' + ch));
+ putRawCh((char)('\u2400' + ch));
}else if(ch == '\u007f'){
- put('\u2421');
+ putRawCh('\u2421');
}else if(prev == '-' && ch == '-'){
- sp().put(ch);
+ sp().putRawCh(ch);
}else{
- put(ch);
+ putRawCh(ch);
}
prev = ch;
*/
public BasicXmlExporter putLineComment(CharSequence comment)
throws IOException{
- put(COMM_START).sp();
+ putRawText(COMM_START).sp();
putCommentContent(comment);
- sp().put(COMM_END);
+ sp().putRawText(COMM_END);
return this;
}
*/
public BasicXmlExporter putBlockComment(CharSequence comment)
throws IOException{
- put(COMM_START).ln();
+ putRawText(COMM_START).ln();
putCommentContent(comment);
}
}
- put(COMM_END).ln();
+ putRawText(COMM_END).ln();
return this;
}
/**
* 同じ親要素と同じ要素名を持つ兄弟要素を列挙する列挙子。
*/
- private static final class ElemIterator implements Iterator<Element>{
+ private static final class ElemIterator implements Iterator<Element> {
private Element next;
/**
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.w3c.dom.ls.LSInput;
private static final String LOCAL_SCHEMA_XML =
"resources/xml-2009-01.xsd";
+
private static final URI EMPTY_URI = URI.create("");
+
private static final Class<?> THISCLASS = XmlResourceResolver.class;
- private final Map<URI, URI> uriMap = new HashMap<URI, URI>();
+
+ private final Map<URI, URI> uriMap;
+
/**
* コンストラクタ。
assert this.getClass().equals(THISCLASS);
+ Map<URI, URI> map;
+ map = new HashMap<URI, URI>();
+ map = Collections.synchronizedMap(map);
+ this.uriMap = map;
+
+ URL redirectRes = THISCLASS.getResource(LOCAL_SCHEMA_XML);
+ String redirectResName = redirectRes.toString();
+
URI originalURI = URI.create(SCHEMA_XML);
- URL redirectURL = THISCLASS.getResource(LOCAL_SCHEMA_XML);
- URI redirectURI;
- try{
- redirectURI = redirectURL.toURI();
- }catch(URISyntaxException e){
- assert false;
- throw new AssertionError(e);
- }
+ URI redirectURI = URI.create(redirectResName);
- this.uriMap.put(originalURI, redirectURI);
+ putURIMapImpl(originalURI, redirectURI);
return;
}
+
/**
* 絶対URIと相対URIを合成したURIを返す。
* 正規化も行われる。
protected static URI buildBaseRelativeURI(String base, String relative)
throws URISyntaxException,
IllegalArgumentException {
- URI baseURI = null;
+ URI baseURI;
if(base != null){
baseURI = new URI(base);
- if( ! baseURI.isAbsolute() ) throw new IllegalArgumentException();
+ if( ! baseURI.isAbsolute() ){
+ throw new IllegalArgumentException();
+ }
+ }else{
+ baseURI = null;
}
- URI relativeURI = EMPTY_URI;
+ URI relativeURI;
if(relative != null){
relativeURI = new URI(relative);
+ }else{
+ relativeURI = EMPTY_URI;
}
URI resultURI;
resultURI = baseURI.resolve(relativeURI);
}
- if( ! resultURI.isAbsolute() ) throw new IllegalArgumentException();
+ if( ! resultURI.isAbsolute() ){
+ throw new IllegalArgumentException();
+ }
resultURI = resultURI.normalize();
return input;
}
+
+ /**
+ * オリジナルURIとリダイレクト先のURIを登録する。
+ * オリジナルURIへのアクセスはリダイレクトされる。
+ * @param original オリジナルURI
+ * @param redirect リダイレクトURI
+ */
+ private void putURIMapImpl(URI original, URI redirect){
+ URI oridinalNorm = original.normalize();
+ URI redirectNorm = redirect.normalize();
+
+ this.uriMap.put(oridinalNorm, redirectNorm);
+
+ return;
+ }
+
/**
* オリジナルURIとリダイレクト先のURIを登録する。
* オリジナルURIへのアクセスはリダイレクトされる。
* @param redirect リダイレクトURI
*/
public void putURIMap(URI original, URI redirect){
- this.uriMap.put(original.normalize(), redirect.normalize());
+ putURIMapImpl(original, redirect);
return;
}
/**
- * 変換後のリソースの入力ストリームを得る。
+ * 登録済みリダイレクト先リソースの入力ストリームを得る。
* @param originalURI オリジナルURI
- * @return 入力ストリーム
- * @throws java.io.IOException 入出力エラー
+ * @return 入力ストリーム。リダイレクト先が未登録の場合はnull
+ * @throws java.io.IOException 入出力エラー。
+ * もしくはリソースが見つからない。
*/
- public InputStream getXMLResourceAsStream(URI originalURI)
+ private InputStream getXMLResourceAsStream(URI originalURI)
throws IOException{
- URI resourceURI = this.uriMap.get(originalURI.normalize());
+ URI keyURI = originalURI.normalize();
+ URI resourceURI = this.uriMap.get(keyURI);
+ if(resourceURI == null){
+ return null;
+ }
+
URL resourceURL = resourceURI.toURL();
InputStream is = resourceURL.openStream();
}catch(IOException e){
return null;
}
+ if(is == null) return null;
LSInput input = createLSInput();
input.setBaseURI(baseURI);
}
InputStream is = getXMLResourceAsStream(originalUri);
+ if(is == null) return null;
InputSource source = new InputSource(is);
source.setPublicId(publicId);
}
- // TODO OASIS XML Catalog などと調和したい。
}
--- /dev/null
+/*
+ */
+
+package jp.sourceforge.mikutoga.typical;
+
+import java.util.List;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class TypicalBoneTest {
+
+ public TypicalBoneTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of findWithPrimary method, of class TypicalBone.
+ */
+ @Test
+ public void testFindWithPrimary() {
+ System.out.println("findWithPrimary");
+
+ TypicalBone result;
+ result = TypicalBone.findWithPrimary("頭");
+
+ assertEquals("頭", result.getTopPrimaryName());
+ assertEquals("head", result.getTopGlobalName());
+ assertEquals(1, result.getPrimaryList().size());
+ assertEquals("頭", result.getPrimaryList().get(0));
+ assertEquals(1, result.getGlobalList().size());
+ assertEquals("head", result.getGlobalList().get(0));
+
+ return;
+ }
+
+ /**
+ * Test of findWithGlobal method, of class TypicalBone.
+ */
+ @Test
+ public void testFindWithGlobal() {
+ System.out.println("findWithGlobal");
+
+ TypicalBone result;
+
+ result = TypicalBone.findWithGlobal("head");
+ assertNotNull(result);
+
+ TypicalBone result2;
+ result2 = TypicalBone.findWithPrimary("頭");
+
+ assertSame(result, result2);
+
+ return;
+ }
+
+ /**
+ * Test of primary2global method, of class TypicalBone.
+ */
+ @Test
+ public void testPrimary2global() {
+ System.out.println("primary2global");
+
+ String result;
+
+ result = TypicalBone.primary2global("頭");
+ assertEquals("head", result);
+
+ String result1;
+ String result2;
+
+ result1 = TypicalBone.primary2global("ボーン15");
+ result2 = TypicalBone.primary2global("ボーン15");
+ assertSame(result1, result2);
+
+ result = TypicalBone.primary2global("XXX");
+ assertNull(result);
+
+ return;
+ }
+
+ /**
+ * Test of global2primary method, of class TypicalBone.
+ */
+ @Test
+ public void testGlobal2primary() {
+ System.out.println("global2primary");
+
+ String result;
+
+ result = TypicalBone.global2primary("head");
+ assertEquals("頭", result);
+
+ result = TypicalBone.global2primary("head");
+ assertEquals("頭", result);
+
+ result = TypicalBone.global2primary("XXX");
+ assertNull(result);
+
+ return;
+ }
+
+ /**
+ * Test of getBoneList method, of class TypicalBone.
+ */
+ @Test
+ public void testGetBoneList() {
+ System.out.println("getBoneList");
+
+ List<TypicalBone> boneList;
+
+ boneList = TypicalBone.getBoneList();
+
+ assertNotNull(boneList);
+ assertEquals(77, boneList.size());
+
+ TypicalBone bone1st = boneList.get(0);
+ TypicalBone boneLast = boneList.get(77-1);
+
+ assertEquals("センター", bone1st.getTopPrimaryName());
+ assertEquals("ボーン15", boneLast.getTopPrimaryName());
+
+ assertEquals("center", bone1st.getTopGlobalName());
+ assertEquals("bone15", boneLast.getTopGlobalName());
+
+ return;
+ }
+
+}
--- /dev/null
+/*
+ */
+
+package jp.sourceforge.mikutoga.typical;
+
+import java.util.List;
+import jp.sourceforge.mikutoga.pmd.MorphType;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class TypicalMorphTest {
+
+ public TypicalMorphTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * Test of getTypedMorphList method, of class TypicalMorph.
+ */
+ @Test
+ public void testGetTypedMorphList() {
+ System.out.println("getTypedMorphList");
+
+ List<TypicalMorph> morphList;
+
+ morphList = TypicalMorph.getTypedMorphList(MorphType.EYEBROW);
+ assertEquals(6, morphList.size());
+
+ morphList = TypicalMorph.getTypedMorphList(MorphType.EYE);
+ assertEquals(7, morphList.size());
+
+ morphList = TypicalMorph.getTypedMorphList(MorphType.LIP);
+ assertEquals(12, morphList.size());
+
+ morphList = TypicalMorph.getTypedMorphList(MorphType.EXTRA);
+ assertEquals(2, morphList.size());
+
+ return;
+ }
+
+ /**
+ * Test of findWithPrimary method, of class TypicalMorph.
+ */
+ @Test
+ public void testFindWithPrimary() {
+ System.out.println("findWithPrimary");
+
+ TypicalMorph result;
+
+ result = TypicalMorph.findWithPrimary("あ");
+ assertNotNull(result);
+ assertEquals(MorphType.LIP, result.getMorphType());
+ assertEquals("あ", result.getTopPrimaryName());
+ assertEquals("a", result.getTopGlobalName());
+ assertEquals(1, result.getPrimaryList().size());
+ assertEquals("あ", result.getPrimaryList().get(0));
+ assertEquals(1, result.getGlobalList().size());
+ assertEquals("a", result.getGlobalList().get(0));
+
+ TypicalMorph result1;
+ TypicalMorph result2;
+
+ result1 = TypicalMorph.findWithPrimary("べー");
+ result2 = TypicalMorph.findWithPrimary("ぺろっ");
+ assertSame(result1, result2);
+ assertEquals(MorphType.EXTRA, result1.getMorphType());
+ assertEquals("べー", result1.getTopPrimaryName());
+ assertEquals("tongue", result1.getTopGlobalName());
+ assertEquals(2, result1.getPrimaryList().size());
+ assertEquals("べー", result1.getPrimaryList().get(0));
+ assertEquals("ぺろっ", result1.getPrimaryList().get(1));
+ assertEquals(1, result1.getGlobalList().size());
+ assertEquals("tongue", result1.getGlobalList().get(0));
+
+ return;
+ }
+
+ /**
+ * Test of findWithGlobal method, of class TypicalMorph.
+ */
+ @Test
+ public void testFindWithGlobal() {
+ System.out.println("findWithGlobal");
+
+ TypicalMorph result;
+
+ result = TypicalMorph.findWithGlobal("a");
+ assertNotNull(result);
+
+ TypicalMorph result2;
+ result2 = TypicalMorph.findWithPrimary("あ");
+
+ assertSame(result, result2);
+
+ return;
+ }
+
+ /**
+ * Test of primary2global method, of class TypicalMorph.
+ */
+ @Test
+ public void testPrimary2global() {
+ System.out.println("primary2global");
+
+ String result;
+
+ result = TypicalMorph.primary2global("あ");
+ assertEquals("a", result);
+
+ String result1;
+ String result2;
+
+ result1 = TypicalMorph.primary2global("べー");
+ result2 = TypicalMorph.primary2global("ぺろっ");
+ assertSame(result1, result2);
+
+ result1 = TypicalMorph.primary2global("ウィンク");
+ result2 = TypicalMorph.primary2global("ウィンク");
+ assertSame(result1, result2);
+
+ result = TypicalMorph.primary2global("XXX");
+ assertNull(result);
+
+ return;
+ }
+
+ /**
+ * Test of global2primary method, of class TypicalMorph.
+ */
+ @Test
+ public void testGlobal2primary() {
+ System.out.println("global2primary");
+
+ String result;
+
+ result = TypicalMorph.global2primary("a");
+ assertEquals("あ", result);
+
+ result = TypicalMorph.global2primary("tongue");
+ assertEquals("べー", result);
+
+ result = TypicalMorph.global2primary("XXX");
+ assertNull(result);
+
+ return;
+ }
+
+ /**
+ * Test of getMorphType method, of class TypicalMorph.
+ */
+ @Test
+ public void testGetMorphType() {
+ System.out.println("getMorphType");
+
+ List<TypicalMorph> morphList;
+
+ morphList = TypicalMorph.getTypedMorphList(MorphType.EYEBROW);
+
+ for(TypicalMorph morph : morphList){
+ MorphType type = morph.getMorphType();
+ assertEquals(MorphType.EYEBROW, type);
+ }
+
+ morphList = TypicalMorph.getTypedMorphList(MorphType.EYE);
+
+ for(TypicalMorph morph : morphList){
+ MorphType type = morph.getMorphType();
+ assertEquals(MorphType.EYE, type);
+ }
+
+ morphList = TypicalMorph.getTypedMorphList(MorphType.LIP);
+
+ for(TypicalMorph morph : morphList){
+ MorphType type = morph.getMorphType();
+ assertEquals(MorphType.LIP, type);
+ }
+
+ morphList = TypicalMorph.getTypedMorphList(MorphType.EXTRA);
+
+ for(TypicalMorph morph : morphList){
+ MorphType type = morph.getMorphType();
+ assertEquals(MorphType.EXTRA, type);
+ }
+
+ return;
+ }
+
+}