OSDN Git Service

a98ceba6d5e1aa7a4b55ab73d3bbececa524b900
[bm-asn1/bm-asn1.git] / jp / bitmeister / asn1 / processor / ASN1StringBuilder.java
1 /*
2  * Copyright 2011 BitMeister Inc.
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package jp.bitmeister.asn1.processor;
17
18 import java.text.DateFormat;
19 import java.text.SimpleDateFormat;
20 import java.util.Iterator;
21
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;
52
53 /**
54  * Processor that builds string representation of ASN.1 data.
55  * 
56  * <p>
57  * An instance of this class is set to the {@code stringBuilder} field of
58  * {@code ASN1Type} class and used for {@code toString} method.
59  * </p>
60  * 
61  * @author WATANABE, Jun. <jwat at bitmeister.jp>
62  * 
63  * @see ASN1Type
64  */
65 public class ASN1StringBuilder implements
66                 ASN1Processor<String, ASN1RuntimeException>,
67                 ASN1Visitor<Void, ASN1RuntimeException> {
68
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";
80
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>() {
97                 @Override
98                 protected DateFormat initialValue() {
99                         return new SimpleDateFormat("[yyyy/MM/dd HH:mm:ss.S z]");
100                 }
101         };
102
103         private StringBuilder builder;
104
105         private int indent;
106
107         /**
108          * Instantiates an {@code ASN1StringBuilder}.
109          */
110         public ASN1StringBuilder() {
111         }
112
113         /**
114          * Returns a string representation of the ASN.1 data.
115          * 
116          * @param data
117          *            The ASN.1 data.
118          * @return A string representation of the ASN.1 data.
119          */
120         @Override
121         public String process(ASN1Type data) {
122                 indent = 0;
123                 builder = new StringBuilder();
124                 write(data);
125                 return builder.toString();
126         }
127
128         /**
129          * Writes descriptions of the data to the 'builder'.
130          * 
131          * @param data
132          *            The ASN.1 data.
133          */
134         private void write(ASN1Type data) {
135                 TypeSpecification specification = data.specification();
136                 while (true) {
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()
145                                                                                         .identifier());
146                                                 }
147                                         }
148                                         break;
149                                 } else {
150                                         builder.append(ASSIGN);
151                                         if (specification.tag() != null) {
152                                                 writeTag(specification.tag());
153                                                 builder.append(SPACE);
154                                         }
155                                 }
156                         }
157                         specification = specification.reference();
158                 }
159                 if (data instanceof PrimitiveType<?>) {
160                         builder.append(VALUE_OPEN);
161                         if (data.hasValue()) {
162                                 data.accept(this);
163                         } else {
164                                 builder.append(NOT_SET);
165                         }
166                         builder.append(VALUE_CLOSE);
167                 } else {
168                         builder.append(CONSTRUCTIVE_OPEN);
169                         indent++;
170                         data.accept(this);
171                         indent--;
172                         builder.append(CONSTRUCTIVE_CLOSE);
173                 }
174         }
175
176         /*
177          * (non-Javadoc)
178          * 
179          * @see
180          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
181          * .builtin.BOOLEAN)
182          */
183         @Override
184         public Void visit(BOOLEAN data) {
185                 builder.append(data.value() ? "TRUE" : "FALSE");
186                 return null;
187         }
188
189         /*
190          * (non-Javadoc)
191          * 
192          * @see
193          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
194          * .builtin.INTEGER)
195          */
196         @Override
197         public Void visit(INTEGER data) {
198                 String numberId = data.identifier();
199                 if (numberId != null) {
200                         builder.append(numberId);
201                 }
202                 builder.append(NUMBER_OPEN).append(data.value()).append(NUMBER_CLOSE);
203                 return null;
204         }
205
206         /*
207          * (non-Javadoc)
208          * 
209          * @see
210          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
211          * .builtin.ENUMERATED)
212          */
213         @Override
214         public Void visit(ENUMERATED data) {
215                 visit((INTEGER) data);
216                 return null;
217         }
218
219         /*
220          * (non-Javadoc)
221          * 
222          * @see
223          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
224          * .builtin.REAL)
225          */
226         @Override
227         public Void visit(REAL data) {
228                 builder.append(NUMBER_OPEN).append(data.value()).append(NUMBER_CLOSE);
229                 return null;
230         }
231
232         /*
233          * (non-Javadoc)
234          * 
235          * @see
236          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
237          * .builtin.BIT_STRING)
238          */
239         @Override
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++) {
245                                 if (data.bit(i)) {
246                                         String identifier = data.nameOfBit(i);
247                                         if (identifier != null) {
248                                                 if (trailing) {
249                                                         builder.append(NAMED_BITS_SEPARATOR).append(SPACE);
250                                                 } else {
251                                                         builder.append(SPACE);
252                                                         trailing = true;
253                                                 }
254                                                 builder.append(identifier);
255                                         }
256                                 }
257                         }
258                         builder.append(SPACE).append(NAMED_BITS_CLOSE).append(SEPARATOR);
259                 }
260                 builder.append(new BinString(data.value()).toString());
261                 return null;
262         }
263
264         /*
265          * (non-Javadoc)
266          * 
267          * @see
268          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
269          * .builtin.OCTET_STRING)
270          */
271         @Override
272         public Void visit(OCTET_STRING data) {
273                 builder.append(new HexString(data.value()).toString());
274                 return null;
275         }
276
277         /*
278          * (non-Javadoc)
279          * 
280          * @see
281          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
282          * .builtin.NULL)
283          */
284         @Override
285         public Void visit(NULL data) {
286                 builder.append(NULL);
287                 return null;
288         }
289
290         /*
291          * (non-Javadoc)
292          * 
293          * @see
294          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
295          * .builtin.SEQUENCE)
296          */
297         @Override
298         public Void visit(SEQUENCE data) {
299                 writeConstructive(data);
300                 return null;
301         }
302
303         /*
304          * (non-Javadoc)
305          * 
306          * @see
307          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
308          * .builtin.SEQUENCE_OF)
309          */
310         @Override
311         public Void visit(SEQUENCE_OF<? extends ASN1Type> data) {
312                 writeCollection(data);
313                 return null;
314         }
315
316         /*
317          * (non-Javadoc)
318          * 
319          * @see
320          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
321          * .builtin.SET)
322          */
323         @Override
324         public Void visit(SET data) {
325                 writeConstructive(data);
326                 return null;
327         }
328
329         /*
330          * (non-Javadoc)
331          * 
332          * @see
333          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
334          * .builtin.SET_OF)
335          */
336         @Override
337         public Void visit(SET_OF<? extends ASN1Type> data) {
338                 writeCollection(data);
339                 return null;
340         }
341
342         /*
343          * (non-Javadoc)
344          * 
345          * @see
346          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
347          * .builtin.CHOICE)
348          */
349         @Override
350         public Void visit(CHOICE data) {
351                 indent();
352                 if (!data.hasValue()) {
353                         builder.append(NOT_SET);
354                 } else {
355                         builder.append(data.selectedIdentifier());
356                         if (data.selectedTag() != null) {
357                                 builder.append(SEPARATOR);
358                                 writeTag(data.selectedTag());
359                         }
360                         builder.append(SEPARATOR);
361                         write(data.selectedValue());
362                 }
363                 return null;
364         }
365
366         /*
367          * (non-Javadoc)
368          * 
369          * @see
370          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
371          * .builtin.OBJECT_IDENTIFIER)
372          */
373         @Override
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));
380                         }
381                         builder.append(SPACE);
382                 }
383                 builder.append(OID_CLOSE);
384                 return null;
385         }
386         
387         /* (non-Javadoc)
388          * @see jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type.builtin.RELATIVE_OID)
389          */
390         @Override
391         public Void visit(RELATIVE_OID data) {
392                 return visit((OBJECT_IDENTIFIER)data);
393         }
394
395         /*
396          * (non-Javadoc)
397          * 
398          * @see
399          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
400          * .StringType)
401          */
402         @Override
403         public Void visit(StringType data) {
404                 try {
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());
409                 }
410                 return null;
411         }
412
413         /*
414          * (non-Javadoc)
415          * 
416          * @see
417          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
418          * .TimeType)
419          */
420         @Override
421         public Void visit(TimeType data) {
422                 visit((StringType)data);
423                 builder.append(SPACE).append(DATE_FORMAT.get().format(data.date()));
424                 return null;
425         }
426
427         /*
428          * (non-Javadoc)
429          * 
430          * @see
431          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
432          * .builtin.ANY)
433          */
434         @Override
435         public Void visit(ANY data) {
436                 write(data.value());
437                 return null;
438         }
439
440         /*
441          * (non-Javadoc)
442          * 
443          * @see
444          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
445          * .UnknownType)
446          */
447         @Override
448         public Void visit(UnknownType data) {
449                 for (int i = 0; i < data.value().length; i++) {
450                         if (i % 16 == 0) {
451                                 indent();
452                         }
453                         builder.append(String.format("%02X", data.value()[i]));
454                         builder.append(i % 16 == 15 ? NEW_LINE : SPACE);
455                 }
456                 return null;
457         }
458
459         /**
460          * Writes descriptions of each element of {@code ConstructiveType}.
461          * 
462          * @param data
463          *            The constructive data.
464          */
465         private void writeConstructive(ConstructiveType data) {
466                 ElementSpecification[] elements = data.getElementTypeList();
467                 for (int i = 0; i < elements.length; i++) {
468                         if (i != 0) {
469                                 builder.append(CONSTRUCTIVE_SEPARATOR);
470                         }
471                         indent();
472                         builder.append(elements[i].identifier()).append(SEPARATOR);
473                         if (elements[i].tag() != null) {
474                                 writeTag(elements[i].tag());
475                                 builder.append(SEPARATOR);
476                         }
477                         ASN1Type element = data.getComponent(elements[i]);
478                         if (element == null) {
479                                 builder.append(NOT_SET);
480                         } else {
481                                 write(element);
482                         }
483                         if (elements[i].optional()) {
484                                 builder.append(OPTIONAL);
485                         }
486                 }
487         }
488
489         /**
490          * Writes descriptions of each member of {@code CollectionType}.
491          * 
492          * @param data
493          *            The collection data.
494          */
495         private void writeCollection(CollectionType<? extends ASN1Type> data) {
496                 Iterator<? extends ASN1Type> itr = data.collection().iterator();
497                 if (itr.hasNext()) {
498                         while (true) {
499                                 indent();
500                                 write(itr.next());
501                                 if (!itr.hasNext()) {
502                                         return;
503                                 }
504                                 builder.append(CONSTRUCTIVE_SEPARATOR);
505                         }
506                 }
507                 indent();
508                 builder.append(NOT_SET);
509         }
510
511         /**
512          * Writes tag description.
513          * 
514          * @param tag
515          *            The tag.
516          */
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);
521                 }
522                 builder.append(tag.tagNumber()).append(TAG_CLOSE);
523                 if (tag.tagMode() == ASN1TagMode.IMPLICIT) {
524                         builder.append(IMPLICIT);
525                 }
526         }
527
528         /**
529          * Writes indents.
530          */
531         private void indent() {
532                 for (int i = 0; i < indent; i++) {
533                         builder.append(INDENT);
534                 }
535         }
536
537 }