OSDN Git Service

e3e3186fd682c954119f283435d3e8af128f5f3e
[bm-asn1/bm-asn1.git] / jp / bitmeister / asn1 / codec / ber / BerEncoder.java
1 /*
2  * Copyright 2011-2012 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.codec.ber;
17
18 import java.io.IOException;
19 import java.io.OutputStream;
20 import java.math.BigInteger;
21 import java.util.ArrayList;
22 import java.util.List;
23
24 import jp.bitmeister.asn1.codec.ASN1Encoder;
25 import jp.bitmeister.asn1.exception.ASN1EncodingException;
26 import jp.bitmeister.asn1.processor.ASN1Visitor;
27 import jp.bitmeister.asn1.type.ASN1TagClass;
28 import jp.bitmeister.asn1.type.ASN1TagMode;
29 import jp.bitmeister.asn1.type.ASN1TagValue;
30 import jp.bitmeister.asn1.type.ASN1Type;
31 import jp.bitmeister.asn1.type.CollectionType;
32 import jp.bitmeister.asn1.type.ConstructiveType;
33 import jp.bitmeister.asn1.type.ElementSpecification;
34 import jp.bitmeister.asn1.type.StringType;
35 import jp.bitmeister.asn1.type.TimeType;
36 import jp.bitmeister.asn1.type.TypeSpecification;
37 import jp.bitmeister.asn1.type.UnknownType;
38 import jp.bitmeister.asn1.type.builtin.ANY;
39 import jp.bitmeister.asn1.type.builtin.BIT_STRING;
40 import jp.bitmeister.asn1.type.builtin.BOOLEAN;
41 import jp.bitmeister.asn1.type.builtin.CHOICE;
42 import jp.bitmeister.asn1.type.builtin.ENUMERATED;
43 import jp.bitmeister.asn1.type.builtin.INTEGER;
44 import jp.bitmeister.asn1.type.builtin.NULL;
45 import jp.bitmeister.asn1.type.builtin.OBJECT_IDENTIFIER;
46 import jp.bitmeister.asn1.type.builtin.OCTET_STRING;
47 import jp.bitmeister.asn1.type.builtin.REAL;
48 import jp.bitmeister.asn1.type.builtin.RELATIVE_OID;
49 import jp.bitmeister.asn1.type.builtin.SEQUENCE;
50 import jp.bitmeister.asn1.type.builtin.SEQUENCE_OF;
51 import jp.bitmeister.asn1.type.builtin.SET;
52 import jp.bitmeister.asn1.type.builtin.SET_OF;
53
54 /**
55  * BER (Basic Encoding Rules) encoder.
56  * 
57  * <p>
58  * {@code BerEncoder} is an implementation of {@code ASN1Encoder}. It encodes an
59  * ASN.1 data to an array of {@code byte} using Basic Encoding Rules(BER) and
60  * writes the result to {@code OutputStream} that is specified when the encoder
61  * was instantiated. BER encoding process is light-weight compared with
62  * Distinguished Encoding Rules (DER) encoding because some restrictions on DER
63  * are not considered.
64  * </p>
65  * 
66  * @author WATANABE, Jun. <jwat at bitmeister.jp>
67  * 
68  * @see ASN1Encoder
69  * @see BerDecoder
70  */
71 public class BerEncoder implements ASN1Encoder,
72                 ASN1Visitor<EncodedOctets, ASN1EncodingException> {
73
74         private OutputStream out;
75
76         /**
77          * Instantiates a BER encoder.
78          * 
79          * @param out
80          *            The {@code OutputStream} that encoded octets will be written.
81          */
82         public BerEncoder(OutputStream out) {
83                 this.out = out;
84         }
85
86         /**
87          * Encodes an ASN.1 data.
88          * 
89          * @param data
90          *            The ASN.1 data to be encoded
91          * @return The size of encoded octets.
92          * @throws ASN1EncodingException
93          *             When an error occurred while the encoding process.
94          */
95         public int encode(ASN1Type data) throws ASN1EncodingException {
96                 try {
97                         data.validate();
98                         return encode(data, null, null).write(out);
99                 } catch (ASN1EncodingException e) {
100                         throw e;
101                 } catch (Exception e) {
102                         ASN1EncodingException ex = new ASN1EncodingException();
103                         ex.setMessage("Exception thrown while encoding process.", e,
104                                         data.getClass(), null, data);
105                         throw ex;
106                 }
107         }
108
109         /**
110          * Encodes an ASN.1 data or an element of ASN.1 data.
111          * 
112          * @param data
113          *            The ASN.1 data to be encoded.
114          * @param tag
115          *            The tag assigned to the element to be encoded.
116          * @param typeSpec
117          *            The {@code TypeSpecification} of a type that tagged
118          *            explicitly.
119          * @throws ASN1EncodingException
120          *             When an error occurred while the encoding process.
121          */
122         EncodedOctets encode(ASN1Type data, ASN1TagValue tag,
123                         TypeSpecification typeSpec) throws ASN1EncodingException {
124                 if (typeSpec == null) {
125                         typeSpec = data.specification();
126                 }
127                 if (tag == null) {
128                         do {
129                                 tag = typeSpec.tag();
130                                 typeSpec = typeSpec.reference();
131                         } while (typeSpec != null && tag == null);
132                 }
133                 EncodedOctets octets;
134                 if (tag != null && tag.tagMode() == ASN1TagMode.EXPLICIT) {
135                         ConstructedOctets constructed = newConstructedOctets();
136                         constructed.addElement(encode(data, null, typeSpec));
137                         octets = constructed;
138                 } else {
139                         octets = data.accept(this);
140                 }
141                 if (tag != null) {
142                         octets.fix(tag.tagClass(), tag.tagNumber());
143                 }
144                 return octets;
145         }
146
147         /*
148          * (non-Javadoc)
149          * 
150          * @see
151          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
152          * .builtin.BOOLEAN)
153          */
154         public EncodedOctets visit(BOOLEAN data) {
155                 return newPrimitiveOctets(data.value() ? (byte) 0xff : (byte) 0x00);
156         }
157
158         /*
159          * (non-Javadoc)
160          * 
161          * @see
162          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
163          * .builtin.INTEGER)
164          */
165         public EncodedOctets visit(INTEGER data) {
166                 return newPrimitiveOctets(data.value().toByteArray());
167         }
168
169         /*
170          * (non-Javadoc)
171          * 
172          * @see
173          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
174          * .builtin.ENUMERATED)
175          */
176         public EncodedOctets visit(ENUMERATED data) {
177                 return visit((INTEGER) data);
178         }
179
180         /*
181          * (non-Javadoc)
182          * 
183          * @see
184          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
185          * .builtin.REAL)
186          */
187         public EncodedOctets visit(REAL data) {
188                 byte[] encoded;
189                 if (data.value() == 0) { // zero.
190                         encoded = new byte[0];
191                 } else if (data.value().isInfinite()) { // special value.
192                         encoded = new byte[] { data.value() == Double.POSITIVE_INFINITY ? (byte) 0x40
193                                         : 0x41 };
194                 } else if (data.value().isNaN()) {
195                         encoded = new byte[] {0x43}; // X.690 Amendment1 (10/2003)
196                 } else { // ISO6093
197                         String str = data.value().toString();
198                         encoded = new byte[str.length() + 1];
199                         if (str.indexOf("E") < 0) {
200                                 encoded[0] = 0x02; // NR2
201                         } else {
202                                 encoded[0] = 0x03; // NR3
203                         }
204                         System.arraycopy(str.getBytes(), 0, encoded, 1, str.length());
205                 }
206                 return newPrimitiveOctets(encoded);
207         }
208
209         /*
210          * (non-Javadoc)
211          * 
212          * @see
213          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
214          * .builtin.BIT_STRING)
215          */
216         public EncodedOctets visit(BIT_STRING data) {
217                 if (data.value().length == 0) {
218                         return newPrimitiveOctets((byte) 0x00);
219                 }
220                 int mod = data.value().length % 8;
221                 byte[] encoded = new byte[1 + data.value().length / 8
222                                 + (mod == 0 ? 0 : 1)];
223                 encoded[0] = (byte) (mod == 0 ? 0 : 8 - mod);
224                 int index = 1;
225                 int mask = 0x80;
226                 for (boolean b : data.value()) {
227                         if (b) {
228                                 encoded[index] |= mask;
229                         }
230                         mask >>>= 1;
231                         if (mask == 0) {
232                                 mask = 0x80;
233                                 index++;
234                         }
235                 }
236                 return newPrimitiveOctets(encoded);
237         }
238
239         /*
240          * (non-Javadoc)
241          * 
242          * @see
243          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
244          * .builtin.OCTET_STRING)
245          */
246         public EncodedOctets visit(OCTET_STRING data) throws ASN1EncodingException {
247                 return newPrimitiveOctets(data.value());
248         }
249
250         /*
251          * (non-Javadoc)
252          * 
253          * @see
254          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
255          * .builtin.NULL)
256          */
257         public EncodedOctets visit(NULL data) throws ASN1EncodingException {
258                 return newPrimitiveOctets();
259         }
260
261         /*
262          * (non-Javadoc)
263          * 
264          * @see
265          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
266          * .builtin.SEQUENCE)
267          */
268         public EncodedOctets visit(SEQUENCE data) throws ASN1EncodingException {
269                 return processConstructive(data);
270         }
271
272         /*
273          * (non-Javadoc)
274          * 
275          * @see
276          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
277          * .builtin.SEQUENCE_OF)
278          */
279         public EncodedOctets visit(SEQUENCE_OF<?> data)
280                         throws ASN1EncodingException {
281                 return processCollection(data);
282         }
283
284         /*
285          * (non-Javadoc)
286          * 
287          * @see
288          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
289          * .builtin.SET)
290          */
291         public ConstructedOctets visit(SET data) throws ASN1EncodingException {
292                 return processConstructive(data);
293         }
294
295         /*
296          * (non-Javadoc)
297          * 
298          * @see
299          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
300          * .builtin.SET_OF)
301          */
302         public ConstructedOctets visit(SET_OF<?> data)
303                         throws ASN1EncodingException {
304                 return processCollection(data);
305         }
306
307         /*
308          * (non-Javadoc)
309          * 
310          * @see
311          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
312          * .builtin.CHOICE)
313          */
314         public EncodedOctets visit(CHOICE data) throws ASN1EncodingException {
315                 return encode(data.selectedValue(), data.selectedTag(), null);
316         }
317
318         /*
319          * (non-Javadoc)
320          * 
321          * @see
322          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
323          * .builtin.OBJECT_IDENTIFIER)
324          */
325         public EncodedOctets visit(OBJECT_IDENTIFIER data)
326                         throws ASN1EncodingException {
327                 if (data.value().size() < 2 || data.value().get(0) < 0
328                                 || 2 < data.value().get(0) || data.value().get(1) < 0
329                                 || 39 < data.value().get(1)) {
330                         ASN1EncodingException ex = new ASN1EncodingException();
331                         ex.setMessage("Invalid OBJECT IDENTIFIER value.", null,
332                                         data.getClass(), null, data);
333                         throw ex;
334                 }
335                 byte[] encoded = new byte[calculateEncodedOidSize(data, 2) + 1];
336                 encoded[0] = (byte) (data.value().get(0) * 40 + data.value().get(1));
337                 encodeOid(data, encoded, 2, 1);
338                 return newPrimitiveOctets(encoded);
339         }
340         
341         /* (non-Javadoc)
342          * @see jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type.builtin.RELATIVE_OID)
343          */
344         public EncodedOctets visit(RELATIVE_OID data) throws ASN1EncodingException {
345                 byte[] encoded = new byte[calculateEncodedOidSize(data, 0)];
346                 encodeOid(data, encoded, 0, 0);
347                 return newPrimitiveOctets(encoded);
348         }       
349
350         private int calculateEncodedOidSize(OBJECT_IDENTIFIER data, int start) throws ASN1EncodingException {
351                 int size = 0;
352                 for (int i = start; i < data.value().size(); i++) {
353                         if (data.value().get(i) < 0) {
354                                 ASN1EncodingException ex = new ASN1EncodingException();
355                                 ex.setMessage(
356                                                 "OBJECT IDENTIFIER value must be a positive number.",
357                                                 null, data.getClass(), null, data);
358                                 throw ex;
359                         }
360                         size += sizeBy7bits(data.value().get(i));
361                 }
362                 return size;
363         }
364         
365         private void encodeOid(OBJECT_IDENTIFIER data, byte[] dest, int start, int offset) {
366                 for (int i = start; i < data.value().size(); i++) {
367                         offset += encodeToMutipleOctets(dest, offset, data.value().get(i));
368                 }
369         }
370         
371         /*
372          * (non-Javadoc)
373          * 
374          * @see
375          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
376          * .StringType)
377          */
378         public EncodedOctets visit(StringType data) throws ASN1EncodingException {
379                 return newPrimitiveOctets(data.value());
380         }
381
382         /*
383          * (non-Javadoc)
384          * 
385          * @see
386          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
387          * .TimeType)
388          */
389         public EncodedOctets visit(TimeType data) throws ASN1EncodingException {
390                 return newPrimitiveOctets(data.value());
391         }
392
393         /*
394          * (non-Javadoc)
395          * 
396          * @see
397          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
398          * .builtin.ANY)
399          */
400         public EncodedOctets visit(ANY data) throws ASN1EncodingException {
401                 return encode(data.value(), null, null);
402         }
403
404         /*
405          * (non-Javadoc)
406          * 
407          * @see
408          * jp.bitmeister.asn1.processor.ASN1Visitor#visit(jp.bitmeister.asn1.type
409          * .UnknownType)
410          */
411         public EncodedOctets visit(UnknownType data) throws ASN1EncodingException {
412                 EncodedOctets octets = newPrimitiveOctets(data.value());
413                 octets.fix(data.tagClass(), data.tagNumber());
414                 return octets;
415         }
416
417         /**
418          * Encodes each element of the {@code ConstructiveType} data.
419          * 
420          * @param data
421          *            The data to be encoded.
422          * @throws ASN1EncodingException
423          *             When an error occurred while the encoding process.
424          */
425         ConstructedOctets processConstructive(ConstructiveType data)
426                         throws ASN1EncodingException {
427                 ConstructedOctets octets = newConstructedOctets();
428                 for (ElementSpecification e : data.getElementTypeList()) {
429                         ASN1Type element = data.getComponent(e);
430                         if (element == null || !element.hasValue()) {
431                                 continue;
432                         }
433                         octets.addElement(encode(element, e.tag(), null));
434                 }
435                 return octets;
436         }
437
438         /**
439          * Encodes each component of the {@code CollectionType} data.
440          * 
441          * @param data
442          *            The data to be encoded.
443          * @throws ASN1EncodingException
444          *             When an error occurred while the encoding process.
445          */
446         ConstructedOctets processCollection(CollectionType<? extends ASN1Type, ?> data)
447                         throws ASN1EncodingException {
448                 ConstructedOctets octets = newConstructedOctets();
449                 for (ASN1Type e : data.collection()) {
450                         octets.addElement(encode(e, null, null));
451                 }
452                 return octets;
453         }
454
455         /**
456          * Encodes ASN.1 tag to octets.
457          * 
458          * @param tagClass
459          *            The tag class.
460          * @param tagNumber
461          *            The tag number.
462          * @param isConstructed
463          *            {@code true} the data applied to this tag is constructed.
464          * @return Encoded octets.
465          */
466         byte[] encodeTag(ASN1TagClass tagClass, int tagNumber, boolean isConstructed) {
467                 byte leading = 0;
468                 switch (tagClass) {
469                 case UNIVERSAL:
470                         // 0x00;
471                         break;
472                 case APPLICATION:
473                         leading = 0x40;
474                         break;
475                 case CONTEXT_SPECIFIC:
476                         leading = (byte) 0x80;
477                         break;
478                 case PRIVATE:
479                         leading = (byte) 0xc0;
480                         break;
481                 }
482                 if (isConstructed) {
483                         // constructed.
484                         leading |= 0x20;
485                 }
486                 if (tagNumber <= 0x1e) {
487                         leading |= tagNumber;
488                         return new byte[] { leading };
489                 }
490                 leading |= 0x1f;
491                 int size = sizeBy7bits(tagNumber);
492                 byte[] id = new byte[size + 1];
493                 id[0] = leading;
494                 encodeToMutipleOctets(id, 1, tagNumber);
495                 return id;
496         }
497
498         /**
499          * Encodes the length to octets.
500          * 
501          * @param length
502          *            The length.
503          * @return Encoded octets.
504          */
505         byte[] encodeLength(int length) {
506                 if (length <= 0x7f) {
507                         // length in short form.
508                         return new byte[] { (byte) length };
509                 }
510                 // length in long form.
511                 byte[] value = BigInteger.valueOf(length).toByteArray();
512                 byte[] encoded = new byte[value.length + 1];
513                 encoded[0] = (byte) (value.length | 0x80);
514                 System.arraycopy(value, 0, encoded, 1, value.length);
515                 return encoded;
516         }
517
518         /**
519          * Encodes the value to long form octets.
520          * 
521          * @param dest
522          *            The array of byte where the result to be written.
523          * @param offset
524          *            The index in the {@code dest} array that indicates where the
525          *            result to be written.
526          * @param value
527          *            The integer value.
528          * @return The size of the result.
529          */
530         private int encodeToMutipleOctets(byte[] dest, int offset, long value) {
531                 int size = sizeBy7bits(value);
532                 int lastIndex = offset + size - 1;
533                 for (int index = lastIndex; index >= offset; index--) {
534                         dest[index] |= (byte) (value & 0x7f);
535                         if (index != lastIndex) {
536                                 dest[index] |= 0x80;
537                         }
538                         value >>= 7;
539                 }
540                 return size;
541         }
542
543         /**
544          * Estimates the size of the result that the value is encoded to long form.
545          * 
546          * @param value
547          *            The value to be encoded.
548          * @return Estimated size.
549          */
550         private int sizeBy7bits(long value) {
551                 int size = 1;
552                 while ((value >>= 7) > 0) {
553                         size++;
554                 }
555                 return size;
556         }
557
558         /**
559          * Instantiates a new primitive octets.
560          * 
561          * @param contents
562          *            The content octets.
563          * @return An instance of primitive octets.
564          */
565         EncodedOctets newPrimitiveOctets(byte... contents) {
566                 return new BerPrimitiveOctets(contents);
567         }
568
569         /**
570          * Instantiates a new constructed octets.
571          * 
572          * @return An instance of constructed octets.
573          */
574         ConstructedOctets newConstructedOctets() {
575                 return new BerConstructedOctets();
576         }
577
578         /**
579          * Abstract base class for classes represent BER encoded octets.
580          * 
581          * @author WATANABE, Jun. <jwat at bitmeister.jp>
582          */
583         abstract class BerOctets implements EncodedOctets {
584
585                 byte[] identifier;
586
587                 byte[] length;
588
589                 /**
590                  * Returns BER encoded octets length includes prefix and contents.
591                  * 
592                  * @return Total length of BER encoded octets.
593                  */
594                 public int totalLength() {
595                         return identifier.length + length.length + contentsLength();
596                 }
597
598                 /**
599                  * Sets identifier and length octets to fix this octets.
600                  * 
601                  * @param tagClass
602                  *            The ASN.1 tag class for this data.
603                  * @param tagNumber
604                  *            The tag number for this data.
605                  */
606                 public void fix(ASN1TagClass tagClass, int tagNumber) {
607                         identifier = encodeTag(tagClass, tagNumber, isConstructed());
608                         length = encodeLength(contentsLength());
609                 }
610
611                 /**
612                  * Writes all BER encoded octets to the {@code OutputStream}
613                  * 
614                  * @param out
615                  *            The stream to be written.
616                  * @throws IOException
617                  *             when {@code IOException} thrown by {@code OutputStream}.
618                  */
619                 public int write(OutputStream out) throws IOException {
620                         out.write(identifier);
621                         out.write(length);
622                         writeContents(out);
623                         return totalLength();
624                 }
625
626                 /**
627                  * Writes contents octets to the {@code OutputStream}.
628                  * 
629                  * @param out
630                  *            The stream to be written.
631                  * @throws IOException
632                  *             when {@code OutputStream} throws {@code IOException}.
633                  */
634                 abstract void writeContents(OutputStream out) throws IOException;
635
636         }
637
638         /**
639          * Represents primitive BER octets.
640          * 
641          * <p>
642          * This class represents a BER encoded octets that has only one contents
643          * octets.
644          * </p>
645          * 
646          * @author WATANABE, Jun. <jwat at bitmeister.jp>
647          */
648         class BerPrimitiveOctets extends BerOctets {
649
650                 private byte[] contents;
651
652                 /**
653                  * Instantiates a {@code PrimitiveOctets}.
654                  * 
655                  * @param contents
656                  */
657                 BerPrimitiveOctets(byte... contents) {
658                         this.contents = contents;
659                 }
660
661                 /*
662                  * (non-Javadoc)
663                  * 
664                  * @see jp.bitmeister.asn1.codec.ber.BerOctets#isConstructed()
665                  */
666                 public boolean isConstructed() {
667                         return false;
668                 }
669
670                 /*
671                  * (non-Javadoc)
672                  * 
673                  * @see
674                  * jp.bitmeister.asn1.codec.ber.BerEncoder2.BerOctets#contentsLength()
675                  */
676                 public int contentsLength() {
677                         return contents.length;
678                 }
679
680                 /*
681                  * (non-Javadoc)
682                  * 
683                  * @see
684                  * jp.bitmeister.asn1.codec.ber.BerEncoder2.BerOctets#writeContents(
685                  * java.io.OutputStream)
686                  */
687                 void writeContents(OutputStream out) throws IOException {
688                         out.write(contents);
689                 }
690
691         }
692
693         /**
694          * Represents constructed BER octets.
695          * 
696          * <p>
697          * This class represents a BER encoded octets that contains some contents
698          * octets.
699          * </p>
700          * 
701          * @author WATANABE, Jun. <jwat at bitmeister.jp>
702          */
703         class BerConstructedOctets extends BerOctets implements ConstructedOctets {
704
705                 private List<EncodedOctets> elements = new ArrayList<EncodedOctets>();
706
707                 private int length;
708
709                 /**
710                  * Appends an element to this octets.
711                  * 
712                  * @param element
713                  *            The element to be added.
714                  */
715                 public void addElement(EncodedOctets element) {
716                         elements.add(element);
717                         length += element.totalLength();
718                 }
719
720                 /*
721                  * (non-Javadoc)
722                  * 
723                  * @see jp.bitmeister.asn1.codec.ber.BerOctets#isConstructed()
724                  */
725                 public boolean isConstructed() {
726                         return true;
727                 }
728
729                 /*
730                  * (non-Javadoc)
731                  * 
732                  * @see jp.bitmeister.asn1.codec.ber.BerOctets#octetsLength()
733                  */
734                 public int contentsLength() {
735                         return length;
736                 }
737
738                 /*
739                  * (non-Javadoc)
740                  * 
741                  * @see
742                  * jp.bitmeister.asn1.codec.ber.BerEncoder.BerOctets#writeContents(java
743                  * .io.OutputStream)
744                  */
745                 void writeContents(OutputStream out) throws IOException {
746                         for (EncodedOctets e : elements) {
747                                 e.write(out);
748                         }
749                 }
750
751         }
752
753 }