From: Olyutorskii Date: Mon, 31 Dec 2012 16:50:40 +0000 (+0900) Subject: XML出力改善 X-Git-Tag: fromMercurial~15 X-Git-Url: http://git.osdn.net/view?p=mikutoga%2FPmd2XML.git;a=commitdiff_plain;h=0f540c10ff143ec7b4087e27c214ebece7c85fe4;ds=sidebyside XML出力改善 ジェネレータ非表示オプション追加 コンバータ分離 --- diff --git a/.hgeol b/.hgeol index 8458257..71b275b 100644 --- a/.hgeol +++ b/.hgeol @@ -17,3 +17,5 @@ **.gif = BIN **.jpeg = BIN **.jpg = BIN +**.pmd = BIN + diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 8c4d115..539010a 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -6,6 +6,7 @@ Pmd2XML 変更履歴 X.XXX.X (20XX-XX-XX) ・Maven3対応。 + ・XML出力改行コードの指定が可能になる。 1.102.4 (2010-10-09) ・TogaGem1.105.2のバグ修正(接続ボーンを持たない剛体の件)に対処。 diff --git a/src/main/java/jp/sourceforge/mikutoga/pmd/model/xml/PmdXmlExporter.java b/src/main/java/jp/sourceforge/mikutoga/pmd/model/xml/PmdXmlExporter.java index 705a67c..ff9856d 100644 --- a/src/main/java/jp/sourceforge/mikutoga/pmd/model/xml/PmdXmlExporter.java +++ b/src/main/java/jp/sourceforge/mikutoga/pmd/model/xml/PmdXmlExporter.java @@ -92,7 +92,7 @@ public class PmdXmlExporter extends BasicXmlExporter{ + "[1 : ONLYDYNAMICS : 物理演算 ]\n" + "[2 : BONEDDYNAMICS : ボーン位置合わせ ]\n"; - private String generator = ""; + private String generator = null; /** * コンストラクタ。 @@ -106,12 +106,9 @@ public class PmdXmlExporter extends BasicXmlExporter{ /** * Generatorメタ情報を設定する。 - * @param generatorArg Generatorメタ情報 - * @throws NullPointerException 引数がnull + * @param generatorArg Generatorメタ情報。表示したくないときはnull */ - public void setGenerator(String generatorArg) - throws NullPointerException{ - if(generatorArg == null) throw new NullPointerException(); + public void setGenerator(String generatorArg){ this.generator = generatorArg; return; } @@ -366,7 +363,6 @@ public class PmdXmlExporter extends BasicXmlExporter{ putBRedContent(text); - ln(); ind().put("").ln(); if( ! hasOnlyBasicLatin(text) && isBasicLatinOnlyOut() ){ @@ -389,26 +385,22 @@ public class PmdXmlExporter extends BasicXmlExporter{ throws IOException{ int length = content.length(); - for(int pos = 0; pos < length; pos++){ - char ch = content.charAt(pos); + int startPos = 0; + + for(int idx = 0; idx < length; idx++){ + char ch = content.charAt(idx); if(ch == '\n'){ - put("
").ln(); - }else if(Character.isISOControl(ch)){ - putCharRef2Hex(ch); - }else if( ! isBasicLatin(ch) && isBasicLatinOnlyOut()){ - putCharRef4Hex(ch); - }else{ - switch(ch){ - case '&': put("&"); break; - case '<': put("<"); break; - case '>': put(">"); break; - case '"': put("""); break; - case '\'': put("'"); break; - default: put(ch); break; - } + CharSequence seq = content.subSequence(startPos, idx); + putContent(seq).put("
").ln(); + startPos = idx + 1; } } + if(startPos < length){ + CharSequence seq = content.subSequence(startPos, length); + putContent(seq).ln(); + } + return this; } @@ -425,10 +417,13 @@ public class PmdXmlExporter extends BasicXmlExporter{ ind().put("").ln(); ind().put("").ln(2); - ind().put("").ln(); + if(this.generator != null){ + ind().put("").ln(); + } + ind().put("").ln(); diff --git a/src/main/java/jp/sourceforge/mikutoga/pmd2xml/ModelFileTypes.java b/src/main/java/jp/sourceforge/mikutoga/pmd2xml/ModelFileTypes.java new file mode 100644 index 0000000..14d51f7 --- /dev/null +++ b/src/main/java/jp/sourceforge/mikutoga/pmd2xml/ModelFileTypes.java @@ -0,0 +1,27 @@ +/* + * MMD model file types. + * + * License : The MIT License + * Copyright(c) 2012 MikuToga Partners + */ + +package jp.sourceforge.mikutoga.pmd2xml; + +/** + * モデルファイル種別。 + */ +public enum ModelFileTypes { + /** 不明。 */ + NONE, + + /** MikuMikuDance ver7 前後で読み書きが可能なPMDファイル。 */ + PMD, + + /** + * スキーマ + * http://mikutoga.sourceforge.jp/xml/xsd/pmdxml-101009.xsd + * で定義されたXMLファイル。 + */ + XML_101009, + +} diff --git a/src/main/java/jp/sourceforge/mikutoga/pmd2xml/OptInfo.java b/src/main/java/jp/sourceforge/mikutoga/pmd2xml/OptInfo.java new file mode 100644 index 0000000..f50f2de --- /dev/null +++ b/src/main/java/jp/sourceforge/mikutoga/pmd2xml/OptInfo.java @@ -0,0 +1,328 @@ +/* + * command line argument info + * + * License : The MIT License + * Copyright(c) 2012 MikuToga Partners + */ + +package jp.sourceforge.mikutoga.pmd2xml; + +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +/** + * コマンドラインオプション情報。 + */ +final class OptInfo { + + private static final String EOL_LF = "\n"; + private static final String EOL_CRLF = "\r\n"; + private static final String EOL_DEFAULT = EOL_LF; + + private static final String GENERATOR = + Pmd2Xml.APPNAME + ' ' + Pmd2Xml.APPVER; + + private static final String HELP_CONSOLE = + "-h : put help message\n" + + "-pmd2xml : convert *.pmd to *.xml\n" + + "-xml2pmd : convert *.xml to *.pmd\n" + + "-i file : specify input file\n" + + "-o file : specify output file\n" + + "-f : force overwriting\n" + + "-lf : use LF as XML-newline (default)\n" + + "-crlf : use CR+LF as XML-newline\n" + + "-gen : print generator to XML (default)\n" + + "-nogen : do not print generator to XML\n" + ; + + private static final String ERRMSG_UNKNOWN = + "Unknown option : {0}"; + private static final String ERRMSG_NODIR = + "You must specify -pmd2xml or -xml2pmd."; + private static final String ERRMSG_NOINFILE = + "You must specify input file with -i."; + private static final String ERRMSG_NOOUTFILE = + "You must specify output file with -o."; + + + private boolean hasError = false; + private String errMsg = null; + + private boolean needHelp = false; + private ModelFileTypes inTypes = ModelFileTypes.NONE; + private ModelFileTypes outTypes = ModelFileTypes.NONE; + private String inFilename = null; + private String outFilename = null; + private boolean overwrite = false; + private String newline = EOL_DEFAULT; + private String generator = GENERATOR; + + + /** + * コンストラクタ。 + */ + private OptInfo(){ + super(); + return; + } + + + /** + * コマンドラインを解析する。 + * @param args コマンドライン + * @return オプション情報 + */ + static OptInfo parseOption(String... args){ + OptInfo result = new OptInfo(); + + int argIdx = 0; + int argLength = args.length; + + argline: while(argIdx < argLength){ + String arg = args[argIdx]; + + OptSwitch opt = OptSwitch.find(arg); + if(opt == null){ + String errMsg = MessageFormat.format(ERRMSG_UNKNOWN, arg); + result.putErrMsg(errMsg); + break argline; + } + + switch(opt){ + case OPT_HELP: + result.needHelp = true; + break argline; + case OPT_FORCE: + result.overwrite = true; + break; + case OPT_PMD2XML: + result.inTypes = ModelFileTypes.PMD; + result.outTypes = ModelFileTypes.XML_101009; + break; + case OPT_XML2PMD: + result.inTypes = ModelFileTypes.XML_101009; + result.outTypes = ModelFileTypes.PMD; + break; + case OPT_INFILE: + argIdx++; + if(argIdx >= argLength){ + result.putErrMsg(ERRMSG_NOINFILE); + break argline; + } + result.inFilename = args[argIdx]; + break; + case OPT_OUTFILE: + argIdx++; + if(argIdx >= argLength){ + result.putErrMsg(ERRMSG_NOOUTFILE); + break argline; + } + result.outFilename = args[argIdx]; + break; + case OPT_LF: + result.newline = EOL_LF; + break; + case OPT_CRLF: + result.newline = EOL_CRLF; + break; + case OPT_GEN: + result.generator = GENERATOR; + break; + case OPT_NOGEN: + result.generator = null; + break; + default: + assert false; + String errMsg = MessageFormat.format(ERRMSG_UNKNOWN, arg); + result.putErrMsg(errMsg); + break argline; + } + + if(result.hasError()) return result; + + argIdx++; + } + + if(result.hasError()) return result; + if(result.needHelp()) return result; + + checkResult(result); + + return result; + } + + /** + * オプション整合性の事後検査。 + * @param result オプション情報 + */ + private static void checkResult(OptInfo result){ + if( result.getInFileType() == ModelFileTypes.NONE + || result.getOutFileType() == ModelFileTypes.NONE ){ + result.putErrMsg(ERRMSG_NODIR); + return; + } + + if(result.getInFilename() == null){ + result.putErrMsg(ERRMSG_NOINFILE); + return; + } + + if(result.getOutFilename() == null){ + result.putErrMsg(ERRMSG_NOOUTFILE); + return; + } + + return; + } + + /** + * コンソール提示用ヘルプ出力文字列を返す。 + * @return オプションヘルプ文字列 + */ + static String getConsoleHelp(){ + return HELP_CONSOLE; + } + + + /** + * 解析中にエラーが起きたか判定する。 + * @return エラーが起きていればtrue + */ + boolean hasError(){ + return this.hasError; + } + + /** + * エラーメッセージを返す。 + * @return エラーメッセージ。なければnull + */ + String getErrorMessage(){ + return this.errMsg; + } + + /** + * ヘルプ表示が必要か否か判定する。 + * @return 必要ならtrue + */ + boolean needHelp(){ + return this.needHelp; + } + + /** + * 入力ファイル種別を返す。 + * @return 入力ファイル種別 + */ + ModelFileTypes getInFileType(){ + return this.inTypes; + } + + /** + * 出力ファイル種別を返す。 + * @return 出力ファイル種別 + */ + ModelFileTypes getOutFileType(){ + return this.outTypes; + } + + /** + * 入力ファイル名を返す。 + * @return 入力ファイル名 + */ + String getInFilename(){ + return this.inFilename; + } + + /** + * 出力ファイル名を返す。 + * @return 出力ファイル名 + */ + String getOutFilename(){ + return this.outFilename; + } + + /** + * 上書きモードか否か返す。 + * @return 上書きモードならtrue + */ + boolean overwriteMode(){ + return this.overwrite; + } + + /** + * XML改行文字を返す。 + * @return 改行文字 + */ + String getNewline(){ + return this.newline; + } + + /** + * ジェネレータ名を返す。 + * @return ジェネレータ名。表示したくない時はnull + */ + String getGenerator(){ + return this.generator; + } + + /** + * オプション解析エラー情報を設定する。 + * @param txt エラー文字列 + */ + private void putErrMsg(String txt){ + this.hasError = true; + this.errMsg = txt; + return; + } + + + /** + * オプションスイッチ群。 + */ + static enum OptSwitch{ + OPT_HELP ("-h", "-help", "-?"), + OPT_XML2PMD ("-xml2pmd"), + OPT_PMD2XML ("-pmd2xml"), + OPT_INFILE ("-i"), + OPT_OUTFILE ("-o"), + OPT_FORCE ("-f"), + OPT_LF ("-lf"), + OPT_CRLF ("-crlf"), + OPT_GEN ("-gen"), + OPT_NOGEN ("-nogen"), + ; + + + /** + * コンストラクタ。 + * @param cmdargs オプションスイッチパターン群 + */ + private OptSwitch(String... cmdargs){ + for(String cmdarg : cmdargs){ + MapHolder.MAP_OPT.put(cmdarg, this); + } + return; + } + + /** + * パターンに合致するオプションを見つける。 + * @param cmd パターン + * @return オプション。見つからなければnull + */ + static OptSwitch find(String cmd){ + OptSwitch result = MapHolder.MAP_OPT.get(cmd); + return result; + } + + + /** + * enumコンストラクタからクラス変数にアクセスできない文法を回避。 + */ + private static class MapHolder{ + static final Map MAP_OPT = + new HashMap(); + } + + } + +} diff --git a/src/main/java/jp/sourceforge/mikutoga/pmd2xml/Pmd2Xml.java b/src/main/java/jp/sourceforge/mikutoga/pmd2xml/Pmd2Xml.java index 0dd61ee..8e0b3c4 100644 --- a/src/main/java/jp/sourceforge/mikutoga/pmd2xml/Pmd2Xml.java +++ b/src/main/java/jp/sourceforge/mikutoga/pmd2xml/Pmd2Xml.java @@ -11,24 +11,17 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.PrintStream; import java.nio.channels.FileChannel; import java.util.Properties; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.ParserConfigurationException; import jp.sourceforge.mikutoga.parser.MmdFormatException; import jp.sourceforge.mikutoga.pmd.IllegalPmdDataException; -import jp.sourceforge.mikutoga.pmd.model.PmdModel; -import jp.sourceforge.mikutoga.pmd.model.binio.PmdExporter; -import jp.sourceforge.mikutoga.pmd.model.binio.PmdLoader; -import jp.sourceforge.mikutoga.pmd.model.xml.PmdXmlExporter; -import jp.sourceforge.mikutoga.pmd.model.xml.PmdXmlResources; -import jp.sourceforge.mikutoga.pmd.model.xml.Xml2PmdLoader; import jp.sourceforge.mikutoga.xml.TogaXmlException; -import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** @@ -36,10 +29,31 @@ import org.xml.sax.SAXException; */ public final class Pmd2Xml { + /** 正常系。 */ + public static final int EXIT_OK = 0; + /** ファイル入出力に起因するエラー。 */ + public static final int EXIT_FILE = 1; + /** XMLフォーマットに起因するエラー。 */ + public static final int EXIT_XML = 2; + /** PMDフォーマットに起因するエラー。 */ + public static final int EXIT_PMD = 3; + /** 実行環境に起因するエラー。 */ + public static final int EXIT_JREVER = 4; + /** オプション指定に起因するエラー。 */ + public static final int EXIT_OPT = 5; + /** 内部エラー。 */ + public static final int EXIT_INTERN = 6; + + /** アプリ名。 */ + public static final String APPNAME; + /** バージョン識別子。 */ + public static final String APPVER; + /** ライセンス種別。 */ + public static final String APPLICENSE; + private static final Class THISCLASS; - private static final String APPNAME; - private static final String APPVER; - private static final String APPLICENSE; + + private static final PrintStream ERROUT = System.err; static{ THISCLASS = Pmd2Xml.class; @@ -47,7 +61,11 @@ public final class Pmd2Xml { THISCLASS.getResourceAsStream("resources/version.properties"); Properties verProps = new Properties(); try{ - verProps.load(ver); + try{ + verProps.load(ver); + }finally{ + ver.close(); + } }catch(IOException e){ throw new ExceptionInInitializerError(e); } @@ -56,11 +74,12 @@ public final class Pmd2Xml { APPVER = verProps.getProperty("app.version"); APPLICENSE = verProps.getProperty("app.license"); - Object dummy = new Pmd2Xml(); + new Pmd2Xml().hashCode(); } + /** - * 隠しコンストラクタ。 + * ダミーコンストラクタ。 */ private Pmd2Xml(){ super(); @@ -68,128 +87,49 @@ public final class Pmd2Xml { return; } + /** - * Mainエントリ。 - * @param args コマンドパラメータ + * VMを終了させる。 + * @param code 終了コード */ - public static void main(String[] args){ - checkJRE(); - - String inputFile = null; - String outputFile = null; - boolean pmd2xml = false; - boolean xml2pmd = false; - boolean force = false; - int argsLen = args.length; - for(int argIdx = 0; argIdx < argsLen; argIdx++){ - String arg = args[argIdx]; - - if(arg.equals("-h")){ - putHelp(); - }else if(arg.equals("-pmd2xml")){ - pmd2xml = true; - xml2pmd = false; - }else if(arg.equals("-xml2pmd")){ - pmd2xml = false; - xml2pmd = true; - }else if(arg.equals("-i")){ - if(++argIdx >= argsLen){ - System.err.println("ERROR:"); - System.err.println("You need -i argument."); - System.err.println("(-h for help)"); - System.exit(5); - } - inputFile = args[argIdx]; - }else if(arg.equals("-o")){ - if(++argIdx >= argsLen){ - System.err.println("ERROR:"); - System.err.println("You need -o argument."); - System.err.println("(-h for help)"); - System.exit(5); - } - outputFile = args[argIdx]; - }else if(arg.equals("-f")){ - force = true; - }else{ - System.err.println("ERROR:"); - System.err.println("Unknown option:"+arg); - System.err.println("(-h for help)"); - System.exit(5); - } - } - - if( ( ! pmd2xml) && ( ! xml2pmd) ){ - System.err.println("ERROR:"); - System.err.println("You must specify -pmd2xml or -xml2pmd."); - System.err.println("(-h for help)"); - System.exit(5); - } - - if(inputFile == null){ - System.err.println("ERROR:"); - System.err.println("You must specify input file with -i."); - System.err.println("(-h for help)"); - System.exit(5); - } - - if(outputFile == null){ - System.err.println("ERROR:"); - System.err.println("You must specify output file with -o."); - System.err.println("(-h for help)"); - System.exit(5); - } + private static void exit(int code){ + System.exit(code); + return; + } - File iFile = new File(inputFile); - if( (! iFile.exists()) || (! iFile.isFile()) ){ - System.err.println("ERROR:"); - System.err.println("Can't find input file:" - + iFile.getAbsolutePath()); - System.err.println("(-h for help)"); - System.exit(1); - } + /** + * 標準エラー出力へ例外情報出力。 + * @param ex 例外 + * @param dumpStack スタックトレースを出力するならtrue + */ + private static void errPrintln(Throwable ex, boolean dumpStack){ + String text = ex.toString(); + ERROUT.println(text); - if( ! force ){ - File oFile = new File(outputFile); - if(oFile.exists()){ - System.err.println("ERROR:"); - System.err.println(oFile.getAbsolutePath() - + " already exists."); - System.err.println("If you want to overwrite, use -f."); - System.err.println("(-h for help)"); - System.exit(1); - } - }else{ - File oFile = new File(outputFile); - if(oFile.exists()){ - if( ! oFile.isFile()){ - System.err.println("ERROR:"); - System.err.println(oFile.getAbsolutePath() - + " is not file."); - System.err.println("(-h for help)"); - System.exit(1); - } - } + if(dumpStack){ + ex.printStackTrace(ERROUT); } - try{ - if(pmd2xml) pmd2xml(inputFile, outputFile); - else xml2pmd(inputFile, outputFile); - }catch(IOException e){ - ioError(e); - }catch(ParserConfigurationException e){ - internalError(e); - }catch(IllegalPmdDataException e){ - internalError(e); - }catch(MmdFormatException e){ - pmdError(e); - }catch(TogaXmlException e){ - xmlError(e); - }catch(SAXException e){ - xmlError(e); - } + return; + } - System.exit(0); + /** + * 標準エラー出力へ例外情報出力。 + * @param ex 例外 + */ + private static void errPrintln(Throwable ex){ + errPrintln(ex, false); + return; + } + /** + * 共通エラーメッセージを出力する。 + * @param text 個別メッセージ + */ + private static void errMsg(String text){ + ERROUT.println("ERROR:"); + ERROUT.println(text); + ERROUT.println("(-h for help)"); return; } @@ -199,8 +139,8 @@ public final class Pmd2Xml { * @param ex 例外 */ private static void ioError(Throwable ex){ - System.err.println(ex); - System.exit(1); + errPrintln(ex); + exit(EXIT_FILE); } /** @@ -209,8 +149,8 @@ public final class Pmd2Xml { * @param ex 例外 */ private static void xmlError(Throwable ex){ - System.err.println(ex); - System.exit(2); + errPrintln(ex); + exit(EXIT_XML); } /** @@ -219,9 +159,8 @@ public final class Pmd2Xml { * @param ex 例外 */ private static void pmdError(Throwable ex){ - System.err.println(ex); - ex.printStackTrace(System.err); - System.exit(3); + errPrintln(ex, true); + exit(EXIT_PMD); } /** @@ -230,9 +169,8 @@ public final class Pmd2Xml { * @param ex 例外 */ private static void internalError(Throwable ex){ - System.err.println(ex); - ex.printStackTrace(System.err); - System.exit(4); + errPrintln(ex, true); + exit(EXIT_INTERN); } /** @@ -242,8 +180,8 @@ public final class Pmd2Xml { private static void checkJRE(){ Package jrePackage = java.lang.Object.class.getPackage(); if( ! jrePackage.isCompatibleWith("1.6")){ - System.err.println("You need JRE 1.6 or later."); - System.exit(4); + ERROUT.println("You need JRE 1.6 or later."); + exit(EXIT_JREVER); } return; } @@ -252,77 +190,20 @@ public final class Pmd2Xml { * ヘルプメッセージを出力してVMを終了させる。 */ private static void putHelp(){ - System.err.println(APPNAME + ' ' + APPVER ); - System.err.println(" License : " + APPLICENSE); - System.err.println(" http://mikutoga.sourceforge.jp/"); - System.err.println(); - System.err.println("-h : put help massage"); - System.err.println("-pmd2xml : convert *.pmd to *.xml"); - System.err.println("-xml2pmd : convert *.xml to *.pmd"); - System.err.println("-i file : specify input file"); - System.err.println("-o file : specify output file"); - System.err.println("-f : force overwriting"); - System.exit(0); - return; - } + StringBuilder appInfo = new StringBuilder(); + String indent = " "; - /** - * PMD->XML変換を行う。 - * @param inputFile 入力ファイル名 - * @param outputFile 出力ファイル名 - * @throws IOException 入出力エラー - * @throws MmdFormatException 不正なPMDファイル - * @throws IllegalPmdDataException 不正なモデルデータ - */ - private static void pmd2xml(String inputFile, String outputFile) - throws IOException, MmdFormatException, IllegalPmdDataException{ - File iFile = new File(inputFile); - InputStream is = new FileInputStream(iFile); - is = new BufferedInputStream(is); - PmdModel model = pmdRead(is); - is.close(); + appInfo.append(APPNAME).append(' ').append(APPVER) + .append('\n'); + appInfo.append(indent) + .append("License").append(" : ").append(APPLICENSE) + .append('\n'); + appInfo.append(indent) + .append("http://mikutoga.sourceforge.jp/") + .append('\n'); - File oFile = new File(outputFile); - trunc(oFile); - OutputStream ostream; - ostream = new FileOutputStream(oFile, false); - ostream = new BufferedOutputStream(ostream); - xmlOut(model, ostream); - ostream.close(); - - return; - } - - /** - * XML->PMD変換を行う。 - * @param inputFile 入力ファイル名 - * @param outputFile 出力ファイル名 - * @throws IOException 入出力エラー - * @throws ParserConfigurationException XML構成のエラー - * @throws SAXException 不正なXMLファイル - * @throws TogaXmlException 不正なXMLファイル - * @throws IllegalPmdDataException 不正なPMDモデルデータ - */ - private static void xml2pmd(String inputFile, String outputFile) - throws IOException, - ParserConfigurationException, - SAXException, - TogaXmlException, - IllegalPmdDataException { - File iFile = new File(inputFile); - InputStream is = new FileInputStream(iFile); - is = new BufferedInputStream(is); - InputSource source = new InputSource(is); - PmdModel model = xmlRead(source); - is.close(); - - File oFile = new File(outputFile); - trunc(oFile); - OutputStream ostream; - ostream = new FileOutputStream(oFile, false); - ostream = new BufferedOutputStream(ostream); - pmdOut(model, ostream); - ostream.close(); + ERROUT.println(appInfo.toString()); + ERROUT.println(OptInfo.getConsoleHelp()); return; } @@ -347,73 +228,135 @@ public final class Pmd2Xml { } /** - * PMDファイルからモデルデータを読み込む。 - * @param is 入力ストリーム - * @return モデルデータ - * @throws IOException 入力エラー - * @throws MmdFormatException 不正なPMDファイルフォーマット + * 入力ストリームを準備する。 + * @param fileName 入力ファイル名 + * @return 入力ストリーム */ - private static PmdModel pmdRead(InputStream is) - throws IOException, MmdFormatException{ - PmdLoader loader = new PmdLoader(is); + private static InputStream openInfile(String fileName){ + File inFile = new File(fileName); - PmdModel model = loader.load(); + if( (! inFile.exists()) || (! inFile.isFile()) ){ + String absPath = inFile.getAbsolutePath(); + errMsg("Can't find input file:" + absPath); + exit(EXIT_FILE); + } - return model; - } + InputStream is = null; + try{ + is = new FileInputStream(inFile); + }catch(FileNotFoundException e){ + ioError(e); + assert false; + } - /** - * XMLファイルからモデルデータを読み込む。 - * @param source 入力ソース - * @return モデルデータ - * @throws IOException 入力エラー - * @throws ParserConfigurationException XML構成エラー - * @throws SAXException XML構文エラー - * @throws TogaXmlException 不正なXMLデータ - */ - private static PmdModel xmlRead(InputSource source) - throws IOException, - ParserConfigurationException, - SAXException, - TogaXmlException { - DocumentBuilder builder = - PmdXmlResources.newBuilder(XmlHandler.HANDLER); - Xml2PmdLoader loader = new Xml2PmdLoader(builder); - - PmdModel model = loader.parse(source); - - return model; + is = new BufferedInputStream(is); + + return is; } /** - * モデルデータをPMDファイルに出力する。 - * @param model モデルデータ - * @param ostream 出力ストリーム - * @throws IOException 出力エラー - * @throws IllegalPmdDataException 不正なモデルデータ + * 出力ストリームを準備する。 + * @param fileName 出力ファイル名 + * @param overWrite 頭から上書きして良ければtrue + * @return 出力ストリーム */ - private static void pmdOut(PmdModel model, OutputStream ostream) - throws IOException, IllegalPmdDataException{ - PmdExporter exporter = new PmdExporter(ostream); - exporter.dumpPmdModel(model); - ostream.close(); - return; + private static OutputStream openOutfile(String fileName, + boolean overWrite) { + File outFile = new File(fileName); + + if(outFile.exists()){ + String absPath = outFile.getAbsolutePath(); + if( ! outFile.isFile() ){ + String msg = absPath + " is not file."; + errMsg(msg); + exit(EXIT_FILE); + }else if( ! overWrite ){ + String msg = + absPath + " already exists.\n" + + "If you want to overwrite, use -f."; + errMsg(msg); + exit(EXIT_FILE); + } + } + + try{ + trunc(outFile); + }catch(IOException e){ + ioError(e); + } + + OutputStream os = null; + try{ + os = new FileOutputStream(outFile); + }catch(FileNotFoundException e){ + ioError(e); + assert false; + } + + os = new BufferedOutputStream(os); + + return os; } /** - * モデルデータをXMLファイルに出力する。 - * @param model モデルデータ - * @param ostream 出力ストリーム - * @throws IOException 出力エラー - * @throws IllegalPmdDataException 不正なモデルデータ + * Mainエントリ。 + * @param args コマンドパラメータ */ - private static void xmlOut(PmdModel model, OutputStream ostream) - throws IOException, IllegalPmdDataException{ - PmdXmlExporter exporter = new PmdXmlExporter(ostream); - exporter.setNewLine("\r\n"); - exporter.setGenerator(APPNAME + ' ' + APPVER); - exporter.putPmdModel(model); - exporter.close(); + public static void main(String[] args){ + checkJRE(); + + Pmd2XmlConv converter = new Pmd2XmlConv(); + + OptInfo optInfo = OptInfo.parseOption(args); + if(optInfo.needHelp()){ + putHelp(); + exit(EXIT_OK); + }else if(optInfo.hasError()){ + String optErrMsg = optInfo.getErrorMessage(); + errMsg(optErrMsg); + exit(EXIT_OPT); + } + + String inputFile = optInfo.getInFilename(); + String outputFile = optInfo.getOutFilename(); + boolean overwrite = optInfo.overwriteMode(); + + InputStream is = openInfile(inputFile); + OutputStream os = openOutfile(outputFile, overwrite); + + converter.setInType(optInfo.getInFileType()); + converter.setOutType(optInfo.getOutFileType()); + + converter.setNewline(optInfo.getNewline()); + converter.setGenerator(optInfo.getGenerator()); + + try{ + converter.convert(is, os); + }catch(IOException e){ + ioError(e); + }catch(IllegalPmdDataException e){ + internalError(e); + }catch(MmdFormatException e){ + pmdError(e); + }catch(TogaXmlException e){ + xmlError(e); + }catch(SAXException e){ + xmlError(e); + } + + try{ + is.close(); + try{ + os.close(); + }catch(IOException e){ + ioError(e); + } + }catch(IOException e){ + ioError(e); + } + + exit(EXIT_OK); + return; } diff --git a/src/main/java/jp/sourceforge/mikutoga/pmd2xml/Pmd2XmlConv.java b/src/main/java/jp/sourceforge/mikutoga/pmd2xml/Pmd2XmlConv.java new file mode 100644 index 0000000..bd99da5 --- /dev/null +++ b/src/main/java/jp/sourceforge/mikutoga/pmd2xml/Pmd2XmlConv.java @@ -0,0 +1,281 @@ +/* + * pmd 2 xml converter + * + * License : The MIT License + * Copyright(c) 2010 MikuToga Partners + */ + +package jp.sourceforge.mikutoga.pmd2xml; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.ParserConfigurationException; +import jp.sourceforge.mikutoga.parser.MmdFormatException; +import jp.sourceforge.mikutoga.pmd.IllegalPmdDataException; +import jp.sourceforge.mikutoga.pmd.model.PmdModel; +import jp.sourceforge.mikutoga.pmd.model.binio.PmdExporter; +import jp.sourceforge.mikutoga.pmd.model.binio.PmdLoader; +import jp.sourceforge.mikutoga.pmd.model.xml.PmdXmlExporter; +import jp.sourceforge.mikutoga.pmd.model.xml.PmdXmlResources; +import jp.sourceforge.mikutoga.pmd.model.xml.Xml2PmdLoader; +import jp.sourceforge.mikutoga.xml.TogaXmlException; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * PMD-XML間コンバータ本体。 + */ +public class Pmd2XmlConv { + + private ModelFileTypes inTypes = ModelFileTypes.NONE; + private ModelFileTypes outTypes = ModelFileTypes.NONE; + private String newLine = "\r\n"; + private String generator = null; + + private final DocumentBuilder builder; + + + /** + * コンストラクタ。 + */ + public Pmd2XmlConv(){ + super(); + + try{ + this.builder = PmdXmlResources.newBuilder(XmlHandler.HANDLER); + }catch(SAXException e){ + throw new AssertionError(e); + }catch(ParserConfigurationException e){ + throw new AssertionError(e); + } + + return; + } + + + /** + * 入力ファイル種別を設定する。 + * @param type ファイル種別 + */ + public void setInType(ModelFileTypes type){ + if(type == null) throw new NullPointerException(); + this.inTypes = type; + return; + } + + /** + * 入力ファイル種別を返す。 + * @return ファイル種別 + */ + public ModelFileTypes getInTypes(){ + return this.inTypes; + } + + /** + * 出力ファイル種別を設定する。 + * @param type ファイル種別 + */ + public void setOutType(ModelFileTypes type){ + if(type == null) throw new NullPointerException(); + this.outTypes = type; + return; + } + + /** + * 出力ファイル種別を返す。 + * @return ファイル種別 + */ + public ModelFileTypes getOutTypes(){ + return this.outTypes; + } + + /** + * XML出力用改行文字列を設定する。 + * @param newline 改行文字 + */ + public void setNewline(String newline){ + this.newLine = newline; + return; + } + + /** + * XML出力用改行文字列を返す。 + * @return 改行文字 + */ + public String getNewLine(){ + return this.newLine; + } + + /** + * ジェネレータ名を設定する。 + * @param generator ジェネレータ名。表示したくない場合はnull + */ + public void setGenerator(String generator){ + this.generator = generator; + return; + } + + /** + * ジェネレータ名を返す。 + * @return ジェネレータ名。非表示の場合はnullを返す。 + */ + public String getGenerator(){ + return this.generator; + } + + /** + * ファイル変換を行う。 + * @param is 入力ストリーム + * @param os 出力ストリーム + * @throws IOException 入力エラー + * @throws MmdFormatException フォーマットエラー + * @throws SAXException XMLエラー + * @throws TogaXmlException XMLエラー + * @throws IllegalPmdDataException 内部エラー + */ + public void convert(InputStream is, OutputStream os) + throws IOException, + MmdFormatException, + SAXException, + TogaXmlException, + IllegalPmdDataException { + PmdModel model = readModel(is); + writeModel(model, os); + return; + } + + /** + * モデルファイルを読み込む。 + * @param is 入力ストリーム + * @return モデルデータ + * @throws IOException 入力エラー + * @throws MmdFormatException フォーマットエラー + * @throws SAXException XMLエラー + * @throws TogaXmlException XMLエラー + */ + public PmdModel readModel(InputStream is) + throws IOException, + MmdFormatException, + SAXException, + TogaXmlException { + PmdModel model = null; + switch(this.inTypes){ + case PMD: + model = pmdRead(is); + break; + case XML_101009: + model = xmlRead(is); + break; + default: + assert false; + break; + } + return model; + } + + /** + * モデルファイルを出力する。 + * @param model モデルデータ + * @param os 出力ストリーム + * @throws IOException 出力エラー + * @throws IllegalPmdDataException データの不備 + */ + public void writeModel(PmdModel model, OutputStream os) + throws IOException, + IllegalPmdDataException { + switch(this.outTypes){ + case PMD: + pmdOut(model, os); + break; + case XML_101009: + xmlOut(model, os); + break; + default: + assert false; + break; + } + } + + /** + * PMDファイルからモデルデータを読み込む。 + * @param is 入力ストリーム + * @return モデルデータ + * @throws IOException 入力エラー + * @throws MmdFormatException 不正なPMDファイルフォーマット + */ + private PmdModel pmdRead(InputStream is) + throws IOException, MmdFormatException{ + PmdLoader loader = new PmdLoader(is); + PmdModel model = loader.load(); + return model; + } + + /** + * XMLファイルからモデルデータを読み込む。 + * @param is 入力ストリーム + * @return モデルデータ + * @throws IOException 入力エラー + * @throws SAXException XML構文エラー + * @throws TogaXmlException 不正なXMLデータ + */ + private PmdModel xmlRead(InputStream is) + throws IOException, + SAXException, + TogaXmlException { + InputSource source = new InputSource(is); + PmdModel result = xmlRead(source); + return result; + } + + /** + * XMLファイルからモデルデータを読み込む。 + * @param source 入力ソース + * @return モデルデータ + * @throws IOException 入力エラー + * @throws SAXException XML構文エラー + * @throws TogaXmlException 不正なXMLデータ + */ + private PmdModel xmlRead(InputSource source) + throws IOException, + SAXException, + TogaXmlException { + Xml2PmdLoader loader = new Xml2PmdLoader(this.builder); + PmdModel model = loader.parse(source); + return model; + } + + /** + * モデルデータをPMDファイルに出力する。 + * @param model モデルデータ + * @param ostream 出力ストリーム + * @throws IOException 出力エラー + * @throws IllegalPmdDataException 不正なモデルデータ + */ + private void pmdOut(PmdModel model, OutputStream ostream) + throws IOException, IllegalPmdDataException{ + PmdExporter exporter = new PmdExporter(ostream); + exporter.dumpPmdModel(model); + ostream.close(); + return; + } + + /** + * モデルデータをXMLファイルに出力する。 + * @param model モデルデータ + * @param ostream 出力ストリーム + * @throws IOException 出力エラー + * @throws IllegalPmdDataException 不正なモデルデータ + */ + private void xmlOut(PmdModel model, OutputStream ostream) + throws IOException, IllegalPmdDataException{ + PmdXmlExporter exporter = new PmdXmlExporter(ostream); + exporter.setNewLine(this.newLine); + exporter.setGenerator(this.generator); + exporter.putPmdModel(model); + exporter.close(); + return; + } + +} diff --git a/src/test/java/testdata/CnvAssert.java b/src/test/java/testdata/CnvAssert.java new file mode 100644 index 0000000..83ca380 --- /dev/null +++ b/src/test/java/testdata/CnvAssert.java @@ -0,0 +1,163 @@ +/* + */ + +package testdata; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import jp.sourceforge.mikutoga.pmd2xml.ModelFileTypes; +import jp.sourceforge.mikutoga.pmd2xml.Pmd2XmlConv; + +import static org.junit.Assert.*; + +/** + * + */ +public class CnvAssert { + + /** + * テスト出力用テンポラリファイルの生成。 + * テスト終了時(VM終了時)に消える。 + * @return テンポラリファイル + * @throws IOException エラー + */ + public static File openTempFile() throws IOException{ + File file = File.createTempFile("pmd2xml", null); + file.deleteOnExit(); + return file; + } + + /** + * XMLリソースをPMDに変換した結果がPMDリソースに等しいと表明する。 + * @param klass リソース元クラス + * @param xmlResource XMLリソース名 + * @param expPmdResource PMDリソース名 + * @throws Exception エラー + */ + public static void assertXml2Pmd( + Class klass, + String xmlResource, + String expPmdResource ) + throws Exception{ + InputStream xmlis = + klass.getResourceAsStream(xmlResource); + assertNotNull(xmlis); + xmlis = new BufferedInputStream(xmlis); + + File destFile = openTempFile(); + OutputStream destOut; + destOut = new FileOutputStream(destFile); + destOut = new BufferedOutputStream(destOut); + + Pmd2XmlConv converter = new Pmd2XmlConv(); + converter.setInType(ModelFileTypes.XML_101009); + converter.setOutType(ModelFileTypes.PMD); + converter.setNewline("\n"); + + converter.convert(xmlis, destOut); + + xmlis.close(); + destOut.close(); + + assertSameFile(klass, expPmdResource, destFile); + + return; + } + + /** + * PMDリソースをXMLに変換した結果がXMLリソースに等しいと表明する。 + * @param klass リソース元クラス + * @param pmdResource PMDリソース名 + * @param expXmlResource XMLリソース名 + * @throws Exception エラー + */ + public static void assertPmd2Xml( + Class klass, + String pmdResource, + String expXmlResource ) + throws Exception{ + InputStream pmdis = + klass.getResourceAsStream(pmdResource); + assertNotNull(pmdis); + pmdis = new BufferedInputStream(pmdis); + + File destFile = openTempFile(); + OutputStream destOut; + destOut = new FileOutputStream(destFile); + destOut = new BufferedOutputStream(destOut); + + Pmd2XmlConv converter = new Pmd2XmlConv(); + converter.setInType(ModelFileTypes.PMD); + converter.setOutType(ModelFileTypes.XML_101009); + converter.setNewline("\n"); + converter.setGenerator(null); + + converter.convert(pmdis, destOut); + + pmdis.close(); + destOut.close(); + + assertSameFile(klass, expXmlResource, destFile); + + return; + } + + /** + * リソースとファイルの内容が等しいと表明する。 + * @param klass リソース元クラス + * @param resourceName リソース名 + * @param resFile ファイル + * @throws IOException 入力エラー + */ + public static void assertSameFile( + Class klass, + String resourceName, + File resFile ) + throws IOException{ + InputStream expis = + klass.getResourceAsStream(resourceName); + assertNotNull(expis); + + InputStream resIn = new FileInputStream(resFile); + + try{ + assertSameStream(expis, resIn); + }finally{ + expis.close(); + resIn.close(); + } + + return; + } + + /** + * 2つの入力ストリーム内容が等しいと表明する。 + * @param expIn 期待する入力ストリーム + * @param resIn 結果入力ストリーム + * @throws IOException 入力エラー + */ + public static void assertSameStream(InputStream expIn, InputStream resIn) + throws IOException{ + InputStream expis = new BufferedInputStream(expIn); + InputStream resis = new BufferedInputStream(resIn); + + + for(;;){ + int expCh = expis.read(); + int resCh = resis.read(); + + assertEquals(expCh, resCh); + + if(expCh < 0) break; + } + + return; + } + +} diff --git a/src/test/java/testdata/charset/CharsetTest.java b/src/test/java/testdata/charset/CharsetTest.java new file mode 100644 index 0000000..1185976 --- /dev/null +++ b/src/test/java/testdata/charset/CharsetTest.java @@ -0,0 +1,56 @@ +/* + */ + +package testdata.charset; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import static testdata.CnvAssert.*; + +/** + * + */ +public class CharsetTest { + + static Class THISCLASS = CharsetTest.class; + + public CharsetTest() { + assert this.getClass() == THISCLASS; + return; + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void pmd2xml() throws Exception{ + System.out.println("pmd2xml"); + assertPmd2Xml(THISCLASS, "test.pmd", "result.xml"); + return; + } + + @Test + public void xml2pmd() throws Exception{ + System.out.println("xml2pmd"); + assertXml2Pmd(THISCLASS, "source.xml", "test.pmd"); + return; + } + +} diff --git a/src/test/java/testdata/minimum/MinimumTest.java b/src/test/java/testdata/minimum/MinimumTest.java new file mode 100644 index 0000000..485b204 --- /dev/null +++ b/src/test/java/testdata/minimum/MinimumTest.java @@ -0,0 +1,56 @@ +/* + */ + +package testdata.minimum; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import static testdata.CnvAssert.*; + +/** + * + */ +public class MinimumTest { + + static Class THISCLASS = MinimumTest.class; + + public MinimumTest() { + assert this.getClass() == THISCLASS; + return; + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void pmd2xml() throws Exception{ + System.out.println("pmd2xml"); + assertPmd2Xml(THISCLASS, "test.pmd", "test.xml"); + return; + } + + @Test + public void xml2pmd() throws Exception{ + System.out.println("xml2pmd"); + assertXml2Pmd(THISCLASS, "test.xml", "test.pmd"); + return; + } + +} diff --git a/src/test/resources/testdata/charset/Readme.txt b/src/test/resources/testdata/charset/Readme.txt new file mode 100644 index 0000000..4a4691b --- /dev/null +++ b/src/test/resources/testdata/charset/Readme.txt @@ -0,0 +1 @@ +文字集合、エンコーディング、XML文字エスケープ、空白文字に関するテストデータ。 diff --git a/src/test/resources/testdata/charset/result.xml b/src/test/resources/testdata/charset/result.xml new file mode 100644 index 0000000..68d22ee --- /dev/null +++ b/src/test/resources/testdata/charset/result.xml @@ -0,0 +1,170 @@ + + + + + + + + + + +azAZAZ0909あアアゑヵヶΩωЖж
+┐└漢峠凜熙
+ヴウ゛ヴパハ゜パ
+壺壷尭堯
+\\\¥
+髙⑨≒∵¬㈱Σ
+#$[\]^{|}~
+cdata'"&<>test
+<!--fake comment-->
+A B C D E F  GHI +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/src/test/resources/testdata/charset/source.xml b/src/test/resources/testdata/charset/source.xml new file mode 100644 index 0000000..0f80ccc --- /dev/null +++ b/src/test/resources/testdata/charset/source.xml @@ -0,0 +1,158 @@ + + + + + + + + + +azAZAZ0909あアアゑヵヶΩωЖж
+┐└漢峠凜熙
+ヴウ゛ヴパハ゜パ
+壺壷尭堯
+\\¥¥
+髙⑨≒∵¬㈱Σ
+#$[\]^{|}~
+test]]>
+]]>
+A B C D E F  G +H I +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/src/test/resources/testdata/charset/test.pmd b/src/test/resources/testdata/charset/test.pmd new file mode 100644 index 0000000..6cb6d5d Binary files /dev/null and b/src/test/resources/testdata/charset/test.pmd differ diff --git a/src/test/resources/testdata/minimum/Readme.txt b/src/test/resources/testdata/minimum/Readme.txt new file mode 100644 index 0000000..7fd068b --- /dev/null +++ b/src/test/resources/testdata/minimum/Readme.txt @@ -0,0 +1,7 @@ +最小構成のPMDファイル。 +※ XMLの改行コードはLF。ジェネレータ名は非表示。 + +名前は空 +説明文は空 +頂点0 +ボーン0 diff --git a/src/test/resources/testdata/minimum/test.pmd b/src/test/resources/testdata/minimum/test.pmd new file mode 100644 index 0000000..c2fb71c Binary files /dev/null and b/src/test/resources/testdata/minimum/test.pmd differ diff --git a/src/test/resources/testdata/minimum/test.xml b/src/test/resources/testdata/minimum/test.xml new file mode 100644 index 0000000..2c33970 --- /dev/null +++ b/src/test/resources/testdata/minimum/test.xml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +