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 "lib/jxl/sanitizers.h"
9 
10 namespace jxl {
11 
JxlBoxContentDecoder()12 JxlBoxContentDecoder::JxlBoxContentDecoder() {}
13 
~JxlBoxContentDecoder()14 JxlBoxContentDecoder::~JxlBoxContentDecoder() {
15   if (brotli_dec) {
16     BrotliDecoderDestroyInstance(brotli_dec);
17   }
18 }
19 
StartBox(bool brob_decode,bool box_until_eof,size_t contents_size)20 void JxlBoxContentDecoder::StartBox(bool brob_decode, bool box_until_eof,
21                                     size_t contents_size) {
22   if (brotli_dec) {
23     BrotliDecoderDestroyInstance(brotli_dec);
24     brotli_dec = nullptr;
25   }
26   header_done_ = false;
27   brob_decode_ = brob_decode;
28   box_until_eof_ = box_until_eof;
29   remaining_ = box_until_eof ? 0 : contents_size;
30   pos_ = 0;
31 }
32 
Process(const uint8_t * next_in,size_t avail_in,size_t box_pos,uint8_t ** next_out,size_t * avail_out)33 JxlDecoderStatus JxlBoxContentDecoder::Process(const uint8_t* next_in,
34                                                size_t avail_in, size_t box_pos,
35                                                uint8_t** next_out,
36                                                size_t* avail_out) {
37   next_in += pos_ - box_pos;
38   avail_in -= pos_ - box_pos;
39 
40   if (brob_decode_) {
41     if (!header_done_) {
42       if (avail_in < 4) return JXL_DEC_NEED_MORE_INPUT;
43       if (!box_until_eof_) {
44         if (remaining_ < 4) return JXL_DEC_ERROR;
45         remaining_ -= 4;
46       }
47       next_in += 4;
48       avail_in -= 4;
49       pos_ += 4;
50       header_done_ = true;
51     }
52 
53     if (!brotli_dec) {
54       brotli_dec = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
55     }
56 
57     const uint8_t* next_in_before = next_in;
58     uint8_t* next_out_before = *next_out;
59     msan::MemoryIsInitialized(next_in, avail_in);
60     BrotliDecoderResult res = BrotliDecoderDecompressStream(
61         brotli_dec, &avail_in, &next_in, avail_out, next_out, nullptr);
62     size_t consumed = next_in - next_in_before;
63     size_t produced = *next_out - next_out_before;
64     if (res == BROTLI_DECODER_RESULT_ERROR) {
65       return JXL_DEC_ERROR;
66     }
67     msan::UnpoisonMemory(next_out_before, produced);
68     pos_ += consumed;
69     if (!box_until_eof_) remaining_ -= consumed;
70     if (res == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
71       return JXL_DEC_NEED_MORE_INPUT;
72     }
73     if (res == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
74       return JXL_DEC_BOX_NEED_MORE_OUTPUT;
75     }
76     if (res == BROTLI_DECODER_RESULT_SUCCESS) {
77       return JXL_DEC_SUCCESS;
78     }
79     // unknown Brotli result
80     return JXL_DEC_ERROR;
81   } else {
82     // remaining box bytes as seen from dec->file_pos
83     size_t can_read = avail_in;
84     if (!box_until_eof_) can_read = std::min<size_t>(can_read, remaining_);
85     size_t to_write = std::min<size_t>(can_read, *avail_out);
86     memcpy(*next_out, next_in, to_write);
87 
88     *next_out += to_write;
89     *avail_out -= to_write;
90     if (!box_until_eof_) remaining_ -= to_write;
91     pos_ += to_write;
92 
93     if (to_write < can_read) return JXL_DEC_BOX_NEED_MORE_OUTPUT;
94 
95     if (!box_until_eof_ && remaining_ > 0) return JXL_DEC_NEED_MORE_INPUT;
96 
97     return JXL_DEC_SUCCESS;
98   }
99 }
100 
101 }  // namespace jxl
102