2 * Copyright 2011 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_PLUS_INFINITY;
23 import java.io.InputStream;
24 import java.math.BigInteger;
25 import java.util.ArrayList;
26 import java.util.List;
28 import jp.bitmeister.asn1.codec.ASN1Decoder;
29 import jp.bitmeister.asn1.exception.ASN1DecodingException;
30 import jp.bitmeister.asn1.processor.ASN1Visitor;
31 import jp.bitmeister.asn1.type.ASN1Module;
32 import jp.bitmeister.asn1.type.ASN1ModuleManager;
33 import jp.bitmeister.asn1.type.ASN1Type;
34 import jp.bitmeister.asn1.type.CollectionType;
35 import jp.bitmeister.asn1.type.NamedTypeSpecification;
36 import jp.bitmeister.asn1.type.StringType;
37 import jp.bitmeister.asn1.type.StructuredType;
38 import jp.bitmeister.asn1.type.TimeType;
39 import jp.bitmeister.asn1.type.UnknownType;
40 import jp.bitmeister.asn1.type.builtin.ANY;
41 import jp.bitmeister.asn1.type.builtin.BIT_STRING;
42 import jp.bitmeister.asn1.type.builtin.BOOLEAN;
43 import jp.bitmeister.asn1.type.builtin.CHOICE;
44 import jp.bitmeister.asn1.type.builtin.ENUMERATED;
45 import jp.bitmeister.asn1.type.builtin.INTEGER;
46 import jp.bitmeister.asn1.type.builtin.NULL;
47 import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
48 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
49 import jp.bitmeister.asn1.type.builtin.REAL;
50 import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
51 import jp.bitmeister.asn1.type.builtin.SEQUENCE;
52 import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
53 import jp.bitmeister.asn1.type.builtin.SET;
54 import jp.bitmeister.asn1.type.builtin.SET_OF;
55 import jp.bitmeister.asn1.value.BinString;
56 import jp.bitmeister.asn1.value.HexString;
58 import org.xml.sax.Attributes;
59 import org.xml.sax.InputSource;
60 import org.xml.sax.SAXException;
61 import org.xml.sax.XMLReader;
62 import org.xml.sax.helpers.DefaultHandler;
63 import org.xml.sax.helpers.XMLReaderFactory;
66 * XER (XML Encoding Rules) decoder.
69 * {@code XerDecoder} is an implementation of {@code ASN1Decoder}. It reads a
70 * number of bytes from an {@code InputStream} that is specified when a decoder
71 * is instantiated, and decodes them to an ASN.1 data with XML Encoding Rules
75 * @author WATANABE, Jun. <jwat at bitmeister.jp>
80 public class XerDecoder implements ASN1Decoder,
81 ASN1Visitor<XerDecoder.DataDecoder, SAXException> {
84 * Abstract handler class used for decoding an XML element to an ASN.1 data.
86 * @author WATANABE, Jun. <jwat at bitmeister.jp>
88 abstract class DataDecoder {
91 * Callback method that is called when the data element started.
93 void startElement(String qName) throws SAXException {
97 * Callback method that is called when a child element started.
101 * @throws SAXException
102 * Thrown when an error occurred while the process.
104 void startChildElement(String qName) throws SAXException {
108 * Callback method that is called when a character sequence detected in
112 * The character sequence.
114 void characters(String characters) {
118 * Callback method that is called when a child element ended.
122 * @throws SAXException
123 * Thrown when an error occurred while the process.
125 void endChildElement(String qName) {
129 * Callback method that is called when the data element ended.
137 * Handler class for constructed data ({@code CollectionType} and
138 * {@code StructuredType}).
140 * @author WATANABE, Jun. <jwat at bitmeister.jp>
142 private abstract class ConstructedDataDecoder extends DataDecoder {
144 ElementDecoder decoder;
150 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters(java
154 void characters(String characters) {
155 if (decoder != null) {
156 decoder.characters(characters);
163 * Abstract handler class used for decoding a sequence of XML elements to an
166 * @author WATANABE, Jun. <jwat at bitmeister.jp>
168 private abstract class ElementDecoder {
173 * Instantiate an {@code ElementDecoder}.
176 * The {@code DataDecoder} used for decode the data.
178 ElementDecoder(DataDecoder decoder) {
179 this.decoder = decoder;
183 * Callback method that is called when an XML element started.
186 * The tag name of the element.
187 * @throws SAXException
188 * Thrown when an error occurred while the process.
190 abstract void startElement(String qName) throws SAXException;
193 * Callback method that is called when a character sequence detected in
197 * The character sequence.
199 void characters(String characters) {
200 decoder.characters(characters);
204 * Callback method that is called when an XML element ended.
207 * The tag name of the element.
208 * @return {@code true} when the element is enclosing element.
210 abstract boolean endElement(String qName);
215 * Handler class used for decoding a sequence of data elements that enclosed
218 * @author WATANABE, Jun. <jwat at bitmeister.jp>
220 private class NamedElementDecoder extends ElementDecoder {
222 private String tagName;
225 * Instantiate a {@code NamedElementDecoder}.
228 * The tag name of enclosing element.
230 * The {@code DataDecoder} used for decoding data elements.
232 NamedElementDecoder(String tagName, DataDecoder decoder) {
234 this.tagName = tagName;
241 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#startElement
244 public void startElement(String qName) throws SAXException {
245 if (qName.equals(tagName)) {
246 decoder.startElement(qName);
248 decoder.startChildElement(qName);
256 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#endElement
259 public boolean endElement(String qName) {
260 if (qName.equals(tagName)) {
261 decoder.endElement();
264 decoder.endChildElement(qName);
272 * Handler class used for decoding an data element that is not enclosed by
275 * @author WATANABE, Jun. <jwat at bitmeister.jp>
277 private class ValueListElementDecoder extends ElementDecoder {
280 * Instantiate a {@code ValueListElementDecoder}.
283 * The {@code DataDecoder} used for decoding the data
286 ValueListElementDecoder(DataDecoder decoder) {
294 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#startElement
297 public void startElement(String qName) throws SAXException {
298 decoder.startElement(qName);
299 decoder.startChildElement(qName);
306 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#endElement
309 public boolean endElement(String qName) {
310 decoder.endChildElement(qName);
311 decoder.endElement();
318 * Abstract handler class used for decosing an XML document to an ASN.1
321 * @author WATANABE, Jun. <jwat at bitmeister.jp>
323 private abstract class XerHandler<T extends ASN1Type> extends
328 private ElementDecoder decoder;
331 * Instantiates an ASN.1 data and sets it to this instance.
334 * The tag name of the head element of the XML document.
335 * @throws SAXException
336 * Thrown when an error occurred while the process.
338 abstract void initializeData(String qName) throws SAXException;
344 * org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
345 * java.lang.String, java.lang.String, org.xml.sax.Attributes)
348 public void startElement(String uri, String localName, String qName,
349 Attributes attributes) throws SAXException {
351 initializeData(qName);
352 decoder = new NamedElementDecoder(qName,
353 data.accept(XerDecoder.this));
355 decoder.startElement(qName);
361 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
364 public void characters(char[] ch, int start, int length) {
365 char[] tmp = new char[length];
366 System.arraycopy(ch, start, tmp, 0, length);
367 decoder.characters(String.valueOf(tmp));
373 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String,
374 * java.lang.String, java.lang.String)
377 public void endElement(String uri, String localName, String qName) {
378 decoder.endElement(qName);
383 private Class<? extends ASN1Module> module;
385 private InputStream in;
387 private XMLReader reader;
390 * Instantiates a {@code XerDecoder}.
393 * The {@code InputStream} to be read.
395 public XerDecoder(InputStream in) {
400 * Instantiates a {@code XerDecoder}.
403 * The {@code InputStream} to be read.
405 public XerDecoder(Class<? extends ASN1Module> module, InputStream in) {
407 this.module = module;
413 * @see jp.bitmeister.asn1.codec.ASN1Decoder#decode(java.lang.Class)
415 public <T extends ASN1Type> T decode(final Class<T> type)
416 throws ASN1DecodingException {
417 XerHandler<T> handler = new XerHandler<T>() {
423 * jp.bitmeister.asn1.codec.xer.XerDecoder.XerHandler#initializeData
426 void initializeData(String qName) throws SAXException {
427 data = ASN1Type.instantiate(type);
428 if (module == null) {
429 module = data.specification().module();
431 if (!(data instanceof ANY)
432 && !qName.equals(data.specification().xmlTypeName(module))) {
433 throw new SAXException("Unexpected xml tag name '" + qName
434 + "'. '" + data.specification().xmlTypeName(module)
447 * @see jp.bitmeister.asn1.codec.ASN1Decoder#decode()
449 public ASN1Type decode() throws ASN1DecodingException {
450 XerHandler<ASN1Type> handler = new XerHandler<ASN1Type>() {
456 * jp.bitmeister.asn1.codec.xer.XerDecoder.XerHandler#initializeData
459 void initializeData(String qName) throws SAXException {
460 data = ASN1ModuleManager.instantiate(module, qName);
462 throw new SAXException("Unknown data type '" + qName + "'.");
472 * Decodes the source XML data read from the {@code InputStream} to the
475 * @throws ASN1DecodingException
476 * When an error occurred while the decoding process.
478 private void parse(XerHandler<?> handler) throws ASN1DecodingException {
480 reader = XMLReaderFactory.createXMLReader();
481 reader.setContentHandler(handler);
482 reader.parse(new InputSource(in));
483 } catch (Exception e) {
484 ASN1DecodingException ex = new ASN1DecodingException();
485 ex.setMessage("An exception thrown while decoding process.", e,
495 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
498 public DataDecoder visit(final BOOLEAN data) {
499 return new DataDecoder() {
505 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
509 void startChildElement(String qName) {
510 if (qName.equals(BOOLEAN_TRUE)) {
512 } else if (qName.equals(BOOLEAN_FALSE)) {
524 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
527 public DataDecoder visit(final INTEGER data) {
528 return new DataDecoder() {
534 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
538 void startChildElement(String qName) {
546 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
550 public void characters(String characters) {
551 data.set(new BigInteger(characters));
561 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
562 * .builtin.BIT_STRING)
564 public DataDecoder visit(final BIT_STRING data) {
565 return new DataDecoder() {
571 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
575 public void startChildElement(String qName) {
583 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
587 public void characters(String characters) {
588 data.set(new BinString(characters));
598 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
599 * .builtin.OCTET_STRING)
601 public DataDecoder visit(final OCTET_STRING data) {
602 return new DataDecoder() {
608 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
612 public void characters(String characters) {
613 data.set(new HexString(characters));
623 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
626 public DataDecoder visit(NULL data) {
627 return new DataDecoder() {
635 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
636 * .builtin.OBJECT_IDENTIFIER)
638 public DataDecoder visit(final OBJECT_IDENTIFIER data) {
639 return new DataDecoder() {
645 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
649 public void characters(String characters) {
650 List<Integer> oids = new ArrayList<Integer>();
651 for (String e : characters.split("\\.")) {
653 if (Character.isLetter(e.charAt(0))) {
654 if (!e.endsWith(")")) {
655 oids.add(OBJECT_IDENTIFIER.nameFormToInt(oids, e));
658 e = e.substring(e.indexOf('(') + 1, e.indexOf(')'));
660 oids.add(Integer.parseInt(e));
672 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
675 public DataDecoder visit(final REAL data) {
676 return new DataDecoder() {
682 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
686 public void startChildElement(String qName) {
687 if (qName.equals(REAL_PLUS_INFINITY)) {
688 data.set(Double.POSITIVE_INFINITY);
689 } else if (qName.equals(REAL_MINUS_INFINITY)) {
690 data.set(Double.NEGATIVE_INFINITY);
698 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
702 public void characters(String characters) {
703 data.set(Double.parseDouble(characters));
713 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
714 * .builtin.ENUMERATED)
716 public DataDecoder visit(ENUMERATED data) {
717 return visit((INTEGER) data);
724 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
725 * .builtin.RELATIVE_OID)
727 public DataDecoder visit(RELATIVE_OID data) {
728 return visit((OBJECT_IDENTIFIER) data);
735 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
738 public DataDecoder visit(final ANY data) {
739 return new DataDecoder() {
741 private DataDecoder decoder;
744 void startElement(String qName) throws SAXException {
745 data.set(ASN1ModuleManager.instantiate(module, qName));
746 decoder = data.value().accept(XerDecoder.this);
747 decoder.startElement(qName);
751 void startChildElement(String qName) throws SAXException {
752 decoder.startChildElement(qName);
756 void characters(String characters) {
757 decoder.characters(characters);
761 void endChildElement(String qName) {
762 decoder.endChildElement(qName);
767 decoder.endElement();
777 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
780 public DataDecoder visit(CHOICE data) {
781 return decoderForStructuredType(data);
788 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
789 * .builtin.SEQUENCE_OF)
791 public DataDecoder visit(SEQUENCE_OF<? extends ASN1Type> data) {
792 return decoderForCollectionType(data);
799 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
802 public DataDecoder visit(SEQUENCE data) {
803 return decoderForStructuredType(data);
810 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
813 public DataDecoder visit(SET_OF<? extends ASN1Type> data) {
814 return decoderForCollectionType(data);
821 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
824 public DataDecoder visit(SET data) {
825 return decoderForStructuredType(data);
832 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
835 public DataDecoder visit(final StringType data) {
836 return new DataDecoder() {
838 private StringBuilder builder = new StringBuilder();
844 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
848 public void startChildElement(String qName) {
849 builder.append(XerStringEscapeUtil.unescapeCtrl(qName));
856 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
860 public void characters(String characters) {
861 builder.append(characters);
868 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endElement()
872 if (builder.length() > 0) {
873 data.set(builder.toString());
884 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
887 public DataDecoder visit(TimeType data) {
888 return visit((StringType) data);
895 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
898 public DataDecoder visit(UnknownType data) throws SAXException {
899 throw new SAXException("UnkownType is not supported by XerDecoder.");
903 * Returns handler for the {@code StructuredType}.
906 * The {@code StructuredType} data.
907 * @return Handler for the data.
909 private DataDecoder decoderForStructuredType(final StructuredType data) {
910 return new ConstructedDataDecoder() {
912 private NamedTypeSpecification namedType;
914 private ASN1Type element;
920 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
924 void startChildElement(String qName) throws SAXException {
925 if (decoder == null) {
926 namedType = data.getElement(qName);
927 element = namedType.instantiate();
928 decoder = new NamedElementDecoder(qName,
929 element.accept(XerDecoder.this));
931 decoder.startElement(qName);
938 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endChildElement
942 void endChildElement(String qName) {
943 if (decoder.endElement(qName)) {
944 data.set(namedType, element);
953 * Returns handler for the {@code CollectionType}.
956 * The {@code CollectionType} data.
957 * @return Handler for the data.
959 private <T extends ASN1Type> DataDecoder decoderForCollectionType(
960 final CollectionType<T, ?> data) {
961 return new ConstructedDataDecoder() {
965 private boolean useXmlValueList = false;
971 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startElement
975 void startElement(String qName) {
976 if (BOOLEAN.class.isAssignableFrom(data.componentType())
977 || ENUMERATED.class.isAssignableFrom(data.componentType())
978 || CHOICE.class.isAssignableFrom(data.componentType())) {
979 useXmlValueList = true;
987 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
991 void startChildElement(String qName) throws SAXException {
992 if (decoder == null) {
993 component = ASN1Type.instantiate(data.componentType());
994 if (useXmlValueList) {
995 decoder = new ValueListElementDecoder(
996 component.accept(XerDecoder.this));
998 decoder = new NamedElementDecoder(qName,
999 component.accept(XerDecoder.this));
1002 decoder.startElement(qName);
1009 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endChildElement
1010 * (java.lang.String)
1013 void endChildElement(String qName) {
1014 if (decoder.endElement(qName)) {
1015 data.collection().add(component);