libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

dec_ma.cc (4956B)


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