OSDN Git Service

Merge topic/xxe into develop
[mikutoga/Pmd2XML.git] / src / main / java / jp / sfjp / mikutoga / pmd2xml / XmlInputUtil.java
1 /*
2  * xml input utility
3  *
4  * License : The MIT License
5  * Copyright(c) 2013 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.pmd2xml;
9
10 import java.io.BufferedInputStream;
11 import java.io.File;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.net.MalformedURLException;
15 import java.net.URI;
16 import java.net.URL;
17 import javax.xml.parsers.ParserConfigurationException;
18 import javax.xml.parsers.SAXParser;
19 import javax.xml.parsers.SAXParserFactory;
20 import javax.xml.validation.Schema;
21 import jp.sfjp.mikutoga.pmd.model.xml.Schema101009;
22 import jp.sfjp.mikutoga.pmd.model.xml.Schema130128;
23 import jp.sfjp.mikutoga.xml.BotherHandler;
24 import jp.sfjp.mikutoga.xml.NoopEntityResolver;
25 import jp.sfjp.mikutoga.xml.SchemaUtil;
26 import org.xml.sax.InputSource;
27 import org.xml.sax.SAXException;
28 import org.xml.sax.XMLReader;
29
30 /**
31  * XML入力に関する各種ユーティリティ。
32  */
33 final class XmlInputUtil {
34
35     /**
36      * 隠しコンストラクタ。
37      */
38     private XmlInputUtil(){
39         assert false;
40         throw new AssertionError();
41     }
42
43
44     /**
45      * 実在ファイルからXML入力ソースを得る。
46      * @param file 実在ファイル
47      * @return XML入力ソース
48      */
49     static InputSource fileToSource(File file){
50         assert file.exists();
51
52         URI uri = file.toURI();
53
54         URL url;
55         try{
56             url = uri.toURL();
57         }catch(MalformedURLException e){
58             // 実在File由来のURLでは起こりえない
59             assert false;
60             throw new AssertionError(e);
61         }
62
63         String systemId = url.toString();
64
65         InputSource source = new InputSource(systemId);
66
67         return source;
68     }
69
70     /**
71      * InputSourceからInputStreamを得る。
72      * <p>入力ソースには、少なくともバイトストリームか
73      * URL文字列(SystemId)のいずれかが設定されていなければならない。
74      * @param source 入力ソース
75      * @return 入力バイトストリーム
76      * @throws IllegalArgumentException 入力ソースの設定が足りない。
77      * @throws IOException 入力ソースにアクセス不能。
78      */
79     static InputStream openInputSource(InputSource source)
80             throws IllegalArgumentException, IOException{
81         InputStream is;
82
83         is = source.getByteStream();
84
85         if(is == null){
86             String systemId = source.getSystemId();
87             if(systemId == null) throw new IllegalArgumentException();
88
89             URL url = new URL(systemId);
90             is = url.openStream();
91         }
92
93         is = new BufferedInputStream(is);
94
95         return is;
96     }
97
98     /**
99      * SAXパーサファクトリを生成する。
100      * <ul>
101      * <li>XML名前空間機能は有効になる。
102      * <li>DTDによる形式検証は無効となる。
103      * <li>XIncludeによる差し込み機能は無効となる。
104      * </ul>
105      * @param schema スキーマ
106      * @return ファクトリ
107      */
108     private static SAXParserFactory buildFactory(Schema schema){
109         SAXParserFactory factory = SAXParserFactory.newInstance();
110
111         factory.setNamespaceAware(true);
112         factory.setValidating(false);
113         factory.setXIncludeAware(false);
114 //      factory.setFeature(name, value);
115
116         factory.setSchema(schema);
117
118         return factory;
119     }
120
121     /**
122      * SAXパーサを生成する。
123      * @param schema スキーマ
124      * @return SAXパーサ
125      */
126     private static SAXParser buildParser(Schema schema){
127         SAXParserFactory factory = buildFactory(schema);
128
129         SAXParser parser;
130         try{
131             parser = factory.newSAXParser();
132         }catch(ParserConfigurationException | SAXException e){
133             assert false;
134             throw new AssertionError(e);
135         }
136
137 //      parser.setProperty(name, value);
138
139         return parser;
140     }
141
142     /**
143      * スキーマを生成する。
144      * @param resolver リゾルバ
145      * @param xmlInType 入力XML種別
146      * @return スキーマ
147      */
148     private static Schema buildSchema(ModelFileType xmlInType ){
149         URI[] schemaUris;
150         switch(xmlInType){
151         case XML_101009:
152             schemaUris = new URI[]{
153                 Schema101009.RES_SCHEMA_PMDXML,
154             };
155             break;
156         case XML_130128:
157             schemaUris = new URI[]{
158                 Schema130128.RES_SCHEMA_PMDXML,
159             };
160             break;
161         case XML_AUTO:
162             schemaUris = new URI[]{
163                 Schema101009.RES_SCHEMA_PMDXML,
164                 Schema130128.RES_SCHEMA_PMDXML,
165             };
166             break;
167         default:
168             throw new IllegalStateException();
169         }
170
171         Schema schema;
172         try{
173             schema = SchemaUtil.newSchema(schemaUris);
174         }catch(IOException | SAXException e){
175             assert false;
176             throw new AssertionError(e);
177         }
178
179         return schema;
180     }
181
182     /**
183      * XMLリーダを生成する。
184      * <p>エラーハンドラには{@link BotherHandler}が指定される。
185      * @param xmlInType 入力XML種別
186      * @return XMLリーダ
187      */
188     static XMLReader buildReader(ModelFileType xmlInType){
189         Schema schema = buildSchema(xmlInType);
190
191         SAXParser parser = buildParser(schema);
192
193         XMLReader reader;
194         try{
195             reader = parser.getXMLReader();
196         }catch(SAXException e){
197             assert false;
198             throw new AssertionError(e);
199         }
200
201         reader.setEntityResolver(NoopEntityResolver.NOOP_RESOLVER);
202         reader.setErrorHandler(BotherHandler.HANDLER);
203
204         return reader;
205     }
206
207 }