tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

toc.cc (3921B)


      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/toc.h"
      7 
      8 #include <jxl/memory_manager.h>
      9 #include <stdint.h>
     10 
     11 #include "lib/jxl/base/common.h"
     12 #include "lib/jxl/coeff_order.h"
     13 #include "lib/jxl/coeff_order_fwd.h"
     14 #include "lib/jxl/fields.h"
     15 
     16 namespace jxl {
     17 size_t MaxBits(const size_t num_sizes) {
     18  const size_t entry_bits = U32Coder::MaxEncodedBits(kTocDist) * num_sizes;
     19  // permutation bit (not its tokens!), padding, entries, padding.
     20  return 1 + kBitsPerByte + entry_bits + kBitsPerByte;
     21 }
     22 
     23 Status ReadToc(JxlMemoryManager* memory_manager, size_t toc_entries,
     24               BitReader* JXL_RESTRICT reader,
     25               std::vector<uint32_t>* JXL_RESTRICT sizes,
     26               std::vector<coeff_order_t>* JXL_RESTRICT permutation) {
     27  if (toc_entries > 65536) {
     28    // Prevent out of memory if invalid JXL codestream causes a bogus amount
     29    // of toc_entries such as 2720436919446 to be computed.
     30    // TODO(lode): verify whether 65536 is a reasonable upper bound
     31    return JXL_FAILURE("too many toc entries");
     32  }
     33 
     34  sizes->clear();
     35  sizes->resize(toc_entries);
     36  if (reader->TotalBitsConsumed() >= reader->TotalBytes() * kBitsPerByte) {
     37    return JXL_STATUS(StatusCode::kNotEnoughBytes, "Not enough bytes for TOC");
     38  }
     39  const auto check_bit_budget = [&](size_t num_entries) -> Status {
     40    // U32Coder reads 2 bits to recognize variant and kTocDist cheapest variant
     41    // is Bits(10), this way at least 12 bits are required per toc-entry.
     42    size_t minimal_bit_cost = num_entries * (2 + 10);
     43    size_t bit_budget = reader->TotalBytes() * 8;
     44    size_t expenses = reader->TotalBitsConsumed();
     45    if ((expenses <= bit_budget) &&
     46        (minimal_bit_cost <= bit_budget - expenses)) {
     47      return true;
     48    }
     49    return JXL_STATUS(StatusCode::kNotEnoughBytes, "Not enough bytes for TOC");
     50  };
     51 
     52  JXL_ENSURE(toc_entries > 0);
     53  if (reader->ReadFixedBits<1>() == 1) {
     54    JXL_RETURN_IF_ERROR(check_bit_budget(toc_entries));
     55    permutation->resize(toc_entries);
     56    JXL_RETURN_IF_ERROR(DecodePermutation(
     57        memory_manager, /*skip=*/0, toc_entries, permutation->data(), reader));
     58  }
     59  JXL_RETURN_IF_ERROR(reader->JumpToByteBoundary());
     60  JXL_RETURN_IF_ERROR(check_bit_budget(toc_entries));
     61  for (size_t i = 0; i < toc_entries; ++i) {
     62    (*sizes)[i] = U32Coder::Read(kTocDist, reader);
     63  }
     64  JXL_RETURN_IF_ERROR(reader->JumpToByteBoundary());
     65  JXL_RETURN_IF_ERROR(check_bit_budget(0));
     66  return true;
     67 }
     68 
     69 Status ReadGroupOffsets(JxlMemoryManager* memory_manager, size_t toc_entries,
     70                        BitReader* JXL_RESTRICT reader,
     71                        std::vector<uint64_t>* JXL_RESTRICT offsets,
     72                        std::vector<uint32_t>* JXL_RESTRICT sizes,
     73                        uint64_t* total_size) {
     74  std::vector<coeff_order_t> permutation;
     75  JXL_RETURN_IF_ERROR(
     76      ReadToc(memory_manager, toc_entries, reader, sizes, &permutation));
     77 
     78  offsets->clear();
     79  offsets->resize(toc_entries);
     80 
     81  // Prefix sum starting with 0 and ending with the offset of the last group
     82  uint64_t offset = 0;
     83  for (size_t i = 0; i < toc_entries; ++i) {
     84    if (offset + (*sizes)[i] < offset) {
     85      return JXL_FAILURE("group offset overflow");
     86    }
     87    (*offsets)[i] = offset;
     88    offset += (*sizes)[i];
     89  }
     90  if (total_size) {
     91    *total_size = offset;
     92  }
     93 
     94  if (!permutation.empty()) {
     95    std::vector<uint64_t> permuted_offsets;
     96    std::vector<uint32_t> permuted_sizes;
     97    permuted_offsets.reserve(toc_entries);
     98    permuted_sizes.reserve(toc_entries);
     99    for (coeff_order_t index : permutation) {
    100      permuted_offsets.push_back((*offsets)[index]);
    101      permuted_sizes.push_back((*sizes)[index]);
    102    }
    103    std::swap(*offsets, permuted_offsets);
    104    std::swap(*sizes, permuted_sizes);
    105  }
    106 
    107  return true;
    108 }
    109 }  // namespace jxl