tor-browser

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

gain_map.cc (8116B)


      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 <jxl/gain_map.h>
      7 
      8 #include <cstddef>
      9 #include <cstdint>
     10 #include <cstdlib>
     11 #include <cstring>
     12 
     13 #include "lib/jxl/base/byte_order.h"
     14 #include "lib/jxl/base/common.h"
     15 #include "lib/jxl/color_encoding_internal.h"
     16 #include "lib/jxl/dec_bit_reader.h"
     17 #include "lib/jxl/enc_aux_out.h"
     18 #include "lib/jxl/enc_bit_writer.h"
     19 #include "lib/jxl/fields.h"
     20 #include "lib/jxl/memory_manager_internal.h"
     21 
     22 namespace {
     23 
     24 template <size_t N>
     25 class FixedSizeMemoryManager {
     26 public:
     27  FixedSizeMemoryManager() = default;
     28 
     29  JxlMemoryManager* memory_manager() { return &manager_; }
     30 
     31 private:
     32  static void* FixedSizeMemoryManagerAlloc(void* opaque, size_t capacity) {
     33    auto manager = static_cast<FixedSizeMemoryManager<N>*>(opaque);
     34    if (capacity > N + jxl::memory_manager_internal::kAlias) {
     35      return nullptr;
     36    }
     37    return manager->memory_;
     38  }
     39  static void FixedSizeMemoryManagerFree(void* opaque, void* pointer) {}
     40 
     41  uint8_t memory_[N + jxl::memory_manager_internal::kAlias];
     42  JxlMemoryManager manager_ = {
     43      /*opaque=*/this,
     44      /*alloc=*/&FixedSizeMemoryManagerAlloc,
     45      /*free=*/&FixedSizeMemoryManagerFree,
     46  };
     47 };
     48 
     49 }  // namespace
     50 
     51 JXL_BOOL JxlGainMapGetBundleSize(const JxlGainMapBundle* map_bundle,
     52                                 size_t* bundle_size) {
     53  if (map_bundle == nullptr) return JXL_FALSE;
     54 
     55  jxl::ColorEncoding internal_color_encoding;
     56  size_t color_encoding_size = 0;
     57  size_t extension_bits = 0;
     58  if (map_bundle->has_color_encoding) {
     59    JXL_RETURN_IF_ERROR(
     60        internal_color_encoding.FromExternal(map_bundle->color_encoding));
     61    if (!jxl::Bundle::CanEncode(internal_color_encoding, &extension_bits,
     62                                &color_encoding_size)) {
     63      return JXL_FALSE;
     64    }
     65  }
     66 
     67  *bundle_size =
     68      1 +                                     // size of jhgm_version
     69      2 +                                     // size_of gain_map_metadata_size
     70      map_bundle->gain_map_metadata_size +    // size of gain_map_metadata
     71      1 +                                     // size of color_encoding_size
     72      jxl::DivCeil(color_encoding_size, 8) +  // size of the color_encoding
     73      4 +                                     // size of compressed_icc_size
     74      map_bundle->alt_icc_size +              // size of compressed_icc
     75      map_bundle->gain_map_size;              // size of gain map
     76  return JXL_TRUE;
     77 }
     78 
     79 JXL_BOOL JxlGainMapWriteBundle(const JxlGainMapBundle* map_bundle,
     80                               uint8_t* output_buffer,
     81                               size_t output_buffer_size,
     82                               size_t* bytes_written) {
     83  if (map_bundle == nullptr) return JXL_FALSE;
     84 
     85  uint8_t jhgm_version = map_bundle->jhgm_version;
     86 
     87  FixedSizeMemoryManager<sizeof(jxl::ColorEncoding)> memory_manager;
     88  jxl::ColorEncoding internal_color_encoding;
     89  jxl::BitWriter color_encoding_writer(memory_manager.memory_manager());
     90  if (map_bundle->has_color_encoding) {
     91    JXL_RETURN_IF_ERROR(
     92        internal_color_encoding.FromExternal(map_bundle->color_encoding));
     93    if (!jxl::Bundle::Write(internal_color_encoding, &color_encoding_writer,
     94                            jxl::LayerType::Header, nullptr)) {
     95      return JXL_FALSE;
     96    }
     97  }
     98 
     99  color_encoding_writer.ZeroPadToByte();
    100 
    101  uint64_t cursor = 0;
    102  uint64_t next_cursor = 0;
    103 
    104 #define SAFE_CURSOR_UPDATE(n)                    \
    105  do {                                           \
    106    cursor = next_cursor;                        \
    107    if (!jxl::SafeAdd(cursor, n, next_cursor) || \
    108        next_cursor > output_buffer_size) {      \
    109      return JXL_FALSE;                          \
    110    }                                            \
    111  } while (false)
    112 
    113  SAFE_CURSOR_UPDATE(1);
    114  memcpy(output_buffer + cursor, &jhgm_version, 1);
    115 
    116  SAFE_CURSOR_UPDATE(2);
    117  StoreBE16(map_bundle->gain_map_metadata_size, output_buffer + cursor);
    118 
    119  SAFE_CURSOR_UPDATE(map_bundle->gain_map_metadata_size);
    120  memcpy(output_buffer + cursor, map_bundle->gain_map_metadata,
    121         map_bundle->gain_map_metadata_size);
    122 
    123  jxl::Bytes bytes = color_encoding_writer.GetSpan();
    124  uint8_t color_enc_size = static_cast<uint8_t>(bytes.size());
    125  if (color_enc_size != bytes.size()) return JXL_FALSE;
    126  SAFE_CURSOR_UPDATE(1);
    127  memcpy(output_buffer + cursor, &color_enc_size, 1);
    128 
    129  SAFE_CURSOR_UPDATE(color_enc_size);
    130  memcpy(output_buffer + cursor, bytes.data(), color_enc_size);
    131 
    132  SAFE_CURSOR_UPDATE(4);
    133  StoreBE32(map_bundle->alt_icc_size, output_buffer + cursor);
    134 
    135  SAFE_CURSOR_UPDATE(map_bundle->alt_icc_size);
    136  memcpy(output_buffer + cursor, map_bundle->alt_icc, map_bundle->alt_icc_size);
    137 
    138  SAFE_CURSOR_UPDATE(map_bundle->gain_map_size);
    139  memcpy(output_buffer + cursor, map_bundle->gain_map,
    140         map_bundle->gain_map_size);
    141 
    142 #undef SAFE_CURSOR_UPDATE
    143 
    144  cursor = next_cursor;
    145 
    146  if (bytes_written != nullptr)
    147    *bytes_written = cursor;  // Ensure size_t compatibility
    148  return cursor == output_buffer_size ? JXL_TRUE : JXL_FALSE;
    149 }
    150 
    151 JXL_BOOL JxlGainMapReadBundle(JxlGainMapBundle* map_bundle,
    152                              const uint8_t* input_buffer,
    153                              const size_t input_buffer_size,
    154                              size_t* bytes_read) {
    155  if (map_bundle == nullptr || input_buffer == nullptr ||
    156      input_buffer_size == 0) {
    157    return JXL_FALSE;
    158  }
    159 
    160  uint64_t cursor = 0;
    161  uint64_t next_cursor = 0;
    162 
    163 #define SAFE_CURSOR_UPDATE(n)                    \
    164  do {                                           \
    165    cursor = next_cursor;                        \
    166    if (!jxl::SafeAdd(cursor, n, next_cursor) || \
    167        next_cursor > input_buffer_size) {       \
    168      return JXL_FALSE;                          \
    169    }                                            \
    170  } while (false)
    171 
    172  // Read the version byte
    173  SAFE_CURSOR_UPDATE(1);
    174  map_bundle->jhgm_version = input_buffer[cursor];
    175 
    176  // Read gain_map_metadata_size
    177  SAFE_CURSOR_UPDATE(2);
    178  uint16_t gain_map_metadata_size = LoadBE16(input_buffer + cursor);
    179 
    180  SAFE_CURSOR_UPDATE(gain_map_metadata_size);
    181  map_bundle->gain_map_metadata_size = gain_map_metadata_size;
    182  map_bundle->gain_map_metadata = input_buffer + cursor;
    183 
    184  // Read compressed_color_encoding_size
    185  SAFE_CURSOR_UPDATE(1);
    186  uint8_t compressed_color_encoding_size;
    187  memcpy(&compressed_color_encoding_size, input_buffer + cursor, 1);
    188 
    189  map_bundle->has_color_encoding = (compressed_color_encoding_size > 0);
    190  if (map_bundle->has_color_encoding) {
    191    SAFE_CURSOR_UPDATE(compressed_color_encoding_size);
    192    // Decode color encoding
    193    jxl::Span<const uint8_t> color_encoding_span(
    194        input_buffer + cursor, compressed_color_encoding_size);
    195    jxl::BitReader color_encoding_reader(color_encoding_span);
    196    jxl::ColorEncoding internal_color_encoding;
    197    if (!jxl::Bundle::Read(&color_encoding_reader, &internal_color_encoding)) {
    198      return JXL_FALSE;
    199    }
    200    JXL_RETURN_IF_ERROR(color_encoding_reader.Close());
    201    map_bundle->color_encoding = internal_color_encoding.ToExternal();
    202  }
    203 
    204  // Read compressed_icc_size
    205  SAFE_CURSOR_UPDATE(4);
    206  uint32_t compressed_icc_size = LoadBE32(input_buffer + cursor);
    207 
    208  SAFE_CURSOR_UPDATE(compressed_icc_size);
    209  map_bundle->alt_icc_size = compressed_icc_size;
    210  map_bundle->alt_icc = input_buffer + cursor;
    211 
    212  // Calculate remaining bytes for gain map
    213  cursor = next_cursor;
    214  // This calculation is guaranteed not to underflow because `cursor` is always
    215  // updated to a position within or at the end of `input_buffer` (not beyond).
    216  // Thus, subtracting `cursor` from `input_buffer_size` (the total size of the
    217  // buffer) will always result in a non-negative integer representing the
    218  // remaining buffer size.
    219  map_bundle->gain_map_size = input_buffer_size - cursor;
    220  SAFE_CURSOR_UPDATE(map_bundle->gain_map_size);
    221  map_bundle->gain_map = input_buffer + cursor;
    222 
    223 #undef SAFE_CURSOR_UPDATE
    224 
    225  cursor = next_cursor;
    226 
    227  if (bytes_read != nullptr) {
    228    *bytes_read = cursor;
    229  }
    230  return JXL_TRUE;
    231 }