/* 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 "util.h" #include #include #include using namespace ttf; Source::Source(std::vector const& data) : _data(data.data()) , _size(data.size()) , _offset(0) { } Source::Source(uint8_t const* data, int size) : _data(data) , _size(size) , _offset(0) { } Source::Source(Source& other, uint32_t offset) : _data(other.data()) , _size(other.size()) , _offset(offset) { } uint16_t Source::get_uint16() { if ((_offset + 2) > _size) { throw ParseError(); } auto p = _data + _offset; _offset += 2; return (static_cast(p[0]) << 8) | static_cast(p[1]); } uint32_t Source::get_uint32() { if ((_offset + 4) > _size) { throw ParseError(); } auto const p = _data + _offset; _offset += 4; return (static_cast(p[0]) << 24) | (static_cast(p[1]) << 16) | (static_cast(p[2]) << 8) | static_cast(p[3]); } std::string Source::get_string(uint32_t offset, uint16_t length) { return std::string(reinterpret_cast(_data) + _offset + offset, length); } /** @param length length in bytes */ std::wstring Source::get_wstring(uint32_t offset, uint16_t length) { std::wstring ws; auto p = _data + _offset + offset; for (int i = 0; i < (length / 2); ++i) { ws += static_cast((p[0] << 8) | p[1]); p += 2; } return ws; } std::vector Source::get_block(uint32_t offset, uint32_t length) { return std::vector(_data + offset, _data + offset + length); } Sink::Sink(std::vector& data, uint32_t offset) : _data(data) , _initial_offset(offset) , _offset(offset) { } void Sink::put(uint16_t value) { while ((_offset + 2) > _data.size()) { _data.resize(_data.size() * 2); } auto p = _data.data() + _offset; p[0] = (value >> 8) & 0xff; p[1] = value & 0xff; _offset += 2; } void Sink::put(uint32_t value) { while ((_offset + 4) > _data.size()) { _data.resize(_data.size() * 2); } auto p = _data.data() + _offset; p[0] = (value >> 24) & 0xff; p[1] = (value >> 16) & 0xff; p[2] = (value >> 8) & 0xff; p[3] = value & 0xff; _offset += 4; } void Sink::put(uint32_t value, uint32_t offset) { while ((offset + 4) > _data.size()) { _data.resize(_data.size() * 2); } auto p = _data.data() + offset; p[0] = (value >> 24) & 0xff; p[1] = (value >> 16) & 0xff; p[2] = (value >> 8) & 0xff; p[3] = value & 0xff; } void Sink::put(std::string const& data) { auto const length = data.size() + 1; while ((_offset + length) > _data.size()) { _data.resize(_data.size() * 2); } memcpy(_data.data() + _offset, data.c_str(), length); _offset += length; } void Sink::put(std::wstring const& data) { auto const length = (data.length() + 1) * 2; while ((_offset + length) > _data.size()) { _data.resize(_data.size() * 2); } auto* p = _data.data() + _offset; for (auto c: data) { *p++ = ((c & 0xff00) >> 8); *p++ = c & 0xff; } *p++ = 0; *p++ = 0; _offset += length; } void Sink::put(std::vector const& data) { while ((_offset + data.size()) > _data.size()) { _data.resize(_data.size() * 2); } memcpy(_data.data() + _offset, data.data(), data.size()); _offset += data.size(); } uint32_t Sink::checksum(uint32_t start) const { return ttf::checksum(_data.data() + start, _offset - start); } void Sink::pad() { if (_offset % 4) { put(std::vector(4 - (_offset % 4))); } } SubSink::SubSink(Sink& parent, uint32_t offset) : Sink(parent.data(), parent.offset() + offset) , _parent(parent) { } SubSink::~SubSink() { _parent.set_offset(offset()); } uint32_t ttf::checksum(std::vector const& data) { return ttf::checksum(data.data(), data.size()); } uint32_t ttf::checksum(uint8_t const* data, uint32_t size) { uint32_t sum = 0; uint32_t complete = size / 4; for (auto i = 0; i < complete; ++i) { sum += (static_cast(data[0]) << 24) | (static_cast(data[1]) << 16) | (static_cast(data[2]) << 8) | (static_cast(data[3]) << 0); data += 4; } auto remaining = size - complete * 4; if (remaining > 0) { sum += data[0] << 24; } if (remaining > 1) { sum += data[1] << 16; } if (remaining > 2) { sum += data[2] << 8; } return sum; }