/src/libjxl/lib/jxl/modular/encoding/dec_ma.cc
Line | Count | Source |
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/modular/encoding/dec_ma.h" |
7 | | |
8 | | #include <jxl/memory_manager.h> |
9 | | |
10 | | #include <algorithm> |
11 | | #include <cstddef> |
12 | | #include <cstdint> |
13 | | #include <limits> |
14 | | #include <utility> |
15 | | #include <vector> |
16 | | |
17 | | #include "lib/jxl/base/printf_macros.h" |
18 | | #include "lib/jxl/base/status.h" |
19 | | #include "lib/jxl/dec_ans.h" |
20 | | #include "lib/jxl/dec_bit_reader.h" |
21 | | #include "lib/jxl/modular/encoding/ma_common.h" |
22 | | #include "lib/jxl/modular/modular_image.h" |
23 | | #include "lib/jxl/modular/options.h" |
24 | | #include "lib/jxl/pack_signed.h" |
25 | | |
26 | | namespace jxl { |
27 | | |
28 | | namespace { |
29 | | |
30 | 32.8k | Status ValidateTree(const Tree &tree) { |
31 | 32.8k | int num_properties = 0; |
32 | 122k | for (auto node : tree) { |
33 | 122k | if (node.property >= num_properties) { |
34 | 3.69k | num_properties = node.property + 1; |
35 | 3.69k | } |
36 | 122k | } |
37 | 32.8k | std::vector<int> height(tree.size()); |
38 | 32.8k | std::vector<std::pair<pixel_type, pixel_type>> property_ranges( |
39 | 32.8k | num_properties * tree.size()); |
40 | 58.3k | for (int i = 0; i < num_properties; i++) { |
41 | 25.4k | property_ranges[i].first = std::numeric_limits<pixel_type>::min(); |
42 | 25.4k | property_ranges[i].second = std::numeric_limits<pixel_type>::max(); |
43 | 25.4k | } |
44 | 32.8k | const int kHeightLimit = 2048; |
45 | 155k | for (size_t i = 0; i < tree.size(); i++) { |
46 | 122k | if (height[i] > kHeightLimit) { |
47 | 0 | return JXL_FAILURE("Tree too tall: %d", height[i]); |
48 | 0 | } |
49 | 122k | if (tree[i].property == -1) continue; |
50 | 44.7k | height[tree[i].lchild] = height[i] + 1; |
51 | 44.7k | height[tree[i].rchild] = height[i] + 1; |
52 | 744k | for (size_t p = 0; p < static_cast<size_t>(num_properties); p++) { |
53 | 699k | if (p == static_cast<size_t>(tree[i].property)) { |
54 | 44.7k | pixel_type l = property_ranges[i * num_properties + p].first; |
55 | 44.7k | pixel_type u = property_ranges[i * num_properties + p].second; |
56 | 44.7k | pixel_type val = tree[i].splitval; |
57 | 44.7k | if (l > val || u <= val) { |
58 | 8 | return JXL_FAILURE("Invalid tree"); |
59 | 8 | } |
60 | 44.7k | property_ranges[tree[i].lchild * num_properties + p] = |
61 | 44.7k | std::make_pair(val + 1, u); |
62 | 44.7k | property_ranges[tree[i].rchild * num_properties + p] = |
63 | 44.7k | std::make_pair(l, val); |
64 | 655k | } else { |
65 | 655k | property_ranges[tree[i].lchild * num_properties + p] = |
66 | 655k | property_ranges[i * num_properties + p]; |
67 | 655k | property_ranges[tree[i].rchild * num_properties + p] = |
68 | 655k | property_ranges[i * num_properties + p]; |
69 | 655k | } |
70 | 699k | } |
71 | 44.7k | } |
72 | 32.8k | return true; |
73 | 32.8k | } |
74 | | |
75 | | Status DecodeTree(BitReader *br, ANSSymbolReader *reader, |
76 | | const std::vector<uint8_t> &context_map, Tree *tree, |
77 | 33.0k | size_t tree_size_limit) { |
78 | 33.0k | size_t leaf_id = 0; |
79 | 33.0k | size_t to_decode = 1; |
80 | 33.0k | tree->clear(); |
81 | 873k | while (to_decode > 0) { |
82 | 840k | JXL_RETURN_IF_ERROR(br->AllReadsWithinBounds()); |
83 | 840k | if (tree->size() > tree_size_limit) { |
84 | 5 | return JXL_FAILURE("Tree is too large: %" PRIuS " nodes vs %" PRIuS |
85 | 5 | " max nodes", |
86 | 5 | tree->size(), tree_size_limit); |
87 | 5 | } |
88 | 840k | to_decode--; |
89 | 840k | uint32_t prop1 = reader->ReadHybridUint(kPropertyContext, br, context_map); |
90 | 840k | if (prop1 > 256) return JXL_FAILURE("Invalid tree property value"); |
91 | 840k | int property = prop1 - 1; |
92 | 840k | if (property == -1) { |
93 | 101k | size_t predictor = |
94 | 101k | reader->ReadHybridUint(kPredictorContext, br, context_map); |
95 | 101k | if (predictor >= kNumModularPredictors) { |
96 | 1 | return JXL_FAILURE("Invalid predictor"); |
97 | 1 | } |
98 | 101k | int64_t predictor_offset = |
99 | 101k | UnpackSigned(reader->ReadHybridUint(kOffsetContext, br, context_map)); |
100 | 101k | uint32_t mul_log = |
101 | 101k | reader->ReadHybridUint(kMultiplierLogContext, br, context_map); |
102 | 101k | if (mul_log >= 31) { |
103 | 1 | return JXL_FAILURE("Invalid multiplier logarithm"); |
104 | 1 | } |
105 | 101k | uint32_t mul_bits = |
106 | 101k | reader->ReadHybridUint(kMultiplierBitsContext, br, context_map); |
107 | 101k | if (mul_bits >= (1u << (31u - mul_log)) - 1u) { |
108 | 1 | return JXL_FAILURE("Invalid multiplier"); |
109 | 1 | } |
110 | 101k | uint32_t multiplier = (mul_bits + 1U) << mul_log; |
111 | 101k | Predictor p = static_cast<Predictor>(static_cast<uint32_t>(predictor)); |
112 | 101k | tree->emplace_back(-1, 0, static_cast<int>(leaf_id), 0, p, |
113 | 101k | predictor_offset, multiplier); |
114 | 101k | leaf_id++; |
115 | 101k | continue; |
116 | 101k | } |
117 | 739k | int splitval = |
118 | 739k | UnpackSigned(reader->ReadHybridUint(kSplitValContext, br, context_map)); |
119 | 739k | tree->emplace_back( |
120 | 739k | property, splitval, static_cast<int>(tree->size() + to_decode + 1), |
121 | 739k | static_cast<int>(tree->size() + to_decode + 2), Predictor::Zero, 0, 1); |
122 | 739k | to_decode += 2; |
123 | 739k | } |
124 | 32.8k | return ValidateTree(*tree); |
125 | 33.0k | } |
126 | | } // namespace |
127 | | |
128 | | Status DecodeTree(JxlMemoryManager *memory_manager, BitReader *br, Tree *tree, |
129 | 33.2k | size_t tree_size_limit) { |
130 | 33.2k | std::vector<uint8_t> tree_context_map; |
131 | 33.2k | ANSCode tree_code; |
132 | 33.2k | JXL_RETURN_IF_ERROR(DecodeHistograms(memory_manager, br, kNumTreeContexts, |
133 | 33.2k | &tree_code, &tree_context_map)); |
134 | | // TODO(eustas): investigate more infinite tree cases. |
135 | 33.0k | if (tree_code.degenerate_symbols[tree_context_map[kPropertyContext]] > 0) { |
136 | 4 | return JXL_FAILURE("Infinite tree"); |
137 | 4 | } |
138 | 66.0k | JXL_ASSIGN_OR_RETURN(ANSSymbolReader reader, |
139 | 66.0k | ANSSymbolReader::Create(&tree_code, br)); |
140 | 66.0k | JXL_RETURN_IF_ERROR(DecodeTree(br, &reader, tree_context_map, tree, |
141 | 66.0k | std::min(tree_size_limit, kMaxTreeSize))); |
142 | 32.8k | if (!reader.CheckANSFinalState()) { |
143 | 0 | return JXL_FAILURE("ANS decode final state failed"); |
144 | 0 | } |
145 | 32.8k | return true; |
146 | 32.8k | } |
147 | | |
148 | | } // namespace jxl |