std::vector Entries::makeData()

in cpp/spectrum/image/metadata/Entries.cpp [287:350]


std::vector<std::uint8_t> Entries::makeData() const {
  const std::uint16_t count = expectedCountOfTiffEntries();
  const std::uint32_t tiffIfdValuesOffset = MemoryLayout::DEFAULT_OFFSET +
      sizeof(std::uint16_t) + count * sizeof(Entry::MemoryLayout) +
      sizeof(std::uint32_t);

  std::vector<std::uint8_t> data = utils::makeDataFromValue(MemoryLayout());
  std::vector<std::uint8_t> trailingData;

  // In reality data will need a bit more space as it also contains the trailing
  // variable-length values.
  data.reserve(
      (count + _exif.size() + _gps.size()) * sizeof(Entry::MemoryLayout));

  // Add tiff entries count to data.
  utils::insertValueIntoData(count, data);

  for (const auto& pair : _tiff) {
    if (pair.first != Entry::EXIF_IFD_POINTER &&
        pair.first != Entry::GPS_INFO_IFD_POINTER) {
      pair.second.insertIntoDataAndValuesData(
          data, trailingData, tiffIfdValuesOffset);
    }
  }

  const std::uint32_t tiffValuesSize =
      SPECTRUM_CONVERT_OR_THROW(trailingData.size(), std::uint32_t);

  // EXIF IFD begins after the tiff values. This only works because both entries
  // that will be conditionally added later (EXIF_IFD & GPS_IFD) have already
  // been accounted for in tiffIfdValuesOffset *and* we're sure both entry's
  // values fit within an entry's fixed size.
  const std::uint32_t exifIfdOffset = tiffIfdValuesOffset +
      SPECTRUM_CONVERT_OR_THROW(trailingData.size(), std::uint32_t);
  if (!_exif.empty()) {
    Entry(Entry::EXIF_IFD_POINTER, Entry::LONG, exifIfdOffset)
        .insertIntoData(data);
  }

  // Add EXIF entries to trailingData. They cannot be added to data directly as
  // the GPS IFD offset entry may be added later on if needed.
  insertSecondaryEntriesIntoData(_exif, trailingData, exifIfdOffset);

  const std::uint32_t gpsIfdOffset = exifIfdOffset +
      SPECTRUM_CONVERT_OR_THROW(trailingData.size(), std::uint32_t) -
      tiffValuesSize;
  if (!_gps.empty()) {
    Entry(Entry::GPS_INFO_IFD_POINTER, Entry::LONG, gpsIfdOffset)
        .insertIntoData(data);
  }

  // Adds Next IFD offset
  utils::insertValueIntoData(std::uint32_t{0}, data);

  // By this point we won't be adding any more tiff entries so we can safely
  // append the TIFF values + EXIF entries & values at the end of data.
  data.insert(data.end(), trailingData.begin(), trailingData.end());

  // And finally append both GPS entries & values if needed.
  insertSecondaryEntriesIntoData(_gps, data, gpsIfdOffset);

  SPECTRUM_ERROR_IF(data.size() > MAX_DATA_LENGTH, error::ExifLengthTooLarge);
  return data;
}