summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2026-07-24 00:46:18 +0200
committerCarl Hetherington <cth@carlh.net>2026-07-24 00:46:18 +0200
commit6d830c63ba53993f2818b4fb61dbc17284f8f557 (patch)
treef37fd664623391a025e37915a681d547e7c4e484
parentc6c34ad5a24f99f9f7919a4bb72f22d7c6452ada (diff)
Basic TTC (collection) support.HEADv0.0.7main
-rw-r--r--src/collection.cc73
-rw-r--r--src/collection.h59
-rw-r--r--src/font.cc6
-rw-r--r--src/font.h1
-rw-r--r--src/wscript4
-rw-r--r--test/data/8fb0935f-28cd-4d8f-9ee9-85897c600364bin0 -> 459376 bytes
-rw-r--r--test/tests.cc16
7 files changed, 157 insertions, 2 deletions
diff --git a/src/collection.cc b/src/collection.cc
new file mode 100644
index 0000000..1482b42
--- /dev/null
+++ b/src/collection.cc
@@ -0,0 +1,73 @@
+/*
+ Copyright (C) 2026 Carl Hetherington <cth@carlh.net>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "collection.h"
+#include "util.h"
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <iostream>
+
+
+using namespace ttf;
+
+
+Collection::Collection(boost::filesystem::path const& ttf_file)
+{
+ boost::filesystem::ifstream str(ttf_file, std::ios::binary);
+ std::vector<uint8_t> data(boost::filesystem::file_size(ttf_file));
+ str.read(reinterpret_cast<char*>(data.data()), data.size());
+
+ Source source(data);
+ read_source(source);
+}
+
+
+Collection::Collection(uint8_t const* data, int size)
+{
+ Source source(data, size);
+ read_source(source);
+}
+
+
+void
+Collection::read_source(Source& source)
+{
+ auto const ttc_tag = source.get_uint32();
+ if (ttc_tag != 0x74746366) {
+ throw InvalidTTCTag(ttc_tag);
+ }
+
+ auto const major_version = source.get_uint16();
+ auto const minor_version = source.get_uint16();
+ auto const num_fonts = source.get_uint32();
+
+ if (num_fonts == 0) {
+ return;
+ }
+
+ uint32_t offset = source.get_uint32();
+ for (uint32_t i = 0; i < num_fonts; ++i) {
+ Source font_source(source, offset);
+ _fonts.push_back(Font(font_source));
+ }
+}
+
+
diff --git a/src/collection.h b/src/collection.h
new file mode 100644
index 0000000..5fdc551
--- /dev/null
+++ b/src/collection.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2026 Carl Hetherington <cth@carlh.net>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#pragma once
+
+#include "font.h"
+#include <boost/filesystem.hpp>
+#include <fmt/format.h>
+
+class Source;
+
+
+namespace ttf {
+
+
+class InvalidTTCTag : public std::runtime_error
+{
+public:
+ InvalidTTCTag(uint32_t ttc_type) : std::runtime_error(fmt::format("Invalid TTC type 0x{0:x}", ttc_type)) {}
+};
+
+
+class Collection
+{
+public:
+ Collection(boost::filesystem::path const& ttc_file);
+ Collection(uint8_t const* data, int size);
+
+ std::vector<Font> fonts() const {
+ return _fonts;
+ }
+
+private:
+ void read_source(Source& source);
+
+ std::vector<Font> _fonts;
+};
+
+
+
+}
diff --git a/src/font.cc b/src/font.cc
index ac2c5a8..f3387a4 100644
--- a/src/font.cc
+++ b/src/font.cc
@@ -51,6 +51,12 @@ Font::Font(uint8_t const* data, int size)
}
+Font::Font(Source& source)
+{
+ read_source(source);
+}
+
+
void
Font::read_source(Source& source)
{
diff --git a/src/font.h b/src/font.h
index 99cb892..e9ce85d 100644
--- a/src/font.h
+++ b/src/font.h
@@ -46,6 +46,7 @@ public:
Font(boost::filesystem::path const& ttf_file);
/** Read and parse a TTF font from a block of memory */
Font(uint8_t const* data, int size);
+ Font(Source& source);
/** Write the font to a file */
void write(boost::filesystem::path const& ttf_file) const;
diff --git a/src/wscript b/src/wscript
index cc77f04..9c268c8 100644
--- a/src/wscript
+++ b/src/wscript
@@ -18,8 +18,8 @@
#
def build(bld):
- sources = 'font.cc name_table.cc table.cc util.cc'
- headers = 'font.h name_table.h table.h util.h'
+ sources = 'collection.cc font.cc name_table.cc table.cc util.cc'
+ headers = 'collection.h font.h name_table.h table.h util.h'
if bld.env.STATIC:
obj = bld(features='cxx cxxstlib')
diff --git a/test/data/8fb0935f-28cd-4d8f-9ee9-85897c600364 b/test/data/8fb0935f-28cd-4d8f-9ee9-85897c600364
new file mode 100644
index 0000000..b91e564
--- /dev/null
+++ b/test/data/8fb0935f-28cd-4d8f-9ee9-85897c600364
Binary files differ
diff --git a/test/tests.cc b/test/tests.cc
index 501806d..f432290 100644
--- a/test/tests.cc
+++ b/test/tests.cc
@@ -21,6 +21,7 @@
#define BOOST_TEST_MODULE libttf_test
+#include "collection.h"
#include "font.h"
#include "name_table.h"
#include <boost/filesystem.hpp>
@@ -144,3 +145,18 @@ BOOST_AUTO_TEST_CASE(set_names_test2)
BOOST_CHECK_EQUAL(boost::variant2::get<0>(font_family[2]), "Arial_0");
}
+
+BOOST_AUTO_TEST_CASE(load_ttc_file)
+{
+ BOOST_CHECK_THROW(ttf::Font("test/data/8fb0935f-28cd-4d8f-9ee9-85897c600364"), ttf::InvalidScalerType);
+ ttf::Collection collection("test/data/8fb0935f-28cd-4d8f-9ee9-85897c600364");
+ auto fonts = collection.fonts();
+ BOOST_CHECK_EQUAL(fonts.size(), 9U);
+
+ BOOST_REQUIRE(fonts[0].name_table());
+ auto const& table = fonts[0].name_table();
+ auto const font_family = table->names(ttf::NameTable::Identifier::FONT_FAMILY);
+ BOOST_REQUIRE_EQUAL(font_family.size(), 2U);
+ BOOST_CHECK_EQUAL(boost::variant2::get<0>(font_family[1]), "Arial Hebrew");
+}
+