using System.Buffers.Binary; namespace MxNativeCodec; public sealed class NmxTransferEnvelopeTemplate { public const int HeaderLength = 46; public const int InnerLengthOffset = 2; private readonly byte[] _header; private NmxTransferEnvelopeTemplate(byte[] header) { _header = header; } public static NmxTransferEnvelopeTemplate FromObserved(ReadOnlySpan observedTransferBody) { if (observedTransferBody.Length < HeaderLength) { throw new ArgumentException("Observed TransferData body is too short.", nameof(observedTransferBody)); } int innerLength = BinaryPrimitives.ReadInt32LittleEndian(observedTransferBody.Slice(InnerLengthOffset, sizeof(int))); if (innerLength != observedTransferBody.Length - HeaderLength) { throw new ArgumentException("Observed TransferData body does not contain the expected inner length.", nameof(observedTransferBody)); } return new NmxTransferEnvelopeTemplate(observedTransferBody[..HeaderLength].ToArray()); } public byte[] Encode(ReadOnlySpan innerPutRequestBody) { byte[] body = new byte[HeaderLength + innerPutRequestBody.Length]; _header.CopyTo(body, 0); BinaryPrimitives.WriteInt32LittleEndian(body.AsSpan(InnerLengthOffset, sizeof(int)), innerPutRequestBody.Length); innerPutRequestBody.CopyTo(body.AsSpan(HeaderLength)); return body; } public ReadOnlyMemory DecodeInner(ReadOnlyMemory transferBody) { if (transferBody.Length < HeaderLength) { throw new ArgumentException("TransferData body is too short.", nameof(transferBody)); } int innerLength = BinaryPrimitives.ReadInt32LittleEndian(transferBody.Span.Slice(InnerLengthOffset, sizeof(int))); if (innerLength != transferBody.Length - HeaderLength) { throw new ArgumentException("TransferData body inner length does not match the body size.", nameof(transferBody)); } return transferBody[HeaderLength..]; } }