/* Copyright (C) 2026 Carl Hetherington This file is part of libttf. libttf is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. libttf is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with libttf. If not, see . */ #include "font.h" #include "name_table.h" #include "util.h" #include #include #include #include #include #include using namespace ttf; Font::Font(boost::filesystem::path const& ttf_file) { boost::filesystem::ifstream str(ttf_file, std::ios::binary); std::vector data(boost::filesystem::file_size(ttf_file)); str.read(reinterpret_cast(data.data()), data.size()); Source source(data); read_source(source); } Font::Font(uint8_t const* data, int size) { Source source(data, size); read_source(source); } Font::Font(Source& source) { read_source(source); } void Font::read_source(Source& source) { _scalar_type = source.get_uint32(); if (_scalar_type != 0x00010000 && _scalar_type != 0x74727565) { throw InvalidScalerType(_scalar_type); } _num_tables = source.get_uint16(); auto const search_range = source.get_uint16(); auto const entry_selector = source.get_uint16(); auto const range_shift = source.get_uint16(); for (auto table = 0; table < _num_tables; ++table) { _tables.push_back(make_table(source, table)); } std::sort(_tables.begin(), _tables.end(), [](std::shared_ptr a, std::shared_ptr b) { return a->offset() < b->offset(); }); } void Font::write(boost::filesystem::path const& ttf_file) const { std::vector data(65536); Sink header_sink(data); header_sink.put(_scalar_type); header_sink.put(_num_tables); auto constexpr TABLE_SIZE = 16; uint16_t const log_max_power = std::floor(std::log(_num_tables) / std::log(2)); uint16_t const search_range = pow(2, log_max_power) * TABLE_SIZE; header_sink.put(search_range); header_sink.put(log_max_power); header_sink.put(static_cast(_num_tables * TABLE_SIZE - search_range)); auto const tables_start = header_sink.offset(); Sink data_sink(data, tables_start + _tables.size() * TABLE_SIZE); for (auto table: _tables) { header_sink.set_offset(tables_start + table->header_index() * TABLE_SIZE); table->write(header_sink, SubSink(data_sink)); } auto const overall_checksum = ttf::checksum(data.data(), data_sink.offset()); for (auto table: _tables) { if (auto head = std::dynamic_pointer_cast(table)) { head->set_checksum_adjustment(data_sink, 0xb1b0afba - overall_checksum); } } boost::filesystem::ofstream file(ttf_file, std::ios::binary); file.write(reinterpret_cast(data.data()), data_sink.offset()); } std::shared_ptr Font::name_table() { auto iter = std::find_if(_tables.begin(), _tables.end(), [](std::shared_ptr t) { return static_cast(std::dynamic_pointer_cast(t)); }); if (iter == _tables.end()) { return {}; } return std::dynamic_pointer_cast(*iter); }