Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pg/src/main/java/org/spongycastle/bcpg/BCPGOutputStream.java')
-rw-r--r--pg/src/main/java/org/spongycastle/bcpg/BCPGOutputStream.java361
1 files changed, 361 insertions, 0 deletions
diff --git a/pg/src/main/java/org/spongycastle/bcpg/BCPGOutputStream.java b/pg/src/main/java/org/spongycastle/bcpg/BCPGOutputStream.java
new file mode 100644
index 00000000..560a6456
--- /dev/null
+++ b/pg/src/main/java/org/spongycastle/bcpg/BCPGOutputStream.java
@@ -0,0 +1,361 @@
+package org.spongycastle.bcpg;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Basic output stream.
+ */
+public class BCPGOutputStream
+ extends OutputStream
+ implements PacketTags, CompressionAlgorithmTags
+{
+ OutputStream out;
+ private byte[] partialBuffer;
+ private int partialBufferLength;
+ private int partialPower;
+ private int partialOffset;
+
+ private static final int BUF_SIZE_POWER = 16; // 2^16 size buffer on long files
+
+ public BCPGOutputStream(
+ OutputStream out)
+ {
+ this.out = out;
+ }
+
+ /**
+ * Create a stream representing an old style partial object.
+ *
+ * @param tag the packet tag for the object.
+ */
+ public BCPGOutputStream(
+ OutputStream out,
+ int tag)
+ throws IOException
+ {
+ this.out = out;
+ this.writeHeader(tag, true, true, 0);
+ }
+
+ /**
+ * Create a stream representing a general packet.
+ *
+ * @param out
+ * @param tag
+ * @param length
+ * @param oldFormat
+ * @throws IOException
+ */
+ public BCPGOutputStream(
+ OutputStream out,
+ int tag,
+ long length,
+ boolean oldFormat)
+ throws IOException
+ {
+ this.out = out;
+
+ if (length > 0xFFFFFFFFL)
+ {
+ this.writeHeader(tag, false, true, 0);
+ this.partialBufferLength = 1 << BUF_SIZE_POWER;
+ this.partialBuffer = new byte[partialBufferLength];
+ this.partialPower = BUF_SIZE_POWER;
+ this.partialOffset = 0;
+ }
+ else
+ {
+ this.writeHeader(tag, oldFormat, false, length);
+ }
+ }
+
+ /**
+ *
+ * @param tag
+ * @param length
+ * @throws IOException
+ */
+ public BCPGOutputStream(
+ OutputStream out,
+ int tag,
+ long length)
+ throws IOException
+ {
+ this.out = out;
+
+ this.writeHeader(tag, false, false, length);
+ }
+
+ /**
+ * Create a new style partial input stream buffered into chunks.
+ *
+ * @param out output stream to write to.
+ * @param tag packet tag.
+ * @param buffer size of chunks making up the packet.
+ * @throws IOException
+ */
+ public BCPGOutputStream(
+ OutputStream out,
+ int tag,
+ byte[] buffer)
+ throws IOException
+ {
+ this.out = out;
+ this.writeHeader(tag, false, true, 0);
+
+ this.partialBuffer = buffer;
+
+ int length = partialBuffer.length;
+
+ for (partialPower = 0; length != 1; partialPower++)
+ {
+ length >>>= 1;
+ }
+
+ if (partialPower > 30)
+ {
+ throw new IOException("Buffer cannot be greater than 2^30 in length.");
+ }
+
+ this.partialBufferLength = 1 << partialPower;
+ this.partialOffset = 0;
+ }
+
+ private void writeNewPacketLength(
+ long bodyLen)
+ throws IOException
+ {
+ if (bodyLen < 192)
+ {
+ out.write((byte)bodyLen);
+ }
+ else if (bodyLen <= 8383)
+ {
+ bodyLen -= 192;
+
+ out.write((byte)(((bodyLen >> 8) & 0xff) + 192));
+ out.write((byte)bodyLen);
+ }
+ else
+ {
+ out.write(0xff);
+ out.write((byte)(bodyLen >> 24));
+ out.write((byte)(bodyLen >> 16));
+ out.write((byte)(bodyLen >> 8));
+ out.write((byte)bodyLen);
+ }
+ }
+
+ private void writeHeader(
+ int tag,
+ boolean oldPackets,
+ boolean partial,
+ long bodyLen)
+ throws IOException
+ {
+ int hdr = 0x80;
+
+ if (partialBuffer != null)
+ {
+ partialFlush(true);
+ partialBuffer = null;
+ }
+
+ if (oldPackets)
+ {
+ hdr |= tag << 2;
+
+ if (partial)
+ {
+ this.write(hdr | 0x03);
+ }
+ else
+ {
+ if (bodyLen <= 0xff)
+ {
+ this.write(hdr);
+ this.write((byte)bodyLen);
+ }
+ else if (bodyLen <= 0xffff)
+ {
+ this.write(hdr | 0x01);
+ this.write((byte)(bodyLen >> 8));
+ this.write((byte)(bodyLen));
+ }
+ else
+ {
+ this.write(hdr | 0x02);
+ this.write((byte)(bodyLen >> 24));
+ this.write((byte)(bodyLen >> 16));
+ this.write((byte)(bodyLen >> 8));
+ this.write((byte)bodyLen);
+ }
+ }
+ }
+ else
+ {
+ hdr |= 0x40 | tag;
+ this.write(hdr);
+
+ if (partial)
+ {
+ partialOffset = 0;
+ }
+ else
+ {
+ this.writeNewPacketLength(bodyLen);
+ }
+ }
+ }
+
+ private void partialFlush(
+ boolean isLast)
+ throws IOException
+ {
+ if (isLast)
+ {
+ writeNewPacketLength(partialOffset);
+ out.write(partialBuffer, 0, partialOffset);
+ }
+ else
+ {
+ out.write(0xE0 | partialPower);
+ out.write(partialBuffer, 0, partialBufferLength);
+ }
+
+ partialOffset = 0;
+ }
+
+ private void writePartial(
+ byte b)
+ throws IOException
+ {
+ if (partialOffset == partialBufferLength)
+ {
+ partialFlush(false);
+ }
+
+ partialBuffer[partialOffset++] = b;
+ }
+
+ private void writePartial(
+ byte[] buf,
+ int off,
+ int len)
+ throws IOException
+ {
+ if (partialOffset == partialBufferLength)
+ {
+ partialFlush(false);
+ }
+
+ if (len <= (partialBufferLength - partialOffset))
+ {
+ System.arraycopy(buf, off, partialBuffer, partialOffset, len);
+ partialOffset += len;
+ }
+ else
+ {
+ System.arraycopy(buf, off, partialBuffer, partialOffset, partialBufferLength - partialOffset);
+ off += partialBufferLength - partialOffset;
+ len -= partialBufferLength - partialOffset;
+ partialFlush(false);
+
+ while (len > partialBufferLength)
+ {
+ System.arraycopy(buf, off, partialBuffer, 0, partialBufferLength);
+ off += partialBufferLength;
+ len -= partialBufferLength;
+ partialFlush(false);
+ }
+
+ System.arraycopy(buf, off, partialBuffer, 0, len);
+ partialOffset += len;
+ }
+ }
+
+ public void write(
+ int b)
+ throws IOException
+ {
+ if (partialBuffer != null)
+ {
+ writePartial((byte)b);
+ }
+ else
+ {
+ out.write(b);
+ }
+ }
+
+ public void write(
+ byte[] bytes,
+ int off,
+ int len)
+ throws IOException
+ {
+ if (partialBuffer != null)
+ {
+ writePartial(bytes, off, len);
+ }
+ else
+ {
+ out.write(bytes, off, len);
+ }
+ }
+
+ public void writePacket(
+ ContainedPacket p)
+ throws IOException
+ {
+ p.encode(this);
+ }
+
+ void writePacket(
+ int tag,
+ byte[] body,
+ boolean oldFormat)
+ throws IOException
+ {
+ this.writeHeader(tag, oldFormat, false, body.length);
+ this.write(body);
+ }
+
+ public void writeObject(
+ BCPGObject o)
+ throws IOException
+ {
+ o.encode(this);
+ }
+
+ /**
+ * Flush the underlying stream.
+ */
+ public void flush()
+ throws IOException
+ {
+ out.flush();
+ }
+
+ /**
+ * Finish writing out the current packet without closing the underlying stream.
+ */
+ public void finish()
+ throws IOException
+ {
+ if (partialBuffer != null)
+ {
+ partialFlush(true);
+ partialBuffer = null;
+ }
+ }
+
+ public void close()
+ throws IOException
+ {
+ this.finish();
+ out.flush();
+ out.close();
+ }
+}