OSDN Git Service

Pmd2XMLとの共通化
[mikutoga/Vmd2XML.git] / src / main / java / jp / sfjp / mikutoga / vmd2xml / Vmd2Xml.java
1 /*
2  * vmd to xml converter main entry
3  *
4  * License : The MIT License
5  * Copyright(c) 2011 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.vmd2xml;
9
10 import java.io.BufferedInputStream;
11 import java.io.BufferedOutputStream;
12 import java.io.File;
13 import java.io.FileInputStream;
14 import java.io.FileNotFoundException;
15 import java.io.FileOutputStream;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.OutputStream;
19 import java.io.PrintStream;
20 import java.nio.channels.FileChannel;
21 import java.text.MessageFormat;
22 import java.util.Properties;
23 import jp.sfjp.mikutoga.bin.parser.MmdFormatException;
24 import jp.sfjp.mikutoga.vmd.IllegalVmdDataException;
25 import jp.sourceforge.mikutoga.xml.TogaXmlException;
26 import org.xml.sax.SAXException;
27
28
29 /**
30  * VMDモーションファイルとXMLとの間で変換を行うアプリケーション。
31  */
32 public final class Vmd2Xml {
33
34     /** 正常系。 */
35     public static final int EXIT_OK     = 0;
36     /** 内部エラー。 */
37     public static final int EXIT_INTERR = 1;
38     /** 実行環境に起因するエラー。 */
39     public static final int EXIT_ENVERR = 2;
40     /** オプション指定に起因するエラー。 */
41     public static final int EXIT_OPTERR = 3;
42     /** ファイル入出力に起因するエラー。 */
43     public static final int EXIT_IOERR  = 4;
44     /** XMLフォーマットに起因するエラー。 */
45     public static final int EXIT_XMLERR = 5;
46     /** VMDフォーマットに起因するエラー。 */
47     public static final int EXIT_VMDERR = 7;
48
49     /** アプリ名。 */
50     public static final String APPNAME;
51     /** バージョン識別子。 */
52     public static final String APPVER;
53     /** ライセンス種別。 */
54     public static final String APPLICENSE;
55     /** 開発元URL。 */
56     public static final String APPURL;
57
58     private static final Class<?> THISCLASS;
59     private static final String RES_VER = "resources/version.properties";
60
61     private static final PrintStream ERROUT = System.err;
62     private static final String MSG_ERR = "ERROR:\n{0}\n(-h for help)";
63     private static final String MSG_HELP =
64               "{0} {1}\n"
65             + "\u0020\u0020License\u0020:\u0020{2}\n"
66             + "\u0020\u0020{3}\n";
67     private static final String MSG_NOINFILE = "Can't find input file:{0}";
68     private static final String MSG_ABNFILE = "{0} is not file.";
69     private static final String MSG_OWOUTFILE =
70               "{0} already exists.\n"
71             + "If you want to overwrite, use -f.";
72
73     private static final String MSG_OLDJRE = "You need JRE {0} or later.";
74     private static final String REQUIRED_JRE = "1.6";
75
76     static{
77         THISCLASS = Vmd2Xml.class;
78         InputStream ver = THISCLASS.getResourceAsStream(RES_VER);
79         Properties verProps = new Properties();
80         try{
81             try{
82                 verProps.load(ver);
83             }finally{
84                 ver.close();
85             }
86         }catch(IOException e){
87             throw new ExceptionInInitializerError(e);
88         }
89
90         APPNAME    = verProps.getProperty("app.name");
91         APPVER     = verProps.getProperty("app.version");
92         APPLICENSE = verProps.getProperty("app.license");
93         APPURL     = verProps.getProperty("app.url");
94
95         new Vmd2Xml().hashCode();
96     }
97
98
99     /**
100      * ダミーコンストラクタ。
101      */
102     private Vmd2Xml(){
103         super();
104         assert this.getClass().equals(THISCLASS);
105         return;
106     }
107
108
109     /**
110      * VMを終了させる。
111      * @param code 終了コード
112      * @see java.lang.System#exit(int)
113      */
114     private static void exit(int code){
115         System.exit(code);
116         assert false;
117         throw new AssertionError();
118     }
119
120     /**
121      * 共通エラーメッセージを出力する。
122      * @param text 個別メッセージ
123      */
124     private static void errMsg(String text){
125         String msg = MessageFormat.format(MSG_ERR, text);
126         ERROUT.println(msg);
127         return;
128     }
129
130     /**
131      * 標準エラー出力へ例外情報出力。
132      * @param ex 例外
133      * @param dumpStack スタックトレースを出力するならtrue
134      */
135     private static void thPrintln(Throwable ex, boolean dumpStack){
136         if(dumpStack){
137             ex.printStackTrace(ERROUT);
138         }else{
139             String text = ex.toString();
140             ERROUT.println(text);
141         }
142
143         return;
144     }
145
146     /**
147      * 標準エラー出力へ例外情報出力。
148      * @param ex 例外
149      */
150     private static void thPrintln(Throwable ex){
151         thPrintln(ex, false);
152         return;
153     }
154
155     /**
156      * 入出力エラー処理。
157      * 例外を出力してVM終了する。
158      * @param ex 例外
159      */
160     private static void ioError(IOException ex){
161         thPrintln(ex);
162         exit(EXIT_IOERR);
163     }
164
165     /**
166      * XML構文エラー処理。
167      * 例外を出力してVM終了する。
168      * @param ex 例外
169      */
170     private static void xmlError(Throwable ex){
171         thPrintln(ex);
172         exit(EXIT_XMLERR);
173     }
174
175     /**
176      * VMDファイルフォーマットエラー処理。
177      * 例外を出力してVM終了する。
178      * @param ex 例外
179      */
180     private static void vmdError(MmdFormatException ex){
181         thPrintln(ex, true);
182         exit(EXIT_VMDERR);
183     }
184
185     /**
186      * 内部エラー処理。
187      * 例外を出力してVM終了する。
188      * @param ex 例外
189      */
190     private static void internalError(Throwable ex){
191         thPrintln(ex, true);
192         exit(EXIT_INTERR);
193     }
194
195     /**
196      * JREのバージョン判定を行う。
197      * 不適切ならVMごと終了。
198      */
199     private static void checkJRE(){
200         Package jrePackage = java.lang.Object.class.getPackage();
201         if( ! jrePackage.isCompatibleWith(REQUIRED_JRE)){
202             String msg = MessageFormat.format(MSG_OLDJRE, REQUIRED_JRE);
203             ERROUT.println(msg);
204             exit(EXIT_ENVERR);
205         }
206         return;
207     }
208
209     /**
210      * ヘルプメッセージを出力する。
211      */
212     private static void putHelp(){
213         String msg =
214                 MessageFormat.format(MSG_HELP,
215                 APPNAME, APPVER, APPLICENSE, APPURL);
216         ERROUT.println(msg);
217         ERROUT.println(OptSwitch.getConsoleHelp());
218         return;
219     }
220
221     /**
222      * ファイルサイズを0に切り詰める。
223      * <p>ファイルが存在しなければなにもしない。
224      * <p>通常ファイルでなければなにもしない。
225      * @param file ファイル
226      * @throws IOException 入出力エラー
227      */
228     private static void trunc(File file) throws IOException{
229         if( ! file.exists() ) return;
230         if( ! file.isFile() ) return;
231
232         if(file.length() <= 0L) return;
233
234         FileOutputStream foStream = new FileOutputStream(file);
235         try{
236             FileChannel channnel = foStream.getChannel();
237             try{
238                 channnel.truncate(0L);
239             }finally{
240                 channnel.close();
241             }
242         }finally{
243             foStream.close();
244         }
245
246         return;
247     }
248
249     /**
250      * 入力ストリームを準備する。
251      * <p>入力ファイルが通常ファイルとして存在しなければエラー終了。
252      * @param fileName 入力ファイル名
253      * @return 入力ストリーム
254      */
255     private static InputStream openInfile(String fileName){
256         File inFile = new File(fileName);
257
258         if( (! inFile.exists()) || (! inFile.isFile()) ){
259             String absPath = inFile.getAbsolutePath();
260             String msg = MessageFormat.format(MSG_NOINFILE, absPath);
261             errMsg(msg);
262             exit(EXIT_IOERR);
263         }
264
265         InputStream is;
266         try{
267             is = new FileInputStream(inFile);
268         }catch(FileNotFoundException e){
269             ioError(e);
270             assert false;
271             throw new AssertionError(e);
272         }
273
274         is = new BufferedInputStream(is);
275
276         return is;
277     }
278
279     /**
280      * 出力ストリームを準備する。
281      * <p>出力ファイルが通常ファイルでない場合はエラー終了。
282      * <p>既存の出力ファイルに上書き指示が伴っていなければエラー終了。
283      * @param fileName 出力ファイル名
284      * @param overWrite 頭から上書きして良ければtrue
285      * @return 出力ストリーム
286      */
287     private static OutputStream openOutfile(String fileName,
288                                             boolean overWrite) {
289         File outFile = new File(fileName);
290
291         if(outFile.exists()){
292             String absPath = outFile.getAbsolutePath();
293             if( ! outFile.isFile() ){
294                 String msg = MessageFormat.format(MSG_ABNFILE, absPath);
295                 errMsg(msg);
296                 exit(EXIT_IOERR);
297             }else if( ! overWrite ){
298                 String msg = MessageFormat.format(MSG_OWOUTFILE, absPath);
299                 errMsg(msg);
300                 exit(EXIT_IOERR);
301             }
302         }
303
304         try{
305             trunc(outFile);
306         }catch(IOException e){
307             ioError(e);
308         }
309
310         OutputStream os;
311         try{
312             os = new FileOutputStream(outFile);
313         }catch(FileNotFoundException e){
314             ioError(e);
315             assert false;
316             throw new AssertionError(e);
317         }
318
319         os = new BufferedOutputStream(os);
320
321         return os;
322     }
323
324     /**
325      * Mainエントリ。
326      * @param args コマンドパラメータ
327      */
328     public static void main(String[] args){
329         checkJRE();
330
331         OptInfo optInfo;
332         try{
333             optInfo = OptInfo.parseOption(args);
334         }catch(CmdLineException e){
335             String optErrMsg = e.getLocalizedMessage();
336             errMsg(optErrMsg);
337             exit(EXIT_OPTERR);
338             return;
339         }
340
341         if(optInfo.needHelp()){
342             putHelp();
343             exit(EXIT_OK);
344         }
345
346         String inputFile  = optInfo.getInFilename();
347         String outputFile = optInfo.getOutFilename();
348         boolean overwrite = optInfo.overwriteMode();
349
350         InputStream  is = openInfile(inputFile);
351         OutputStream os = openOutfile(outputFile, overwrite);
352
353         Vmd2XmlConv converter = new Vmd2XmlConv();
354
355         converter.setInType (optInfo.getInFileType());
356         converter.setOutType(optInfo.getOutFileType());
357
358         converter.setNewline(optInfo.getNewline());
359         converter.setGenerator(optInfo.getGenerator());
360         converter.setQuaterniomMode(optInfo.isQuaterniomMode());
361
362         try{
363             converter.convert(is, os);
364         }catch(IOException e){
365             ioError(e);
366         }catch(IllegalVmdDataException e){
367             internalError(e);
368         }catch(MmdFormatException e){
369             vmdError(e);
370         }catch(TogaXmlException e){
371             xmlError(e);
372         }catch(SAXException e){
373             xmlError(e);
374         }
375
376         try{
377             is.close();
378             try{
379                 os.close();
380             }catch(IOException e){
381                 ioError(e);
382             }
383         }catch(IOException e){
384             ioError(e);
385         }
386
387         exit(EXIT_OK);
388
389         return;
390     }
391
392 }