<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.0" />

BcpgOutputStream

using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Utilities.IO; using System; using System.IO; namespace Org.BouncyCastle.Bcpg { public class BcpgOutputStream : BaseOutputStream { private Stream outStr; private bool useOldFormat; private byte[] partialBuffer; private int partialBufferLength; private int partialPower; private int partialOffset; private const int BufferSizePower = 16; internal static BcpgOutputStream Wrap(Stream outStr) { BcpgOutputStream bcpgOutputStream = outStr as BcpgOutputStream; if (bcpgOutputStream != null) return bcpgOutputStream; return new BcpgOutputStream(outStr); } public BcpgOutputStream(Stream outStr) : this(outStr, false) { } public BcpgOutputStream(Stream outStr, bool newFormatOnly) { if (outStr == null) throw new ArgumentNullException("outStr"); this.outStr = outStr; useOldFormat = !newFormatOnly; } public BcpgOutputStream(Stream outStr, PacketTag tag) { if (outStr == null) throw new ArgumentNullException("outStr"); this.outStr = outStr; WriteHeader(tag, true, true, 0); } public BcpgOutputStream(Stream outStr, PacketTag tag, long length, bool oldFormat) { if (outStr == null) throw new ArgumentNullException("outStr"); this.outStr = outStr; if (length > uint.MaxValue) { WriteHeader(tag, false, true, 0); partialBufferLength = 65536; partialBuffer = new byte[partialBufferLength]; partialPower = 16; partialOffset = 0; } else WriteHeader(tag, oldFormat, false, length); } public BcpgOutputStream(Stream outStr, PacketTag tag, long length) { if (outStr == null) throw new ArgumentNullException("outStr"); this.outStr = outStr; WriteHeader(tag, false, false, length); } public BcpgOutputStream(Stream outStr, PacketTag tag, byte[] buffer) { if (outStr == null) throw new ArgumentNullException("outStr"); this.outStr = outStr; WriteHeader(tag, false, true, 0); partialBuffer = buffer; uint num = (uint)partialBuffer.Length; partialPower = 0; while (num != 1) { num >>= 1; partialPower++; } if (partialPower > 30) throw new IOException("Buffer cannot be greater than 2^30 in length."); partialBufferLength = 1 << partialPower; partialOffset = 0; } private unsafe void WriteNewPacketLength(long bodyLen) { if (bodyLen < 192) outStr.WriteByte((byte)bodyLen); else if (bodyLen <= 8383) { bodyLen -= 192; outStr.WriteByte((byte)(((bodyLen >> 8) & 255) + 192)); outStr.WriteByte((byte)bodyLen); } else { Span<byte> span = new Span<byte>(stackalloc byte[5], 5); span[0] = byte.MaxValue; Pack.UInt32_To_BE((uint)bodyLen, span, 1); outStr.Write(span); } } private unsafe void WriteHeader(PacketTag packetTag, bool oldPackets, bool partial, long bodyLen) { int num = 128; if (partialBuffer != null) { PartialFlushLast(); partialBuffer = null; } if ((packetTag <= (PacketTag)15) & oldPackets) { num |= (int)packetTag << 2; if (partial) WriteByte((byte)(num | 3)); else if (bodyLen <= 255) { WriteByte((byte)num); WriteByte((byte)bodyLen); } else if (bodyLen <= 65535) { WriteByte((byte)(num | 1)); WriteByte((byte)(bodyLen >> 8)); WriteByte((byte)bodyLen); } else { Span<byte> span = new Span<byte>(stackalloc byte[5], 5); span[0] = (byte)(num | 2); Pack.UInt32_To_BE((uint)bodyLen, span, 1); Write(span); } } else { num |= (int)((PacketTag)64 | packetTag); WriteByte((byte)num); if (partial) partialOffset = 0; else WriteNewPacketLength(bodyLen); } } private void PartialFlush() { outStr.WriteByte((byte)(224 | partialPower)); outStr.Write(partialBuffer, 0, partialBufferLength); partialOffset = 0; } private void PartialFlush(ref ReadOnlySpan<byte> buffer) { outStr.WriteByte((byte)(224 | partialPower)); outStr.Write(buffer.Slice(0, partialBufferLength)); int num = partialBufferLength; buffer = buffer.Slice(num, buffer.Length - num); } private void PartialFlushLast() { WriteNewPacketLength(partialOffset); outStr.Write(partialBuffer, 0, partialOffset); partialOffset = 0; } private void PartialWrite(byte[] buffer, int offset, int count) { Streams.ValidateBufferArguments(buffer, offset, count); PartialWrite(buffer.AsSpan(offset, count)); } private void PartialWrite(ReadOnlySpan<byte> buffer) { if (partialOffset == partialBufferLength) PartialFlush(); if (buffer.Length <= partialBufferLength - partialOffset) { buffer.CopyTo(partialBuffer.AsSpan(partialOffset)); partialOffset += buffer.Length; } else { int num = partialBufferLength - partialOffset; buffer.Slice(0, num).CopyTo(partialBuffer.AsSpan(partialOffset)); int num2 = num; buffer = buffer.Slice(num2, buffer.Length - num2); PartialFlush(); while (buffer.Length > partialBufferLength) { PartialFlush(ref buffer); } buffer.CopyTo(partialBuffer); partialOffset = buffer.Length; } } private void PartialWriteByte(byte value) { if (partialOffset == partialBufferLength) PartialFlush(); partialBuffer[partialOffset++] = value; } public override void Write(byte[] buffer, int offset, int count) { if (partialBuffer != null) PartialWrite(buffer, offset, count); else outStr.Write(buffer, offset, count); } public override void Write(ReadOnlySpan<byte> buffer) { if (partialBuffer != null) PartialWrite(buffer); else outStr.Write(buffer); } public override void WriteByte(byte value) { if (partialBuffer != null) PartialWriteByte(value); else outStr.WriteByte(value); } internal virtual void WriteShort(short n) { Write((byte)(n >> 8), (byte)n); } internal virtual void WriteInt(int n) { Write((byte)(n >> 24), (byte)(n >> 16), (byte)(n >> 8), (byte)n); } internal virtual void WriteLong(long n) { Write((byte)(n >> 56), (byte)(n >> 48), (byte)(n >> 40), (byte)(n >> 32), (byte)(n >> 24), (byte)(n >> 16), (byte)(n >> 8), (byte)n); } public void WritePacket(ContainedPacket p) { p.Encode(this); } internal void WritePacket(PacketTag tag, byte[] body) { WritePacket(tag, body, useOldFormat); } internal void WritePacket(PacketTag tag, byte[] body, bool oldFormat) { WriteHeader(tag, oldFormat, false, body.Length); Write(body); } public void WriteObject(BcpgObject bcpgObject) { bcpgObject.Encode(this); } public void WriteObjects(params BcpgObject[] v) { for (int i = 0; i < v.Length; i++) { v[i].Encode(this); } } public override void Flush() { outStr.Flush(); } public void Finish() { if (partialBuffer != null) { PartialFlushLast(); Array.Clear(partialBuffer, 0, partialBuffer.Length); partialBuffer = null; } } protected override void Dispose(bool disposing) { if (disposing) { Finish(); outStr.Flush(); outStr.Dispose(); } base.Dispose(disposing); } } }