Sometimes all you need to compress a byte array and decompress it later. You do not want to handle all the memory buffer allocations. Two methods have been added to LZ4Codec (not released yet).

Note, for now it is using regular compression (not HC). Just replace Encode(...) with EncodeHC(...) if you need HC variant.

#region Envelope

private const int WRAP_OFFSET_0 = 0;
private const int WRAP_OFFSET_4 = sizeof(int);
private const int WRAP_OFFSET_8 = 2 * sizeof(int);
private const int WRAP_LENGTH = WRAP_OFFSET_8;

private static void Poke4(byte[] buffer, int offset, uint value)
{
    buffer[offset + 0] = (byte)value;
    buffer[offset + 1] = (byte)(value >> 8);
    buffer[offset + 2] = (byte)(value >> 16);
    buffer[offset + 3] = (byte)(value >> 24);
}

private static uint Peek4(byte[] buffer, int offset)
{
    // NOTE: It's faster than BitConverter.ToUInt32 (suprised? me too)
    return
        ((uint)buffer[offset]) |
        ((uint)buffer[offset + 1] << 8) |
        ((uint)buffer[offset + 2] << 16) |
        ((uint)buffer[offset + 3] << 24);
}

public static byte[] Wrap(
    byte[] inputBuffer, int inputOffset = 0, int inputLength = int.MaxValue)
{
    inputLength = Math.Min(inputBuffer.Length - inputOffset, inputLength);
    if (inputLength < 0)
        throw new ArgumentException("inputBuffer size of inputLength is invalid");
    if (inputLength == 0)
        return new byte[WRAP_LENGTH];

    var outputLength = inputLength; // MaximumOutputLength(inputLength);
    var outputBuffer = new byte[outputLength];
    outputLength = Encode(
        inputBuffer, inputOffset, inputLength, outputBuffer, 0, outputLength);

    byte[] result;

    if (outputLength >= inputLength || outputLength == 0)
    {
        result = new byte[inputLength + WRAP_LENGTH];
        Poke4(result, WRAP_OFFSET_0, (uint)inputLength);
        Poke4(result, WRAP_OFFSET_4, (uint)inputLength);
        Buffer.BlockCopy(inputBuffer, inputOffset, result, WRAP_OFFSET_8, inputLength);
    }
    else
    {
        result = new byte[outputLength + WRAP_LENGTH];
        Poke4(result, WRAP_OFFSET_0, (uint)inputLength);
        Poke4(result, WRAP_OFFSET_4, (uint)outputLength);
        Buffer.BlockCopy(outputBuffer, 0, result, WRAP_OFFSET_8, outputLength);
    }

    return result;
}

public static byte[] Unwrap(
    byte[] inputBuffer, int inputOffset = 0)
{
    var inputLength = inputBuffer.Length - inputOffset;
    if (inputLength < WRAP_LENGTH)
        throw new ArgumentException("inputBuffer size is invalid");

    var outputLength = (int)Peek4(inputBuffer, inputOffset + WRAP_OFFSET_0);
    inputLength = (int)Peek4(inputBuffer, inputOffset + WRAP_OFFSET_4);
    if (inputLength > inputBuffer.Length - inputOffset - WRAP_LENGTH)
        throw new ArgumentException("inputBuffer size is invalid or has been corrupted");

    byte[] result;

    if (inputLength >= outputLength)
    {
        result = new byte[inputLength];
        Buffer.BlockCopy(
            inputBuffer, inputOffset + WRAP_OFFSET_8, 
            result, 0, inputLength);
    }
    else
    {
        result = new byte[outputLength];
        Decode(
            inputBuffer, inputOffset + WRAP_OFFSET_8, inputLength, 
            result, 0, outputLength, 
            true);
    }

    return result;
}

#endregion