OSDN Git Service

version 0.2
authorjwat <jwat@users.sourceforge.jp>
Fri, 2 Sep 2011 12:15:54 +0000 (21:15 +0900)
committerjwat <jwat@users.sourceforge.jp>
Fri, 2 Sep 2011 12:15:54 +0000 (21:15 +0900)
- Add: XER codec
- Add: RELATIVE_OID
- Add: ASN1ModuleManager
- Mod: ASN1Module definition
- Del: ASN1Modules

41 files changed:
jp/bitmeister/asn1/annotation/ASN1DefinedTypes.java [new file with mode: 0644]
jp/bitmeister/asn1/annotation/ASN1ImportedModules.java [new file with mode: 0644]
jp/bitmeister/asn1/annotation/ASN1XmlTypeName.java [new file with mode: 0644]
jp/bitmeister/asn1/codec/ASN1Decoder.java
jp/bitmeister/asn1/codec/ber/BerDecoder.java
jp/bitmeister/asn1/codec/ber/BerEncoder.java
jp/bitmeister/asn1/codec/xer/XerConstants.java [new file with mode: 0644]
jp/bitmeister/asn1/codec/xer/XerDecoder.java [new file with mode: 0644]
jp/bitmeister/asn1/codec/xer/XerEncoder.java [new file with mode: 0644]
jp/bitmeister/asn1/codec/xer/XerStringEscapeUtil.java [new file with mode: 0644]
jp/bitmeister/asn1/codec/xer/package-info.java [new file with mode: 0644]
jp/bitmeister/asn1/processor/ASN1StringBuilder.java
jp/bitmeister/asn1/processor/ASN1Visitor.java
jp/bitmeister/asn1/processor/ASN1VisitorAdaptor.java
jp/bitmeister/asn1/sample/FrightStatusMain.java
jp/bitmeister/asn1/sample/FrightStatusTypes.asn
jp/bitmeister/asn1/sample/FrightStatusTypes.java
jp/bitmeister/asn1/type/ASN1Module.java
jp/bitmeister/asn1/type/ASN1ModuleManager.java [new file with mode: 0644]
jp/bitmeister/asn1/type/ASN1Type.java
jp/bitmeister/asn1/type/BuiltInModule.java
jp/bitmeister/asn1/type/CollectionType.java
jp/bitmeister/asn1/type/ConstructiveType.java
jp/bitmeister/asn1/type/ModuleSpecification.java [new file with mode: 0644]
jp/bitmeister/asn1/type/NamedTypeSpecification.java
jp/bitmeister/asn1/type/SelectiveType.java
jp/bitmeister/asn1/type/StructuredType.java
jp/bitmeister/asn1/type/TypeSpecification.java
jp/bitmeister/asn1/type/UnknownType.java
jp/bitmeister/asn1/type/builtin/BIT_STRING.java
jp/bitmeister/asn1/type/builtin/INTEGER.java
jp/bitmeister/asn1/type/builtin/OBJECT_IDENTIFIER.java
jp/bitmeister/asn1/type/builtin/OCTET_STRING.java
jp/bitmeister/asn1/type/builtin/RELATIVE_OID.java [new file with mode: 0644]
jp/bitmeister/asn1/type/builtin/SEQUENCE_OF.java
jp/bitmeister/asn1/type/builtin/SET_OF.java
jp/bitmeister/asn1/type/useful/CHARACTER_STRING.java
jp/bitmeister/asn1/type/useful/EMBEDDED_PDV.java
jp/bitmeister/asn1/value/BinString.java
jp/bitmeister/asn1/value/HexString.java
jp/bitmeister/asn1/value/StringItem.java

diff --git a/jp/bitmeister/asn1/annotation/ASN1DefinedTypes.java b/jp/bitmeister/asn1/annotation/ASN1DefinedTypes.java
new file mode 100644 (file)
index 0000000..6229c44
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011 BitMeister Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package jp.bitmeister.asn1.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jp.bitmeister.asn1.type.ASN1Module;
+import jp.bitmeister.asn1.type.ASN1Type;
+
+/**
+ * Indicates ASN.1 types which are included in this module.
+ * 
+ * <p>
+ * {@code ASN1DefinedTypes} annotation indicates ASN.1 types which are included
+ * in this module but defined at outside of the ASN.1 module class. ASN.1 types
+ * defined as static public member classes of an ASN.1 module class will be
+ * registered to the module automatically.
+ * </p>
+ * 
+ * @author WATANABE, Jun. <jwat at bitmeister.jp>
+ * 
+ * @see ASN1Module
+ * @see ASN1Type
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ASN1DefinedTypes {
+
+       /**
+        * Indicates ASN.1 type classes defined at outside of the module class.
+        * 
+        * @return An array of {@code Class} object of {@code ASN1Type}.
+        */
+       public Class<? extends ASN1Type>[] value();
+
+}
diff --git a/jp/bitmeister/asn1/annotation/ASN1ImportedModules.java b/jp/bitmeister/asn1/annotation/ASN1ImportedModules.java
new file mode 100644 (file)
index 0000000..1cad242
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011 BitMeister Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package jp.bitmeister.asn1.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jp.bitmeister.asn1.type.ASN1Module;
+
+/**
+ * Indicates ASN.1 modules which are imported by this module.
+ * 
+ * <p>
+ * {@code ASN1ImportedModules} annotation indicates ASN.1 modules which are
+ * imported by this module.
+ * </p>
+ * 
+ * @author WATANABE, Jun. <jwat at bitmeister.jp>
+ * 
+ * @see ASN1Module
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ASN1ImportedModules {
+
+       /**
+        * Indicates ASN.1 module classes imported by the ASN.1 module.
+        * 
+        * @return An array of {@code Class} object of {@code ASN1Module}.
+        */
+       public Class<? extends ASN1Module>[] value();
+
+}
diff --git a/jp/bitmeister/asn1/annotation/ASN1XmlTypeName.java b/jp/bitmeister/asn1/annotation/ASN1XmlTypeName.java
new file mode 100644 (file)
index 0000000..42339bb
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011 BitMeister Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package jp.bitmeister.asn1.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates xml type name for an ASN.1 type.
+ * 
+ * <p>
+ * If an {@code @ASN1XmlTypeName} annotation is present on a type,
+ * this value is used as xml tag name instead of their class name that taken
+ * by calling {@code Class.getSimpleName()} when the XER encoding process.
+ * If an ASN.1 identifier includes whitespace, this annotation shall be used.
+ * </p>
+ * 
+ * @author WATANABE, Jun. <jwat at bitmeister.jp>
+ */
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ASN1XmlTypeName {
+
+       /**
+        * Indicates the xml tag name for this ASN.1 type.
+        * 
+        * @return The xml tag name.
+        */
+       public String value();
+       
+}
index 8219866..cffea2c 100644 (file)
@@ -50,5 +50,5 @@ public interface ASN1Decoder {
         *             Thrown when an error occurred while the decoding process.
         */
        public ASN1Type decode() throws ASN1DecodingException;
-
+       
 }
index 15c2e49..f90e362 100644 (file)
@@ -25,7 +25,8 @@ import java.util.List;
 import jp.bitmeister.asn1.codec.ASN1Decoder;
 import jp.bitmeister.asn1.exception.ASN1DecodingException;
 import jp.bitmeister.asn1.processor.ASN1Visitor;
-import jp.bitmeister.asn1.type.ASN1Modules;
+import jp.bitmeister.asn1.type.ASN1Module;
+import jp.bitmeister.asn1.type.ASN1ModuleManager;
 import jp.bitmeister.asn1.type.ASN1TagClass;
 import jp.bitmeister.asn1.type.ASN1TagMode;
 import jp.bitmeister.asn1.type.ASN1TagValue;
@@ -49,6 +50,7 @@ import jp.bitmeister.asn1.type.builtin.NULL;
 import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
 import jp.bitmeister.asn1.type.builtin.REAL;
+import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
 import jp.bitmeister.asn1.type.builtin.SEQUENCE;
 import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
 import jp.bitmeister.asn1.type.builtin.SET;
@@ -71,6 +73,8 @@ import jp.bitmeister.asn1.type.builtin.SET_OF;
  */
 public class BerDecoder implements ASN1Decoder,
                ASN1Visitor<Void, ASN1DecodingException> {
+       
+       private Class<? extends ASN1Module> module;
 
        private InputStream in;
 
@@ -91,6 +95,19 @@ public class BerDecoder implements ASN1Decoder,
        public BerDecoder(InputStream in) {
                this.in = in;
        }
+       
+       /**
+        * Instantiates a {@code BerDecoder}.
+        * 
+        * @param module
+        *            The ASN.1 module used for decoding.
+        * @param in
+        *            The {@code InputStream} to be read.
+        */
+       public BerDecoder(Class<? extends ASN1Module> module, InputStream in) {
+               this(in);
+               this.module = module;
+       }
 
        /*
         * (non-Javadoc)
@@ -110,7 +127,11 @@ public class BerDecoder implements ASN1Decoder,
        @Override
        public <T extends ASN1Type> T decode(Class<T> type)
                        throws ASN1DecodingException {
-               return decodeImpl(ASN1Type.instantiate(type));
+               T data = ASN1Type.instantiate(type);
+               if (module == null) {
+                       module = data.specification().module();
+               }
+               return decodeImpl(data);
        }
 
        /**
@@ -137,7 +158,7 @@ public class BerDecoder implements ASN1Decoder,
                        throws ASN1DecodingException {
                readTag();
                if (data == null) {
-                       data = (T) ASN1Modules.instantiate(tagClass, tagNumber);
+                       data = (T) ASN1ModuleManager.instantiate(module, tagClass, tagNumber);
                }
                TypeSpecification specification = data.specification();
                do {
@@ -468,13 +489,28 @@ public class BerDecoder implements ASN1Decoder,
                byte[] octets = readStream(1);
                oids.add(octets[0] / 40);
                oids.add(octets[0] % 40);
-               processMultipleOctets(length - 1, new ElementProcessor() {
+               decodeOids(oids, length - 1);
+               data.set(oids);
+               return null;
+       }
+       
+       /* (non-Javadoc)
+        * @see jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type.builtin.RELATIVE_OID)
+        */
+       @Override
+       public Void visit(RELATIVE_OID data) throws ASN1DecodingException {
+               List<Integer> oids = new ArrayList<Integer>();
+               decodeOids(oids, readLength());
+               data.set(oids);
+               return null;
+       }
+       
+       private void decodeOids(final List<Integer> oids, int length) throws ASN1DecodingException {
+               processMultipleOctets(length, new ElementProcessor() {
                        public void process() throws ASN1DecodingException {
                                oids.add(readMultipleOctets());
                        }
                });
-               data.set(oids);
-               return null;
        }
 
        /*
@@ -513,7 +549,7 @@ public class BerDecoder implements ASN1Decoder,
        @Override
        public Void visit(ANY data) throws ASN1DecodingException {
                if (data.value() == null) {
-                       data.set(ASN1Modules.instantiate(tagClass, tagNumber));
+                       data.set(ASN1ModuleManager.instantiate(module, tagClass, tagNumber));
                }
                data.value().accept(this);
                return null;
index fef2b65..7e9d2d8 100644 (file)
@@ -45,6 +45,7 @@ import jp.bitmeister.asn1.type.builtin.NULL;
 import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
 import jp.bitmeister.asn1.type.builtin.REAL;
+import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
 import jp.bitmeister.asn1.type.builtin.SEQUENCE;
 import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
 import jp.bitmeister.asn1.type.builtin.SET;
@@ -343,8 +344,25 @@ public class BerEncoder implements ASN1Encoder,
                                        data.getClass(), null, data);
                        throw ex;
                }
-               int size = 1;
-               for (int i = 2; i < data.value().size(); i++) {
+               byte[] encoded = new byte[calculateEncodedOidSize(data, 2) + 1];
+               encoded[0] = (byte) (data.value().get(0) * 40 + data.value().get(1));
+               encodeOid(data, encoded, 2, 1);
+               return newPrimitiveOctets(encoded);
+       }
+       
+       /* (non-Javadoc)
+        * @see jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type.builtin.RELATIVE_OID)
+        */
+       @Override
+       public EncodedOctets visit(RELATIVE_OID data) throws ASN1EncodingException {
+               byte[] encoded = new byte[calculateEncodedOidSize(data, 0)];
+               encodeOid(data, encoded, 0, 0);
+               return newPrimitiveOctets(encoded);
+       }       
+
+       private int calculateEncodedOidSize(OBJECT_IDENTIFIER data, int start) throws ASN1EncodingException {
+               int size = 0;
+               for (int i = start; i < data.value().size(); i++) {
                        if (data.value().get(i) < 0) {
                                ASN1EncodingException ex = new ASN1EncodingException();
                                ex.setMessage(
@@ -354,16 +372,15 @@ public class BerEncoder implements ASN1Encoder,
                        }
                        size += sizeBy7bits(data.value().get(i));
                }
-               byte[] encoded = new byte[size];
-               encoded[0] = (byte) (data.value().get(0) * 40 + data.value().get(1));
-               int offset = 1;
-               for (int i = 2; i < data.value().size(); i++) {
-                       offset += encodeToMutipleOctets(encoded, offset, data.value()
-                                       .get(i));
+               return size;
+       }
+       
+       private void encodeOid(OBJECT_IDENTIFIER data, byte[] dest, int start, int offset) {
+               for (int i = start; i < data.value().size(); i++) {
+                       offset += encodeToMutipleOctets(dest, offset, data.value().get(i));
                }
-               return newPrimitiveOctets(encoded);
        }
-
+       
        /*
         * (non-Javadoc)
         * 
diff --git a/jp/bitmeister/asn1/codec/xer/XerConstants.java b/jp/bitmeister/asn1/codec/xer/XerConstants.java
new file mode 100644 (file)
index 0000000..18a5139
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 BitMeister Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package jp.bitmeister.asn1.codec.xer;
+
+/**
+ * XER constants.
+ * 
+ * <p>
+ * This class contains some constants used by XER codec.
+ * </p>
+ * 
+ * @author WATANABE, Jun. <jwat at bitmeister.jp>
+ */
+class XerConstants {
+       static final String XML_PROLOG = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+       static final String TAG_START = "<";
+       static final String END_TAG_START = "</";
+       static final String TAG_END = ">";
+       static final String SINGLE_TAG_END = "/>";
+       static final String BOOLEAN_TRUE = "true";
+       static final String BOOLEAN_FALSE = "false";
+       static final String REAL_PLUS_INFINITY = "PLUS-INFINITY";
+       static final String REAL_MINUS_INFINITY = "MINUS-INFINITY";
+       static final String REAL_ZERO = "0";
+}
diff --git a/jp/bitmeister/asn1/codec/xer/XerDecoder.java b/jp/bitmeister/asn1/codec/xer/XerDecoder.java
new file mode 100644 (file)
index 0000000..7068a1a
--- /dev/null
@@ -0,0 +1,1044 @@
+/*
+ * Copyright 2011 BitMeister Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package jp.bitmeister.asn1.codec.xer;
+
+import static jp.bitmeister.asn1.codec.xer.XerConstants.BOOLEAN_FALSE;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.BOOLEAN_TRUE;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.REAL_MINUS_INFINITY;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.REAL_PLUS_INFINITY;
+
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import jp.bitmeister.asn1.codec.ASN1Decoder;
+import jp.bitmeister.asn1.exception.ASN1DecodingException;
+import jp.bitmeister.asn1.processor.ASN1Visitor;
+import jp.bitmeister.asn1.type.ASN1Module;
+import jp.bitmeister.asn1.type.ASN1ModuleManager;
+import jp.bitmeister.asn1.type.ASN1Type;
+import jp.bitmeister.asn1.type.CollectionType;
+import jp.bitmeister.asn1.type.NamedTypeSpecification;
+import jp.bitmeister.asn1.type.StringType;
+import jp.bitmeister.asn1.type.StructuredType;
+import jp.bitmeister.asn1.type.TimeType;
+import jp.bitmeister.asn1.type.UnknownType;
+import jp.bitmeister.asn1.type.builtin.ANY;
+import jp.bitmeister.asn1.type.builtin.BIT_STRING;
+import jp.bitmeister.asn1.type.builtin.BOOLEAN;
+import jp.bitmeister.asn1.type.builtin.CHOICE;
+import jp.bitmeister.asn1.type.builtin.ENUMERATED;
+import jp.bitmeister.asn1.type.builtin.INTEGER;
+import jp.bitmeister.asn1.type.builtin.NULL;
+import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
+import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
+import jp.bitmeister.asn1.type.builtin.REAL;
+import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
+import jp.bitmeister.asn1.type.builtin.SEQUENCE;
+import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
+import jp.bitmeister.asn1.type.builtin.SET;
+import jp.bitmeister.asn1.type.builtin.SET_OF;
+import jp.bitmeister.asn1.value.BinString;
+import jp.bitmeister.asn1.value.HexString;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * XER (XML Encoding Rules) decoder.
+ * 
+ * <p>
+ * {@code XerDecoder} is an implementation of {@code ASN1Decoder}. It reads a
+ * number of bytes from an {@code InputStream} that is specified when a decoder
+ * is instantiated, and decodes them to an ASN.1 data with XML Encoding Rules
+ * (XER).
+ * </p>
+ * 
+ * @author WATANABE, Jun. <jwat at bitmeister.jp>
+ * 
+ * @see ASN1Decoder
+ * @see XerEncoder
+ */
+public class XerDecoder implements ASN1Decoder,
+               ASN1Visitor<XerDecoder.DataDecoder, SAXException> {
+
+       /**
+        * Abstract handler class used for decoding an XML element to an ASN.1 data.
+        * 
+        * @author WATANABE, Jun. <jwat at bitmeister.jp>
+        */
+       abstract class DataDecoder {
+
+               /**
+                * Callback method that is called when the data element started.
+                */
+               void startElement(String qName) throws SAXException {
+               }
+
+               /**
+                * Callback method that is called when a child element started.
+                * 
+                * @param qName
+                *            The element name.
+                * @throws SAXException
+                *             Thrown when an error occurred while the process.
+                */
+               void startChildElement(String qName) throws SAXException {
+               }
+
+               /**
+                * Callback method that is called when a character sequence detected in
+                * the XML element.
+                * 
+                * @param characters
+                *            The character sequence.
+                */
+               void characters(String characters) {
+               }
+
+               /**
+                * Callback method that is called when a child element ended.
+                * 
+                * @param qName
+                *            The element name.
+                * @throws SAXException
+                *             Thrown when an error occurred while the process.
+                */
+               void endChildElement(String qName) {
+               }
+
+               /**
+                * Callback method that is called when the data element ended.
+                */
+               void endElement() {
+               }
+
+       }
+
+       /**
+        * Handler class for constructed data ({@code CollectionType} and
+        * {@code StructuredType}).
+        * 
+        * @author WATANABE, Jun. <jwat at bitmeister.jp>
+        */
+       private abstract class ConstructedDataDecoder extends DataDecoder {
+
+               ElementDecoder decoder;
+
+               /*
+                * (non-Javadoc)
+                * 
+                * @see
+                * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters(java
+                * .lang.String)
+                */
+               @Override
+               void characters(String characters) {
+                       decoder.characters(characters);
+               }
+
+       }
+
+       /**
+        * Abstract handler class used for decoding a sequence of XML elements to an
+        * ASN.1 type data.
+        * 
+        * @author WATANABE, Jun. <jwat at bitmeister.jp>
+        */
+       private abstract class ElementDecoder {
+
+               DataDecoder decoder;
+
+               /**
+                * Instantiate an {@code ElementDecoder}.
+                * 
+                * @param decoder
+                *            The {@code DataDecoder} used for decode the data.
+                */
+               ElementDecoder(DataDecoder decoder) {
+                       this.decoder = decoder;
+               }
+
+               /**
+                * Callback method that is called when an XML element started.
+                * 
+                * @param qName
+                *            The tag name of the element.
+                * @throws SAXException
+                *             Thrown when an error occurred while the process.
+                */
+               abstract void startElement(String qName) throws SAXException;
+
+               /**
+                * Callback method that is called when a character sequence detected in
+                * an XML element.
+                * 
+                * @param characters
+                *            The character sequence.
+                */
+               void characters(String characters) {
+                       decoder.characters(characters);
+               }
+
+               /**
+                * Callback method that is called when an XML element ended.
+                * 
+                * @param qName
+                *            The tag name of the element.
+                * @return {@code true} when the element is enclosing element.
+                */
+               abstract boolean endElement(String qName);
+
+       }
+
+       /**
+        * Handler class used for decoding a sequence of data elements that enclosed
+        * by an element.
+        * 
+        * @author WATANABE, Jun. <jwat at bitmeister.jp>
+        */
+       private class NamedElementDecoder extends ElementDecoder {
+
+               private String tagName;
+
+               /**
+                * Instantiate a {@code NamedElementDecoder}.
+                * 
+                * @param tagName
+                *            The tag name of enclosing element.
+                * @param decoder
+                *            The {@code DataDecoder} used for decoding data elements.
+                */
+               NamedElementDecoder(String tagName, DataDecoder decoder) {
+                       super(decoder);
+                       this.tagName = tagName;
+               }
+
+               /*
+                * (non-Javadoc)
+                * 
+                * @see
+                * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#startElement
+                * (java.lang.String)
+                */
+               @Override
+               public void startElement(String qName) throws SAXException {
+                       if (qName.equals(tagName)) {
+                               decoder.startElement(qName);
+                       } else {
+                               decoder.startChildElement(qName);
+                       }
+               }
+
+               /*
+                * (non-Javadoc)
+                * 
+                * @see
+                * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#endElement
+                * (java.lang.String)
+                */
+               @Override
+               public boolean endElement(String qName) {
+                       if (qName.equals(tagName)) {
+                               decoder.endElement();
+                               return true;
+                       } else {
+                               decoder.endChildElement(qName);
+                               return false;
+                       }
+               }
+
+       }
+
+       /**
+        * Handler class used for decoding an data element that is not enclosed by
+        * element.
+        * 
+        * @author WATANABE, Jun. <jwat at bitmeister.jp>
+        */
+       private class ValueListElementDecoder extends ElementDecoder {
+
+               /**
+                * Instantiate a {@code ValueListElementDecoder}.
+                * 
+                * @param decoder
+                *            The {@code DataDecoder} used for decoding the data
+                *            element.
+                */
+               ValueListElementDecoder(DataDecoder decoder) {
+                       super(decoder);
+               }
+
+               /*
+                * (non-Javadoc)
+                * 
+                * @see
+                * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#startElement
+                * (java.lang.String)
+                */
+               @Override
+               public void startElement(String qName) throws SAXException {
+                       decoder.startElement(qName);
+                       decoder.startChildElement(qName);
+               }
+
+               /*
+                * (non-Javadoc)
+                * 
+                * @see
+                * jp.bitmeister.asn1.codec.xer.XerDecoder.ElementDecoder#endElement
+                * (java.lang.String)
+                */
+               @Override
+               public boolean endElement(String qName) {
+                       decoder.endChildElement(qName);
+                       decoder.endElement();
+                       return true;
+               }
+
+       }
+
+       /**
+        * Abstract handler class used for decosing an XML document to an ASN.1
+        * data.
+        * 
+        * @author WATANABE, Jun. <jwat at bitmeister.jp>
+        */
+       private abstract class XerHandler<T extends ASN1Type> extends
+                       DefaultHandler {
+
+               T data;
+
+               private ElementDecoder decoder;
+
+               /**
+                * Instantiates an ASN.1 data and sets it to this instance.
+                * 
+                * @param qName
+                *            The tag name of the head element of the XML document.
+                * @throws SAXException
+                *             Thrown when an error occurred while the process.
+                */
+               abstract void initializeData(String qName) throws SAXException;
+
+               /*
+                * (non-Javadoc)
+                * 
+                * @see
+                * org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
+                * java.lang.String, java.lang.String, org.xml.sax.Attributes)
+                */
+               @Override
+               public void startElement(String uri, String localName, String qName,
+                               Attributes attributes) throws SAXException {
+                       if (data == null) {
+                               initializeData(qName);
+                               decoder = new NamedElementDecoder(qName,
+                                               data.accept(XerDecoder.this));
+                       }
+                       decoder.startElement(qName);
+               }
+
+               /*
+                * (non-Javadoc)
+                * 
+                * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
+                */
+               @Override
+               public void characters(char[] ch, int start, int length) {
+                       decoder.characters(String.valueOf(Arrays.copyOfRange(ch, start,
+                                       start + length)));
+               }
+
+               /*
+                * (non-Javadoc)
+                * 
+                * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String,
+                * java.lang.String, java.lang.String)
+                */
+               @Override
+               public void endElement(String uri, String localName, String qName) {
+                       decoder.endElement(qName);
+               }
+
+       }
+       
+       private Class<? extends ASN1Module> module;
+
+       private InputStream in;
+
+       private XMLReader reader;
+
+       /**
+        * Instantiates a {@code XerDecoder}.
+        * 
+        * @param in
+        *            The {@code InputStream} to be read.
+        */
+       public XerDecoder(InputStream in) {
+               this.in = in;
+       }
+
+       /**
+        * Instantiates a {@code XerDecoder}.
+        * 
+        * @param in
+        *            The {@code InputStream} to be read.
+        */
+       public XerDecoder(Class<? extends ASN1Module> module, InputStream in) {
+               this(in);
+               this.module = module;
+       }
+       
+       /*
+        * (non-Javadoc)
+        * 
+        * @see jp.bitmeister.asn1.codec.ASN1Decoder#decode(java.lang.Class)
+        */
+       @Override
+       public <T extends ASN1Type> T decode(final Class<T> type)
+                       throws ASN1DecodingException {
+               XerHandler<T> handler = new XerHandler<T>() {
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.XerHandler#initializeData
+                        * (java.lang.String)
+                        */
+                       @Override
+                       void initializeData(String qName) throws SAXException {
+                               data = ASN1Type.instantiate(type);
+                               if (module == null) {
+                                       module = data.specification().module();
+                               }
+                               if (!(data instanceof ANY)
+                                               && !qName.equals(data.specification().xmlTypeName(module))) {
+                                       throw new SAXException("Unexpected xml tag name '" + qName
+                                                       + "'. '" + data.specification().xmlTypeName(module)
+                                                       + "' is expected.");
+                               }
+                       }
+
+               };
+               parse(handler);
+               return handler.data;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see jp.bitmeister.asn1.codec.ASN1Decoder#decode()
+        */
+       @Override
+       public ASN1Type decode() throws ASN1DecodingException {
+               XerHandler<ASN1Type> handler = new XerHandler<ASN1Type>() {
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.XerHandler#initializeData
+                        * (java.lang.String)
+                        */
+                       @Override
+                       void initializeData(String qName) {
+                               data = ASN1ModuleManager.instantiate(module, qName);
+                       }
+
+               };
+               parse(handler);
+               return handler.data;
+       }
+
+       /**
+        * Decodes the source XML data read from the {@code InputStream} to the
+        * ASN.1 data.
+        * 
+        * @throws ASN1DecodingException
+        *             When an error occurred while the decoding process.
+        */
+       private void parse(XerHandler<?> handler) throws ASN1DecodingException {
+               try {
+                       reader = XMLReaderFactory.createXMLReader();
+                       reader.setContentHandler(handler);
+                       reader.parse(new InputSource(in));
+               } catch (Exception e) {
+                       ASN1DecodingException ex = new ASN1DecodingException();
+                       ex.setMessage("An exception thrown while decoding process.", e,
+                                       null, null, null);
+                       throw ex;
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.BOOLEAN)
+        */
+       @Override
+       public DataDecoder visit(final BOOLEAN data) {
+               return new DataDecoder() {
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
+                        * (java.lang.String)
+                        */
+                       @Override
+                       void startChildElement(String qName) {
+                               if (qName.equals(BOOLEAN_TRUE)) {
+                                       data.set(true);
+                               } else if (qName.equals(BOOLEAN_FALSE)) {
+                                       data.set(false);
+                               }
+                       }
+
+               };
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.INTEGER)
+        */
+       @Override
+       public DataDecoder visit(final INTEGER data) {
+               return new DataDecoder() {
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
+                        * (java.lang.String)
+                        */
+                       @Override
+                       void startChildElement(String qName) {
+                               data.set(qName);
+                       }
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
+                        * (java.lang.String)
+                        */
+                       @Override
+                       public void characters(String characters) {
+                               data.set(new BigInteger(characters));
+                       }
+
+               };
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.BIT_STRING)
+        */
+       @Override
+       public DataDecoder visit(final BIT_STRING data) {
+               return new DataDecoder() {
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
+                        * (java.lang.String)
+                        */
+                       @Override
+                       public void startChildElement(String qName) {
+                               data.set(qName);
+                       }
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
+                        * (java.lang.String)
+                        */
+                       @Override
+                       public void characters(String characters) {
+                               data.set(new BinString(characters));
+                       }
+
+               };
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.OCTET_STRING)
+        */
+       @Override
+       public DataDecoder visit(final OCTET_STRING data) {
+               return new DataDecoder() {
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
+                        * (java.lang.String)
+                        */
+                       @Override
+                       public void characters(String characters) {
+                               data.set(new HexString(characters));
+                       }
+
+               };
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.NULL)
+        */
+       @Override
+       public DataDecoder visit(NULL data) {
+               return new DataDecoder() {
+               };
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.OBJECT_IDENTIFIER)
+        */
+       @Override
+       public DataDecoder visit(final OBJECT_IDENTIFIER data) {
+               return new DataDecoder() {
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
+                        * (java.lang.String)
+                        */
+                       @Override
+                       public void characters(String characters) {
+                               List<Integer> oids = new ArrayList<Integer>();
+                               for (String e : characters.split("\\.")) {
+                                       e.trim();
+                                       if (Character.isLetter(e.charAt(0))) {
+                                               if (!e.endsWith(")")) {
+                                                       oids.add(OBJECT_IDENTIFIER.nameFormToInt(oids, e));
+                                                       continue;
+                                               }
+                                               e = e.substring(e.indexOf('(') + 1, e.indexOf(')'));
+                                       }
+                                       oids.add(Integer.parseInt(e));
+                               }
+                               data.set(oids);
+                       }
+
+               };
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.REAL)
+        */
+       @Override
+       public DataDecoder visit(final REAL data) {
+               return new DataDecoder() {
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
+                        * (java.lang.String)
+                        */
+                       @Override
+                       public void startChildElement(String qName) {
+                               if (qName.equals(REAL_PLUS_INFINITY)) {
+                                       data.set(Double.POSITIVE_INFINITY);
+                               } else if (qName.equals(REAL_MINUS_INFINITY)) {
+                                       data.set(Double.NEGATIVE_INFINITY);
+                               }
+                       }
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
+                        * (java.lang.String)
+                        */
+                       @Override
+                       public void characters(String characters) {
+                               data.set(Double.parseDouble(characters));
+                       }
+
+               };
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.ENUMERATED)
+        */
+       @Override
+       public DataDecoder visit(ENUMERATED data) {
+               return visit((INTEGER) data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.RELATIVE_OID)
+        */
+       @Override
+       public DataDecoder visit(RELATIVE_OID data) {
+               return visit((OBJECT_IDENTIFIER) data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.ANY)
+        */
+       @Override
+       public DataDecoder visit(final ANY data) {
+               return new DataDecoder() {
+
+                       private DataDecoder decoder;
+
+                       @Override
+                       void startElement(String qName) throws SAXException {
+                               data.set(ASN1ModuleManager.instantiate(module, qName));
+                               decoder = data.value().accept(XerDecoder.this);
+                               decoder.startElement(qName);
+                       }
+
+                       @Override
+                       void startChildElement(String qName) throws SAXException {
+                               decoder.startChildElement(qName);
+                       }
+
+                       @Override
+                       void characters(String characters) {
+                               decoder.characters(characters);
+                       }
+
+                       @Override
+                       void endChildElement(String qName) {
+                               decoder.endChildElement(qName);
+                       }
+
+                       @Override
+                       void endElement() {
+                               decoder.endElement();
+                       }
+
+               };
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.CHOICE)
+        */
+       @Override
+       public DataDecoder visit(CHOICE data) {
+               return decoderForStructuredType(data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.SEQUENCE_OF)
+        */
+       @Override
+       public DataDecoder visit(SEQUENCE_OF<? extends ASN1Type> data) {
+               return decoderForCollectionType(data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.SEQUENCE)
+        */
+       @Override
+       public DataDecoder visit(SEQUENCE data) {
+               return decoderForStructuredType(data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.SET_OF)
+        */
+       @Override
+       public DataDecoder visit(SET_OF<? extends ASN1Type> data) {
+               return decoderForCollectionType(data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.SET)
+        */
+       @Override
+       public DataDecoder visit(SET data) {
+               return decoderForStructuredType(data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .StringType)
+        */
+       @Override
+       public DataDecoder visit(final StringType data) {
+               return new DataDecoder() {
+
+                       private StringBuilder builder = new StringBuilder();
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
+                        * (java.lang.String)
+                        */
+                       @Override
+                       public void startChildElement(String qName) {
+                               builder.append(XerStringEscapeUtil.unescapeCtrl(qName));
+                       }
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#characters
+                        * (java.lang.String)
+                        */
+                       @Override
+                       public void characters(String characters) {
+                               builder.append(characters);
+                       }
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endElement()
+                        */
+                       @Override
+                       void endElement() {
+                               if (builder.length() > 0) {
+                                       data.set(builder.toString());
+                               }
+                       }
+
+               };
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .TimeType)
+        */
+       @Override
+       public DataDecoder visit(TimeType data) {
+               return visit((StringType) data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .UnknownType)
+        */
+       @Override
+       public DataDecoder visit(UnknownType data) throws SAXException {
+               throw new SAXException("UnkownType is not supported by XerDecoder.");
+       }
+
+       /**
+        * Returns handler for the {@code StructuredType}.
+        * 
+        * @param data
+        *            The {@code StructuredType} data.
+        * @return Handler for the data.
+        */
+       private DataDecoder decoderForStructuredType(final StructuredType data) {
+               return new ConstructedDataDecoder() {
+
+                       private NamedTypeSpecification namedType;
+
+                       private ASN1Type element;
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
+                        * (java.lang.String)
+                        */
+                       @Override
+                       void startChildElement(String qName) throws SAXException {
+                               if (decoder == null) {
+                                       namedType = data.getElement(qName);
+                                       element = namedType.instantiate();
+                                       decoder = new NamedElementDecoder(qName,
+                                                       element.accept(XerDecoder.this));
+                               }
+                               decoder.startElement(qName);
+                       }
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endChildElement
+                        * (java.lang.String)
+                        */
+                       @Override
+                       void endChildElement(String qName) {
+                               if (decoder.endElement(qName)) {
+                                       data.set(namedType, element);
+                                       decoder = null;
+                               }
+                       }
+
+               };
+       }
+
+       /**
+        * Returns handler for the {@code CollectionType}.
+        * 
+        * @param data
+        *            The {@code CollectionType} data.
+        * @return Handler for the data.
+        */
+       private <T extends ASN1Type> DataDecoder decoderForCollectionType(
+                       final CollectionType<T> data) {
+               return new ConstructedDataDecoder() {
+
+                       private T component;
+
+                       private boolean useXmlValueList = false;
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startElement
+                        * ()
+                        */
+                       @Override
+                       void startElement(String qName) {
+                               if (BOOLEAN.class.isAssignableFrom(data.componentType())
+                                               || ENUMERATED.class.isAssignableFrom(data.componentType())
+                                               || CHOICE.class.isAssignableFrom(data.componentType())) {
+                                       useXmlValueList = true;
+                               }
+                       }
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#startChildElement
+                        * (java.lang.String)
+                        */
+                       @Override
+                       void startChildElement(String qName) throws SAXException {
+                               if (decoder == null) {
+                                       component = ASN1Type.instantiate(data.componentType());
+                                       if (useXmlValueList) {
+                                               decoder = new ValueListElementDecoder(
+                                                               component.accept(XerDecoder.this));
+                                       } else {
+                                               decoder = new NamedElementDecoder(qName,
+                                                               component.accept(XerDecoder.this));
+                                       }
+                               }
+                               decoder.startElement(qName);
+                       }
+
+                       /*
+                        * (non-Javadoc)
+                        * 
+                        * @see
+                        * jp.bitmeister.asn1.codec.xer.XerDecoder.DataDecoder#endChildElement
+                        * (java.lang.String)
+                        */
+                       @Override
+                       void endChildElement(String qName) {
+                               if (decoder.endElement(qName)) {
+                                       data.collection().add(component);
+                                       decoder = null;
+                               }
+                       }
+
+               };
+       }
+
+}
diff --git a/jp/bitmeister/asn1/codec/xer/XerEncoder.java b/jp/bitmeister/asn1/codec/xer/XerEncoder.java
new file mode 100644 (file)
index 0000000..53a97b7
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * Copyright 2011 BitMeister Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package jp.bitmeister.asn1.codec.xer;
+
+import static jp.bitmeister.asn1.codec.xer.XerConstants.BOOLEAN_FALSE;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.BOOLEAN_TRUE;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.END_TAG_START;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.REAL_MINUS_INFINITY;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.REAL_PLUS_INFINITY;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.REAL_ZERO;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.SINGLE_TAG_END;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.TAG_END;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.TAG_START;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.XML_PROLOG;
+
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+
+import jp.bitmeister.asn1.codec.ASN1Encoder;
+import jp.bitmeister.asn1.exception.ASN1EncodingException;
+import jp.bitmeister.asn1.processor.ASN1Visitor;
+import jp.bitmeister.asn1.type.ASN1Module;
+import jp.bitmeister.asn1.type.ASN1Type;
+import jp.bitmeister.asn1.type.CollectionType;
+import jp.bitmeister.asn1.type.ConstructiveType;
+import jp.bitmeister.asn1.type.ElementSpecification;
+import jp.bitmeister.asn1.type.StringType;
+import jp.bitmeister.asn1.type.TimeType;
+import jp.bitmeister.asn1.type.UnknownType;
+import jp.bitmeister.asn1.type.builtin.ANY;
+import jp.bitmeister.asn1.type.builtin.BIT_STRING;
+import jp.bitmeister.asn1.type.builtin.BOOLEAN;
+import jp.bitmeister.asn1.type.builtin.CHOICE;
+import jp.bitmeister.asn1.type.builtin.ENUMERATED;
+import jp.bitmeister.asn1.type.builtin.INTEGER;
+import jp.bitmeister.asn1.type.builtin.NULL;
+import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
+import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
+import jp.bitmeister.asn1.type.builtin.REAL;
+import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
+import jp.bitmeister.asn1.type.builtin.SEQUENCE;
+import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
+import jp.bitmeister.asn1.type.builtin.SET;
+import jp.bitmeister.asn1.type.builtin.SET_OF;
+import jp.bitmeister.asn1.value.BinString;
+import jp.bitmeister.asn1.value.HexString;
+
+/**
+ * XER (XML Encoding Rules) encoder.
+ * 
+ * <p>
+ * {@code XerEncoder} is an implementation of {@code ASN1Encoder}. It encodes an
+ * ASN.1 data to an XML document with XML Encoding Rules(XER) and writes the
+ * result to {@code OutputStream} that is specified when the encoder was
+ * instantiated. XER encoding process is light-weight compared with Canonical
+ * XML Encoding Rules (CXER) encoding because some restrictions on CXER are not
+ * considered.
+ * </p>
+ * 
+ * @author WATANABE, Jun. <jwat at bitmeister.jp>
+ * 
+ * @see ASN1Encoder
+ * @see XerDecoder
+ */
+public class XerEncoder implements ASN1Encoder,
+               ASN1Visitor<String, ASN1EncodingException> {
+
+       private Class<? extends ASN1Module> module;
+
+       private OutputStream out;
+
+       private StringBuilder builder;
+
+       private boolean prologIsEmpty = false;
+
+       /**
+        * Instantiates a {@code XEREncoder}.
+        * 
+        * @param out
+        *            The {@code OutputStream} that encoded octets will be written.
+        */
+       public XerEncoder(OutputStream out) {
+               this.out = out;
+       }
+
+       /**
+        * Instantiates a {@code XEREncoder}.
+        * 
+        * @param module
+        *            The ASN.1 module used for encoding.
+        * @param out
+        *            The {@code OutputStream} that encoded octets will be written.
+        */
+       public XerEncoder(Class<? extends ASN1Module> module, OutputStream out) {
+               this(out);
+               this.module = module;
+       }
+
+       /**
+        * Instantiates a {@code XEREncoder}.
+        * 
+        * @param out
+        *            The {@code OutputStream} that encoded octets will be written.
+        * @param prologIsEmpty
+        *            If {@code true}, the XML prolog for result XML document will
+        *            be empty.
+        */
+       public XerEncoder(OutputStream out, boolean prologIsEmpty) {
+               this(out);
+               this.prologIsEmpty = prologIsEmpty;
+       }
+
+       /**
+        * Instantiates a {@code XEREncoder}.
+        * 
+        * @param module
+        *            The ASN.1 module used for encoding.
+        * @param out
+        *            The {@code OutputStream} that encoded octets will be written.
+        * @param prologIsEmpty
+        *            If {@code true}, the XML prolog for result XML document will
+        *            be empty.
+        */
+       public XerEncoder(Class<? extends ASN1Module> module, OutputStream out, boolean prologIsEmpty) {
+               this(module, out);
+               this.prologIsEmpty = prologIsEmpty;
+       }
+       
+       /**
+        * Encodes an ASN.1 data.
+        * 
+        * @param data
+        *            The ASN.1 data to be encoded.
+        * @return The size of encoded octets.
+        * @throws ASN1EncodingException
+        *             When an error occurred while the encoding process.
+        */
+       @Override
+       public int encode(ASN1Type data) throws ASN1EncodingException {
+               if (module == null) {
+                       module = data.specification().module();
+               }
+               builder = new StringBuilder();
+               if (!prologIsEmpty) {
+                       builder.append(XML_PROLOG);
+               }
+               encodeImpl(data, data.specification().xmlTypeName(module));
+               try {
+                       byte[] result = builder.toString().getBytes("UTF-8");
+                       out.write(result);
+                       return result.length;
+               } catch (Exception e) {
+                       ASN1EncodingException ex = new ASN1EncodingException();
+                       ex.setMessage("Failed to write result to stream.", e, null, null,
+                                       data);
+                       throw ex;
+               }
+       }
+
+       /**
+        * Encodes the source data to xml documents and writes it to the
+        * {@code builder}.
+        * 
+        * @param data
+        *            The ASN.1 data to be encoded.
+        * @param xmlTagName
+        *            The xml tag name to be set.
+        * @throws ASN1EncodingException
+        *             When an error occurred while the encoding process.
+        */
+       private void encodeImpl(ASN1Type data, String xmlTagName)
+                       throws ASN1EncodingException {
+               String contents = data.accept(this);
+               if (contents == null) {
+                       return;
+               } else if (contents.length() == 0) {
+                       builder.append(TAG_START).append(xmlTagName).append(SINGLE_TAG_END);
+               } else {
+                       builder.append(TAG_START).append(xmlTagName).append(TAG_END);
+                       builder.append(contents);
+                       builder.append(END_TAG_START).append(xmlTagName).append(TAG_END);
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.BOOLEAN)
+        */
+       @Override
+       public String visit(BOOLEAN data) {
+               return TAG_START + (data.value() ? BOOLEAN_TRUE : BOOLEAN_FALSE)
+                               + SINGLE_TAG_END;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.INTEGER)
+        */
+       @Override
+       public String visit(INTEGER data) {
+               String numberId = data.identifier();
+               if (numberId != null) {
+                       return TAG_START + numberId + SINGLE_TAG_END;
+               } else {
+                       return data.value().toString();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.BIT_STRING)
+        */
+       @Override
+       public String visit(BIT_STRING data) {
+               if (data.hasNamedBits()) {
+                       StringBuilder builder = new StringBuilder();
+                       for (int i = 0; i < data.size(); i++) {
+                               if (data.bit(i)) {
+                                       String name = data.nameOfBit(i);
+                                       if (name != null) {
+                                               builder.append(TAG_START).append(name)
+                                                               .append(SINGLE_TAG_END);
+                                       }
+                               }
+                       }
+                       return builder.toString();
+               } else {
+                       return new BinString(data.value()).toString();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.OCTET_STRING)
+        */
+       @Override
+       public String visit(OCTET_STRING data) {
+               return new HexString(data.value()).toString();
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.NULL)
+        */
+       @Override
+       public String visit(NULL data) {
+               return "";
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.OBJECT_IDENTIFIER)
+        */
+       @Override
+       public String visit(OBJECT_IDENTIFIER data) {
+               StringBuilder builder = new StringBuilder();
+               if (data.value().size() > 0) {
+                       builder.append(data.value().get(0));
+                       for (int i = 1; i < data.value().size(); i++) {
+                               builder.append('.').append(data.value().get(i));
+                       }
+               }
+               return builder.toString();
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.RELATIVE_OID)
+        */
+       @Override
+       public String visit(RELATIVE_OID data) {
+               return visit((OBJECT_IDENTIFIER) data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.REAL)
+        */
+       @Override
+       public String visit(REAL data) {
+               if (data.value().isInfinite()) {
+                       return TAG_START
+                                       + (data.value() == Double.POSITIVE_INFINITY ? REAL_PLUS_INFINITY
+                                                       : REAL_MINUS_INFINITY) + SINGLE_TAG_END;
+               }
+               if (data.value() == 0) {
+                       return REAL_ZERO;
+               }
+               return BigDecimal.valueOf(data.value()).stripTrailingZeros()
+                               .toPlainString();
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.ENUMERATED)
+        */
+       @Override
+       public String visit(ENUMERATED data) {
+               return visit((INTEGER) data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.ANY)
+        */
+       @Override
+       public String visit(ANY data) throws ASN1EncodingException {
+               encodeImpl(data.value(),
+                               data.value().specification().xmlTypeName(module));
+               return null;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.CHOICE)
+        */
+       @Override
+       public String visit(CHOICE data) throws ASN1EncodingException {
+               StringBuilder enclosure = builder;
+               builder = new StringBuilder();
+               encodeImpl(data.selectedValue(), data.selectedIdentifier());
+               String result = builder.toString();
+               builder = enclosure;
+               return result;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.SEQUENCE_OF)
+        */
+       @Override
+       public String visit(SEQUENCE_OF<? extends ASN1Type> data)
+                       throws ASN1EncodingException {
+               return processCollection(data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.SEQUENCE)
+        */
+       @Override
+       public String visit(SEQUENCE data) throws ASN1EncodingException {
+               return processConstructive(data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.SET_OF)
+        */
+       @Override
+       public String visit(SET_OF<? extends ASN1Type> data)
+                       throws ASN1EncodingException {
+               return processCollection(data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .builtin.SET)
+        */
+       @Override
+       public String visit(SET data) throws ASN1EncodingException {
+               return processConstructive(data);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .StringType)
+        */
+       @Override
+       public String visit(StringType data) throws ASN1EncodingException {
+               try {
+                       return new String(XerStringEscapeUtil.escape(data.stringValue())
+                                       .getBytes("Shift_JIS"));
+               } catch (UnsupportedEncodingException e) {
+                       throw new ASN1EncodingException();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .TimeType)
+        */
+       @Override
+       public String visit(TimeType data) throws ASN1EncodingException {
+               return data.stringValue();
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
+        * .UnknownType)
+        */
+       @Override
+       public String visit(UnknownType data) throws ASN1EncodingException {
+               ASN1EncodingException ex = new ASN1EncodingException();
+               ex.setMessage("Can't encode unknown type.", null, data.getClass(),
+                               null, data);
+               throw ex;
+       }
+
+       /**
+        * Encodes each element of the {@code ConstructiveType} data.
+        * 
+        * @param data
+        *            The data to be encoded.
+        * @throws ASN1EncodingException
+        *             When an error occurred while the encoding process.
+        */
+       private String processConstructive(ConstructiveType data)
+                       throws ASN1EncodingException {
+               StringBuilder enclosure = builder;
+               builder = new StringBuilder();
+               for (ElementSpecification e : data.getElementTypeList()) {
+                       ASN1Type component = data.getComponent(e);
+                       if (component != null) {
+                               encodeImpl(component, e.identifier());
+                       }
+               }
+               String result = builder.toString();
+               builder = enclosure;
+               return result;
+       }
+
+       /**
+        * Encodes each component of the {@code CollectionType} data.
+        * 
+        * @param data
+        *            The data to be encoded.
+        * @throws ASN1EncodingException
+        *             When an error occurred while the encoding process.
+        */
+       private String processCollection(CollectionType<? extends ASN1Type> data)
+                       throws ASN1EncodingException {
+               StringBuilder enclosure = builder;
+               builder = new StringBuilder();
+               if (BOOLEAN.class.isAssignableFrom(data.componentType())
+                               || ENUMERATED.class.isAssignableFrom(data.componentType())
+                               || CHOICE.class.isAssignableFrom(data.componentType())) {
+                       for (ASN1Type e : data.collection()) {
+                               builder.append(e.accept(this));
+                       }
+               } else {
+                       for (ASN1Type e : data.collection()) {
+                               encodeImpl(e, e.specification().xmlTypeName(module));
+                       }
+               }
+               String result = builder.toString();
+               builder = enclosure;
+               return result;
+       }
+
+}
diff --git a/jp/bitmeister/asn1/codec/xer/XerStringEscapeUtil.java b/jp/bitmeister/asn1/codec/xer/XerStringEscapeUtil.java
new file mode 100644 (file)
index 0000000..40cb2aa
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011 BitMeister Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package jp.bitmeister.asn1.codec.xer;
+
+import static jp.bitmeister.asn1.codec.xer.XerConstants.SINGLE_TAG_END;
+import static jp.bitmeister.asn1.codec.xer.XerConstants.TAG_START;
+
+/**
+ * Utility class used for escaping/unescaping strings.
+ * 
+ * <p>
+ * This class provides utility methods used for escaping and unescaping strings
+ * to follow XER encoding rules.
+ * </p>
+ * 
+ * @author WATANABE, Jun. <jwat at bitmeister.jp>
+ */
+class XerStringEscapeUtil {
+
+       private static final String AMP = "amp";
+       private static final String LT = "lt";
+       private static final String GT = "gt";
+
+       private static final String CTRL[] = { "nul", "soh", "stx", "etx", "eot",
+                       "enq", "ack", "bel", "bs", "", "", "vt", "ff", "", "so", "si",
+                       "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", "can",
+                       "em", "sub", "esc", "is4", "is3", "is2", "is1" };
+
+       /**
+        * Converts the source string to XER escaped string.
+        * 
+        * @param string
+        *            The source string.
+        * @return Escaped string.
+        */
+       static String escape(String string) {
+               StringBuilder builder = new StringBuilder();
+               for (char c : string.toCharArray()) {
+                       if (c < 32 && c != 9 && c != 10 && c != 13) {
+                               builder.append(TAG_START).append(CTRL[c])
+                                               .append(SINGLE_TAG_END);
+                       } else if (c == '&') {
+                               builder.append('&').append(AMP).append(';');
+                       } else if (c == '<') {
+                               builder.append('&').append(LT).append(';');
+                       } else if (c == '>') {
+                               builder.append('&').append(GT).append(';');
+                       } else {
+                               builder.append(c);
+                       }
+               }
+               return builder.toString();
+       }
+
+       /**
+        * Returns a control character specified by the string represents a control
+        * code.
+        * 
+        * @param string
+        *            The string represents a control code.
+        * @return A control character.
+        */
+       static char unescapeCtrl(String string) {
+               for (char i = 0; i < CTRL.length; i++) {
+                       if (string.equals(CTRL[i])) {
+                               return i;
+                       }
+               }
+               return 0;
+       }
+
+}
diff --git a/jp/bitmeister/asn1/codec/xer/package-info.java b/jp/bitmeister/asn1/codec/xer/package-info.java
new file mode 100644 (file)
index 0000000..ecdc3f3
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2011 BitMeister Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Contains the codec classes used for XER(XML Encoding Rules) encoding and decoding.
+ */
+package jp.bitmeister.asn1.codec.xer;
\ No newline at end of file
index 173d8f7..a98ceba 100644 (file)
@@ -42,6 +42,7 @@ import jp.bitmeister.asn1.type.builtin.NULL;
 import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
 import jp.bitmeister.asn1.type.builtin.REAL;
+import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
 import jp.bitmeister.asn1.type.builtin.SEQUENCE;
 import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
 import jp.bitmeister.asn1.type.builtin.SET;
@@ -371,13 +372,25 @@ public class ASN1StringBuilder implements
         */
        @Override
        public Void visit(OBJECT_IDENTIFIER data) {
-               builder.append(OID_OPEN).append(SPACE);
-               for (int i : data.value()) {
-                       builder.append(i).append(SPACE);
+               builder.append(OID_OPEN);
+               if (data.value().size() > 0) {
+                       builder.append(SPACE).append(data.value().get(0));
+                       for (int i = 1; i < data.value().size(); i++) {
+                               builder.append('.').append(data.value().get(i));
+                       }
+                       builder.append(SPACE);
                }
                builder.append(OID_CLOSE);
                return null;
        }
+       
+       /* (non-Javadoc)
+        * @see jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type.builtin.RELATIVE_OID)
+        */
+       @Override
+       public Void visit(RELATIVE_OID data) {
+               return visit((OBJECT_IDENTIFIER)data);
+       }
 
        /*
         * (non-Javadoc)
index 8e3ab9c..fe3bdc8 100644 (file)
@@ -29,6 +29,7 @@ import jp.bitmeister.asn1.type.builtin.NULL;
 import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
 import jp.bitmeister.asn1.type.builtin.REAL;
+import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
 import jp.bitmeister.asn1.type.builtin.SEQUENCE;
 import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
 import jp.bitmeister.asn1.type.builtin.SET;
@@ -130,6 +131,17 @@ public interface ASN1Visitor<R, E extends Throwable> {
        public R visit(ENUMERATED data) throws E;
 
        /**
+        * Visits the {@code RELATIVE_OID} data.
+        * 
+        * @param data
+        *            The data to be visited.
+        * @return Result.
+        * @throws E
+        *             When an error occured in the {@code accept} method.
+        */
+       public R visit(RELATIVE_OID data) throws E;
+
+       /**
         * Visits the {@code ANY} data.
         * 
         * @param data
index def393d..f099cf6 100644 (file)
@@ -29,6 +29,7 @@ import jp.bitmeister.asn1.type.builtin.NULL;
 import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
 import jp.bitmeister.asn1.type.builtin.REAL;
+import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
 import jp.bitmeister.asn1.type.builtin.SEQUENCE;
 import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
 import jp.bitmeister.asn1.type.builtin.SET;
@@ -145,6 +146,14 @@ public class ASN1VisitorAdaptor<R, E extends Throwable> implements ASN1Visitor<R
                return null;
        }
 
+       /* (non-Javadoc)
+        * @see jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type.builtin.RELATIVE_OID)
+        */
+       @Override
+       public R visit(RELATIVE_OID data) throws E {
+               return null;
+       }
+       
        /*
         * (non-Javadoc)
         * 
index a562e5f..5544629 100644 (file)
@@ -21,25 +21,25 @@ import java.io.ByteArrayOutputStream;
 import jp.bitmeister.asn1.codec.ber.BerDecoder;
 import jp.bitmeister.asn1.codec.ber.BerEncoder;
 import jp.bitmeister.asn1.codec.ber.DerEncoder;
+import jp.bitmeister.asn1.codec.xer.XerDecoder;
+import jp.bitmeister.asn1.codec.xer.XerEncoder;
 import jp.bitmeister.asn1.exception.ASN1DecodingException;
 import jp.bitmeister.asn1.exception.ASN1EncodingException;
 import jp.bitmeister.asn1.sample.FrightStatusTypes.Airport;
+import jp.bitmeister.asn1.sample.FrightStatusTypes.AllFrights;
 import jp.bitmeister.asn1.sample.FrightStatusTypes.FrightNumber;
 import jp.bitmeister.asn1.sample.FrightStatusTypes.Information;
 import jp.bitmeister.asn1.sample.FrightStatusTypes.Status;
-import jp.bitmeister.asn1.type.ASN1Modules;
 import jp.bitmeister.asn1.type.ASN1TagClass;
 import jp.bitmeister.asn1.type.ASN1Type;
 import jp.bitmeister.asn1.type.builtin.INTEGER;
-import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
 import jp.bitmeister.asn1.type.useful.UTCTime;
+import jp.bitmeister.asn1.value.HexString;
 
 public class FrightStatusMain {
        
        public static void main(String[] args) {
-               
-               ASN1Modules.using(new FrightStatusTypes());
-               
+                                               
                FrightStatus ontime = new FrightStatus(
                                new FrightNumber("JP041"),
                                new Information(
@@ -52,9 +52,7 @@ public class FrightStatusMain {
                                                new UTCTime("110627090000"),
                                                null
                                                )
-                               );
-               
-               derEncAndDec(ontime);
+                               );              
 
                FrightStatus delay = new FrightStatus(
                                new FrightNumber("NI022"),
@@ -71,13 +69,21 @@ public class FrightStatusMain {
                                new Status(ASN1TagClass.CONTEXT_SPECIFIC, 1, new INTEGER(10))
                                );
                
-               derEncAndDec(delay);
-
+               AllFrights frights = new AllFrights();
+               frights.collection().add(delay);
+               frights.collection().add(ontime);
+               
+               System.out.println("Source data:");
+               System.out.println(frights);
+               
+               System.out.println("BER encoding:");
+               derEncAndDec(frights);
+               
+               System.out.println("XER encoding:");
+               xerEncAndDec(frights);
        }
        
        static void derEncAndDec(ASN1Type data) {
-               
-               System.out.println(data);
                ByteArrayOutputStream bo = new ByteArrayOutputStream();
                BerEncoder enc = new DerEncoder(bo);
                try {
@@ -87,12 +93,38 @@ public class FrightStatusMain {
                        e.printStackTrace();
                }
                
-               System.out.println(new OCTET_STRING(bo.toByteArray()));
+               System.out.println(new HexString(bo.toByteArray()));
+               
+               ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
+               BerDecoder dec = new BerDecoder(FrightStatusTypes.class, bi);
+               try {
+                       ASN1Type result = dec.decode();
+                       System.out.println("BER decoding:");
+                       System.out.println(result);
+               }
+               catch (ASN1DecodingException e) {
+                       e.printStackTrace();
+               }
+               
+       }
+       
+       static void xerEncAndDec(ASN1Type data) {
+               
+               ByteArrayOutputStream bo = new ByteArrayOutputStream();
+               XerEncoder enc = new XerEncoder(bo);
+               try {
+                       enc.encode(data);
+               }
+               catch (ASN1EncodingException e) {
+                       e.printStackTrace();
+               }
+               System.out.println(new String(bo.toByteArray()));
                
                ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
-               BerDecoder dec = new BerDecoder(bi);
+               XerDecoder dec = new XerDecoder(FrightStatusTypes.class, bi);
                try {
                        ASN1Type result = dec.decode();
+                       System.out.println("XER decoding:");
                        System.out.println(result);
                }
                catch (ASN1DecodingException e) {
index cb427ff..511196d 100644 (file)
@@ -11,8 +11,8 @@ FrightStatusTypes DEFINITIONS AUTOMATIC TAGS ::= BEGIN
        
        Information ::= SEQUENCE {
                airport Airport,
-               scheduled GeneralizedTime,
-               actual GeneralizedTime OPTIONAL
+               scheduled UTCTime,
+               actual UTCTime OPTIONAL
        }
        
        Status ::= CHOICE {
@@ -27,6 +27,6 @@ FrightStatusTypes DEFINITIONS AUTOMATIC TAGS ::= BEGIN
                status [2] Status DEFAULT onTime:NULL
        }
        
-       AllFrights ::= SEQUENCE OF FrightStatus
+       AllFrights ::= [APPLICATION 1] IMPLICIT SEQUENCE OF FrightStatus
        
 END
index 2b54511..b432785 100644 (file)
@@ -18,12 +18,15 @@ package jp.bitmeister.asn1.sample;
 import java.math.BigInteger;
 
 import jp.bitmeister.asn1.annotation.ASN1Alternative;
+import jp.bitmeister.asn1.annotation.ASN1DefinedTypes;
 import jp.bitmeister.asn1.annotation.ASN1Element;
 import jp.bitmeister.asn1.annotation.ASN1Enumeration;
 import jp.bitmeister.asn1.annotation.ASN1ModuleTags;
+import jp.bitmeister.asn1.annotation.ASN1Tag;
 import jp.bitmeister.asn1.type.ASN1Module;
 import jp.bitmeister.asn1.type.ASN1TagClass;
 import jp.bitmeister.asn1.type.ASN1TagDefault;
+import jp.bitmeister.asn1.type.ASN1TagMode;
 import jp.bitmeister.asn1.type.ASN1Type;
 import jp.bitmeister.asn1.type.builtin.CHOICE;
 import jp.bitmeister.asn1.type.builtin.ENUMERATED;
@@ -35,11 +38,8 @@ import jp.bitmeister.asn1.type.useful.PrintableString;
 import jp.bitmeister.asn1.type.useful.UTCTime;
 
 @ASN1ModuleTags(ASN1TagDefault.AUTOMATIC_TAGS)
+@ASN1DefinedTypes(FrightStatus.class)
 public class FrightStatusTypes extends ASN1Module {
-       
-       public FrightStatusTypes() {
-               register(FrightStatus.class);
-       }
 
        public static class FrightNumber extends PrintableString {
 
@@ -124,6 +124,7 @@ public class FrightStatusTypes extends ASN1Module {
 
        }
        
+       @ASN1Tag(value = 1, tagClass = ASN1TagClass.APPLICATION, tagMode = ASN1TagMode.IMPLICIT)
        public static class AllFrights extends SEQUENCE_OF<FrightStatus> {
 
                public AllFrights() {
index cedc665..37fd422 100644 (file)
  */
 package jp.bitmeister.asn1.type;
 
-import static java.lang.reflect.Modifier.ABSTRACT;
-import static java.lang.reflect.Modifier.INTERFACE;
-import static java.lang.reflect.Modifier.PUBLIC;
-import static java.lang.reflect.Modifier.STATIC;
-
-import java.util.HashMap;
-import java.util.Map;
-
+import jp.bitmeister.asn1.annotation.ASN1DefinedTypes;
 import jp.bitmeister.asn1.annotation.ASN1Identifier;
+import jp.bitmeister.asn1.annotation.ASN1ImportedModules;
 import jp.bitmeister.asn1.annotation.ASN1ModuleRef;
 import jp.bitmeister.asn1.annotation.ASN1ModuleTags;
-import jp.bitmeister.asn1.exception.ASN1IllegalDefinition;
 
 /**
  * The base class for classes which represents an ASN.1 module.
  * 
  * <p>
- * An instance of sub-class of {@code ASN1Module} represents an ASN.1 module and
- * provides {@code instantiate} methods that instantiates an ASN.1 data from an
- * ASN.1 tag or a type identifier. ASN.1 types can indicate a module that they
- * are included in by {@code ASN1ModuleRef} annotation. In addition, ASN.1 types
- * declared as {@code public} {@code static} member classes of an sub-class of
+ * An instance of sub-class of {@code ASN1Module} represents an ASN.1 module.
+ * ASN.1 types can indicate a module that they are included in by
+ * {@code ASN1ModuleRef} annotation. In addition, ASN.1 types declared as
+ * {@code public} {@code static} member classes of an sub-class of
  * {@code ASN1Module} class are automatically included in the module.
  * </p>
  * <p>
- * Default tagging mode for this module may be indicated by an
- * {@code @ASN1ModuleTags} annotation or explicit tagging is used as default.
+ * Default tagging mode for a module may be indicated by {@code @ASN1ModuleTags}
+ * annotation or explicit tagging is used as default.
  * </p>
  * 
  * @author WATANABE, Jun. <jwat at bitmeister.jp>
  * 
- * @see ASN1Modules
+ * @see ASN1ModuleManager
  * @see ASN1ModuleTags
  * @see ASN1ModuleRef
  */
@@ -55,13 +47,13 @@ public abstract class ASN1Module {
        /**
         * Returns the default tagging mode of the ASN.1 module.
         * 
-        * @param moduleref
+        * @param module
         *            The ASN.1 module.
         * @return The default tagging mode of the module.
         */
-       static ASN1TagDefault tagDefault(Class<? extends ASN1Module> moduleref) {
-               if (moduleref.isAnnotationPresent(ASN1ModuleTags.class)) {
-                       return moduleref.getAnnotation(ASN1ModuleTags.class).value();
+       static ASN1TagDefault tagDefault(Class<? extends ASN1Module> module) {
+               if (module.isAnnotationPresent(ASN1ModuleTags.class)) {
+                       return module.getAnnotation(ASN1ModuleTags.class).value();
                }
                return ASN1TagDefault.EXPLICIT_TAGS;
        }
@@ -69,144 +61,71 @@ public abstract class ASN1Module {
        /**
         * Returns the identifier of the ASN.1 module.
         * 
-        * @param moduleref
+        * @param module
         *            The ASN.1 module.
         * @return The identifier of the module.
         */
-       static String identifier(Class<? extends ASN1Module> moduleref) {
-               if (moduleref.isAnnotationPresent(ASN1Identifier.class)) {
-                       return moduleref.getAnnotation(ASN1Identifier.class).value();
-               }
-               return moduleref.getSimpleName();
-       }
-
-       private String identifier;
-
-       private Map<String, Class<? extends ASN1Type>> identifierMap = new HashMap<String, Class<? extends ASN1Type>>();
-
-       private Map<ASN1TagClass, Map<Integer, Class<? extends ASN1Type>>> tagMap = new HashMap<ASN1TagClass, Map<Integer, Class<? extends ASN1Type>>>();
-
-       /**
-        * Instantiates an {@code ASN1Module}. The parameter indicates that this
-        * module is universal or not.
-        * 
-        * @param isUniversal
-        *            {@code true} if this module is universal.
-        */
-       ASN1Module(boolean isUniversal) {
-               identifier = identifier(getClass());
-               if (isUniversal) {
-                       tagMap.put(ASN1TagClass.UNIVERSAL,
-                                       new HashMap<Integer, Class<? extends ASN1Type>>());
-               } else {
-                       tagMap.put(ASN1TagClass.APPLICATION,
-                                       new HashMap<Integer, Class<? extends ASN1Type>>());
-                       tagMap.put(ASN1TagClass.PRIVATE,
-                                       new HashMap<Integer, Class<? extends ASN1Type>>());
+       static String identifier(Class<? extends ASN1Module> module) {
+               if (module.isAnnotationPresent(ASN1Identifier.class)) {
+                       return module.getAnnotation(ASN1Identifier.class).value();
                }
-               for (Class<?> e : getClass().getDeclaredClasses()) {
-                       if (ASN1Type.class.isAssignableFrom(e)) {
-                               @SuppressWarnings("unchecked")
-                               Class<? extends ASN1Type> type = (Class<? extends ASN1Type>) e;
-                               register(type);
-                       }
-               }
-       }
-
-       /**
-        * Instantiates an {@code ASN1Module}.
-        */
-       protected ASN1Module() {
-               this(false);
+               return module.getSimpleName();
        }
 
        /**
-        * Returns the identifier of this module.
+        * Tests if the module is the universal module.
         * 
-        * @return The identifier of this module.
+        * @param module
+        *            The module to be tested.
+        * @return {@code true} if the module is the universal module.
         */
-       public String identifier() {
-               return identifier;
+       static boolean isUniversal(Class<? extends ASN1Module> module) {
+               return module == BuiltInModule.class;
        }
 
        /**
-        * Registers the ASN.1 type to this module.
+        * Registers ASN.1 types which are contained in the ASN.1 module to the
+        * specification.
         * 
-        * @param type
-        *            The type to be registered.
+        * @param module
+        *            The ASN.1 module.
+        * @param spec
+        *            The module specification.
         */
-       protected void register(Class<? extends ASN1Type> type) {
-               if ((type.getModifiers() & (ABSTRACT | INTERFACE)) != 0) {
-                       ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
-                       ex.setMessage("An ASN.1 type class must be instantiatable.", null,
-                                       type, null, null);
-                       throw ex;
-               }
-               if ((type.getModifiers() & PUBLIC) == 0) {
-                       ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
-                       ex.setMessage("An ASN.1 type class must be a public class", null,
-                                       type, null, null);
-                       throw ex;
-               }
-               if (type.isMemberClass() && (type.getModifiers() & STATIC) == 0) {
-                       ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
-                       ex.setMessage(
-                                       "If an ASN.1 type class is a member class, it must be static.",
-                                       null, type, null, null);
-                       throw ex;
-               }
-               TypeSpecification typeSpec = TypeSpecification.getSpecification(type);
-               if (typeSpec.tag() != null) {
-                       Map<Integer, Class<? extends ASN1Type>> map = tagMap.get(typeSpec
-                                       .tag().tagClass());
-                       if (map == null) {
-                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
-                               ex.setMessage("Tag class '" + typeSpec.tag().tagClass()
-                                               + "'is not allowed to this module.", null, type, null,
-                                               null);
-                               throw ex;
-                       }
-                       if (map.containsKey(typeSpec.tag().tagNumber())) {
-                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
-                               ex.setMessage("Tag number '" + typeSpec.tag().tagNumber()
-                                               + "' is dupulicated.", null, type, null, null);
-                               throw ex;
+       static void registerTypes(Class<? extends ASN1Module> module,
+                       ModuleSpecification spec) {
+               for (Class<?> e : module.getDeclaredClasses()) {
+                       if (ASN1Type.class.isAssignableFrom(e)) {
+                               @SuppressWarnings("unchecked")
+                               Class<? extends ASN1Type> type = (Class<? extends ASN1Type>) e;
+                               spec.register(type);
                        }
-                       map.put(typeSpec.tag().tagNumber(), type);
                }
-               identifierMap.put(typeSpec.identifier(), type);
-       }
-
-       /**
-        * Instantiates an ASN.1 data specified by the tag.
-        * 
-        * @param tagClass
-        *            The tag class.
-        * @param tagNumber
-        *            The tag number.
-        * @return An instance of ASN.1 data.
-        */
-       public ASN1Type instantiate(ASN1TagClass tagClass, int tagNumber) {
-               Class<? extends ASN1Type> type = tagMap.get(tagClass).get(tagNumber);
-               if (type != null) {
-                       return ASN1Type.instantiate(type);
+               if (module.isAnnotationPresent(ASN1DefinedTypes.class)) {
+                       for (Class<? extends ASN1Type> e : module.getAnnotation(
+                                       ASN1DefinedTypes.class).value()) {
+                               spec.register(e);
+                       }
                }
-               return null;
        }
 
        /**
-        * Instantiates an ASN.1 data specified by the type identifier.
+        * Registers ASN.1 modules which are imported by the ASN.1 module to the
+        * specification.
         * 
-        * @param typeIdentifier
-        *            The identifier of the type.
-        * @return An instance of ASN.1 data.
+        * @param module
+        *            The ASN.1 module.
+        * @param spec
+        *            The module specification.
         */
-       public ASN1Type instantiate(String typeIdentifier) {
-               Class<? extends ASN1Type> type = identifierMap.get(typeIdentifier);
-               if (type != null) {
-                       return ASN1Type.instantiate(type);
+       static void importModules(Class<? extends ASN1Module> module,
+                       ModuleSpecification spec) {
+               if (module.isAnnotationPresent(ASN1ImportedModules.class)) {
+                       for (Class<? extends ASN1Module> e : module.getAnnotation(
+                                       ASN1ImportedModules.class).value()) {
+                               spec.imports(e);
+                       }
                }
-               return null;
        }
 
 }
diff --git a/jp/bitmeister/asn1/type/ASN1ModuleManager.java b/jp/bitmeister/asn1/type/ASN1ModuleManager.java
new file mode 100644 (file)
index 0000000..a8b18b6
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2011 BitMeister Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package jp.bitmeister.asn1.type;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Manager of all ASN.1 modules.
+ * 
+ * <p>
+ * This class manages all of the ASN.1 modules which are sub-class of
+ * {@code ASN1Module} and provides {@code instantiate} methods which instantiate
+ * an ASN.1 data from an ASN.1 tag or identifier.
+ * </p>
+ * 
+ * @author WATANABE, Jun. <jwat at bitmeister.jp>
+ * 
+ * @see ASN1Module
+ */
+public class ASN1ModuleManager {
+
+       /**
+        * The manager of ASN.1 modules.
+        */
+       private static ASN1ModuleManager instance = new ASN1ModuleManager();
+
+       /**
+        * Instantiates an ASN.1 data specified by the ASN.1 tag and the tag class.
+        * 
+        * @param module 
+        *            The {@code Class} object of an {@code ASN1Module}.
+        * @param tagClass
+        *            The tag class.
+        * @param tagNumber
+        *            The tag number.
+        * @return An instance of ASN.1 data.
+        */
+       public static ASN1Type instantiate(Class<? extends ASN1Module> module,
+                       ASN1TagClass tagClass, int tagNumber) {
+               if (tagClass == ASN1TagClass.UNIVERSAL) {
+                       return specification(BuiltInModule.class).instantiate(tagClass,
+                                       tagNumber);
+               } else if (module != null) {
+                       return specification(module).instantiate(tagClass, tagNumber);
+               }
+               return null;
+       }
+
+       /**
+        * Instantiates an ASN.1 data specified by the type identifier.
+        * 
+        * @param module 
+        *            The {@code Class} object of an {@code ASN1Module}.
+        * @param typeIdentifier
+        *            The identifier of a type.
+        * @return An instance of ASN.1 data.
+        */
+       public static ASN1Type instantiate(Class<? extends ASN1Module> module,
+                       String typeIdentifier) {
+               ASN1Type data = specification(BuiltInModule.class).instantiate(
+                               typeIdentifier);
+               if (data == null && module != null) {
+                       data = specification(module).instantiate(typeIdentifier);
+               }
+               return data;
+       }
+
+       /**
+        * Returns a {@code ModuleSpecification} instance contains specifications of
+        * the module.
+        * 
+        * @param module
+        *            The {@code Class} object of an {@code ASN1Module}.
+        * @return A {@code ModuleSpecification} instance.
+        */
+       static ModuleSpecification specification(Class<? extends ASN1Module> module) {
+               if (module == null) {
+                       module = BuiltInModule.class;
+               }
+               ModuleSpecification spec = instance.definedModules.get(module);
+               if (spec == null) {
+                       spec = new ModuleSpecification(module);
+                       instance.definedModules.put(module, spec);
+               }
+               return spec;
+       }
+
+       /**
+        * Returns default tag mode of the module.
+        * 
+        * @param module
+        *            The {@code Class} object of the {@code ASN1Module}.
+        * @return Default tag mode of the module.
+        */
+       static ASN1TagDefault tagDefault(Class<? extends ASN1Module> module) {
+               return specification(module).tagDefault();
+       }
+
+       /**
+        * Returns identifier of the module.
+        * 
+        * @param module
+        *            The {@code Class} object of the {@code ASN1Module}.
+        * @return Identifier of this module.
+        */
+       public static String identifier(Class<? extends ASN1Module> module) {
+               return specification(module).identifier();
+       }
+
+       private Map<Class<? extends ASN1Module>, ModuleSpecification> definedModules = new HashMap<Class<? extends ASN1Module>, ModuleSpecification>();
+
+       /**
+        * Instantiates an {@code ASN1ModuleManager}.
+        */
+       private ASN1ModuleManager() {
+
+       }
+
+}
index 624ad5d..a412d2a 100644 (file)
@@ -77,7 +77,7 @@ public abstract class ASN1Type implements Cloneable {
                        throw ex;
                }
        }
-
+       
        /**
         * The constructor with no argument.
         */
@@ -134,7 +134,7 @@ public abstract class ASN1Type implements Cloneable {
         * @return {@code true} when this ASN.1 data has value.
         */
        public abstract boolean hasValue();
-
+       
        /**
         * Accepts the {@link ASN1Visitor} and calls a {@code visit} method of the
         * visitor.
index 32e008e..cd0c4b1 100644 (file)
@@ -16,6 +16,7 @@
 package jp.bitmeister.asn1.type;
 
 import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
+import jp.bitmeister.asn1.annotation.ASN1DefinedTypes;
 import jp.bitmeister.asn1.annotation.ASN1Identifier;
 import jp.bitmeister.asn1.annotation.ASN1ModuleTags;
 import jp.bitmeister.asn1.annotation.ASN1Tag;
@@ -28,6 +29,7 @@ import jp.bitmeister.asn1.type.builtin.NULL;
 import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
 import jp.bitmeister.asn1.type.builtin.REAL;
+import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
 import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
 import jp.bitmeister.asn1.type.builtin.SET_OF;
 import jp.bitmeister.asn1.type.useful.BMPString;
@@ -59,42 +61,38 @@ import jp.bitmeister.asn1.type.useful.VisibleString;
  * @author WATANABE, Jun. <jwat at bitmeister.jp>
  */
 @ASN1ModuleTags(ASN1TagDefault.AUTOMATIC_TAGS)
-public class BuiltInModule extends ASN1Module {
-
-       /**
-        * Registers all of the UNIVERSAL ASN.1 types to this module.
-        */
-       BuiltInModule() {
-               super(true);
-               register(BOOLEAN.class); // UNIVERSAL 1
-               register(INTEGER.class); // UNIVERSAL 2
-               register(BIT_STRING.class); // UNIVERSAL 3
-               register(OCTET_STRING.class); // UNIVERSAL 4
-               register(NULL.class); // UNIVERSAL 5
-               register(OBJECT_IDENTIFIER.class); // UNIVERSAL 6
-               register(ObjectDescriptor.class); // UNIVERSAL 7
-               register(EXTERNAL.class); // UNIVERSAL 8
-               register(REAL.class); // UNIVERSAL 9
+@ASN1DefinedTypes({
+               BOOLEAN.class,           // UNIVERSAL 1
+               INTEGER.class,           // UNIVERSAL 2
+               BIT_STRING.class,        // UNIVERSAL 3
+               OCTET_STRING.class,      // UNIVERSAL 4
+               NULL.class,              // UNIVERSAL 5
+               OBJECT_IDENTIFIER.class, // UNIVERSAL 6
+               ObjectDescriptor.class,  // UNIVERSAL 7
+               EXTERNAL.class,          // UNIVERSAL 8
+               REAL.class,              // UNIVERSAL 9
                // UnkonwnEnumerated is registered automatically for UNIVERSAL 10.
-               register(EMBEDDED_PDV.class); // UNIVERSAL 11
-               register(UTF8String.class); // UNIVERSAL 12
-                                                                       // 13-15 reserved
+               EMBEDDED_PDV.class,      // UNIVERSAL 11
+               UTF8String.class,        // UNIVERSAL 12
+               RELATIVE_OID.class,      // UNIVERSAL 13
+                                                            // 14-15 reserved
                // UnkownSequence is registered automatically for UNIVERSAL16
                // UnkownSet is registered automatically for UNIVERSAL 17
-               register(NumericString.class); // UNIVERSAL 18
-               register(PrintableString.class); // UNIVERSAL 19
-               register(TeletexString.class); // UNIVERSAL 20
-               register(VideotexString.class); // UNIVERSAL 21
-               register(IA5String.class); // UNIVERSAL 22
-               register(UTCTime.class); // UNIVERSAL 23
-               register(GeneralizedTime.class); // UNIVERSAL 24
-               register(GraphicString.class); // UNIVERSAL 25
-               register(VisibleString.class); // UNIVERSAL 26
-               register(GeneralString.class); // UNIVERSAL27
-               register(UniversalString.class); // UNIVERSAL 28
-               register(CHARACTER_STRING.class); // UNIVERSAL 29
-               register(BMPString.class); // UNIVERSAL 30
-       }
+               NumericString.class,     // UNIVERSAL 18
+               PrintableString.class,   // UNIVERSAL 19
+               TeletexString.class,     // UNIVERSAL 20
+               VideotexString.class,    // UNIVERSAL 21
+               IA5String.class,         // UNIVERSAL 22
+               UTCTime.class,           // UNIVERSAL 23
+               GeneralizedTime.class,   // UNIVERSAL 24
+               GraphicString.class,     // UNIVERSAL 25
+               VisibleString.class,     // UNIVERSAL 26
+               GeneralString.class,     // UNIVERSAL27
+               UniversalString.class,   // UNIVERSAL 28
+               CHARACTER_STRING.class,  // UNIVERSAL 29
+               BMPString.class          // UNIVERSAL 30
+})
+class BuiltInModule extends ASN1Module {
 
        /**
         * Represents unknown 'ENUMERATED' type.
index a095949..26312aa 100644 (file)
@@ -116,7 +116,7 @@ public abstract class CollectionType<T extends ASN1Type> extends ASN1Type
        public boolean hasValue() {
                return true;
        }
-
+       
        /*
         * (non-Javadoc)
         * 
index b7808ea..cac6eb8 100644 (file)
@@ -143,16 +143,7 @@ public abstract class ConstructiveType extends StructuredType {
         */
        @Override
        public void set(String elementName, ASN1Type component) {
-               for (ElementSpecification e : getElementTypeList()) {
-                       if (e.identifier().equals(elementName)) {
-                               e.assign(this, component);
-                               return;
-                       }
-               }
-               ASN1IllegalArgument ex = new ASN1IllegalArgument();
-               ex.setMessage("No such element '" + elementName + "' in this type.",
-                               null, getClass(), null, null);
-               throw ex;
+               set(getElement(elementName), component);
        }
 
        /*
@@ -162,9 +153,17 @@ public abstract class ConstructiveType extends StructuredType {
         */
        @Override
        public ASN1Type get(String elementName) {
+               return getElement(elementName).retrieve(this);
+       }
+       
+       /* (non-Javadoc)
+        * @see jp.bitmeister.asn1.type.StructuredType#getElement(java.lang.String)
+        */
+       @Override
+       public NamedTypeSpecification getElement(String elementName) {
                for (ElementSpecification e : getElementTypeList()) {
                        if (e.identifier().equals(elementName)) {
-                               return e.retrieve(this);
+                               return e;
                        }
                }
                ASN1IllegalArgument ex = new ASN1IllegalArgument();
diff --git a/jp/bitmeister/asn1/type/ModuleSpecification.java b/jp/bitmeister/asn1/type/ModuleSpecification.java
new file mode 100644 (file)
index 0000000..8c6a1e3
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2011 BitMeister Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package jp.bitmeister.asn1.type;
+
+import static java.lang.reflect.Modifier.ABSTRACT;
+import static java.lang.reflect.Modifier.INTERFACE;
+import static java.lang.reflect.Modifier.PUBLIC;
+import static java.lang.reflect.Modifier.STATIC;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import jp.bitmeister.asn1.exception.ASN1IllegalDefinition;
+
+/**
+ * Specifications of an ASN.1 module.
+ * 
+ * <p>
+ * An instance of this class contains static information of an ASN.1 module.
+ * </p>
+ * 
+ * @author WATANABE, Jun. <jwat at bitmeister.jp>
+ */
+class ModuleSpecification {
+
+       private String identifier;
+
+       private ASN1TagDefault tagDefault;
+
+       private Map<String, Class<? extends ASN1Type>> identifierMap = new HashMap<String, Class<? extends ASN1Type>>();
+
+       private Map<ASN1TagClass, Map<Integer, Class<? extends ASN1Type>>> tagMap = new HashMap<ASN1TagClass, Map<Integer, Class<? extends ASN1Type>>>();
+
+       private Map<String, Class<? extends ASN1Module>> importedModules = new HashMap<String, Class<? extends ASN1Module>>();
+
+       /**
+        * Instantiates a {@code ModuleSpecification} contains specifications of the
+        * ASN.1 module.
+        * 
+        * @param module
+        *            The {@code Class} object of an {@code ASN1Module}.
+        */
+       ModuleSpecification(Class<? extends ASN1Module> module) {
+               identifier = ASN1Module.identifier(module);
+               tagDefault = ASN1Module.tagDefault(module);
+               if (ASN1Module.isUniversal(module)) {
+                       tagMap.put(ASN1TagClass.UNIVERSAL,
+                                       new HashMap<Integer, Class<? extends ASN1Type>>());
+               } else {
+                       tagMap.put(ASN1TagClass.APPLICATION,
+                                       new HashMap<Integer, Class<? extends ASN1Type>>());
+                       tagMap.put(ASN1TagClass.PRIVATE,
+                                       new HashMap<Integer, Class<? extends ASN1Type>>());
+               }
+               ASN1Module.registerTypes(module, this);
+               ASN1Module.importModules(module, this);
+       }
+
+       /**
+        * Registers an imported module to this module.
+        * 
+        * @param module
+        *            An ASN.1 module imported by this module.
+        */
+       void imports(Class<? extends ASN1Module> module) {
+               importedModules.put(ASN1Module.identifier(module), module);
+       }
+
+       /**
+        * Registers a ASN.1 type to this module.
+        * 
+        * @param type
+        *            An ASN.1 type contained in this module.
+        */
+       void register(Class<? extends ASN1Type> type) {
+               if ((type.getModifiers() & (ABSTRACT | INTERFACE)) != 0) {
+                       ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
+                       ex.setMessage("An ASN.1 type class must be instantiatable.", null,
+                                       type, null, null);
+                       throw ex;
+               }
+               if ((type.getModifiers() & PUBLIC) == 0) {
+                       ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
+                       ex.setMessage("An ASN.1 type class must be a public class", null,
+                                       type, null, null);
+                       throw ex;
+               }
+               if (type.isMemberClass() && (type.getModifiers() & STATIC) == 0) {
+                       ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
+                       ex.setMessage(
+                                       "If an ASN.1 type class is a member class, it must be static.",
+                                       null, type, null, null);
+                       throw ex;
+               }
+               TypeSpecification typeSpec = TypeSpecification.getSpecification(type);
+               if (typeSpec.tag() != null) {
+                       Map<Integer, Class<? extends ASN1Type>> map = tagMap.get(typeSpec
+                                       .tag().tagClass());
+                       if (map == null) {
+                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
+                               ex.setMessage("Tag class '" + typeSpec.tag().tagClass()
+                                               + "'is not allowed to this module.", null, type, null,
+                                               null);
+                               throw ex;
+                       }
+                       if (map.containsKey(typeSpec.tag().tagNumber())) {
+                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
+                               ex.setMessage("Tag number '" + typeSpec.tag().tagNumber()
+                                               + "' is dupulicated.", null, type, null, null);
+                               throw ex;
+                       }
+                       map.put(typeSpec.tag().tagNumber(), type);
+               }
+               identifierMap.put(typeSpec.xmlTypeName(), type);
+       }
+
+       /**
+        * Returns identifier of this module.
+        * 
+        * @return Identifier.
+        */
+       String identifier() {
+               return identifier;
+       }
+
+       /**
+        * Returns default tag mode of this module.
+        * 
+        * @return Default tag mode.
+        */
+       ASN1TagDefault tagDefault() {
+               return tagDefault;
+       }
+
+       /**
+        * Instantiates an ASN.1 data specified by the tag.
+        * 
+        * @param tagClass
+        *            The tag class.
+        * @param tagNumber
+        *            The tag number.
+        * @return An instance of ASN.1 data.
+        */
+       ASN1Type instantiate(ASN1TagClass tagClass, int tagNumber) {
+               Class<? extends ASN1Type> type = tagMap.get(tagClass).get(tagNumber);
+               if (type != null) {
+                       return ASN1Type.instantiate(type);
+               }
+               for (Entry<String, Class<? extends ASN1Module>> e : importedModules
+                               .entrySet()) {
+                       ModuleSpecification spec = ASN1ModuleManager.specification(e
+                                       .getValue());
+                       ASN1Type data = spec.instantiate(tagClass, tagNumber);
+                       if (data != null) {
+                               return data;
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * Instantiates an ASN.1 data specified by the type identifier.
+        * 
+        * @param typeIdentifier
+        *            The identifier of the type.
+        * @return An instance of ASN.1 data.
+        */
+       ASN1Type instantiate(String typeIdentifier) {
+               if (typeIdentifier.indexOf('.') >= 0) {
+                       String[] identifier = typeIdentifier.split(".");
+                       return instantiate(identifier[0], identifier[1]);
+               }
+               Class<? extends ASN1Type> type = identifierMap.get(typeIdentifier);
+               if (type != null) {
+                       return ASN1Type.instantiate(type);
+               }
+               return null;
+       }
+
+       /**
+        * Instantiates an ASN.1 data specified by the module identifier and the
+        * type identifier.
+        * 
+        * @param moduleIdentifier
+        *            The identifier of the module.
+        * @param typeIdentifier
+        *            The identifier of the type.
+        * @return An instance of ASN.1 data.
+        */
+       private ASN1Type instantiate(String moduleIdentifier, String typeIdentifier) {
+               ModuleSpecification spec = ASN1ModuleManager
+                               .specification(importedModules.get(moduleIdentifier));
+               if (spec != null) {
+                       return spec.instantiate(typeIdentifier);
+               }
+               return null;
+       }
+
+}
index f5ce464..af93086 100644 (file)
@@ -239,7 +239,7 @@ public class NamedTypeSpecification implements
                        ASN1IllegalArgument ex = new ASN1IllegalArgument();
                        ex.setMessage(
                                        "The type '"
-                                                       + data.specification().identifier()
+                                                       + data.specification().fullIdentifier()
                                                        + "' of the data to be assigned is not the same type of this element.",
                                        null, enclosure.getClass(), identifier, null);
                        throw ex;
index 7b95872..0393f7f 100644 (file)
@@ -199,17 +199,7 @@ public abstract class SelectiveType extends StructuredType {
         */
        @Override
        public void set(String elementName, ASN1Type component) {
-               for (NamedTypeSpecification e : getAlternativeTypeList(getClass())) {
-                       if (e.identifier().equals(elementName)) {
-                               set(e, component);
-                               return;
-                       }
-               }
-               ASN1IllegalArgument ex = new ASN1IllegalArgument();
-               ex.setMessage(
-                               "No such alternative '" + elementName + "' in this type.",
-                               null, getClass(), null, null);
-               throw ex;
+               set(getElement(elementName), component);
        }
 
        /*
@@ -219,14 +209,21 @@ public abstract class SelectiveType extends StructuredType {
         */
        @Override
        public ASN1Type get(String elementName) {
+               return getElement(elementName).retrieve(this);
+       }
+       
+       /* (non-Javadoc)
+        * @see jp.bitmeister.asn1.type.StructuredType#getElement(java.lang.String)
+        */
+       @Override
+       public NamedTypeSpecification getElement(String elementName) {
                for (NamedTypeSpecification e : getAlternativeTypeList(getClass())) {
                        if (e.identifier().equals(elementName)) {
-                               return e.retrieve(this);
+                               return e;
                        }
                }
                ASN1IllegalArgument ex = new ASN1IllegalArgument();
-               ex.setMessage(
-                               "No such alternative '" + elementName + "' in this type.",
+               ex.setMessage("No such alternative '" + elementName + "' in this type.",
                                null, getClass(), null, null);
                throw ex;
        }
index a2568c1..b976ac8 100644 (file)
@@ -37,7 +37,7 @@ public abstract class StructuredType extends ASN1Type {
         *            The elements to be tagged.
         */
        static void generateAutomaticTags(NamedTypeSpecification[] array) {
-               for (NamedTypeSpecification e: array) {
+               for (NamedTypeSpecification e : array) {
                        if (e.tag() != null) {
                                return;
                        }
@@ -80,4 +80,13 @@ public abstract class StructuredType extends ASN1Type {
         */
        public abstract ASN1Type get(String elementName);
 
+       /**
+        * Returns an element specification specified by the element name.
+        * 
+        * @param elementName
+        *            The element name.
+        * @return The element specification specified by the name.
+        */
+       public abstract NamedTypeSpecification getElement(String elementName);
+
 }
index 6103a3d..5b7085b 100644 (file)
@@ -23,6 +23,7 @@ import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
 import jp.bitmeister.asn1.annotation.ASN1Identifier;
 import jp.bitmeister.asn1.annotation.ASN1ModuleRef;
 import jp.bitmeister.asn1.annotation.ASN1Tag;
+import jp.bitmeister.asn1.annotation.ASN1XmlTypeName;
 import jp.bitmeister.asn1.exception.ASN1IllegalDefinition;
 
 /**
@@ -100,6 +101,13 @@ public class TypeSpecification {
                        } else {
                                specification.identifier = type.getSimpleName();
                        }
+                       ASN1XmlTypeName xmlName = type.getAnnotation(ASN1XmlTypeName.class);
+                       if (xmlName != null) {
+                               specification.xmlTypeName = xmlName.value();
+                       }
+                       else {
+                               specification.xmlTypeName = specification.identifier;
+                       }
                }
 
                // set tag.
@@ -122,6 +130,11 @@ public class TypeSpecification {
        private String identifier;
 
        /**
+        * XML type name of this type.
+        */
+       private String xmlTypeName;
+       
+       /**
         * ASN.1 tag assigned to this type.
         */
        private ASN1TagValue tag;
@@ -138,13 +151,22 @@ public class TypeSpecification {
        }
 
        /**
+        * Returns the {@code Class} object of an ASN.1 module that this type is defined.
+        * 
+        * @return The {@code Class} object of an ASN.1 module.
+        */
+       public Class<? extends ASN1Module> module() {
+               return module;
+       }
+       
+       /**
         * Returns the default tagging mode for the ASN.1 module that this type is
         * defined.
         * 
         * @return The default tagging mode.
         */
-       public ASN1TagDefault tagDefault() {
-               return ASN1Module.tagDefault(module);
+       ASN1TagDefault tagDefault() {
+               return ASN1ModuleManager.tagDefault(module);
        }
 
        /**
@@ -169,18 +191,38 @@ public class TypeSpecification {
        }
 
        /**
-        * Returns the full identifier of this type that made from ASN.1 module
-        * identifier and type identifier.
+        * Returns the ASN.1 identifier with the module identifier of this type.
         * 
-        * @return The full identifier of this type.
+        * @return The ASN.1 identifier of this type.
         */
        public String fullIdentifier() {
-               if (module != BuiltInModule.class) {
-                       return ASN1Module.identifier(module) + "." + identifier();
+               return ASN1ModuleManager.identifier(module) + "." + identifier();
+       }
+       
+       /**
+        * Returns the XML type name of this type.
+        * 
+        * @return The XML type name of this type.
+        */
+       public String xmlTypeName() {
+               return xmlTypeName;
+       }
+       
+       /**
+        * Returns the XML type name of this type. If the type 
+        * 
+        * @return The XML type name of this type.
+        */
+       public String xmlTypeName(Class<? extends ASN1Module> module) {
+               if (!hasIdentifier()) {
+                       return reference.xmlTypeName(module);
                }
-               return identifier();
+               if (this.module != BuiltInModule.class && this.module != module) {
+                       return ASN1ModuleManager.identifier(this.module) + "." + xmlTypeName;
+               }
+               return xmlTypeName;
        }
-
+       
        /**
         * Tests if this type is tagged or references a tagged type.
         * 
index cf967dd..f36d49a 100644 (file)
@@ -27,14 +27,14 @@ import jp.bitmeister.asn1.processor.ASN1Visitor;
  * 
  * <p>
  * When a decoder meets a source data with a tag that is not registered to
- * {@code ASN1Modules}, decoder decodes the data as an {@code UnknownType}. An
+ * {@code ASN1ModuleManager}, decoder decodes the data as an {@code UnknownType}. An
  * instance of this class contains a tag class, a tag number and an array of
  * {@code byte} represents row contents octets.
  * </p>
  * 
  * @author WATANABE, Jun. <jwat at bitmeister.jp>
  * 
- * @see ASN1Modules
+ * @see ASN1ModuleManager
  * @see BerDecoder
  */
 @ASN1BuiltIn
index 7a4bb37..773a6b0 100644 (file)
@@ -20,11 +20,13 @@ import java.lang.reflect.Modifier;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
 import jp.bitmeister.asn1.annotation.ASN1Identifier;
 import jp.bitmeister.asn1.annotation.ASN1NamedBit;
 import jp.bitmeister.asn1.annotation.ASN1Tag;
+import jp.bitmeister.asn1.annotation.ASN1XmlTypeName;
 import jp.bitmeister.asn1.exception.ASN1IllegalArgument;
 import jp.bitmeister.asn1.exception.ASN1IllegalDefinition;
 import jp.bitmeister.asn1.exception.ASN1RuntimeException;
@@ -56,6 +58,7 @@ import jp.bitmeister.asn1.value.StringItem;
  */
 @ASN1BuiltIn
 @ASN1Identifier("BIT STRING")
+@ASN1XmlTypeName("BIT_STRING")
 @ASN1Tag(tagClass = ASN1TagClass.UNIVERSAL, value = 3, tagMode = ASN1TagMode.IMPLICIT)
 public class BIT_STRING extends PrimitiveType<boolean[]> implements
                Concatenatable<BIT_STRING>, SizeCountable {
@@ -123,7 +126,7 @@ public class BIT_STRING extends PrimitiveType<boolean[]> implements
                                throw ex;
                        }
                        if (map.containsKey(value)) {
-                               ASN1RuntimeException ex = new ASN1RuntimeException();
+                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
                                ex.setMessage(
                                                "A value of named bit shall be distinct from all other named bits in the type.",
                                                null, type, fieldId, null);
@@ -203,7 +206,7 @@ public class BIT_STRING extends PrimitiveType<boolean[]> implements
         * to hold the bit specified by the biggest index, it will be expanded
         * automatically.
         * 
-        * @param index
+        * @param indexes
         *            Indexes of bits to be set true.
         */
        public void set(int ...indexes) {
@@ -213,6 +216,24 @@ public class BIT_STRING extends PrimitiveType<boolean[]> implements
                        value()[e] = true;
                }
        }
+       
+       /**
+        * Sets {@code true} to bits specified by the name of bit. 
+        * 
+        * @param nameOfBit
+        *            The name of bit.
+        */
+       public void set(String nameOfBit) {
+               for (Entry<Integer, String> e: getNamedBitMap(getClass()).entrySet()) {
+                       if (e.getValue().equals(nameOfBit)) {
+                               set(e.getKey());
+                               return;
+                       }
+               }
+               ASN1IllegalArgument e = new ASN1IllegalArgument();
+               e.setMessage("The name '" + nameOfBit + "' is not defined in this type.", null, getClass(), null, null);
+               throw e;
+       }
 
        /**
         * Sets {@code false} to bits specified by index numbers. If the
@@ -220,7 +241,7 @@ public class BIT_STRING extends PrimitiveType<boolean[]> implements
         * to hold the bit specified by the biggest index, it will be expanded
         * automatically.
         * 
-        * @param index
+        * @param indexes
         *            Indexes of bits to be set false.
         */
        public void unset(int ...indexes) {
@@ -318,7 +339,7 @@ public class BIT_STRING extends PrimitiveType<boolean[]> implements
                        ASN1IllegalArgument ex = new ASN1IllegalArgument();
                        ex.setMessage(
                                        "The type '"
-                                                       + data.specification().identifier()
+                                                       + data.specification().fullIdentifier()
                                                        + "' of the data to be concatenated is not the same type of this data.",
                                        null, getClass(), null, null);
                        throw ex;
index 4315365..50d1f0a 100644 (file)
@@ -20,6 +20,7 @@ import java.lang.reflect.Modifier;
 import java.math.BigInteger;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
 import jp.bitmeister.asn1.annotation.ASN1Enumeration;
@@ -124,7 +125,7 @@ public class INTEGER extends PrimitiveType<BigInteger> implements
                                throw ex;
                        }
                        if (map.containsKey(value)) {
-                               ASN1RuntimeException ex = new ASN1RuntimeException();
+                               ASN1IllegalDefinition ex = new ASN1IllegalDefinition();
                                ex.setMessage(
                                                "Each number of enumerations shall be distinct from all other enumerations in the type.",
                                                null, type, fieldId, null);
@@ -216,6 +217,24 @@ public class INTEGER extends PrimitiveType<BigInteger> implements
        }
 
        /**
+        * Sets the value specified by the name of number to this data.
+        * 
+        * @param nameOfNumber
+        *            The name of number.
+        */
+       public void set(String nameOfNumber) {
+               for (Entry<BigInteger, String> e: getNamedNumberMap(getClass()).entrySet()) {
+                       if (e.getValue().equals(nameOfNumber)) {
+                               set(e.getKey());
+                               return;
+                       }
+               }
+               ASN1IllegalArgument e = new ASN1IllegalArgument();
+               e.setMessage("The name '" + nameOfNumber + "' is not defined in this type.", null, getClass(), null, null);
+               throw e;
+       }
+
+       /**
         * Returns an identifier related to the value of this data if the type has
         * {@code @ASN1Enumeration} fields.
         * 
index 9d710e2..0c584aa 100644 (file)
 package jp.bitmeister.asn1.type.builtin;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
 import jp.bitmeister.asn1.annotation.ASN1Identifier;
 import jp.bitmeister.asn1.annotation.ASN1Tag;
+import jp.bitmeister.asn1.annotation.ASN1XmlTypeName;
+import jp.bitmeister.asn1.exception.ASN1IllegalArgument;
 import jp.bitmeister.asn1.processor.ASN1Visitor;
 import jp.bitmeister.asn1.type.ASN1TagClass;
 import jp.bitmeister.asn1.type.ASN1TagMode;
@@ -39,9 +43,64 @@ import jp.bitmeister.asn1.type.PrimitiveType;
  */
 @ASN1BuiltIn
 @ASN1Identifier("OBJECT IDENTIFIER")
+@ASN1XmlTypeName("OBJECT_IDENTIFIER")
 @ASN1Tag(tagClass = ASN1TagClass.UNIVERSAL, value = 6, tagMode = ASN1TagMode.IMPLICIT)
 public class OBJECT_IDENTIFIER extends PrimitiveType<List<Integer>> {
-
+       
+       private static Map<String, Integer> NAMES_ROOT = new HashMap<String, Integer>();
+       private static Map<String, Integer> NAMES_ITU_T = new HashMap<String, Integer>();
+       private static Map<String, Integer> NAMES_ISO = new HashMap<String, Integer>();
+       private static Map<String, Integer> NAMES_ITU_T_REC = new HashMap<String, Integer>();
+       
+       static {
+               // top level
+               NAMES_ROOT.put("itu-t", 0);
+               NAMES_ROOT.put("ccitt", 0);
+               NAMES_ROOT.put("iso", 1);
+               NAMES_ROOT.put("joint-iso-itu-t", 2);
+               NAMES_ROOT.put("joint-iso-ccitt", 2);
+               // itu-t/ccitt
+               NAMES_ITU_T.put("recommendation", 0);
+               NAMES_ITU_T.put("question", 1);
+               NAMES_ITU_T.put("administration", 2);
+               NAMES_ITU_T.put("network-operator", 3);
+               NAMES_ITU_T.put("identified-organization", 4);
+               NAMES_ITU_T.put("r-recommendation", 5);
+               // iso
+               NAMES_ISO.put("standard", 0);
+               NAMES_ISO.put("registration-authority", 1);
+               NAMES_ISO.put("member-body", 2);
+               NAMES_ISO.put("identified-organization", 3);
+               // itu-t recommendation
+               for (char c = 'a'; c <= 'z'; c++) {
+                       NAMES_ITU_T_REC.put(String.valueOf(c), c - 'a');
+               } 
+       }
+       
+       public static int nameFormToInt(List<Integer> list, String nameForm) {
+               Integer number = null;
+               if (list.size() == 0) {
+                       number = NAMES_ROOT.get(nameForm);
+               }
+               else if (list.size() == 1) {
+                       if (list.get(0) == 0) {
+                               number = NAMES_ITU_T.get(nameForm);
+                       }
+                       else if (list.get(0) == 1) {
+                               number = NAMES_ISO.get(nameForm);
+                       }
+               }
+               else if (list.size() == 2 && list.get(0) == 0 && list.get(1) == 0) {
+                       number = NAMES_ITU_T_REC.get(nameForm);
+               }
+               if (number == null) {
+                       ASN1IllegalArgument e = new ASN1IllegalArgument();
+                       e.setMessage("Invalid OID name form '" + nameForm + "'.", null, OBJECT_IDENTIFIER.class, null, null);
+                       throw e;
+               }
+               return number;
+       }
+       
        /**
         * Instantiates an empty {@code OBJECT_IDENTIFIER}.
         */
@@ -84,7 +143,7 @@ public class OBJECT_IDENTIFIER extends PrimitiveType<List<Integer>> {
                }
                set(oids);
        }
-
+       
        /*
         * (non-Javadoc)
         * 
index 1a0e4e5..5dc740f 100644 (file)
@@ -20,6 +20,7 @@ import java.util.Arrays;
 import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
 import jp.bitmeister.asn1.annotation.ASN1Identifier;
 import jp.bitmeister.asn1.annotation.ASN1Tag;
+import jp.bitmeister.asn1.annotation.ASN1XmlTypeName;
 import jp.bitmeister.asn1.exception.ASN1IllegalArgument;
 import jp.bitmeister.asn1.processor.ASN1Visitor;
 import jp.bitmeister.asn1.type.ASN1TagClass;
@@ -41,6 +42,7 @@ import jp.bitmeister.asn1.value.StringItem;
  */
 @ASN1BuiltIn
 @ASN1Identifier("OCTET STRING")
+@ASN1XmlTypeName("OCTET_STRING")
 @ASN1Tag(tagClass = ASN1TagClass.UNIVERSAL, value = 4, tagMode = ASN1TagMode.IMPLICIT)
 public class OCTET_STRING extends PrimitiveType<byte[]> implements
                Concatenatable<OCTET_STRING>, SizeCountable {
@@ -97,7 +99,7 @@ public class OCTET_STRING extends PrimitiveType<byte[]> implements
                        ASN1IllegalArgument ex = new ASN1IllegalArgument();
                        ex.setMessage(
                                        "The type '"
-                                                       + data.specification().identifier()
+                                                       + data.specification().fullIdentifier()
                                                        + "' of the data to be concatenated is not the same type of this instance.",
                                        null, getClass(), null, null);
                        throw ex;
diff --git a/jp/bitmeister/asn1/type/builtin/RELATIVE_OID.java b/jp/bitmeister/asn1/type/builtin/RELATIVE_OID.java
new file mode 100644 (file)
index 0000000..bf23672
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2011 BitMeister Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package jp.bitmeister.asn1.type.builtin;
+
+import java.util.List;
+
+import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
+import jp.bitmeister.asn1.annotation.ASN1Identifier;
+import jp.bitmeister.asn1.annotation.ASN1Tag;
+import jp.bitmeister.asn1.annotation.ASN1XmlTypeName;
+import jp.bitmeister.asn1.processor.ASN1Visitor;
+import jp.bitmeister.asn1.type.ASN1TagClass;
+import jp.bitmeister.asn1.type.ASN1TagMode;
+
+/**
+ * Represents ASN.1 'RELATIVE-OID' type.
+ * 
+ * <p>
+ * An instance of this class represents an 'RELATIVE-OID' type data and
+ * contains a {@code List} of {@code Integer}. Each element of the {@code List}
+ * represents an object id component.
+ * </p>
+ * 
+ * @author WATANABE, Jun. <jwat at bitmeister.jp>
+ */
+@ASN1BuiltIn
+@ASN1Identifier("RELATIVE-OID")
+@ASN1XmlTypeName("RELATIVE_OID")
+@ASN1Tag(tagClass = ASN1TagClass.UNIVERSAL, value = 13, tagMode = ASN1TagMode.IMPLICIT)
+public class RELATIVE_OID extends OBJECT_IDENTIFIER {
+       
+       /**
+        * Instantiates an empty {@code RELATIVE_OID}.
+        */
+       public RELATIVE_OID() {
+       }
+
+       /**
+        * Instantiates an {@code RELATIVE_OID} and initialize it with the
+        * {@code List<Integer>} value.
+        * 
+        * @param value
+        *            the {@code List} of {@code Integer} represents an object
+        *            identifier.
+        */
+       public RELATIVE_OID(List<Integer> value) {
+               set(value);
+       }
+
+       /**
+        * Instantiates an {@code RELATIVE_OID} and initialize it with the
+        * array of {@code int} value.
+        * 
+        * @param value
+        *            the array of {@code int} represents an object identifier.
+        */
+       public RELATIVE_OID(int... value) {
+               set(value);
+       }
+       
+       /*
+        * (non-Javadoc)
+        * 
+        * @see
+        * jp.bitmeister.asn1.type.ASN1Type#accept(jp.bitmeister.asn1.processor.
+        * ASN1Visitor)
+        */
+       @Override
+       public <R, E extends Throwable> R accept(ASN1Visitor<R, E> visitor) throws E {
+               return visitor.visit(this);
+       }
+
+}
index 7222740..7a778a3 100644 (file)
@@ -21,6 +21,7 @@ import java.util.Collection;
 import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
 import jp.bitmeister.asn1.annotation.ASN1Identifier;
 import jp.bitmeister.asn1.annotation.ASN1Tag;
+import jp.bitmeister.asn1.annotation.ASN1XmlTypeName;
 import jp.bitmeister.asn1.processor.ASN1Visitor;
 import jp.bitmeister.asn1.type.ASN1TagClass;
 import jp.bitmeister.asn1.type.ASN1TagMode;
@@ -42,8 +43,9 @@ import jp.bitmeister.asn1.type.CollectionType;
  */
 @ASN1BuiltIn
 @ASN1Identifier("SEQUENCE")
+@ASN1XmlTypeName("SEQUENCE_OF")
 @ASN1Tag(tagClass = ASN1TagClass.UNIVERSAL, value = 16, tagMode = ASN1TagMode.IMPLICIT)
-public class SEQUENCE_OF<T extends ASN1Type> extends CollectionType<T> {
+public abstract class SEQUENCE_OF<T extends ASN1Type> extends CollectionType<T> {
 
        /**
         * Instantiate an empty {@code SEQUENCE_OF}.
index 95a0646..01e5027 100644 (file)
@@ -21,6 +21,7 @@ import java.util.Collection;
 import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
 import jp.bitmeister.asn1.annotation.ASN1Identifier;
 import jp.bitmeister.asn1.annotation.ASN1Tag;
+import jp.bitmeister.asn1.annotation.ASN1XmlTypeName;
 import jp.bitmeister.asn1.processor.ASN1Visitor;
 import jp.bitmeister.asn1.type.ASN1TagClass;
 import jp.bitmeister.asn1.type.ASN1TagMode;
@@ -41,8 +42,9 @@ import jp.bitmeister.asn1.type.CollectionType;
  */
 @ASN1BuiltIn
 @ASN1Identifier("SET")
+@ASN1XmlTypeName("SET_OF")
 @ASN1Tag(tagClass = ASN1TagClass.UNIVERSAL, value = 17, tagMode = ASN1TagMode.IMPLICIT)
-public class SET_OF<T extends ASN1Type> extends CollectionType<T> {
+public abstract class SET_OF<T extends ASN1Type> extends CollectionType<T> {
 
        /**
         * Instantiate an empty {@code SET_OF}.
index 8a77606..b06989d 100644 (file)
@@ -18,6 +18,7 @@ package jp.bitmeister.asn1.type.useful;
 import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
 import jp.bitmeister.asn1.annotation.ASN1Identifier;
 import jp.bitmeister.asn1.annotation.ASN1Tag;
+import jp.bitmeister.asn1.annotation.ASN1XmlTypeName;
 import jp.bitmeister.asn1.type.ASN1TagClass;
 import jp.bitmeister.asn1.type.ASN1TagMode;
 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
@@ -34,6 +35,7 @@ import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
  */
 @ASN1BuiltIn
 @ASN1Identifier("CHARACTER STRING")
+@ASN1XmlTypeName("CHARACTER_STRING")
 @ASN1Tag(tagClass = ASN1TagClass.UNIVERSAL, value = 29, tagMode = ASN1TagMode.IMPLICIT)
 public class CHARACTER_STRING extends EMBEDDED_PDV {
 
index 1d1d553..ffabbc9 100644 (file)
@@ -21,6 +21,7 @@ import jp.bitmeister.asn1.annotation.ASN1BuiltIn;
 import jp.bitmeister.asn1.annotation.ASN1Element;
 import jp.bitmeister.asn1.annotation.ASN1Identifier;
 import jp.bitmeister.asn1.annotation.ASN1Tag;
+import jp.bitmeister.asn1.annotation.ASN1XmlTypeName;
 import jp.bitmeister.asn1.type.ASN1TagClass;
 import jp.bitmeister.asn1.type.ASN1TagMode;
 import jp.bitmeister.asn1.type.ASN1Type;
@@ -66,6 +67,7 @@ import jp.bitmeister.asn1.type.builtin.SEQUENCE;
  */
 @ASN1BuiltIn
 @ASN1Identifier("EMBEDDED PDV")
+@ASN1XmlTypeName("SEQUENCE")
 @ASN1Tag(tagClass = ASN1TagClass.UNIVERSAL, value = 11, tagMode = ASN1TagMode.IMPLICIT)
 public class EMBEDDED_PDV extends SEQUENCE {
 
index f1dba86..1fa820e 100644 (file)
@@ -37,14 +37,14 @@ public class BinString implements StringItem {
         *            The {@code String} consist of '0's and '1's.
         */
        public BinString(String string) {
-               if (!string.matches("[01]*")) {
+               if (!string.matches("[01 ]*")) {
                        ASN1IllegalArgument ex = new ASN1IllegalArgument();
                        ex.setMessage("Invalid string '" + string
                                        + "'. bString shall consist of '0's and '1's.", null, null,
                                        null, null);
                        throw ex;
                }
-               this.string = string;
+               this.string = string.trim();
        }
 
        /**
index a78df5f..1cbd259 100644 (file)
@@ -48,7 +48,7 @@ public class HexString implements StringItem {
                                        null, null, null);
                        throw ex;
                }
-               this.string = string.toUpperCase();
+               this.string = string.trim().toUpperCase();
        }
 
        /**
index 07ec3ca..38a5299 100644 (file)
@@ -42,5 +42,5 @@ public interface StringItem {
         * @return An array of {@code byte}.
         */
        public byte[] toByteArray();
-
+       
 }