Coverage Report

Created: 2025-06-22 08:04

/src/libjxl/lib/jxl/toc.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/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
0
size_t MaxBits(const size_t num_sizes) {
18
0
  const size_t entry_bits = U32Coder::MaxEncodedBits(kTocDist) * num_sizes;
19
  // permutation bit (not its tokens!), padding, entries, padding.
20
0
  return 1 + kBitsPerByte + entry_bits + kBitsPerByte;
21
0
}
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
95.1k
               std::vector<coeff_order_t>* JXL_RESTRICT permutation) {
27
95.1k
  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
49
    return JXL_FAILURE("too many toc entries");
32
49
  }
33
34
95.1k
  sizes->clear();
35
95.1k
  sizes->resize(toc_entries);
36
95.1k
  if (reader->TotalBitsConsumed() >= reader->TotalBytes() * kBitsPerByte) {
37
92
    return JXL_STATUS(StatusCode::kNotEnoughBytes, "Not enough bytes for TOC");
38
92
  }
39
185k
  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
185k
    size_t minimal_bit_cost = num_entries * (2 + 10);
43
185k
    size_t bit_budget = reader->TotalBytes() * 8;
44
185k
    size_t expenses = reader->TotalBitsConsumed();
45
185k
    if ((expenses <= bit_budget) &&
46
185k
        (minimal_bit_cost <= bit_budget - expenses)) {
47
182k
      return true;
48
182k
    }
49
3.38k
    return JXL_STATUS(StatusCode::kNotEnoughBytes, "Not enough bytes for TOC");
50
185k
  };
51
52
95.0k
  JXL_ENSURE(toc_entries > 0);
53
95.0k
  if (reader->ReadFixedBits<1>() == 1) {
54
5.99k
    JXL_RETURN_IF_ERROR(check_bit_budget(toc_entries));
55
5.04k
    permutation->resize(toc_entries);
56
5.04k
    JXL_RETURN_IF_ERROR(DecodePermutation(
57
5.04k
        memory_manager, /*skip=*/0, toc_entries, permutation->data(), reader));
58
5.04k
  }
59
91.1k
  JXL_RETURN_IF_ERROR(reader->JumpToByteBoundary());
60
90.9k
  JXL_RETURN_IF_ERROR(check_bit_budget(toc_entries));
61
659k
  for (size_t i = 0; i < toc_entries; ++i) {
62
570k
    (*sizes)[i] = U32Coder::Read(kTocDist, reader);
63
570k
  }
64
88.9k
  JXL_RETURN_IF_ERROR(reader->JumpToByteBoundary());
65
88.9k
  JXL_RETURN_IF_ERROR(check_bit_budget(0));
66
88.4k
  return true;
67
88.9k
}
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
0
                        uint64_t* total_size) {
74
0
  std::vector<coeff_order_t> permutation;
75
0
  JXL_RETURN_IF_ERROR(
76
0
      ReadToc(memory_manager, toc_entries, reader, sizes, &permutation));
77
78
0
  offsets->clear();
79
0
  offsets->resize(toc_entries);
80
81
  // Prefix sum starting with 0 and ending with the offset of the last group
82
0
  uint64_t offset = 0;
83
0
  for (size_t i = 0; i < toc_entries; ++i) {
84
0
    if (offset + (*sizes)[i] < offset) {
85
0
      return JXL_FAILURE("group offset overflow");
86
0
    }
87
0
    (*offsets)[i] = offset;
88
0
    offset += (*sizes)[i];
89
0
  }
90
0
  if (total_size) {
91
0
    *total_size = offset;
92
0
  }
93
94
0
  if (!permutation.empty()) {
95
0
    std::vector<uint64_t> permuted_offsets;
96
0
    std::vector<uint32_t> permuted_sizes;
97
0
    permuted_offsets.reserve(toc_entries);
98
0
    permuted_sizes.reserve(toc_entries);
99
0
    for (coeff_order_t index : permutation) {
100
0
      permuted_offsets.push_back((*offsets)[index]);
101
0
      permuted_sizes.push_back((*sizes)[index]);
102
0
    }
103
0
    std::swap(*offsets, permuted_offsets);
104
0
    std::swap(*sizes, permuted_sizes);
105
0
  }
106
107
0
  return true;
108
0
}
109
}  // namespace jxl