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.CHOICE;
45 import jp.bitmeister.asn1.type.builtin.ENUMERATED;
46 import jp.bitmeister.asn1.type.builtin.INTEGER;
47 import jp.bitmeister.asn1.type.builtin.NULL;
48 import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
49 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
50 import jp.bitmeister.asn1.type.builtin.REAL;
51 import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
52 import jp.bitmeister.asn1.type.builtin.SEQUENCE;
53 import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
54 import jp.bitmeister.asn1.type.builtin.SET;
55 import jp.bitmeister.asn1.type.builtin.SET_OF;
56 import jp.bitmeister.asn1.value.BinString;
57 import jp.bitmeister.asn1.value.HexString;
59 import org.xml.sax.Attributes;
60 import org.xml.sax.InputSource;
61 import org.xml.sax.SAXException;
62 import org.xml.sax.XMLReader;
63 import org.xml.sax.helpers.DefaultHandler;
64 import org.xml.sax.helpers.XMLReaderFactory;
67 * XER (XML Encoding Rules) decoder.
70 * {@code XerDecoder} is an implementation of {@code ASN1Decoder}. It reads a
71 * number of bytes from an {@code InputStream} that is specified when a decoder
72 * is instantiated, and decodes them to an ASN.1 data using XML Encoding Rules
76 * @author WATANABE, Jun. <jwat at bitmeister.jp>
81 public class XerDecoder implements ASN1Decoder,
82 ASN1Visitor<XerDecoder.DataDecoder, SAXException> {
85 * Abstract handler class used for decoding an XML element to an ASN.1 data.
87 * @author WATANABE, Jun. <jwat at bitmeister.jp>
89 abstract class DataDecoder {
92 * Callback method that is called when the data element started.
94 void startElement(String qName) throws SAXException {
98 * Callback method that is called when a child element started.
102 * @throws SAXException
103 * Thrown when an error occurred while the process.
105 void startChildElement(String qName) throws SAXException {
109 * Callback method that is called when a character sequence detected in
113 * The character sequence.
115 void characters(String characters) {
119 * Callback method that is called when a child element ended.
123 * @throws SAXException
124 * Thrown when an error occurred while the process.
126 void endChildElement(String qName) {
130 * Callback method that is called when the data element ended.
138 * Handler class for constructed data ({@code CollectionType} and
139 * {@code StructuredType}).
141 * @author WATANABE, Jun. <jwat at bitmeister.jp>
143 private abstract class ConstructedDataDecoder extends DataDecoder {
145 ElementDecoder decoder;
151 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters(java
155 void characters(String characters) {
156 if (decoder != null) {
157 decoder.characters(characters);
164 * Abstract handler class used for decoding a sequence of XML elements to an
167 * @author WATANABE, Jun. <jwat at bitmeister.jp>
169 private abstract class ElementDecoder {
174 * Instantiate an {@code ElementDecoder}.
177 * The {@code DataDecoder} used for decode the data.
179 ElementDecoder(DataDecoder decoder) {
180 this.decoder = decoder;
184 * Callback method that is called when an XML element started.
187 * The tag name of the element.
188 * @throws SAXException
189 * Thrown when an error occurred while the process.
191 abstract void startElement(String qName) throws SAXException;
194 * Callback method that is called when a character sequence detected in
198 * The character sequence.
200 void characters(String characters) {
201 decoder.characters(characters);
205 * Callback method that is called when an XML element ended.
208 * The tag name of the element.
209 * @return {@code true} when the element is enclosing element.
211 abstract boolean endElement(String qName);
216 * Handler class used for decoding a sequence of data elements that enclosed
219 * @author WATANABE, Jun. <jwat at bitmeister.jp>
221 private class NamedElementDecoder extends ElementDecoder {
223 private String tagName;
226 * Instantiate a {@code NamedElementDecoder}.
229 * The tag name of enclosing element.
231 * The {@code DataDecoder} used for decoding data elements.
233 NamedElementDecoder(String tagName, DataDecoder decoder) {
235 this.tagName = tagName;
242 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#startElement
245 public void startElement(String qName) throws SAXException {
246 if (qName.equals(tagName)) {
247 decoder.startElement(qName);
249 decoder.startChildElement(qName);
257 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#endElement
260 public boolean endElement(String qName) {
261 if (qName.equals(tagName)) {
262 decoder.endElement();
265 decoder.endChildElement(qName);
273 * Handler class used for decoding an data element that is not enclosed by
276 * @author WATANABE, Jun. <jwat at bitmeister.jp>
278 private class ValueListElementDecoder extends ElementDecoder {
281 * Instantiate a {@code ValueListElementDecoder}.
284 * The {@code DataDecoder} used for decoding the data
287 ValueListElementDecoder(DataDecoder decoder) {
295 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#startElement
298 public void startElement(String qName) throws SAXException {
299 decoder.startElement(qName);
300 decoder.startChildElement(qName);
307 * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#endElement
310 public boolean endElement(String qName) {
311 decoder.endChildElement(qName);
312 decoder.endElement();
319 * Abstract handler class used for decosing an XML document to an ASN.1
322 * @author WATANABE, Jun. <jwat at bitmeister.jp>
324 private abstract class XerHandler<T extends ASN1Type> extends
329 private ElementDecoder decoder;
332 * Instantiates an ASN.1 data and sets it to this instance.
335 * The tag name of the head element of the XML document.
336 * @throws SAXException
337 * Thrown when an error occurred while the process.
339 abstract void initializeData(String qName) throws SAXException;
345 * org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
346 * java.lang.String, java.lang.String, org.xml.sax.Attributes)
349 public void startElement(String uri, String localName, String qName,
350 Attributes attributes) throws SAXException {
352 initializeData(qName);
353 decoder = new NamedElementDecoder(qName,
354 data.accept(XerDecoder.this));
356 decoder.startElement(qName);
362 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
365 public void characters(char[] ch, int start, int length) {
366 char[] tmp = new char[length];
367 System.arraycopy(ch, start, tmp, 0, length);
368 decoder.characters(String.valueOf(tmp));
374 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String,
375 * java.lang.String, java.lang.String)
378 public void endElement(String uri, String localName, String qName) {
379 decoder.endElement(qName);
384 private Class<? extends ASN1Module> module;
386 private InputStream in;
388 private XMLReader reader;
391 * Instantiates a {@code XerDecoder}.
394 * The {@code InputStream} to be read.
396 public XerDecoder(InputStream in) {
401 * Instantiates a {@code XerDecoder}.
404 * The {@code InputStream} to be read.
406 public XerDecoder(Class<? extends ASN1Module> module, InputStream in) {
408 this.module = module;
414 * @see jp.bitmeister.asn1.codec.ASN1Decoder#decode(java.lang.Class)
416 public <T extends ASN1Type> T decode(final Class<T> type)
417 throws ASN1DecodingException {
418 XerHandler<T> handler = new XerHandler<T>() {
424 * jp.bitmeister.asn1.codec.xer.XerDecoder.XerHandler#initializeData
427 void initializeData(String qName) throws SAXException {
428 data = ASN1Type.instantiate(type);
429 if (module == null) {
430 module = data.specification().module();
432 if (!(data instanceof ANY)
433 && !qName.equals(data.specification().xmlTypeName(module))) {
434 throw new SAXException("Unexpected xml tag name '" + qName
435 + "'. '" + data.specification().xmlTypeName(module)
448 * @see jp.bitmeister.asn1.codec.ASN1Decoder#decode()
450 public ASN1Type decode() throws ASN1DecodingException {
451 XerHandler<ASN1Type> handler = new XerHandler<ASN1Type>() {
457 * jp.bitmeister.asn1.codec.xer.XerDecoder.XerHandler#initializeData
460 void initializeData(String qName) throws SAXException {
461 data = ASN1ModuleManager.instantiate(module, qName);
463 throw new SAXException("Unknown data type '" + qName + "'.");
473 * Decodes the source XML data read from the {@code InputStream} to the
476 * @throws ASN1DecodingException
477 * When an error occurred while the decoding process.
479 private void parse(XerHandler<?> handler) throws ASN1DecodingException {
481 reader = XMLReaderFactory.createXMLReader();
482 reader.setContentHandler(handler);
483 reader.parse(new InputSource(in));
484 } catch (Exception e) {
485 ASN1DecodingException ex = new ASN1DecodingException();
486 ex.setMessage("An exception thrown while decoding process.", e,
496 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
499 public DataDecoder visit(final BOOLEAN data) {
500 return new DataDecoder() {
506 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
510 void startChildElement(String qName) {
511 if (qName.equals(BOOLEAN_TRUE)) {
513 } else if (qName.equals(BOOLEAN_FALSE)) {
525 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
528 public DataDecoder visit(final INTEGER data) {
529 return new DataDecoder() {
535 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
539 void startChildElement(String qName) {
547 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
551 public void characters(String characters) {
552 data.set(new BigInteger(characters));
562 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
563 * .builtin.BIT_STRING)
565 public DataDecoder visit(final BIT_STRING data) {
566 return new DataDecoder() {
572 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
576 public void startChildElement(String qName) {
584 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
588 public void characters(String characters) {
589 data.set(new BinString(characters));
599 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
600 * .builtin.OCTET_STRING)
602 public DataDecoder visit(final OCTET_STRING data) {
603 return new DataDecoder() {
609 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
613 public void characters(String characters) {
614 data.set(new HexString(characters));
624 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
627 public DataDecoder visit(NULL data) {
628 return new DataDecoder() {
636 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
637 * .builtin.OBJECT_IDENTIFIER)
639 public DataDecoder visit(final OBJECT_IDENTIFIER data) {
640 return new DataDecoder() {
646 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
650 public void characters(String characters) {
651 List<Integer> oids = new ArrayList<Integer>();
652 for (String e : characters.split("\\.")) {
654 if (Character.isLetter(e.charAt(0))) {
655 if (!e.endsWith(")")) {
656 oids.add(OBJECT_IDENTIFIER.nameFormToInt(oids, e));
659 e = e.substring(e.indexOf('(') + 1, e.indexOf(')'));
661 oids.add(Integer.parseInt(e));
673 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
676 public DataDecoder visit(final REAL data) {
677 return new DataDecoder() {
683 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
687 public void startChildElement(String qName) {
688 if (qName.equals(REAL_PLUS_INFINITY)) {
689 data.set(Double.POSITIVE_INFINITY);
690 } else if (qName.equals(REAL_MINUS_INFINITY)) {
691 data.set(Double.NEGATIVE_INFINITY);
692 } else if (qName.equals(REAL_NAN)) {
693 data.set(Double.NaN);
701 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
705 public void characters(String characters) {
706 data.set(Double.parseDouble(characters));
716 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
717 * .builtin.ENUMERATED)
719 public DataDecoder visit(ENUMERATED data) {
720 return visit((INTEGER) data);
727 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
728 * .builtin.RELATIVE_OID)
730 public DataDecoder visit(RELATIVE_OID data) {
731 return visit((OBJECT_IDENTIFIER) data);
738 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
741 public DataDecoder visit(final ANY data) {
742 return new DataDecoder() {
744 private DataDecoder decoder;
747 void startElement(String qName) throws SAXException {
748 data.set(ASN1ModuleManager.instantiate(module, qName));
749 decoder = data.value().accept(XerDecoder.this);
750 decoder.startElement(qName);
754 void startChildElement(String qName) throws SAXException {
755 decoder.startChildElement(qName);
759 void characters(String characters) {
760 decoder.characters(characters);
764 void endChildElement(String qName) {
765 decoder.endChildElement(qName);
770 decoder.endElement();
780 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
783 public DataDecoder visit(CHOICE data) {
784 return decoderForStructuredType(data);
791 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
792 * .builtin.SEQUENCE_OF)
794 public DataDecoder visit(SEQUENCE_OF<? extends ASN1Type> data) {
795 return decoderForCollectionType(data);
802 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
805 public DataDecoder visit(SEQUENCE data) {
806 return decoderForStructuredType(data);
813 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
816 public DataDecoder visit(SET_OF<? extends ASN1Type> data) {
817 return decoderForCollectionType(data);
824 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
827 public DataDecoder visit(SET data) {
828 return decoderForStructuredType(data);
835 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
838 public DataDecoder visit(final StringType data) {
839 return new DataDecoder() {
841 private StringBuilder builder = new StringBuilder();
847 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
851 public void startChildElement(String qName) {
852 builder.append(XerStringEscapeUtil.unescapeCtrl(qName));
859 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
863 public void characters(String characters) {
864 builder.append(characters);
871 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endElement()
875 if (builder.length() > 0) {
876 data.set(builder.toString());
887 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
890 public DataDecoder visit(TimeType data) {
891 return visit((StringType) data);
898 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
901 public DataDecoder visit(UnknownType data) throws SAXException {
902 throw new SAXException("UnkownType is not supported by XerDecoder.");
906 * Returns handler for the {@code StructuredType}.
909 * The {@code StructuredType} data.
910 * @return Handler for the data.
912 private DataDecoder decoderForStructuredType(final StructuredType data) {
913 return new ConstructedDataDecoder() {
915 private NamedTypeSpecification namedType;
917 private ASN1Type element;
923 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
927 void startChildElement(String qName) throws SAXException {
928 if (decoder == null) {
929 namedType = data.getElement(qName);
930 element = namedType.instantiate();
931 decoder = new NamedElementDecoder(qName,
932 element.accept(XerDecoder.this));
934 decoder.startElement(qName);
941 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endChildElement
945 void endChildElement(String qName) {
946 if (decoder.endElement(qName)) {
947 data.set(namedType, element);
956 * Returns handler for the {@code CollectionType}.
959 * The {@code CollectionType} data.
960 * @return Handler for the data.
962 private <T extends ASN1Type> DataDecoder decoderForCollectionType(
963 final CollectionType<T, ?> data) {
964 return new ConstructedDataDecoder() {
968 private boolean useXmlValueList = false;
974 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startElement
978 void startElement(String qName) {
979 if (BOOLEAN.class.isAssignableFrom(data.componentType())
980 || ENUMERATED.class.isAssignableFrom(data.componentType())
981 || CHOICE.class.isAssignableFrom(data.componentType())) {
982 useXmlValueList = true;
990 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
994 void startChildElement(String qName) throws SAXException {
995 if (decoder == null) {
996 component = ASN1Type.instantiate(data.componentType());
997 if (useXmlValueList) {
998 decoder = new ValueListElementDecoder(
999 component.accept(XerDecoder.this));
1001 decoder = new NamedElementDecoder(qName,
1002 component.accept(XerDecoder.this));
1005 decoder.startElement(qName);
1012 * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endChildElement
1013 * (java.lang.String)
1016 void endChildElement(String qName) {
1017 if (decoder.endElement(qName)) {
1018 data.collection().add(component);