LoginSignup
1
0

More than 1 year has passed since last update.

[C#] BrotliEncoder/BrotliDecoderの使い方

Last updated at Posted at 2021-05-20

この記事の目的

C#でBrotliEncoder/BrotliDecoderを使った際に苦戦したので、試行錯誤の結果を自分以外の人に共有したい。

前提条件

  • .Net 6を想定。
  • エンコードとデコードのInputはReadOnlySequence<byte>、OutputはIBufferWriter<byte>とする。

サンプルコード

Compress

public static void Compress(ReadOnlySequence<byte> sequence, IBufferWriter<byte> writer)
{
    using var encoder = new BrotliEncoder(11, 24);

    var reader = new SequenceReader<byte>(sequence);

    for (; ; )
    {
        var status = encoder.Compress(reader.UnreadSpan, writer.GetSpan(), out var consumed, out var written, false);
        if (status == OperationStatus.InvalidData) throw new Exception("invalid data");

        reader.Advance(consumed);
        writer.Advance(written);
        if (status == OperationStatus.Done) break;
    }

    for (; ; )
    {
        var status = encoder.Compress(ReadOnlySpan<byte>.Empty, writer.GetSpan(), out _, out var written, true);
        if (status == OperationStatus.InvalidData) throw new Exception("invalid data");

        writer.Advance(written);
        if (written == 0) break;
    }
}

訂正 (2022/10/08)

neueccさんにご指摘いただき、Compressが正しく処理できていないことが分かりました:bow_tone1:

statusOperationStatus.Doneなら圧縮完了だと理解していたのですが、正しくは

The entire input buffer has been processed and the operation is complete.

とドキュメントにも記載されている通り、inputの処理が完了したのみで、flush処理を別途行う必要がありました...

neueccさんありがとうございました:bow_tone1:

Decompress

public static void Decompress(ReadOnlySequence<byte> sequence, IBufferWriter<byte> writer)
{
    var reader = new SequenceReader<byte>(sequence);

    using var decoder = new BrotliDecoder();

    for (; ; )
    {
        var status = decoder.Decompress(reader.UnreadSpan, writer.GetSpan(), out var consumed, out var written);
        if (status == OperationStatus.InvalidData) throw new Exception("invalid data");

        reader.Advance(consumed);
        writer.Advance(written);
        if (written == 0) break;
    }
}

ハマったポイント

  • OperationStatus.DestinationTooSmallはエラーというよりも、destinationに最大まで書き込んだというお知らせなので、新しいdestinationを指定すればよい。
  • BrotliEncoder.CompressisFinalBlockにfalseを指定した場合、Decompress時にデータの末尾になってもOperationStatus.DoneではなくOperationStatus.NeedMoreDataが常に返ってくる。 -> isFinalBlock: trueで最後に処理すればOKでした

リンク

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0