Coverage Report

Created: 2025-06-16 07:00

/src/libjxl/lib/jxl/box_content_decoder.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2
//
3
// Use of this source code is governed by a BSD-style
4
// license that can be found in the LICENSE file.
5
6
#include "lib/jxl/box_content_decoder.h"
7
8
#include <brotli/decode.h>
9
#include <jxl/decode.h>
10
11
#include <algorithm>
12
#include <cstddef>
13
#include <cstdint>
14
#include <cstring>
15
16
#include "lib/jxl/base/sanitizers.h"
17
18
namespace jxl {
19
20
28.7k
JxlBoxContentDecoder::JxlBoxContentDecoder() = default;
21
22
28.7k
JxlBoxContentDecoder::~JxlBoxContentDecoder() {
23
28.7k
  if (brotli_dec) {
24
0
    BrotliDecoderDestroyInstance(brotli_dec);
25
0
  }
26
28.7k
}
27
28
void JxlBoxContentDecoder::StartBox(bool brob_decode, bool box_until_eof,
29
741
                                    size_t contents_size) {
30
741
  if (brotli_dec) {
31
0
    BrotliDecoderDestroyInstance(brotli_dec);
32
0
    brotli_dec = nullptr;
33
0
  }
34
741
  header_done_ = false;
35
741
  brob_decode_ = brob_decode;
36
741
  box_until_eof_ = box_until_eof;
37
741
  remaining_ = box_until_eof ? 0 : contents_size;
38
741
  pos_ = 0;
39
741
}
40
41
JxlDecoderStatus JxlBoxContentDecoder::Process(const uint8_t* next_in,
42
                                               size_t avail_in, size_t box_pos,
43
                                               uint8_t** next_out,
44
73
                                               size_t* avail_out) {
45
73
  next_in += pos_ - box_pos;
46
73
  avail_in -= pos_ - box_pos;
47
48
73
  if (brob_decode_) {
49
0
    if (!header_done_) {
50
0
      if (avail_in < 4) return JXL_DEC_NEED_MORE_INPUT;
51
0
      if (!box_until_eof_) {
52
0
        if (remaining_ < 4) return JXL_DEC_ERROR;
53
0
        remaining_ -= 4;
54
0
      }
55
0
      next_in += 4;
56
0
      avail_in -= 4;
57
0
      pos_ += 4;
58
0
      header_done_ = true;
59
0
    }
60
61
0
    if (!brotli_dec) {
62
0
      brotli_dec = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
63
0
    }
64
65
0
    const uint8_t* next_in_before = next_in;
66
0
    uint8_t* next_out_before = *next_out;
67
0
    msan::MemoryIsInitialized(next_in, avail_in);
68
0
    BrotliDecoderResult res = BrotliDecoderDecompressStream(
69
0
        brotli_dec, &avail_in, &next_in, avail_out, next_out, nullptr);
70
0
    size_t consumed = next_in - next_in_before;
71
0
    size_t produced = *next_out - next_out_before;
72
0
    if (res == BROTLI_DECODER_RESULT_ERROR) {
73
0
      return JXL_DEC_ERROR;
74
0
    }
75
0
    msan::UnpoisonMemory(next_out_before, produced);
76
0
    pos_ += consumed;
77
0
    if (!box_until_eof_) remaining_ -= consumed;
78
0
    if (res == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
79
0
      return JXL_DEC_NEED_MORE_INPUT;
80
0
    }
81
0
    if (res == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
82
0
      return JXL_DEC_BOX_NEED_MORE_OUTPUT;
83
0
    }
84
0
    if (res == BROTLI_DECODER_RESULT_SUCCESS) {
85
0
      return JXL_DEC_BOX_COMPLETE;
86
0
    }
87
    // unknown Brotli result
88
0
    return JXL_DEC_ERROR;
89
73
  } else {
90
    // remaining box bytes as seen from dec->file_pos
91
73
    size_t can_read = avail_in;
92
73
    if (!box_until_eof_) can_read = std::min<size_t>(can_read, remaining_);
93
73
    size_t to_write = std::min<size_t>(can_read, *avail_out);
94
73
    memcpy(*next_out, next_in, to_write);
95
96
73
    *next_out += to_write;
97
73
    *avail_out -= to_write;
98
73
    if (!box_until_eof_) remaining_ -= to_write;
99
73
    pos_ += to_write;
100
101
73
    if (to_write < can_read) return JXL_DEC_BOX_NEED_MORE_OUTPUT;
102
103
73
    if (!box_until_eof_ && remaining_ > 0) return JXL_DEC_NEED_MORE_INPUT;
104
105
67
    return JXL_DEC_BOX_COMPLETE;
106
73
  }
107
73
}
108
109
}  // namespace jxl