<PackageReference Include="BouncyCastle.Cryptography" Version="2.7.0-beta.98" />

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 const int BufferSizePower = 16; private readonly Stream outStr; private readonly bool useOldFormat; private readonly int partialBufferLength; private readonly int partialPower; private byte[] partialBuffer; private int partialOffset; 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 WriteHeader(PacketTag packetTag, bool oldFormat, bool partial, long bodyLen) { int num = 128; if (partialBuffer != null) { PartialFlushLast(); partialBuffer = null; } if ((packetTag <= (PacketTag)15) & oldFormat) { num |= (int)packetTag << 2; if (partial) WriteByte((byte)(num | 3)); else if (bodyLen <= 255) { Span<byte> span = new Span<byte>(stackalloc byte[2], 2); span[0] = (byte)num; span[1] = (byte)bodyLen; Write(span); } else if (bodyLen <= 65535) { Span<byte> span2 = new Span<byte>(stackalloc byte[3], 3); span2[0] = (byte)(num | 1); Pack.UInt16_To_BE((ushort)bodyLen, span2, 1); Write(span2); } else { Span<byte> span3 = new Span<byte>(stackalloc byte[5], 5); span3[0] = (byte)(num | 2); Pack.UInt32_To_BE((uint)bodyLen, span3, 1); Write(span3); } } else { num |= (int)((PacketTag)64 | packetTag); WriteByte((byte)num); if (partial) partialOffset = 0; else StreamUtilities.WriteNewPacketLength(outStr, bodyLen, false); } } 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() { StreamUtilities.WriteNewPacketLength(outStr, partialOffset, false); 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); } 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); } internal static byte[] GetEncoded(BcpgObject bcpgObject) { MemoryStream memoryStream = new MemoryStream(); using (BcpgOutputStream bcpgOut = new BcpgOutputStream(memoryStream)) bcpgObject.Encode(bcpgOut); return memoryStream.ToArray(); } internal static byte[] GetEncodedOrNull(BcpgObject bcpgObject) { try { return GetEncoded(bcpgObject); } catch (Exception) { return null; } } } }