1package org.bouncycastle.asn1; 2 3import java.io.IOException; 4import java.io.OutputStream; 5 6/** 7 * A generator for indefinite-length OCTET STRINGs 8 */ 9public class BEROctetStringGenerator 10 extends BERGenerator 11{ 12 /** 13 * Use the passed in stream as the target for the generator, writing out the header tag 14 * for a constructed OCTET STRING. 15 * 16 * @param out target stream 17 * @throws IOException if the target stream cannot be written to. 18 */ 19 public BEROctetStringGenerator(OutputStream out) 20 throws IOException 21 { 22 super(out); 23 24 writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING); 25 } 26 27 /** 28 * Use the passed in stream as the target for the generator, writing out the header tag 29 * for a tagged constructed OCTET STRING (possibly implicit). 30 * 31 * @param out target stream 32 * @param tagNo the tag number to introduce 33 * @param isExplicit true if this is an explicitly tagged object, false otherwise. 34 * @throws IOException if the target stream cannot be written to. 35 */ 36 public BEROctetStringGenerator( 37 OutputStream out, 38 int tagNo, 39 boolean isExplicit) 40 throws IOException 41 { 42 super(out, tagNo, isExplicit); 43 44 writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING); 45 } 46 47 /** 48 * Return a stream representing the content target for this OCTET STRING 49 * 50 * @return an OutputStream which chunks data in blocks of 1000 (CER limit). 51 */ 52 public OutputStream getOctetOutputStream() 53 { 54 return getOctetOutputStream(new byte[1000]); // limit for CER encoding. 55 } 56 57 /** 58 * Return a stream representing the content target for this OCTET STRING 59 * 60 * @param buf the buffer to use for chunking the data. 61 * @return an OutputStream which chunks data in blocks of buf length. 62 */ 63 public OutputStream getOctetOutputStream( 64 byte[] buf) 65 { 66 return new BufferedBEROctetStream(buf); 67 } 68 69 private class BufferedBEROctetStream 70 extends OutputStream 71 { 72 private byte[] _buf; 73 private int _off; 74 private DEROutputStream _derOut; 75 76 BufferedBEROctetStream( 77 byte[] buf) 78 { 79 _buf = buf; 80 _off = 0; 81 _derOut = new DEROutputStream(_out); 82 } 83 84 public void write( 85 int b) 86 throws IOException 87 { 88 _buf[_off++] = (byte)b; 89 90 if (_off == _buf.length) 91 { 92 DEROctetString.encode(_derOut, _buf); 93 _off = 0; 94 } 95 } 96 97 public void write(byte[] b, int off, int len) throws IOException 98 { 99 while (len > 0) 100 { 101 int numToCopy = Math.min(len, _buf.length - _off); 102 System.arraycopy(b, off, _buf, _off, numToCopy); 103 104 _off += numToCopy; 105 if (_off < _buf.length) 106 { 107 break; 108 } 109 110 DEROctetString.encode(_derOut, _buf); 111 _off = 0; 112 113 off += numToCopy; 114 len -= numToCopy; 115 } 116 } 117 118 public void close() 119 throws IOException 120 { 121 if (_off != 0) 122 { 123 byte[] bytes = new byte[_off]; 124 System.arraycopy(_buf, 0, bytes, 0, _off); 125 126 DEROctetString.encode(_derOut, bytes); 127 } 128 129 writeBEREnd(); 130 } 131 } 132} 133