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 decoder.characters(characters);
161 * Abstract handler class used for decoding a sequence of XML elements to an
164 * @author WATANABE, Jun. <jwat at bitmeister.jp>
166 private abstract class ElementDecoder {
171 * Instantiate an {@code ElementDecoder}.
174 * The {@code DataDecoder} used for decode the data.
176 ElementDecoder(DataDecoder decoder) {
177 this.decoder = decoder;
181 * Callback method that is called when an XML element started.
184 * The tag name of the element.
185 * @throws SAXException
186 * Thrown when an error occurred while the process.
188 abstract void startElement(String qName) throws SAXException;
191 * Callback method that is called when a character sequence detected in
195 * The character sequence.
197 void characters(String characters) {
198 decoder.characters(characters);
202 * Callback method that is called when an XML element ended.
205 * The tag name of the element.
206 * @return {@code true} when the element is enclosing element.
208 abstract boolean endElement(String qName);
213 * Handler class used for decoding a sequence of data elements that enclosed
216 * @author WATANABE, Jun. <jwat at bitmeister.jp>
218 private class NamedElementDecoder extends ElementDecoder {
220 private String tagName;
223 * Instantiate a {@code NamedElementDecoder}.
226 * The tag name of enclosing element.
228 * The {@code DataDecoder} used for decoding data elements.
230 NamedElementDecoder(String tagName, DataDecoder decoder) {
232 this.tagName = tagName;
239 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#startElement
242 public void startElement(String qName) throws SAXException {
243 if (qName.equals(tagName)) {
244 decoder.startElement(qName);
246 decoder.startChildElement(qName);
254 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#endElement
257 public boolean endElement(String qName) {
258 if (qName.equals(tagName)) {
259 decoder.endElement();
262 decoder.endChildElement(qName);
270 * Handler class used for decoding an data element that is not enclosed by
273 * @author WATANABE, Jun. <jwat at bitmeister.jp>
275 private class ValueListElementDecoder extends ElementDecoder {
278 * Instantiate a {@code ValueListElementDecoder}.
281 * The {@code DataDecoder} used for decoding the data
284 ValueListElementDecoder(DataDecoder decoder) {
292 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#startElement
295 public void startElement(String qName) throws SAXException {
296 decoder.startElement(qName);
297 decoder.startChildElement(qName);
304 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#endElement
307 public boolean endElement(String qName) {
308 decoder.endChildElement(qName);
309 decoder.endElement();
316 * Abstract handler class used for decosing an XML document to an ASN.1
319 * @author WATANABE, Jun. <jwat at bitmeister.jp>
321 private abstract class XerHandler<T extends ASN1Type> extends
326 private ElementDecoder decoder;
329 * Instantiates an ASN.1 data and sets it to this instance.
332 * The tag name of the head element of the XML document.
333 * @throws SAXException
334 * Thrown when an error occurred while the process.
336 abstract void initializeData(String qName) throws SAXException;
342 * org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
343 * java.lang.String, java.lang.String, org.xml.sax.Attributes)
346 public void startElement(String uri, String localName, String qName,
347 Attributes attributes) throws SAXException {
349 initializeData(qName);
350 decoder = new NamedElementDecoder(qName,
351 data.accept(XerDecoder.this));
353 decoder.startElement(qName);
359 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
362 public void characters(char[] ch, int start, int length) {
363 char[] tmp = new char[length];
364 System.arraycopy(ch, start, tmp, 0, length);
365 decoder.characters(String.valueOf(tmp));
371 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String,
372 * java.lang.String, java.lang.String)
375 public void endElement(String uri, String localName, String qName) {
376 decoder.endElement(qName);
381 private Class<? extends ASN1Module> module;
383 private InputStream in;
385 private XMLReader reader;
388 * Instantiates a {@code XerDecoder}.
391 * The {@code InputStream} to be read.
393 public XerDecoder(InputStream in) {
398 * Instantiates a {@code XerDecoder}.
401 * The {@code InputStream} to be read.
403 public XerDecoder(Class<? extends ASN1Module> module, InputStream in) {
405 this.module = module;
411 * @see jp.bitmeister.asn1.codec.ASN1Decoder#decode(java.lang.Class)
413 public <T extends ASN1Type> T decode(final Class<T> type)
414 throws ASN1DecodingException {
415 XerHandler<T> handler = new XerHandler<T>() {
421 * jp.bitmeister.asn1.codec.xer.XerDecoder.XerHandler#initializeData
424 void initializeData(String qName) throws SAXException {
425 data = ASN1Type.instantiate(type);
426 if (module == null) {
427 module = data.specification().module();
429 if (!(data instanceof ANY)
430 && !qName.equals(data.specification().xmlTypeName(module))) {
431 throw new SAXException("Unexpected xml tag name '" + qName
432 + "'. '" + data.specification().xmlTypeName(module)
445 * @see jp.bitmeister.asn1.codec.ASN1Decoder#decode()
447 public ASN1Type decode() throws ASN1DecodingException {
448 XerHandler<ASN1Type> handler = new XerHandler<ASN1Type>() {
454 * jp.bitmeister.asn1.codec.xer.XerDecoder.XerHandler#initializeData
457 void initializeData(String qName) {
458 data = ASN1ModuleManager.instantiate(module, qName);
467 * Decodes the source XML data read from the {@code InputStream} to the
470 * @throws ASN1DecodingException
471 * When an error occurred while the decoding process.
473 private void parse(XerHandler<?> handler) throws ASN1DecodingException {
475 reader = XMLReaderFactory.createXMLReader();
476 reader.setContentHandler(handler);
477 reader.parse(new InputSource(in));
478 } catch (Exception e) {
479 ASN1DecodingException ex = new ASN1DecodingException();
480 ex.setMessage("An exception thrown while decoding process.", e,
490 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
493 public DataDecoder visit(final BOOLEAN data) {
494 return new DataDecoder() {
500 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
504 void startChildElement(String qName) {
505 if (qName.equals(BOOLEAN_TRUE)) {
507 } else if (qName.equals(BOOLEAN_FALSE)) {
519 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
522 public DataDecoder visit(final INTEGER data) {
523 return new DataDecoder() {
529 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
533 void startChildElement(String qName) {
541 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
545 public void characters(String characters) {
546 data.set(new BigInteger(characters));
556 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
557 * .builtin.BIT_STRING)
559 public DataDecoder visit(final BIT_STRING data) {
560 return new DataDecoder() {
566 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
570 public void startChildElement(String qName) {
578 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
582 public void characters(String characters) {
583 data.set(new BinString(characters));
593 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
594 * .builtin.OCTET_STRING)
596 public DataDecoder visit(final OCTET_STRING data) {
597 return new DataDecoder() {
603 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
607 public void characters(String characters) {
608 data.set(new HexString(characters));
618 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
621 public DataDecoder visit(NULL data) {
622 return new DataDecoder() {
630 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
631 * .builtin.OBJECT_IDENTIFIER)
633 public DataDecoder visit(final OBJECT_IDENTIFIER data) {
634 return new DataDecoder() {
640 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
644 public void characters(String characters) {
645 List<Integer> oids = new ArrayList<Integer>();
646 for (String e : characters.split("\\.")) {
648 if (Character.isLetter(e.charAt(0))) {
649 if (!e.endsWith(")")) {
650 oids.add(OBJECT_IDENTIFIER.nameFormToInt(oids, e));
653 e = e.substring(e.indexOf('(') + 1, e.indexOf(')'));
655 oids.add(Integer.parseInt(e));
667 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
670 public DataDecoder visit(final REAL data) {
671 return new DataDecoder() {
677 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
681 public void startChildElement(String qName) {
682 if (qName.equals(REAL_PLUS_INFINITY)) {
683 data.set(Double.POSITIVE_INFINITY);
684 } else if (qName.equals(REAL_MINUS_INFINITY)) {
685 data.set(Double.NEGATIVE_INFINITY);
693 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
697 public void characters(String characters) {
698 data.set(Double.parseDouble(characters));
708 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
709 * .builtin.ENUMERATED)
711 public DataDecoder visit(ENUMERATED data) {
712 return visit((INTEGER) data);
719 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
720 * .builtin.RELATIVE_OID)
722 public DataDecoder visit(RELATIVE_OID data) {
723 return visit((OBJECT_IDENTIFIER) data);
730 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
733 public DataDecoder visit(final ANY data) {
734 return new DataDecoder() {
736 private DataDecoder decoder;
739 void startElement(String qName) throws SAXException {
740 data.set(ASN1ModuleManager.instantiate(module, qName));
741 decoder = data.value().accept(XerDecoder.this);
742 decoder.startElement(qName);
746 void startChildElement(String qName) throws SAXException {
747 decoder.startChildElement(qName);
751 void characters(String characters) {
752 decoder.characters(characters);
756 void endChildElement(String qName) {
757 decoder.endChildElement(qName);
762 decoder.endElement();
772 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
775 public DataDecoder visit(CHOICE data) {
776 return decoderForStructuredType(data);
783 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
784 * .builtin.SEQUENCE_OF)
786 public DataDecoder visit(SEQUENCE_OF<? extends ASN1Type> data) {
787 return decoderForCollectionType(data);
794 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
797 public DataDecoder visit(SEQUENCE data) {
798 return decoderForStructuredType(data);
805 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
808 public DataDecoder visit(SET_OF<? extends ASN1Type> data) {
809 return decoderForCollectionType(data);
816 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
819 public DataDecoder visit(SET data) {
820 return decoderForStructuredType(data);
827 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
830 public DataDecoder visit(final StringType data) {
831 return new DataDecoder() {
833 private StringBuilder builder = new StringBuilder();
839 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
843 public void startChildElement(String qName) {
844 builder.append(XerStringEscapeUtil.unescapeCtrl(qName));
851 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
855 public void characters(String characters) {
856 builder.append(characters);
863 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endElement()
867 if (builder.length() > 0) {
868 data.set(builder.toString());
879 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
882 public DataDecoder visit(TimeType data) {
883 return visit((StringType) data);
890 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
893 public DataDecoder visit(UnknownType data) throws SAXException {
894 throw new SAXException("UnkownType is not supported by XerDecoder.");
898 * Returns handler for the {@code StructuredType}.
901 * The {@code StructuredType} data.
902 * @return Handler for the data.
904 private DataDecoder decoderForStructuredType(final StructuredType data) {
905 return new ConstructedDataDecoder() {
907 private NamedTypeSpecification namedType;
909 private ASN1Type element;
915 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
919 void startChildElement(String qName) throws SAXException {
920 if (decoder == null) {
921 namedType = data.getElement(qName);
922 element = namedType.instantiate();
923 decoder = new NamedElementDecoder(qName,
924 element.accept(XerDecoder.this));
926 decoder.startElement(qName);
933 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endChildElement
937 void endChildElement(String qName) {
938 if (decoder.endElement(qName)) {
939 data.set(namedType, element);
948 * Returns handler for the {@code CollectionType}.
951 * The {@code CollectionType} data.
952 * @return Handler for the data.
954 private <T extends ASN1Type> DataDecoder decoderForCollectionType(
955 final CollectionType<T> data) {
956 return new ConstructedDataDecoder() {
960 private boolean useXmlValueList = false;
966 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startElement
970 void startElement(String qName) {
971 if (BOOLEAN.class.isAssignableFrom(data.componentType())
972 || ENUMERATED.class.isAssignableFrom(data.componentType())
973 || CHOICE.class.isAssignableFrom(data.componentType())) {
974 useXmlValueList = true;
982 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
986 void startChildElement(String qName) throws SAXException {
987 if (decoder == null) {
988 component = ASN1Type.instantiate(data.componentType());
989 if (useXmlValueList) {
990 decoder = new ValueListElementDecoder(
991 component.accept(XerDecoder.this));
993 decoder = new NamedElementDecoder(qName,
994 component.accept(XerDecoder.this));
997 decoder.startElement(qName);
1004 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endChildElement
1005 * (java.lang.String)
1008 void endChildElement(String qName) {
1009 if (decoder.endElement(qName)) {
1010 data.collection().add(component);