summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jxl/box_content_decoder.cc
blob: c4cba3a31aee7abe8bf837a26cffe04693f95e07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "lib/jxl/box_content_decoder.h"

#include "lib/jxl/sanitizers.h"

namespace jxl {

JxlBoxContentDecoder::JxlBoxContentDecoder() {}

JxlBoxContentDecoder::~JxlBoxContentDecoder() {
  if (brotli_dec) {
    BrotliDecoderDestroyInstance(brotli_dec);
  }
}

void JxlBoxContentDecoder::StartBox(bool brob_decode, bool box_until_eof,
                                    size_t contents_size) {
  if (brotli_dec) {
    BrotliDecoderDestroyInstance(brotli_dec);
    brotli_dec = nullptr;
  }
  header_done_ = false;
  brob_decode_ = brob_decode;
  box_until_eof_ = box_until_eof;
  remaining_ = box_until_eof ? 0 : contents_size;
  pos_ = 0;
}

JxlDecoderStatus JxlBoxContentDecoder::Process(const uint8_t* next_in,
                                               size_t avail_in, size_t box_pos,
                                               uint8_t** next_out,
                                               size_t* avail_out) {
  next_in += pos_ - box_pos;
  avail_in -= pos_ - box_pos;

  if (brob_decode_) {
    if (!header_done_) {
      if (avail_in < 4) return JXL_DEC_NEED_MORE_INPUT;
      if (!box_until_eof_) {
        if (remaining_ < 4) return JXL_DEC_ERROR;
        remaining_ -= 4;
      }
      next_in += 4;
      avail_in -= 4;
      pos_ += 4;
      header_done_ = true;
    }

    if (!brotli_dec) {
      brotli_dec = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
    }

    const uint8_t* next_in_before = next_in;
    uint8_t* next_out_before = *next_out;
    msan::MemoryIsInitialized(next_in, avail_in);
    BrotliDecoderResult res = BrotliDecoderDecompressStream(
        brotli_dec, &avail_in, &next_in, avail_out, next_out, nullptr);
    size_t consumed = next_in - next_in_before;
    size_t produced = *next_out - next_out_before;
    if (res == BROTLI_DECODER_RESULT_ERROR) {
      return JXL_DEC_ERROR;
    }
    msan::UnpoisonMemory(next_out_before, produced);
    pos_ += consumed;
    if (!box_until_eof_) remaining_ -= consumed;
    if (res == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
      return JXL_DEC_NEED_MORE_INPUT;
    }
    if (res == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
      return JXL_DEC_BOX_NEED_MORE_OUTPUT;
    }
    if (res == BROTLI_DECODER_RESULT_SUCCESS) {
      return JXL_DEC_SUCCESS;
    }
    // unknown Brotli result
    return JXL_DEC_ERROR;
  } else {
    // remaining box bytes as seen from dec->file_pos
    size_t can_read = avail_in;
    if (!box_until_eof_) can_read = std::min<size_t>(can_read, remaining_);
    size_t to_write = std::min<size_t>(can_read, *avail_out);
    memcpy(*next_out, next_in, to_write);

    *next_out += to_write;
    *avail_out -= to_write;
    if (!box_until_eof_) remaining_ -= to_write;
    pos_ += to_write;

    if (to_write < can_read) return JXL_DEC_BOX_NEED_MORE_OUTPUT;

    if (!box_until_eof_ && remaining_ > 0) return JXL_DEC_NEED_MORE_INPUT;

    return JXL_DEC_SUCCESS;
  }
}

}  // namespace jxl