001 package org.apache.commons.ssl.asn1;
002
003 import java.io.IOException;
004
005 /**
006 * ASN.1 TaggedObject - in ASN.1 nottation this is any object proceeded by
007 * a [n] where n is some number - these are assume to follow the construction
008 * rules (as with sequences).
009 */
010 public abstract class ASN1TaggedObject
011 extends ASN1Object
012 implements ASN1TaggedObjectParser {
013 int tagNo;
014 boolean empty = false;
015 boolean explicit = true;
016 DEREncodable obj = null;
017
018 static public ASN1TaggedObject getInstance(
019 ASN1TaggedObject obj,
020 boolean explicit) {
021 if (explicit) {
022 return (ASN1TaggedObject) obj.getObject();
023 }
024
025 throw new IllegalArgumentException("implicitly tagged tagged object");
026 }
027
028 static public ASN1TaggedObject getInstance(
029 Object obj) {
030 if (obj == null || obj instanceof ASN1TaggedObject) {
031 return (ASN1TaggedObject) obj;
032 }
033
034 throw new IllegalArgumentException("unknown object in getInstance");
035 }
036
037 /**
038 * Create a tagged object in the explicit style.
039 *
040 * @param tagNo the tag number for this object.
041 * @param obj the tagged object.
042 */
043 public ASN1TaggedObject(
044 int tagNo,
045 DEREncodable obj) {
046 this.explicit = true;
047 this.tagNo = tagNo;
048 this.obj = obj;
049 }
050
051 /**
052 * Create a tagged object with the style given by the value of explicit.
053 * <p>
054 * If the object implements ASN1Choice the tag style will always be changed
055 * to explicit in accordance with the ASN.1 encoding rules.
056 * </p>
057 *
058 * @param explicit true if the object is explicitly tagged.
059 * @param tagNo the tag number for this object.
060 * @param obj the tagged object.
061 */
062 public ASN1TaggedObject(
063 boolean explicit,
064 int tagNo,
065 DEREncodable obj) {
066 if (obj instanceof ASN1Choice) {
067 this.explicit = true;
068 } else {
069 this.explicit = explicit;
070 }
071
072 this.tagNo = tagNo;
073 this.obj = obj;
074 }
075
076 boolean asn1Equals(
077 DERObject o) {
078 if (!(o instanceof ASN1TaggedObject)) {
079 return false;
080 }
081
082 ASN1TaggedObject other = (ASN1TaggedObject) o;
083
084 if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit) {
085 return false;
086 }
087
088 if (obj == null) {
089 if (other.obj != null) {
090 return false;
091 }
092 } else {
093 if (!(obj.getDERObject().equals(other.obj.getDERObject()))) {
094 return false;
095 }
096 }
097
098 return true;
099 }
100
101 public int hashCode() {
102 int code = tagNo;
103
104 if (obj != null) {
105 code ^= obj.hashCode();
106 }
107
108 return code;
109 }
110
111 public int getTagNo() {
112 return tagNo;
113 }
114
115 /**
116 * return whether or not the object may be explicitly tagged.
117 * <p/>
118 * Note: if the object has been read from an input stream, the only
119 * time you can be sure if isExplicit is returning the true state of
120 * affairs is if it returns false. An implicitly tagged object may appear
121 * to be explicitly tagged, so you need to understand the context under
122 * which the reading was done as well, see getObject below.
123 */
124 public boolean isExplicit() {
125 return explicit;
126 }
127
128 public boolean isEmpty() {
129 return empty;
130 }
131
132 /**
133 * return whatever was following the tag.
134 * <p/>
135 * Note: tagged objects are generally context dependent if you're
136 * trying to extract a tagged object you should be going via the
137 * appropriate getInstance method.
138 */
139 public DERObject getObject() {
140 if (obj != null) {
141 return obj.getDERObject();
142 }
143
144 return null;
145 }
146
147 /**
148 * Return the object held in this tagged object as a parser assuming it has
149 * the type of the passed in tag. If the object doesn't have a parser
150 * associated with it, the base object is returned.
151 */
152 public DEREncodable getObjectParser(
153 int tag,
154 boolean isExplicit) {
155 switch (tag) {
156 case DERTags.SET:
157 return ASN1Set.getInstance(this, isExplicit).parser();
158 case DERTags.SEQUENCE:
159 return ASN1Sequence.getInstance(this, isExplicit).parser();
160 case DERTags.OCTET_STRING:
161 return ASN1OctetString.getInstance(this, isExplicit).parser();
162 }
163
164 if (isExplicit) {
165 return getObject();
166 }
167
168 throw new RuntimeException("implicit tagging not implemented for tag: " + tag);
169 }
170
171 abstract void encode(DEROutputStream out)
172 throws IOException;
173
174 public String toString() {
175 return "[" + tagNo + "]" + obj;
176 }
177 }