2 * Copyright 2011 BitMeister Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package jp.bitmeister.asn1.processor;
18 import java.text.DateFormat;
19 import java.text.SimpleDateFormat;
20 import java.util.Iterator;
22 import jp.bitmeister.asn1.exception.ASN1RuntimeException;
23 import jp.bitmeister.asn1.type.ASN1TagClass;
24 import jp.bitmeister.asn1.type.ASN1TagMode;
25 import jp.bitmeister.asn1.type.ASN1TagValue;
26 import jp.bitmeister.asn1.type.ASN1Type;
27 import jp.bitmeister.asn1.type.CollectionType;
28 import jp.bitmeister.asn1.type.ConstructiveType;
29 import jp.bitmeister.asn1.type.ElementSpecification;
30 import jp.bitmeister.asn1.type.PrimitiveType;
31 import jp.bitmeister.asn1.type.StringType;
32 import jp.bitmeister.asn1.type.TimeType;
33 import jp.bitmeister.asn1.type.TypeSpecification;
34 import jp.bitmeister.asn1.type.UnknownType;
35 import jp.bitmeister.asn1.type.builtin.ANY;
36 import jp.bitmeister.asn1.type.builtin.BIT_STRING;
37 import jp.bitmeister.asn1.type.builtin.BOOLEAN;
38 import jp.bitmeister.asn1.type.builtin.CHOICE;
39 import jp.bitmeister.asn1.type.builtin.ENUMERATED;
40 import jp.bitmeister.asn1.type.builtin.INTEGER;
41 import jp.bitmeister.asn1.type.builtin.NULL;
42 import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
43 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
44 import jp.bitmeister.asn1.type.builtin.REAL;
45 import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
46 import jp.bitmeister.asn1.type.builtin.SEQUENCE;
47 import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
48 import jp.bitmeister.asn1.type.builtin.SET;
49 import jp.bitmeister.asn1.type.builtin.SET_OF;
50 import jp.bitmeister.asn1.value.BinString;
51 import jp.bitmeister.asn1.value.HexString;
54 * Processor that builds string representation of ASN.1 data.
57 * An instance of this class is set to the {@code stringBuilder} field of
58 * {@code ASN1Type} class and used for {@code toString} method.
61 * @author WATANABE, Jun. <jwat at bitmeister.jp>
65 public class ASN1StringBuilder implements
66 ASN1Processor<String, ASN1RuntimeException>,
67 ASN1Visitor<Void, ASN1RuntimeException> {
69 private static final String NEW_LINE = System.getProperty("line.separator");
70 private static final String SPACE = " ";
71 private static final String INDENT = "\t";
72 private static final String SEPARATOR = "\t";
73 private static final String ASSIGN = SPACE + "::=" + SPACE;
74 private static final String CONSTRUCTIVE_OPEN = SPACE + "{" + NEW_LINE;
75 private static final String CONSTRUCTIVE_SEPARATOR = "," + NEW_LINE;
76 private static final String CONSTRUCTIVE_CLOSE = SPACE + "}";
77 private static final String COLLECTION_OF = SPACE + "OF" + SPACE;
78 private static final String IMPLICIT = SPACE + "IMPLICIT";
79 private static final String OPTIONAL = SPACE + "OPTIONAL";
81 private static final String VALUE_OPEN = SEPARATOR;
82 private static final String VALUE_CLOSE = "";
83 private static final String TAG_OPEN = "[";
84 private static final String TAG_CLOSE = "]";
85 private static final String NUMBER_OPEN = "(";
86 private static final String NUMBER_CLOSE = ")";
87 private static final String NULL = "null";
88 private static final String NAMED_BITS_OPEN = "{";
89 private static final String NAMED_BITS_CLOSE = "}";
90 private static final String NAMED_BITS_SEPARATOR = ",";
91 private static final String OID_OPEN = "{";
92 private static final String OID_CLOSE = "}";
93 private static final String STRING_OPEN = "\"";
94 private static final String STRING_CLOSE = "\"";
95 private static final String NOT_SET = "<No value>";
96 private static final ThreadLocal<DateFormat> DATE_FORMAT = new ThreadLocal<DateFormat>() {
98 protected DateFormat initialValue() {
99 return new SimpleDateFormat("[yyyy/MM/dd HH:mm:ss.S z]");
103 private StringBuilder builder;
108 * Instantiates an {@code ASN1StringBuilder}.
110 public ASN1StringBuilder() {
114 * Returns a string representation of the ASN.1 data.
118 * @return A string representation of the ASN.1 data.
121 public String process(ASN1Type data) {
123 builder = new StringBuilder();
125 return builder.toString();
129 * Writes descriptions of the data to the 'builder'.
134 private void write(ASN1Type data) {
135 TypeSpecification specification = data.specification();
137 if (specification.hasIdentifier()) {
138 builder.append(specification.identifier());
139 if (specification.reference() == null) {
140 if (data instanceof CollectionType<?>) {
141 CollectionType<?> collection = (CollectionType<?>) data;
142 if (!collection.componentType().equals(ANY.class)) {
143 builder.append(COLLECTION_OF).append(
144 collection.componentSpecification()
150 builder.append(ASSIGN);
151 if (specification.tag() != null) {
152 writeTag(specification.tag());
153 builder.append(SPACE);
157 specification = specification.reference();
159 if (data instanceof PrimitiveType<?>) {
160 builder.append(VALUE_OPEN);
161 if (data.hasValue()) {
164 builder.append(NOT_SET);
166 builder.append(VALUE_CLOSE);
168 builder.append(CONSTRUCTIVE_OPEN);
172 builder.append(CONSTRUCTIVE_CLOSE);
180 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
184 public Void visit(BOOLEAN data) {
185 builder.append(data.value() ? "TRUE" : "FALSE");
193 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
197 public Void visit(INTEGER data) {
198 String numberId = data.identifier();
199 if (numberId != null) {
200 builder.append(numberId);
202 builder.append(NUMBER_OPEN).append(data.value()).append(NUMBER_CLOSE);
210 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
211 * .builtin.ENUMERATED)
214 public Void visit(ENUMERATED data) {
215 visit((INTEGER) data);
223 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
227 public Void visit(REAL data) {
228 builder.append(NUMBER_OPEN).append(data.value()).append(NUMBER_CLOSE);
236 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
237 * .builtin.BIT_STRING)
240 public Void visit(BIT_STRING data) {
241 if (data.hasNamedBits()) {
242 builder.append(NAMED_BITS_OPEN);
243 boolean trailing = false;
244 for (int i = 0; i < data.size(); i++) {
246 String identifier = data.nameOfBit(i);
247 if (identifier != null) {
249 builder.append(NAMED_BITS_SEPARATOR).append(SPACE);
251 builder.append(SPACE);
254 builder.append(identifier);
258 builder.append(SPACE).append(NAMED_BITS_CLOSE).append(SEPARATOR);
260 builder.append(new BinString(data.value()).toString());
268 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
269 * .builtin.OCTET_STRING)
272 public Void visit(OCTET_STRING data) {
273 builder.append(new HexString(data.value()).toString());
281 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
285 public Void visit(NULL data) {
286 builder.append(NULL);
294 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
298 public Void visit(SEQUENCE data) {
299 writeConstructive(data);
307 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
308 * .builtin.SEQUENCE_OF)
311 public Void visit(SEQUENCE_OF<? extends ASN1Type> data) {
312 writeCollection(data);
320 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
324 public Void visit(SET data) {
325 writeConstructive(data);
333 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
337 public Void visit(SET_OF<? extends ASN1Type> data) {
338 writeCollection(data);
346 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
350 public Void visit(CHOICE data) {
352 if (!data.hasValue()) {
353 builder.append(NOT_SET);
355 builder.append(data.selectedIdentifier());
356 if (data.selectedTag() != null) {
357 builder.append(SEPARATOR);
358 writeTag(data.selectedTag());
360 builder.append(SEPARATOR);
361 write(data.selectedValue());
370 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
371 * .builtin.OBJECT_IDENTIFIER)
374 public Void visit(OBJECT_IDENTIFIER data) {
375 builder.append(OID_OPEN);
376 if (data.value().size() > 0) {
377 builder.append(SPACE).append(data.value().get(0));
378 for (int i = 1; i < data.value().size(); i++) {
379 builder.append('.').append(data.value().get(i));
381 builder.append(SPACE);
383 builder.append(OID_CLOSE);
388 * @see jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type.builtin.RELATIVE_OID)
391 public Void visit(RELATIVE_OID data) {
392 return visit((OBJECT_IDENTIFIER)data);
399 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
403 public Void visit(StringType data) {
405 String value = data.stringValue();
406 builder.append(STRING_OPEN).append(value).append(STRING_CLOSE);
407 } catch (Exception e) {
408 builder.append(new HexString(data.value()).toString());
417 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
421 public Void visit(TimeType data) {
422 visit((StringType)data);
423 builder.append(SPACE).append(DATE_FORMAT.get().format(data.date()));
431 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
435 public Void visit(ANY data) {
444 * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
448 public Void visit(UnknownType data) {
449 for (int i = 0; i < data.value().length; i++) {
453 builder.append(String.format("%02X", data.value()[i]));
454 builder.append(i % 16 == 15 ? NEW_LINE : SPACE);
460 * Writes descriptions of each element of {@code ConstructiveType}.
463 * The constructive data.
465 private void writeConstructive(ConstructiveType data) {
466 ElementSpecification[] elements = data.getElementTypeList();
467 for (int i = 0; i < elements.length; i++) {
469 builder.append(CONSTRUCTIVE_SEPARATOR);
472 builder.append(elements[i].identifier()).append(SEPARATOR);
473 if (elements[i].tag() != null) {
474 writeTag(elements[i].tag());
475 builder.append(SEPARATOR);
477 ASN1Type element = data.getComponent(elements[i]);
478 if (element == null) {
479 builder.append(NOT_SET);
483 if (elements[i].optional()) {
484 builder.append(OPTIONAL);
490 * Writes descriptions of each member of {@code CollectionType}.
493 * The collection data.
495 private void writeCollection(CollectionType<? extends ASN1Type> data) {
496 Iterator<? extends ASN1Type> itr = data.collection().iterator();
501 if (!itr.hasNext()) {
504 builder.append(CONSTRUCTIVE_SEPARATOR);
508 builder.append(NOT_SET);
512 * Writes tag description.
517 private void writeTag(ASN1TagValue tag) {
518 builder.append(TAG_OPEN);
519 if (tag.tagClass() != ASN1TagClass.CONTEXT_SPECIFIC) {
520 builder.append(tag.tagClass()).append(SPACE);
522 builder.append(tag.tagNumber()).append(TAG_CLOSE);
523 if (tag.tagMode() == ASN1TagMode.IMPLICIT) {
524 builder.append(IMPLICIT);
531 private void indent() {
532 for (int i = 0; i < indent; i++) {
533 builder.append(INDENT);