4 * License : The MIT License
5 * Copyright(c) 2013 MikuToga Partners
8 package jp.sfjp.mikutoga.vmd2xml;
10 import java.io.BufferedInputStream;
11 import java.io.BufferedWriter;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.OutputStream;
15 import java.io.OutputStreamWriter;
16 import java.io.Writer;
18 import java.nio.charset.Charset;
19 import javax.xml.parsers.ParserConfigurationException;
20 import javax.xml.parsers.SAXParser;
21 import javax.xml.parsers.SAXParserFactory;
22 import javax.xml.validation.Schema;
23 import jp.sfjp.mikutoga.bin.parser.MmdFormatException;
24 import jp.sfjp.mikutoga.vmd.IllegalVmdDataException;
25 import jp.sfjp.mikutoga.vmd.model.VmdMotion;
26 import jp.sfjp.mikutoga.vmd.model.binio.VmdExporter;
27 import jp.sfjp.mikutoga.vmd.model.binio.VmdLoader;
28 import jp.sfjp.mikutoga.vmd.model.xml.Schema110820;
29 import jp.sfjp.mikutoga.vmd.model.xml.VmdXmlExporter;
30 import jp.sfjp.mikutoga.vmd.model.xml.XmlVmdLoader;
31 import jp.sourceforge.mikutoga.xml.BotherHandler;
32 import jp.sourceforge.mikutoga.xml.SchemaUtil;
33 import jp.sourceforge.mikutoga.xml.TogaXmlException;
34 import jp.sourceforge.mikutoga.xml.XmlResourceResolver;
35 import org.xml.sax.InputSource;
36 import org.xml.sax.SAXException;
37 import org.xml.sax.XMLReader;
42 public class Vmd2XmlConv {
45 private static final Charset CS_UTF8 = Charset.forName("UTF-8");
48 private MotionFileType inTypes = MotionFileType.NONE;
49 private MotionFileType outTypes = MotionFileType.NONE;
50 private String newLine = "\r\n";
51 private String generator = null;
52 private boolean isQuaternionMode = true;
65 * InputSourceからInputStreamを得る。
66 * <p>入力ソースには、少なくともバイトストリームか
67 * URL文字列(SystemId)のいずれかが設定されていなければならない。
70 * @throws IllegalArgumentException 入力ソースの設定が足りない。
71 * @throws IOException 入力ソースにアクセス不能。
73 private static InputStream openInputSource(InputSource source)
74 throws IllegalArgumentException, IOException{
77 is = source.getByteStream();
80 String systemId = source.getSystemId();
81 if(systemId == null) throw new IllegalArgumentException();
83 URL url = new URL(systemId);
84 is = url.openStream();
87 is = new BufferedInputStream(is);
95 * <li>XML名前空間機能は有効になる。
96 * <li>DTDによる形式検証は無効となる。
97 * <li>XIncludeによる差し込み機能は無効となる。
102 private static SAXParserFactory buildFactory(Schema schema){
103 SAXParserFactory factory = SAXParserFactory.newInstance();
105 factory.setNamespaceAware(true);
106 factory.setValidating(false);
107 factory.setXIncludeAware(false);
108 // factory.setFeature(name, value);
110 factory.setSchema(schema);
120 private static SAXParser buildParser(Schema schema){
121 SAXParserFactory factory = buildFactory(schema);
125 parser = factory.newSAXParser();
126 }catch(ParserConfigurationException e){
128 throw new AssertionError(e);
129 }catch(SAXException e){
131 throw new AssertionError(e);
134 // parser.setProperty(name, value);
141 * <p>エラーハンドラには{@link BotherHandler}が指定される。
142 * @param resolver リゾルバ
145 private static XMLReader buildReader(XmlResourceResolver resolver){
147 schema = SchemaUtil.newSchema(resolver, Schema110820.SINGLETON);
149 SAXParser parser = buildParser(schema);
153 reader = parser.getXMLReader();
154 }catch(SAXException e){
156 throw new AssertionError(e);
159 reader.setEntityResolver(resolver);
160 reader.setErrorHandler(BotherHandler.HANDLER);
168 * @throws IllegalArgumentException 具体的な種別を渡さなかった
170 public void setInType(MotionFileType type)
171 throws IllegalArgumentException {
172 if(type == null) throw new NullPointerException();
173 if(type == MotionFileType.NONE) throw new IllegalArgumentException();
182 public MotionFileType getInTypes(){
189 * @throws IllegalArgumentException 具体的な種別を渡さなかった
191 public void setOutType(MotionFileType type)
192 throws IllegalArgumentException {
193 if(type == null) throw new NullPointerException();
194 if(type == MotionFileType.NONE) throw new IllegalArgumentException();
195 this.outTypes = type;
203 public MotionFileType getOutTypes(){
204 return this.outTypes;
209 * @param newline 改行文字
211 public void setNewline(String newline){
212 this.newLine = newline;
220 public String getNewline(){
226 * @param generator ジェネレータ名。表示したくない場合はnull
228 public void setGenerator(String generator){
229 this.generator = generator;
235 * @return ジェネレータ名。非表示の場合はnullを返す。
237 public String getGenerator(){
238 return this.generator;
242 * 回転情報をクォータニオン形式でXML出力するか設定する。
243 * @param sw クォータニオン形式ならtrue、
244 * YXZオイラー角で出力したければfalse。
246 public void setQuaterniomMode(boolean sw){
247 this.isQuaternionMode = sw;
253 * @return クォータニオン形式ならtrue、YXZオイラー角形式ならfalse。
255 public boolean isQuaterniomMode(){
256 return this.isQuaternionMode;
261 * <p>XML入力の場合は{@link #convert(InputSource, OutputStream)}を
265 * @throws IOException 入力エラー
266 * @throws MmdFormatException フォーマットエラー
267 * @throws SAXException XMLエラー
268 * @throws TogaXmlException XMLエラー
269 * @throws IllegalVmdDataException 内部エラー
271 public void convert(InputStream is, OutputStream os)
276 IllegalVmdDataException {
277 VmdMotion motion = readMotion(is);
279 writeMotion(motion, os);
285 * <p>VMD入力の場合は{@link InputStream}に
286 * バイトストリームが直接設定されていなければならない。
287 * <p>XML入力の場合は{@link InputStream}に
288 * URL(systemId)のみの設定を推奨する。
289 * @param source 入力ソース
291 * @throws IOException 入力エラー
292 * @throws MmdFormatException フォーマットエラー
293 * @throws SAXException XMLエラー
294 * @throws TogaXmlException XMLエラー
295 * @throws IllegalVmdDataException 内部エラー
297 public void convert(InputSource source, OutputStream os)
302 IllegalVmdDataException {
303 VmdMotion motion = readMotion(source);
305 writeMotion(motion, os);
312 * こちらより{@link #readMotion(InputSource)}版を推奨する。
315 * @throws IOException 入力エラー
316 * @throws MmdFormatException フォーマットエラー
317 * @throws SAXException XMLエラー
318 * @throws TogaXmlException XMLエラー
320 public VmdMotion readMotion(InputStream is)
325 InputSource source = new InputSource(is);
329 motion = readMotion(source);
339 * <p>VMD入力の場合は、{@link InputStream}に
340 * 納められたバイトストリームかSystemId-URLから読み込む。
341 * @param source 入力ソース
343 * @throws IOException 入力エラー
344 * @throws MmdFormatException フォーマットエラー
345 * @throws SAXException XMLエラー
346 * @throws TogaXmlException XMLエラー
348 public VmdMotion readMotion(InputSource source)
353 VmdMotion motion = null;
355 if(this.inTypes.isVmd()){
356 InputStream is = openInputSource(source);
358 motion = vmdRead(is);
362 }else if(this.inTypes.isXml()){
363 motion = xmlRead(source);
365 throw new IllegalStateException();
373 * @param motion モーションデータ
375 * @throws IOException 出力エラー
376 * @throws IllegalVmdDataException データの不備
378 public void writeMotion(VmdMotion motion, OutputStream os)
380 IllegalVmdDataException {
381 if(this.outTypes.isVmd()){
383 }else if(this.outTypes.isXml()){
386 throw new IllegalStateException();
393 * VMDファイルからモーションデータを読み込む。
394 * <p>入力ストリームは最後に閉じられる。
397 * @throws IOException 入力エラー
398 * @throws MmdFormatException 不正なVMDファイルフォーマット
400 private VmdMotion vmdRead(InputStream is)
401 throws IOException, MmdFormatException{
402 VmdLoader loader = new VmdLoader();
404 loader.setRedundantCheck(false);
406 VmdMotion motion = loader.load(is);
412 * XMLファイルからモーションデータを読み込む。
413 * @param source 入力ソース
415 * @throws IOException 入力エラー
416 * @throws SAXException XML構文エラー
417 * @throws TogaXmlException 不正なXMLデータ
419 private VmdMotion xmlRead(InputSource source)
423 XmlResourceResolver resolver = new XmlResourceResolver();
424 XMLReader reader = buildReader(resolver);
425 XmlVmdLoader loader = new XmlVmdLoader(reader);
427 VmdMotion motion = loader.parse(source);
433 * モーションデータをVMDファイルに出力する。
434 * @param motion モーションデータ
435 * @param ostream 出力ストリーム
436 * @throws IOException 出力エラー
437 * @throws IllegalVmdDataException 不正なモーションデータ
439 private void vmdOut(VmdMotion motion, OutputStream ostream)
440 throws IOException, IllegalVmdDataException{
441 VmdExporter exporter = new VmdExporter();
442 exporter.dumpVmdMotion(motion, ostream);
448 * モーションデータをXMLファイルに出力する。
449 * @param motion モーションデータ
450 * @param ostream 出力ストリーム
451 * @throws IOException 出力エラー
452 * @throws IllegalVmdDataException 不正なモーションデータ
454 private void xmlOut(VmdMotion motion, OutputStream ostream)
455 throws IOException, IllegalVmdDataException{
456 VmdXmlExporter exporter = new VmdXmlExporter();
458 exporter.setNewLine(this.newLine);
459 exporter.setGenerator(this.generator);
460 exporter.setQuaternionMode(this.isQuaternionMode);
463 writer = new OutputStreamWriter(ostream, CS_UTF8);
464 writer = new BufferedWriter(writer);
466 exporter.putVmdXml(motion, writer);