2 * Copyright 2011-2012 BitMeister Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package jp.bitmeister.asn1.codec.xer;
18 import static jp.bitmeister.asn1.codec.xer.XerConstants.BOOLEAN_FALSE;
19 import static jp.bitmeister.asn1.codec.xer.XerConstants.BOOLEAN_TRUE;
20 import static jp.bitmeister.asn1.codec.xer.XerConstants.REAL_MINUS_INFINITY;
21 import static jp.bitmeister.asn1.codec.xer.XerConstants.REAL_NAN;
22 import static jp.bitmeister.asn1.codec.xer.XerConstants.REAL_PLUS_INFINITY;
24 import java.io.InputStream;
25 import java.math.BigInteger;
26 import java.util.ArrayList;
27 import java.util.List;
29 import jp.bitmeister.asn1.codec.ASN1Decoder;
30 import jp.bitmeister.asn1.exception.ASN1DecodingException;
31 import jp.bitmeister.asn1.processor.ASN1Visitor;
32 import jp.bitmeister.asn1.type.ASN1Module;
33 import jp.bitmeister.asn1.type.ASN1ModuleManager;
34 import jp.bitmeister.asn1.type.ASN1Type;
35 import jp.bitmeister.asn1.type.CollectionType;
36 import jp.bitmeister.asn1.type.NamedTypeSpecification;
37 import jp.bitmeister.asn1.type.StringType;
38 import jp.bitmeister.asn1.type.StructuredType;
39 import jp.bitmeister.asn1.type.TimeType;
40 import jp.bitmeister.asn1.type.UnknownType;
41 import jp.bitmeister.asn1.type.builtin.ANY;
42 import jp.bitmeister.asn1.type.builtin.BIT_STRING;
43 import jp.bitmeister.asn1.type.builtin.BOOLEAN;
44 import jp.bitmeister.asn1.type.builtin.BigENUMERATED;
45 import jp.bitmeister.asn1.type.builtin.BigINTEGER;
46 import jp.bitmeister.asn1.type.builtin.CHOICE;
47 import jp.bitmeister.asn1.type.builtin.ENUMERATED;
48 import jp.bitmeister.asn1.type.builtin.INTEGER;
49 import jp.bitmeister.asn1.type.builtin.NULL;
50 import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
51 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
52 import jp.bitmeister.asn1.type.builtin.REAL;
53 import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
54 import jp.bitmeister.asn1.type.builtin.SEQUENCE;
55 import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
56 import jp.bitmeister.asn1.type.builtin.SET;
57 import jp.bitmeister.asn1.type.builtin.SET_OF;
58 import jp.bitmeister.asn1.value.BinString;
59 import jp.bitmeister.asn1.value.HexString;
61 import org.xml.sax.Attributes;
62 import org.xml.sax.InputSource;
63 import org.xml.sax.SAXException;
64 import org.xml.sax.XMLReader;
65 import org.xml.sax.helpers.DefaultHandler;
66 import org.xml.sax.helpers.XMLReaderFactory;
69 * XER (XML Encoding Rules) decoder.
72 * {@code XerDecoder} is an implementation of {@code ASN1Decoder}. It reads a
73 * number of bytes from an {@code InputStream} that is specified when a decoder
74 * is instantiated, and decodes them to an ASN.1 data using XML Encoding Rules
78 * @author WATANABE, Jun. <jwat at bitmeister.jp>
83 public class XerDecoder implements ASN1Decoder,
84 ASN1Visitor<XerDecoder.DataDecoder, SAXException> {
87 * Abstract handler class used for decoding an XML element to an ASN.1 data.
89 * @author WATANABE, Jun. <jwat at bitmeister.jp>
91 abstract class DataDecoder {
94 * Callback method that is called when the data element started.
96 void startElement(String qName) throws SAXException {
100 * Callback method that is called when a child element started.
104 * @throws SAXException
105 * Thrown when an error occurred while the process.
107 void startChildElement(String qName) throws SAXException {
111 * Callback method that is called when a character sequence detected in
115 * The character sequence.
117 void characters(String characters) {
121 * Callback method that is called when a child element ended.
125 * @throws SAXException
126 * Thrown when an error occurred while the process.
128 void endChildElement(String qName) {
132 * Callback method that is called when the data element ended.
140 * Handler class for constructed data ({@code CollectionType} and
141 * {@code StructuredType}).
143 * @author WATANABE, Jun. <jwat at bitmeister.jp>
145 private abstract class ConstructedDataDecoder extends DataDecoder {
147 ElementDecoder decoder;
153 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters(java
157 void characters(String characters) {
158 if (decoder != null) {
159 decoder.characters(characters);
166 * Abstract handler class used for decoding a sequence of XML elements to an
169 * @author WATANABE, Jun. <jwat at bitmeister.jp>
171 private abstract class ElementDecoder {
176 * Instantiate an {@code ElementDecoder}.
179 * The {@code DataDecoder} used for decode the data.
181 ElementDecoder(DataDecoder decoder) {
182 this.decoder = decoder;
186 * Callback method that is called when an XML element started.
189 * The tag name of the element.
190 * @throws SAXException
191 * Thrown when an error occurred while the process.
193 abstract void startElement(String qName) throws SAXException;
196 * Callback method that is called when a character sequence detected in
200 * The character sequence.
202 void characters(String characters) {
203 decoder.characters(characters);
207 * Callback method that is called when an XML element ended.
210 * The tag name of the element.
211 * @return {@code true} when the element is enclosing element.
213 abstract boolean endElement(String qName);
218 * Handler class used for decoding a sequence of data elements that enclosed
221 * @author WATANABE, Jun. <jwat at bitmeister.jp>
223 private class NamedElementDecoder extends ElementDecoder {
225 private String tagName;
228 * Instantiate a {@code NamedElementDecoder}.
231 * The tag name of enclosing element.
233 * The {@code DataDecoder} used for decoding data elements.
235 NamedElementDecoder(String tagName, DataDecoder decoder) {
237 this.tagName = tagName;
244 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#startElement
247 public void startElement(String qName) throws SAXException {
248 if (qName.equals(tagName)) {
249 decoder.startElement(qName);
251 decoder.startChildElement(qName);
259 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#endElement
262 public boolean endElement(String qName) {
263 if (qName.equals(tagName)) {
264 decoder.endElement();
267 decoder.endChildElement(qName);
275 * Handler class used for decoding an data element that is not enclosed by
278 * @author WATANABE, Jun. <jwat at bitmeister.jp>
280 private class ValueListElementDecoder extends ElementDecoder {
283 * Instantiate a {@code ValueListElementDecoder}.
286 * The {@code DataDecoder} used for decoding the data
289 ValueListElementDecoder(DataDecoder decoder) {
297 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#startElement
300 public void startElement(String qName) throws SAXException {
301 decoder.startElement(qName);
302 decoder.startChildElement(qName);
309 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#endElement
312 public boolean endElement(String qName) {
313 decoder.endChildElement(qName);
314 decoder.endElement();
321 * Abstract handler class used for decosing an XML document to an ASN.1
324 * @author WATANABE, Jun. <jwat at bitmeister.jp>
326 private abstract class XerHandler<T extends ASN1Type> extends
331 private ElementDecoder decoder;
334 * Instantiates an ASN.1 data and sets it to this instance.
337 * The tag name of the head element of the XML document.
338 * @throws SAXException
339 * Thrown when an error occurred while the process.
341 abstract void initializeData(String qName) throws SAXException;
347 * org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
348 * java.lang.String, java.lang.String, org.xml.sax.Attributes)
351 public void startElement(String uri, String localName, String qName,
352 Attributes attributes) throws SAXException {
354 initializeData(qName);
355 decoder = new NamedElementDecoder(qName,
356 data.accept(XerDecoder.this));
358 decoder.startElement(qName);
364 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
367 public void characters(char[] ch, int start, int length) {
368 char[] tmp = new char[length];
369 System.arraycopy(ch, start, tmp, 0, length);
370 decoder.characters(String.valueOf(tmp));
376 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String,
377 * java.lang.String, java.lang.String)
380 public void endElement(String uri, String localName, String qName) {
381 decoder.endElement(qName);
386 private Class<? extends ASN1Module> module;
388 private InputStream in;
390 private XMLReader reader;
393 * Instantiates a {@code XerDecoder}.
396 * The {@code InputStream} to be read.
398 public XerDecoder(InputStream in) {
403 * Instantiates a {@code XerDecoder}.
406 * The {@code InputStream} to be read.
408 public XerDecoder(Class<? extends ASN1Module> module, InputStream in) {
410 this.module = module;
416 * @see jp.bitmeister.asn1.codec.ASN1Decoder#decode(java.lang.Class)
418 public <T extends ASN1Type> T decode(final Class<T> type)
419 throws ASN1DecodingException {
420 XerHandler<T> handler = new XerHandler<T>() {
426 * jp.bitmeister.asn1.codec.xer.XerDecoder.XerHandler#initializeData
429 void initializeData(String qName) throws SAXException {
430 data = ASN1Type.instantiate(type);
431 if (module == null) {
432 module = data.specification().module();
434 if (!(data instanceof ANY)
435 && !qName.equals(data.specification().xmlTypeName(module))) {
436 throw new SAXException("Unexpected xml tag name '" + qName
437 + "'. '" + data.specification().xmlTypeName(module)
450 * @see jp.bitmeister.asn1.codec.ASN1Decoder#decode()
452 public ASN1Type decode() throws ASN1DecodingException {
453 XerHandler<ASN1Type> handler = new XerHandler<ASN1Type>() {
459 * jp.bitmeister.asn1.codec.xer.XerDecoder.XerHandler#initializeData
462 void initializeData(String qName) throws SAXException {
463 data = ASN1ModuleManager.instantiate(module, qName);
465 throw new SAXException("Unknown data type '" + qName + "'.");
475 * Decodes the source XML data read from the {@code InputStream} to the
478 * @throws ASN1DecodingException
479 * When an error occurred while the decoding process.
481 private void parse(XerHandler<?> handler) throws ASN1DecodingException {
483 reader = XMLReaderFactory.createXMLReader();
484 reader.setContentHandler(handler);
485 reader.parse(new InputSource(in));
486 } catch (Exception e) {
487 ASN1DecodingException ex = new ASN1DecodingException();
488 ex.setMessage("An exception thrown while decoding process.", e,
498 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
501 public DataDecoder visit(final BOOLEAN data) {
502 return new DataDecoder() {
508 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
512 void startChildElement(String qName) {
513 if (qName.equals(BOOLEAN_TRUE)) {
515 } else if (qName.equals(BOOLEAN_FALSE)) {
527 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
530 public DataDecoder visit(final INTEGER data) {
531 return new DataDecoder() {
537 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
541 void startChildElement(String qName) {
549 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
553 public void characters(String characters) {
554 data.set(Long.valueOf(characters));
564 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
565 * .builtin.BigINTEGER)
567 public DataDecoder visit(final BigINTEGER data) {
568 return new DataDecoder() {
574 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
578 void startChildElement(String qName) {
586 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
590 public void characters(String characters) {
591 data.set(new BigInteger(characters));
601 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
602 * .builtin.BIT_STRING)
604 public DataDecoder visit(final BIT_STRING data) {
605 return new DataDecoder() {
611 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
615 public void startChildElement(String qName) {
623 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
627 public void characters(String characters) {
628 data.set(new BinString(characters));
638 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
639 * .builtin.OCTET_STRING)
641 public DataDecoder visit(final OCTET_STRING data) {
642 return new DataDecoder() {
648 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
652 public void characters(String characters) {
653 data.set(new HexString(characters));
663 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
666 public DataDecoder visit(NULL data) {
667 return new DataDecoder() {
675 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
676 * .builtin.OBJECT_IDENTIFIER)
678 public DataDecoder visit(final OBJECT_IDENTIFIER data) {
679 return new DataDecoder() {
685 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
689 public void characters(String characters) {
690 List<Integer> oids = new ArrayList<Integer>();
691 for (String e : characters.split("\\.")) {
693 if (Character.isLetter(e.charAt(0))) {
694 if (!e.endsWith(")")) {
695 oids.add(OBJECT_IDENTIFIER.nameFormToInt(oids, e));
698 e = e.substring(e.indexOf('(') + 1, e.indexOf(')'));
700 oids.add(Integer.parseInt(e));
712 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
715 public DataDecoder visit(final REAL data) {
716 return new DataDecoder() {
722 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
726 public void startChildElement(String qName) {
727 if (qName.equals(REAL_PLUS_INFINITY)) {
728 data.set(Double.POSITIVE_INFINITY);
729 } else if (qName.equals(REAL_MINUS_INFINITY)) {
730 data.set(Double.NEGATIVE_INFINITY);
731 } else if (qName.equals(REAL_NAN)) {
732 data.set(Double.NaN);
740 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
744 public void characters(String characters) {
745 data.set(Double.parseDouble(characters));
755 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
756 * .builtin.ENUMERATED)
758 public DataDecoder visit(ENUMERATED data) {
759 return visit((INTEGER) data);
766 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
767 * .builtin.BigENUMERATED)
769 public DataDecoder visit(BigENUMERATED data) {
770 return visit((BigINTEGER) data);
777 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
778 * .builtin.RELATIVE_OID)
780 public DataDecoder visit(RELATIVE_OID data) {
781 return visit((OBJECT_IDENTIFIER) data);
788 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
791 public DataDecoder visit(final ANY data) {
792 return new DataDecoder() {
794 private DataDecoder decoder;
797 void startElement(String qName) throws SAXException {
798 data.set(ASN1ModuleManager.instantiate(module, qName));
799 decoder = data.value().accept(XerDecoder.this);
800 decoder.startElement(qName);
804 void startChildElement(String qName) throws SAXException {
805 decoder.startChildElement(qName);
809 void characters(String characters) {
810 decoder.characters(characters);
814 void endChildElement(String qName) {
815 decoder.endChildElement(qName);
820 decoder.endElement();
830 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
833 public DataDecoder visit(CHOICE data) {
834 return decoderForStructuredType(data);
841 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
842 * .builtin.SEQUENCE_OF)
844 public DataDecoder visit(SEQUENCE_OF<? extends ASN1Type> data) {
845 return decoderForCollectionType(data);
852 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
855 public DataDecoder visit(SEQUENCE data) {
856 return decoderForStructuredType(data);
863 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
866 public DataDecoder visit(SET_OF<? extends ASN1Type> data) {
867 return decoderForCollectionType(data);
874 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
877 public DataDecoder visit(SET data) {
878 return decoderForStructuredType(data);
885 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
888 public DataDecoder visit(final StringType data) {
889 return new DataDecoder() {
891 private StringBuilder builder = new StringBuilder();
897 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
901 public void startChildElement(String qName) {
902 builder.append(XerStringEscapeUtil.unescapeCtrl(qName));
909 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
913 public void characters(String characters) {
914 builder.append(characters);
921 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endElement()
925 if (builder.length() > 0) {
926 data.set(builder.toString());
937 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
940 public DataDecoder visit(TimeType data) {
941 return visit((StringType) data);
948 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
951 public DataDecoder visit(UnknownType data) throws SAXException {
952 throw new SAXException("UnkownType is not supported by XerDecoder.");
956 * Returns handler for the {@code StructuredType}.
959 * The {@code StructuredType} data.
960 * @return Handler for the data.
962 private DataDecoder decoderForStructuredType(final StructuredType data) {
963 return new ConstructedDataDecoder() {
965 private NamedTypeSpecification namedType;
967 private ASN1Type element;
973 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
977 void startChildElement(String qName) throws SAXException {
978 if (decoder == null) {
979 namedType = data.getElement(qName);
980 element = namedType.instantiate();
981 decoder = new NamedElementDecoder(qName,
982 element.accept(XerDecoder.this));
984 decoder.startElement(qName);
991 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endChildElement
995 void endChildElement(String qName) {
996 if (decoder.endElement(qName)) {
997 data.set(namedType, element);
1006 * Returns handler for the {@code CollectionType}.
1009 * The {@code CollectionType} data.
1010 * @return Handler for the data.
1012 private <T extends ASN1Type> DataDecoder decoderForCollectionType(
1013 final CollectionType<T, ?> data) {
1014 return new ConstructedDataDecoder() {
1016 private T component;
1018 private boolean useXmlValueList = false;
1024 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startElement
1028 void startElement(String qName) {
1029 if (BOOLEAN.class.isAssignableFrom(data.componentType())
1030 || ENUMERATED.class.isAssignableFrom(data.componentType())
1031 || BigENUMERATED.class.isAssignableFrom(data.componentType())
1032 || CHOICE.class.isAssignableFrom(data.componentType())) {
1033 useXmlValueList = true;
1041 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
1042 * (java.lang.String)
1045 void startChildElement(String qName) throws SAXException {
1046 if (decoder == null) {
1047 component = ASN1Type.instantiate(data.componentType());
1048 if (useXmlValueList) {
1049 decoder = new ValueListElementDecoder(
1050 component.accept(XerDecoder.this));
1052 decoder = new NamedElementDecoder(qName,
1053 component.accept(XerDecoder.this));
1056 decoder.startElement(qName);
1063 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endChildElement
1064 * (java.lang.String)
1067 void endChildElement(String qName) {
1068 if (decoder.endElement(qName)) {
1069 data.collection().add(component);