001: /* $Id: AsnOutputStream.java,v 1.1 2004/01/19 02:03:49 rgrimm Exp $
002: *
003: * Copyright (c) 2000 The Cryptix Foundation Limited. All rights reserved.
004: */
005:
006: package cryptix.jce.provider.asn;
007:
008: import java.io.ByteArrayOutputStream;
009: import java.io.IOException;
010: import java.io.OutputStream;
011:
012: /**
013: * Class for writing DER-encoded AsnObjects to an OutputStream.
014: *
015: * @version $Revision: 1.1 $
016: * @author Jeroen C. van Gelderen (gelderen@cryptix.org)
017: */
018: public final class AsnOutputStream {
019:
020: // Instance variables
021: //............................................................................
022:
023: private final OutputStream os;
024:
025: // Constructors and java.lang.Object overrides
026: //............................................................................
027:
028: /**
029: * Convenience method that constructs an instance on top of an
030: * internal ByteArrayOutputStream.
031: */
032: public AsnOutputStream() {
033: this .os = new ByteArrayOutputStream();
034: }
035:
036: /**
037: * Constructs an instance on top of the given OutputStream.
038: */
039: public AsnOutputStream(OutputStream os) {
040: this .os = os;
041: }
042:
043: // Public interface
044: //............................................................................
045:
046: /**
047: * Calls flush() then close() on the underlying stream. Exceptions are
048: * propagated up.
049: *
050: * @throws IOException
051: * When underlying stream does so.
052: */
053: public void close() throws IOException {
054: this .os.flush();
055: this .os.close();
056: }
057:
058: /**
059: * Calls flush() on the underlying stream. Exceptions are propagated up.
060: *
061: * @throws IOException
062: * When underlying stream does so.
063: */
064: public void flush() throws IOException {
065: this .os.flush();
066: }
067:
068: /**
069: * Writes a DER-encoded AsnObject to the underlying stream.
070: */
071: public void write(AsnObject obj) throws IOException {
072: obj.encode(this );
073: }
074:
075: /**
076: * Delegates to the underlying ByteArrayOutputStream if any.
077: *
078: * @throws IllegalStateException
079: * If the underlying stream is not a ByteArrayOutputStream.
080: */
081: public byte[] toByteArray() {
082:
083: if (!(this .os instanceof ByteArrayOutputStream))
084: throw new IllegalStateException(
085: "Underlying stream is not instanceof ByteArrayOutputStream.");
086:
087: ByteArrayOutputStream baos = (ByteArrayOutputStream) this .os;
088: return baos.toByteArray();
089: }
090:
091: // AsnObject.encode(...) callbacks and helpers
092: //............................................................................
093:
094: /**
095: * Returns the number of bytes writeLength() will write when called
096: * with the given 'len'. Yes, ASN/DER encoding sucks, don't get me started.
097: */
098: /*package*/int getLengthOfLength(int len) {
099: if (len <= 127)
100: return 1;
101: else if (len <= 0xFF)
102: return 2;
103: else if (len <= 0xFFFF)
104: return 3;
105: else if (len <= 0xFFFFFF)
106: return 4;
107: else
108: return 5;
109: }
110:
111: /*package*/void writeByte(byte b) throws IOException {
112: this .os.write(b & 0xFF);
113: }
114:
115: /*package*/void writeBytes(byte[] data) throws IOException {
116: this .os.write(data);
117: }
118:
119: /**
120: * Write a variable length length (yuk!) as per ASN.1/DER specification.
121: */
122: /*package*/void writeLength(int len) throws IOException {
123:
124: if (len < 0)
125: throw new IllegalArgumentException("len: < 0");
126:
127: // shortcut for short form
128: if (len <= 127) {
129: this .os.write((char) len);
130: return;
131: }
132:
133: // long form
134: int lenOfLenData = getLengthOfLength(len) - 1;
135: this .os.write((byte) (lenOfLenData | 0x80));
136: while (lenOfLenData-- > 0)
137: this .os.write((byte) (len >>> (lenOfLenData * 8)));
138: }
139:
140: /*package*/void writeType(byte type) throws IOException {
141: this.os.write(type);
142: }
143: }
|