summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2021-08-13 18:06:45 +0200
committerMattias Andrée <maandree@kth.se>2021-08-13 18:06:45 +0200
commitfcffe4810f59de6a4f39596a37242022b68e7bc5 (patch)
treed91ef754fe3b24ecfea8270ef4ef0c070de8c359
downloadlibparsesfnt-fcffe4810f59de6a4f39596a37242022b68e7bc5.tar.gz
libparsesfnt-fcffe4810f59de6a4f39596a37242022b68e7bc5.tar.bz2
libparsesfnt-fcffe4810f59de6a4f39596a37242022b68e7bc5.tar.xz
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--.gitignore13
-rw-r--r--LICENSE15
-rw-r--r--Makefile79
-rw-r--r--avar.c73
-rw-r--r--bhed.c12
-rw-r--r--common.h15
-rw-r--r--config.mk8
-rw-r--r--fdsc.c27
-rw-r--r--fmtx.c12
-rw-r--r--fpgm.c22
-rw-r--r--gasp.c27
-rw-r--r--gcid.c35
-rw-r--r--head.c12
-rw-r--r--hhea.c12
-rw-r--r--hmtx.c44
-rw-r--r--libparsesfnt.h771
-rw-r--r--libparsesfnt_parse___.c188
-rw-r--r--libparsesfnt_parse_fontdir.c11
-rw-r--r--libparsesfnt_parse_tabdir.c12
-rw-r--r--loca.c24
-rw-r--r--ltag.c44
-rw-r--r--maxp.c34
-rw-r--r--meta.c32
-rw-r--r--name.c33
-rw-r--r--trak.c76
-rw-r--r--vhea.c12
-rw-r--r--vmtx.c44
-rw-r--r--xref.c48
28 files changed, 1735 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..048b700
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+*\#*
+*~
+*.o
+*.a
+*.lo
+*.su
+*.so
+*.so.*
+*.gch
+*.gcov
+*.gcno
+*.gcda
+/libparsesfnt-all.c
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c97d5c1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+© 2020, 2021 Mattias Andrée <maandree@kth.se>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..11982d0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,79 @@
+.POSIX:
+
+CONFIGFILE = config.mk
+include $(CONFIGFILE)
+
+MODULES =\
+ head\
+ bhed\
+ hhea\
+ hmtx\
+ vhea\
+ vmtx\
+ maxp\
+ loca\
+ name\
+ fmtx\
+ ltag\
+ xref\
+ trak\
+ gcid\
+ fpgm\
+ fdsc\
+ gasp\
+ avar\
+ meta
+
+OBJ =\
+ libparsesfnt_parse___.o\
+ libparsesfnt_parse_fontdir.o\
+ libparsesfnt_parse_tabdir.o\
+ $(MODULES:=.o)
+
+HDR =\
+ libparsesfnt.h\
+ common.h
+
+AR_OBJ = $(OBJ)
+# Using "AR_OBJ=libparsesfnt-all.o" can reduce the size of the
+# library, however this may affect the size of applications that
+# don't use most of the functions. If you are compiling for your
+# application specification you can combine this with setting
+# MODULES to the parts your application will use; note however
+# that 'fpgm' covers both 'fpgm' and 'prep'.
+
+all: libparsesfnt.a
+$(OBJ): $(@:.o=.c) $(HDR)
+libparsesfnt-all.o: libparsesfnt-all.c $(HDR)
+
+libparsesfnt-all.c: $(OBJ:.o=.c)
+ cat $(OBJ:.o=.c) > $@
+
+.c.o:
+ $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+
+.c.lo:
+ $(CC) -fPIC -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+
+libparsesfnt.a: $(AR_OBJ)
+ @rm -f -- $@
+ $(AR) rc $@ $(AR_OBJ)
+
+install: libparsesfnt.a
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/lib"
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/include"
+ cp -- libparsesfnt.a "$(DESTDIR)$(PREFIX)/lib/"
+ cp -- libparsesfnt.h "$(DESTDIR)$(PREFIX)/include/"
+
+uninstall:
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libparsesfnt.a"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/include/libparsesfnt.h"
+
+clean:
+ -rm -f -- *.o *.a *.lo *.su *.so *.so.* *.gch *.gcov *.gcno *.gcda
+ -rm -f -- libparsesfnt-all.c
+
+.SUFFIXES:
+.SUFFIXES: .lo .o .c
+
+.PHONY: all install uninstall clean
diff --git a/avar.c b/avar.c
new file mode 100644
index 0000000..ad7293e
--- /dev/null
+++ b/avar.c
@@ -0,0 +1,73 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_avar(
+ const char *data, size_t size,
+ struct libparsesfnt_avar *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ return PARSE(LIBPARSESFNT_AVAR__, tag->offset, 0, 0, 0, 1, tag);
+}
+
+
+static uint16_t
+avar_parse16(const char *data)
+{
+ uint16_t b1 = (uint16_t)((const uint8_t *)data)[0];
+ uint16_t b2 = (uint16_t)((const uint8_t *)data)[1];
+ b1 = (uint16_t)(b1 << 8);
+ b2 = (uint16_t)(b2 << 0);
+ return (uint16_t)(b1 | b2);
+}
+
+int
+libparsesfnt_parse_avar_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_avar_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t *offsetp, size_t count)
+{
+ size_t offset = offsetp ? *offsetp : 0;
+ if (offset < 8) {
+ if (tag->length < 8) {
+ errno = EBFONT;
+ return -1;
+ }
+ offset = 8;
+ }
+ if ((size_t)tag->length < offset || size < (size_t)tag->length - offset) {
+ errno = EBFONT;
+ return -1;
+ }
+ while (count--) {
+ if (tag->length - offset < 2) {
+ errno = EBFONT;
+ return -1;
+ }
+ infop->pair_count = avar_parse16(&data[offset]);
+ offset += 2;
+ infop->libparsesfnt_subentry_location = offset;
+ memset(infop->__padding1, 0, sizeof(infop->__padding1));
+ if ((size_t)infop->pair_count > ((size_t)tag->length - offset) / 4) {
+ errno = EBFONT;
+ return -1;
+ }
+ infop++;
+ }
+ if (offsetp)
+ *offsetp = offset;
+ return 0;
+}
+
+
+int
+libparsesfnt_parse_avar_subentries(
+ const char *data, size_t size,
+ struct libparsesfnt_avar_subentry *infop,
+ const struct libparsesfnt_avar_entry *entry,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_AVAR_SUBENTRY__, entry->libparsesfnt_subentry_location, 0, 0, first, count, NULL);
+}
diff --git a/bhed.c b/bhed.c
new file mode 100644
index 0000000..c78c12a
--- /dev/null
+++ b/bhed.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_bhed(
+ const char *data, size_t size,
+ struct libparsesfnt_bhed *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ return PARSE(LIBPARSESFNT_BHED__, tag->offset, 0, 0, 0, 1, tag);
+}
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..a1b0f87
--- /dev/null
+++ b/common.h
@@ -0,0 +1,15 @@
+/* See LICENSE file for copyright and license details. */
+#include "libparsesfnt.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+int libparsesfnt_parse___(const char *data, size_t size, void *infop, size_t esize,
+ const char *fmt, size_t offset, size_t offset2, size_t offset3,
+ size_t first, size_t count, const struct libparsesfnt_tabdir_entry *tag);
+
+#define PARSE(...) libparsesfnt_parse___(data, size, infop, sizeof(*infop), __VA_ARGS__)
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..af85cea
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,8 @@
+PREFIX = /usr
+MANPREFIX = $(PREFIX)/share/man
+
+CC = cc
+
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE
+CFLAGS = -std=c99 -Wall
+LDFLAGS =
diff --git a/fdsc.c b/fdsc.c
new file mode 100644
index 0000000..86477a8
--- /dev/null
+++ b/fdsc.c
@@ -0,0 +1,27 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_fdsc(
+ const char *data, size_t size,
+ struct libparsesfnt_fdsc *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ if ((tag->length - 8) % 8) {
+ errno = EBFONT;
+ return -1;
+ }
+ return PARSE(LIBPARSESFNT_FDSC__, tag->offset, 0, 0, 0, 1, tag);
+}
+
+
+int
+libparsesfnt_parse_fdsc_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_fdsc_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_FDSC_ENTRY__, tag->offset, 8, 0, first, count, tag);
+}
diff --git a/fmtx.c b/fmtx.c
new file mode 100644
index 0000000..26bfafa
--- /dev/null
+++ b/fmtx.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_fmtx(
+ const char *data, size_t size,
+ struct libparsesfnt_fmtx *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ return PARSE(LIBPARSESFNT_NAME__, tag->offset, 0, 0, 0, 1, tag);
+}
diff --git a/fpgm.c b/fpgm.c
new file mode 100644
index 0000000..65df105
--- /dev/null
+++ b/fpgm.c
@@ -0,0 +1,22 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_fpgm(
+ const char *data, size_t size,
+ uint8_t *programp,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count)
+{
+ if (count > SIZE_MAX - first) {
+ errno = EFBIG;
+ return -1;
+ }
+ if (tag->offset < size || first + count > size - tag->offset) {
+ errno = EBFONT;
+ return -1;
+ }
+ memcpy(programp, &data[tag->offset + first], count - first);
+ return 0;
+}
diff --git a/gasp.c b/gasp.c
new file mode 100644
index 0000000..5d5e0ca
--- /dev/null
+++ b/gasp.c
@@ -0,0 +1,27 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_gasp(
+ const char *data, size_t size,
+ struct libparsesfnt_gasp *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ if ((tag->length - 4) % 4) {
+ errno = EBFONT;
+ return -1;
+ }
+ return PARSE(LIBPARSESFNT_GASP__, tag->offset, 0, 0, 0, 1, tag);
+}
+
+
+int
+libparsesfnt_parse_gasp_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_gasp_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_GASP_ENTRY__, tag->offset, 4, 0, first, count, tag);
+}
diff --git a/gcid.c b/gcid.c
new file mode 100644
index 0000000..bad7848
--- /dev/null
+++ b/gcid.c
@@ -0,0 +1,35 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_gcid(
+ const char *data, size_t size,
+ struct libparsesfnt_gcid *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ if ((tag->length - 144) % 2)
+ goto ebfont;
+ if (PARSE(LIBPARSESFNT_GCID__, tag->offset, 0, 0, 0, 1, tag))
+ return -1;
+ if (((size_t)(tag->length - 144) / 2 != (size_t)infop->count &&
+ (size_t)(tag->length - 144) / 2 != (size_t)infop->count + 1) ||
+ tag->length != infop->size)
+ goto ebfont;
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
+
+
+int
+libparsesfnt_parse_gcid_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_gcid_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_GCID_ENTRY__, tag->offset, 144, 0, first, count, tag);
+}
diff --git a/head.c b/head.c
new file mode 100644
index 0000000..f8c7591
--- /dev/null
+++ b/head.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_head(
+ const char *data, size_t size,
+ struct libparsesfnt_head *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ return PARSE(LIBPARSESFNT_HEAD__, tag->offset, 0, 0, 0, 1, tag);
+}
diff --git a/hhea.c b/hhea.c
new file mode 100644
index 0000000..e2a14b5
--- /dev/null
+++ b/hhea.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_hhea(
+ const char *data, size_t size,
+ struct libparsesfnt_hhea *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ return PARSE(LIBPARSESFNT_HHEA__, tag->offset, 0, 0, 0, 1, tag);
+}
diff --git a/hmtx.c b/hmtx.c
new file mode 100644
index 0000000..bb63af5
--- /dev/null
+++ b/hmtx.c
@@ -0,0 +1,44 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_hmtx(
+ const char *data, size_t size,
+ struct libparsesfnt_hmtx_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_HMTX_ENTRY__, tag->offset, 0, 0, first, count, tag);
+}
+
+
+int
+libparsesfnt_get_hmtx_lsb_subtable_length(
+ size_t *lengthp,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_hhea *hhea)
+{
+ size_t off;
+ /* hhea->num_advances_in_hmtx_table is uint16_t, so overflow is impossible */
+ off = (size_t)hhea->num_advances_in_hmtx_table * 4;
+ if (off > tag->length || (tag->length - off) % 2) {
+ errno = EBFONT;
+ return -1;
+ }
+ *lengthp = (tag->length - off) / 2;
+ return 0;
+}
+
+
+int
+libparsesfnt_parse_hmtx_lsb_subtable(
+ const char *data, size_t size,
+ struct libparsesfnt_hmtx_lsb_subtable_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_hhea *hhea,
+ size_t first, size_t count)
+{
+ size_t off;
+ /* hhea->num_advances_in_hmtx_table is uint16_t, so overflow is impossible */
+ off = (size_t)hhea->num_advances_in_hmtx_table * 4;
+ return PARSE(LIBPARSESFNT_HMTX_LSB_SUBTABLE_ENTRY__, tag->offset, off, 0, first, count, NULL);
+}
diff --git a/libparsesfnt.h b/libparsesfnt.h
new file mode 100644
index 0000000..809fad7
--- /dev/null
+++ b/libparsesfnt.h
@@ -0,0 +1,771 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBPARSESFNT_H
+#define LIBPARSESFNT_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+
+#define LIBPARSESFNT_8C__ "1111""1111"
+#define LIBPARSESFNT_16C__ LIBPARSESFNT_8C__""LIBPARSESFNT_8C__
+#define LIBPARSESFNT_32C__ LIBPARSESFNT_16C__""LIBPARSESFNT_16C__
+#define LIBPARSESFNT_64C__ LIBPARSESFNT_32C__""LIBPARSESFNT_32C__
+#define LIBPARSESFNT_128C__ LIBPARSESFNT_64C__""LIBPARSESFNT_64C__
+#define LIBPARSESFNT_255C__ LIBPARSESFNT_128C__""LIBPARSESFNT_64C__""LIBPARSESFNT_32C__""\
+ LIBPARSESFNT_32C__""LIBPARSESFNT_16C__""LIBPARSESFNT_16C__""\
+ LIBPARSESFNT_8C__"1111""11""1"
+
+
+#define LIBPARSESFNT_UNIX_EPOCH ((time_t)-2082844800L) /* 1904-01-01 00:00:00 */
+#define LIBPARSESFNT_TO_UNIX_EPOCH(TIME) ((time_t)(TIME) + LIBPARSESFNT_UNIX_EPOCH)
+
+
+
+/* === font directory === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html */
+
+struct libparsesfnt_fontdir {
+ char scaler_type[4];
+ uint16_t num_tables;
+ uint16_t search_range; /* use to determine how to bsearch(3) the table directory */
+ uint16_t entry_selector; /* use to determine whether to bsearch(3) the table directory */
+ uint16_t range_shift; /* use to determine how to bsearch(3) the table directory */
+};
+#define LIBPARSESFNT_FONTDIR__ "11112222"
+
+int libparsesfnt_parse_fontdir(
+ const char *data, size_t size,
+ struct libparsesfnt_fontdir *infop);
+
+
+
+/* === table directory === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html */
+
+struct libparsesfnt_tabdir_entry {
+ char tab[4];
+ uint32_t checksum;
+ uint32_t offset;
+ uint32_t length;
+};
+#define LIBPARSESFNT_TABDIR_ENTRY__ "1111444"
+
+int libparsesfnt_parse_tabdir(
+ const char *data, size_t size,
+ struct libparsesfnt_tabdir_entry *infop,
+ size_t first, size_t count);
+
+
+
+/* === 'head' (font header) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6head.html */
+
+struct libparsesfnt_head {
+ uint32_t version;
+ uint32_t font_revision;
+ uint32_t checksum_adjustment;
+ uint32_t magic_number;
+#define LIBPARSESFNT_HEAD_MAGIC_NUMBER_EXPECTED UINT32_C(0x5f0f3cf5)
+ uint16_t flags;
+ uint16_t units_per_em;
+#define LIBPARSESFNT_HEAD_UNITS_PER_EM_MIN 64
+#define LIBPARSESFNT_HEAD_UNITS_PER_EM_MAX 16384
+ uint32_t __padding1;
+ uint64_t created;
+ uint64_t modified;
+ int16_t x_min;
+ int16_t y_min;
+ int16_t x_max;
+ int16_t y_max;
+ uint16_t style_flags;
+ uint16_t lowest_ppem; /* smallest readable size in pixels (per em) */
+ int16_t font_direction_hint;
+ int16_t loca_table_format; /* 0 = "short" offsets, 1 = "long" offsets */
+ int16_t glyph_data_format;
+ uint16_t __padding2[3];
+};
+#define LIBPARSESFNT_HEAD__ "444422pppp88-2222+22-222pppppp"
+
+int libparsesfnt_parse_head(
+ const char *data, size_t size,
+ struct libparsesfnt_head *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+
+
+/* === 'bhed' (bitmap font header) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bhed.html */
+
+struct libparsesfnt_bhed {
+ uint32_t version;
+ uint32_t font_revision;
+ uint32_t checksum_adjustment;
+ uint32_t magic_number;
+#define LIBPARSESFNT_BHED_MAGIC_NUMBER_EXPECTED HEAD_MAGIC_NUMBER_EXPECTED
+ uint16_t flags;
+ uint16_t units_per_em;
+#define LIBPARSESFNT_BHED_UNITS_PER_EM_MIN LIBPARSESFNT_HEAD_UNITS_PER_EM_MIN
+#define LIBPARSESFNT_BHED_UNITS_PER_EM_MAX LIBPARSESFNT_HEAD_UNITS_PER_EM_MAX
+ uint32_t __padding1;
+ uint64_t created;
+ uint64_t modified;
+ int16_t x_min;
+ int16_t y_min;
+ int16_t x_max;
+ int16_t y_max;
+ uint16_t style_flags;
+ uint16_t lowest_ppem; /* smallest readable size in pixels (per em) */
+ int16_t font_direction_hint;
+ int16_t bloc_table_format; /* 0 = "short" offsets, 1 = "long" offsets */
+ int16_t glyph_data_format;
+ uint16_t __padding2[3];
+};
+#define LIBPARSESFNT_BHED__ "444422pppp88-2222+22-222pppppp"
+
+int libparsesfnt_parse_bhed(
+ const char *data, size_t size,
+ struct libparsesfnt_bhed *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+
+
+/* === 'hhea' (horizontal header) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hhea.html */
+
+struct libparsesfnt_hhea {
+ uint32_t version;
+ int16_t max_ascent;
+ int16_t max_descent;
+ int16_t line_gap;
+ uint16_t max_advance;
+ int16_t min_left_side_bearing;
+ int16_t max_left_side_bearing;
+ int16_t x_max_extent;
+ int16_t caret_slope_rise;
+ int16_t caret_slope_run;
+ int16_t caret_offset;
+ uint8_t ___reserved1[8];
+ int16_t metric_data_format;
+ uint16_t num_advances_in_hmtx_table;
+};
+#define LIBPARSESFNT_HHEA__ "4-222+2-222222........2+2"
+
+int libparsesfnt_parse_hhea(
+ const char *data, size_t size,
+ struct libparsesfnt_hhea *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+
+
+/* === 'hmtx' (horizontal metrics) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hmtx.html */
+
+struct libparsesfnt_hmtx_entry {
+ uint16_t advance;
+ int16_t left_side_bearing;
+};
+#define LIBPARSESFNT_HMTX_ENTRY__ "2-2"
+
+struct libparsesfnt_hmtx_lsb_subtable_entry {
+ int16_t left_side_bearing2;
+};
+#define LIBPARSESFNT_HMTX_LSB_SUBTABLE_ENTRY__ "-2"
+
+int libparsesfnt_parse_hmtx(
+ const char *data, size_t size,
+ struct libparsesfnt_hmtx_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count);
+
+int libparsesfnt_get_hmtx_lsb_subtable_length(
+ size_t *lengthp,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_hhea *hhea);
+
+int libparsesfnt_parse_hmtx_lsb_subtable(
+ const char *data, size_t size,
+ struct libparsesfnt_hmtx_lsb_subtable_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_hhea *hhea,
+ size_t first, size_t count);
+
+
+
+/* === 'vhea' (vertical header) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6vhea.html */
+
+struct libparsesfnt_vhea {
+ int32_t version;
+ int16_t max_ascent;
+ int16_t max_descent;
+ int16_t line_gap;
+ uint16_t max_advance;
+ int16_t min_top_side_bearing;
+ int16_t min_bottom_side_bearing;
+ int16_t y_max_extent;
+ int16_t caret_slope_rise;
+ int16_t caret_slope_run;
+ int16_t caret_offset;
+ uint8_t ___reserved1[8];
+ int16_t metric_data_format;
+ uint16_t num_advances_in_vmtx_table;
+};
+#define LIBPARSESFNT_VHEA__ "4-222+2-222222........2+2"
+
+int libparsesfnt_parse_vhea(
+ const char *data, size_t size,
+ struct libparsesfnt_vhea *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+
+
+/* === 'vmtx' (vertical metrics) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6vmtx.html */
+
+struct libparsesfnt_vmtx_entry {
+ uint16_t advance;
+ int16_t top_side_bearing;
+};
+#define LIBPARSESFNT_VMTX_ENTRY__ "2-2"
+
+struct libparsesfnt_vmtx_tsb_subtable_entry {
+ int16_t top_side_bearing2;
+};
+#define LIBPARSESFNT_VMTX_TSB_SUBTABLE_ENTRY__ "-2"
+
+int libparsesfnt_parse_vmtx(
+ const char *data, size_t size,
+ struct libparsesfnt_vmtx_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count);
+
+int libparsesfnt_get_vmtx_tsb_subtable_length(
+ size_t *lengthp,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_vhea *vhea);
+
+int libparsesfnt_parse_vmtx_tsb_subtable(
+ const char *data, size_t size,
+ struct libparsesfnt_vmtx_tsb_subtable_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_vhea *vhea,
+ size_t first, size_t count);
+
+
+
+/* === 'maxp' (maximum profile) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6maxp.html */
+
+struct libparsesfnt_maxp_0_5 {
+ uint16_t num_glyphs;
+};
+#define LIBPARSESFNT_MAXP_0_5__ "2"
+
+struct libparsesfnt_maxp_1_0 {
+ uint16_t num_glyphs;
+ uint16_t max_points_noncompound;
+ uint16_t max_contours_noncompound;
+ uint16_t max_points_compound;
+ uint16_t max_contours_compound;
+ uint16_t max_zones; /* should be 2 */
+ uint16_t max_twilight_points;
+ uint16_t max_storage_areas;
+ uint16_t max_fdefs;
+ uint16_t max_odefs;
+ uint16_t max_stack_depth;
+ uint16_t max_size_of_instructions;
+ uint16_t max_top_level_glyphs;
+ uint16_t max_recursion;
+};
+#define LIBPARSESFNT_MAXP_1_0__ "22222222222222"
+
+struct libparsesfnt_maxp {
+ uint32_t version;
+ union {
+ struct libparsesfnt_maxp_0_5 v0_5;
+ struct libparsesfnt_maxp_1_0 v1_0; /* extends .v0_5 */
+ } v;
+};
+#define LIBPARSESFNT_MAXP__ "4"
+
+int libparsesfnt_parse_maxp(
+ const char *data, size_t size,
+ struct libparsesfnt_maxp *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+
+
+/* === 'loca' (glyph locations) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6loca.html */
+
+/* There is one extra entry at the end, so that (entry[i + 1].offset - entry[i].offset)
+ * calculates the size of entry i. */
+
+struct libparsesfnt_loca_short_entry {
+ uint16_t offset;
+};
+#define LIBPARSESFNT_LOCA_SHORT_ENTRY__ "2"
+
+struct libparsesfnt_loca_long_entry {
+ uint32_t offset;
+};
+#define LIBPARSESFNT_LOCA_LONG_ENTRY__ "4"
+
+int libparsesfnt_parse_loca_short(
+ const char *data, size_t size,
+ struct libparsesfnt_loca_short_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count);
+
+int libparsesfnt_parse_loca_long(
+ const char *data, size_t size,
+ struct libparsesfnt_loca_long_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count);
+
+
+
+/* === 'name' (name) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html */
+/* TODO platform ID, platform-specific ID, language ID */
+
+struct libparsesfnt_name {
+ uint16_t format;
+ uint16_t count;
+ uint16_t string_offset;
+};
+#define LIBPARSESFNT_NAME__ "222"
+
+struct libparsesfnt_name_entry {
+ uint16_t platform_id;
+ uint16_t platform_specific_id;
+ uint16_t language_id;
+ uint16_t name_id;
+ uint16_t name_length;
+ uint16_t name_offset;
+};
+#define LIBPARSESFNT_NAME_ENTRY__ "222222"
+
+enum libparsesfnt_name_id {
+ LIBPARSESFNT_NAME_ID_COPYRIGHT_NOTICE = 0,
+ LIBPARSESFNT_NAME_ID_FONT_FAMILY = 1,
+ LIBPARSESFNT_NAME_ID_FONT_SUBFAMILY = 2,
+ LIBPARSESFNT_NAME_ID_UNIQUE_SUBFAMILY_IDENTIFICATION = 3,
+ LIBPARSESFNT_NAME_ID_FULL_NAME_OF_THE_FONT = 4,
+ LIBPARSESFNT_NAME_ID_VERSION_OF_THE_NAME_TABLE = 5,
+ LIBPARSESFNT_NAME_ID_POSTSCRIPT_NAME_OF_THE_FONT = 6,
+ LIBPARSESFNT_NAME_ID_TRADEMARK_NOTICE = 7,
+ LIBPARSESFNT_NAME_ID_MANUFACTURER = 8,
+ LIBPARSESFNT_NAME_ID_DESIGNER = 9,
+ LIBPARSESFNT_NAME_ID_DESCRIPTION = 10,
+ LIBPARSESFNT_NAME_ID_VENDOR_URL = 11,
+ LIBPARSESFNT_NAME_ID_DESIGNER_URL = 12,
+ LIBPARSESFNT_NAME_ID_LICENSE_DESCRIPTION = 13,
+ LIBPARSESFNT_NAME_ID_LICENSE_INFORMATION_URL = 14,
+ /* 15 is reserved */
+ LIBPARSESFNT_NAME_ID_PREFERRED_FAMILY = 16,
+ LIBPARSESFNT_NAME_ID_PREFERRED_SUBFAMILY = 17,
+ LIBPARSESFNT_NAME_ID_COMPATIBLE_FULL = 18,
+ LIBPARSESFNT_NAME_ID_SAMPLE_TEXT = 19
+ /* 20–22 are defined by OpenType */
+ /* 23–255 are reserved for future expansions*/
+ /* 256–32767 are for font-specific names */
+};
+
+int libparsesfnt_parse_name(
+ const char *data, size_t size,
+ struct libparsesfnt_name *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+int libparsesfnt_parse_name_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_name_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count);
+
+
+
+/* === 'fmtx' (font metrics) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fmtx.html */
+
+struct libparsesfnt_fmtx {
+ uint32_t version;
+ uint32_t glyph_index;
+ uint8_t horizontal_before;
+ uint8_t horizontal_after;
+ uint8_t horizontal_caret_head;
+ uint8_t horizontal_caret_base;
+ uint8_t vertical_before;
+ uint8_t vertical_after;
+ uint8_t vertical_caret_head;
+ uint8_t vertical_caret_base;
+};
+#define LIBPARSESFNT_FMTX__ "4411111111"
+
+int libparsesfnt_parse_fmtx(
+ const char *data, size_t size,
+ struct libparsesfnt_fmtx *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+
+
+/* === 'ltag' (language tag) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6ltag.html */
+
+struct libparsesfnt_ltag {
+ uint32_t version;
+ uint32_t flags; /* unused, should be 0 */
+ uint32_t num_tags;
+};
+#define LIBPARSESFNT_LTAG__ "444"
+
+struct libparsesfnt_ltag_entry {
+ uint16_t offset; /* relative to the beginning of the 'ltag' table */
+ uint16_t length;
+};
+#define LIBPARSESFNT_LTAG_ENTRY__ "22"
+
+int libparsesfnt_parse_ltag(
+ const char *data, size_t size,
+ struct libparsesfnt_ltag *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+int libparsesfnt_parse_ltag_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_ltag_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count);
+
+int libparsesfnt_get_ltag_offset(
+ size_t size,
+ size_t *offsetp,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_ltag_entry *entry);
+
+
+
+/* === 'xref' (cross-reference) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6xref.html */
+
+struct libparsesfnt_xref {
+ uint32_t version;
+ uint32_t flags; /* unused, should be 0 */
+ uint32_t num_entries;
+ uint32_t string_offset; /* position of the string table: relative to the beginning of this table */
+};
+#define LIBPARSESFNT_XREF__ "4444"
+
+struct libparsesfnt_xref_entry {
+ char table_tab[4];
+ int16_t chain_index;
+ int16_t subtable_index;
+ int16_t table_type;
+ uint16_t string_offset; /* relative to the beginning of the string table */
+ uint16_t string_length;
+};
+#define LIBPARSESFNT_XREF_ENTRY__ "1111-2222+22"
+
+enum libparsesfnt_xref_table_type {
+ LIBPARSESFNT_XREF_CLASS_NAME_TABLE = 0,
+ LIBPARSESFNT_XREF_STATE_NAME_TABLE = 1,
+ LIBPARSESFNT_XREF_ENTRY_TRANSITION_NAME_TABLE = 2,
+ LIBPARSESFNT_XREF_ACTION_NAME_TABLE = 3,
+ LIBPARSESFNT_XREF_COLUMN_CLASS_NAME_TABLE = 4,
+ LIBPARSESFNT_XREF_ROW_CLASS_NAME_TABLE = 5
+};
+
+int libparsesfnt_parse_xref(
+ const char *data, size_t size,
+ struct libparsesfnt_xref *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+int libparsesfnt_parse_xref_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_xref_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count);
+
+int libparsesfnt_get_xref_offset(
+ size_t size,
+ size_t *offsetp,
+ const struct libparsesfnt_tabdir_entry *tag,
+ const struct libparsesfnt_xref *xref,
+ const struct libparsesfnt_xref_entry *entry);
+
+
+
+/* === 'trak' (tracking) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html */
+
+struct libparsesfnt_trak {
+ uint32_t version;
+ uint16_t format;
+ uint16_t horiz_offset; /* relative to the beginning of this table, 0 if missing */
+ uint16_t vert_offset; /* relative to the beginning of this table, 0 if missing */
+ uint8_t __reserved1[2];
+};
+#define LIBPARSESFNT_TRAK__ "4222.."
+
+struct libparsesfnt_trak_data {
+ uint16_t n_tracks;
+ uint16_t n_sizes;
+ uint32_t size_table_offset; /* position of the size subtable: relative to the beginning of the 'trak' tabletable */
+};
+#define LIBPARSESFNT_TRAK_DATA__ "224"
+
+struct libparsesfnt_trak_track_entry {
+ int32_t track;
+ uint16_t name_index; /* should be > 255 */
+ uint16_t offset; /* position of this track's per-size tracking values: relative to the beginning of the 'trak' table */
+};
+#define LIBPARSESFNT_TRAK_TRACK_ENTRY__ "-4+22"
+
+struct libparsesfnt_trak_size_entry {
+ int32_t size;
+};
+#define LIBPARSESFNT_TRAK_SIZE_ENTRY__ "-4"
+
+int libparsesfnt_parse_trak(
+ const char *data, size_t size,
+ struct libparsesfnt_trak *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+int libparsesfnt_parse_trak_horiz(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_data *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak *trak);
+
+int libparsesfnt_parse_trak_vert(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_data *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak *trak);
+
+int libparsesfnt_parse_trak_horiz_track_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_track_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak *trak,
+ size_t first, size_t count);
+
+int libparsesfnt_parse_trak_vert_track_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_track_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak *trak,
+ size_t first, size_t count);
+
+int libparsesfnt_parse_trak_size_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_size_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak_data *trak_data,
+ size_t first, size_t count);
+
+int libparsesfnt_parse_trak_track_size_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_size_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak_track_entry *track,
+ size_t first, size_t count);
+
+
+
+/* === 'cvt ' (control value) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cvt.html */
+
+struct libparsesfnt_cvt_entry {
+ int16_t control_value;
+};
+
+/* TODO it is documented that entry count is table length divided by 4,
+ * however the element type (FWord) is 2 bytes wide */
+
+
+
+/* === 'gcid' (glyph to CID mapping) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6gcid.html */
+
+struct libparsesfnt_gcid {
+ uint16_t version;
+ uint16_t format;
+ uint32_t size;
+ uint16_t registry;
+ char registry_name[64];
+ uint16_t order;
+ char order_name[64];
+ uint16_t supplement_version;
+ uint16_t count;
+};
+#define LIBPARSESFNT_GCID__ "2242"LIBPARSESFNT_64C__"2"LIBPARSESFNT_64C__"22"
+
+struct libparsesfnt_gcid_entry {
+ uint16_t cid;
+#define LIBPARSESFNT_GCID_NO_CID UINT16_C(0xFFFF)
+};
+#define LIBPARSESFNT_GCID_ENTRY__ "2"
+
+int libparsesfnt_parse_gcid(
+ const char *data, size_t size,
+ struct libparsesfnt_gcid *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+int libparsesfnt_parse_gcid_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_gcid_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count);
+
+
+
+/* === 'fpgm' (font program) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fpgm.html */
+
+int libparsesfnt_parse_fpgm(
+ const char *data, size_t size,
+ uint8_t *programp,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count);
+
+
+
+/* === 'prep' (control value program) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6prep.html */
+
+#define libparsesfnt_parse_prep libparsesfnt_parse_fpgm
+
+
+
+/* === 'fdsc' (font descriptors) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fdsc.html */
+
+struct libparsesfnt_fdsc {
+ uint32_t version;
+ uint32_t descriptor_count;
+};
+#define LIBPARSESFNT_FDSC__ "44"
+
+struct libparsesfnt_fdsc_entry {
+ char tag[4];
+ int32_t value;
+};
+#define LIBPARSESFNT_FDSC_ENTRY__ "1111-4"
+
+enum libparsesfnt_fdsc_nalf {
+ LIBPARSESFNT_FDSC_NALF_ALPHABETIC = 0,
+ LIBPARSESFNT_FDSC_NALF_DINGBATS = 1,
+ LIBPARSESFNT_FDSC_NALF_PI_CHARACTERS = 2,
+ LIBPARSESFNT_FDSC_NALF_FLEURONS = 3,
+ LIBPARSESFNT_FDSC_NALF_DECORATIVE_BORDERS = 4,
+ LIBPARSESFNT_FDSC_NALF_INTERNATIONAL_SYMBOLS = 5,
+ LIBPARSESFNT_FDSC_NALF_MATH_SYMBOLS = 6
+};
+
+int libparsesfnt_parse_fdsc(
+ const char *data, size_t size,
+ struct libparsesfnt_fdsc *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+int libparsesfnt_parse_fdsc_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_fdsc_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count);
+
+
+
+/* === 'gasp' (grid-fitting and scan-conversion procedure) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6gasp.html */
+
+struct libparsesfnt_gasp {
+ uint16_t version;
+ uint16_t num_ranges;
+};
+#define LIBPARSESFNT_GASP__ "22"
+
+struct libparsesfnt_gasp_entry {
+ uint16_t range_max_ppem;
+ uint16_t range_gasp_behaviour;
+};
+#define LIBPARSESFNT_GASP_ENTRY__ "22"
+
+enum libparsesfnt_gasp_behaviour {
+ LIBPARSESFNT_GASP_BEHAVIOUR_GRID_FIT = 0x0001,
+ LIBPARSESFNT_GASP_BEHAVIOUR_DO_GREY = 0x0002
+};
+
+int libparsesfnt_parse_gasp(
+ const char *data, size_t size,
+ struct libparsesfnt_gasp *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+int libparsesfnt_parse_gasp_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_gasp_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count);
+
+
+
+/* === 'avar' (axis variation) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6avar.html */
+
+struct libparsesfnt_avar {
+ uint32_t name;
+ uint32_t axis_count;
+};
+#define LIBPARSESFNT_AVAR__ "44"
+
+struct libparsesfnt_avar_entry {
+ uint16_t pair_count;
+ char __padding1[sizeof(size_t) - sizeof(uint16_t)]; /* using sizeof for simplicity (may have same alignment) */
+ size_t libparsesfnt_subentry_location;
+};
+#define LIBPARSESFNT_AVAR_ENTRY__ "2"
+
+struct libparsesfnt_avar_subentry {
+ int16_t from_coord;
+ int16_t to_coord;
+};
+#define LIBPARSESFNT_AVAR_SUBENTRY__ "22"
+
+int libparsesfnt_parse_avar(
+ const char *data, size_t size,
+ struct libparsesfnt_avar *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+int libparsesfnt_parse_avar_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_avar_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t *offsetp /* start at 0 */, size_t count);
+
+int libparsesfnt_parse_avar_subentries(
+ const char *data, size_t size,
+ struct libparsesfnt_avar_subentry *infop,
+ const struct libparsesfnt_avar_entry *entry,
+ size_t first, size_t count);
+
+
+
+/* === 'meta' (metadata) === */
+/* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6meta.html */
+
+struct libparsesfnt_meta {
+ uint32_t version;
+ uint32_t flags;
+ uint32_t data_offset; /* relative to the beginning of this table */
+ uint32_t num_data_maps;
+};
+#define LIBPARSESFNT_META__ "4444"
+
+struct libparsesfnt_meta_entry {
+ char tag[4];
+ uint32_t data_offset; /* relative to the beginning of the 'meta' table */
+ uint32_t data_length;
+};
+#define LIBPARSESFNT_META_ENTRY__ "111144"
+
+int libparsesfnt_parse_meta(
+ const char *data, size_t size,
+ struct libparsesfnt_meta *infop,
+ const struct libparsesfnt_tabdir_entry *tag);
+
+int libparsesfnt_parse_meta_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_meta_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_meta *meta,
+ size_t first, size_t count);
+
+
+#endif
diff --git a/libparsesfnt_parse___.c b/libparsesfnt_parse___.c
new file mode 100644
index 0000000..17ee018
--- /dev/null
+++ b/libparsesfnt_parse___.c
@@ -0,0 +1,188 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+static uint16_t
+parse16(const char *data)
+{
+ uint16_t b1 = (uint16_t)((const uint8_t *)data)[0];
+ uint16_t b2 = (uint16_t)((const uint8_t *)data)[1];
+ b1 = (uint16_t)(b1 << 8);
+ b2 = (uint16_t)(b2 << 0);
+ return (uint16_t)(b1 | b2);
+}
+
+static uint32_t
+parse32(const char *data)
+{
+ uint32_t b1 = (uint32_t)((const uint8_t *)data)[0];
+ uint32_t b2 = (uint32_t)((const uint8_t *)data)[1];
+ uint32_t b3 = (uint32_t)((const uint8_t *)data)[2];
+ uint32_t b4 = (uint32_t)((const uint8_t *)data)[3];
+ b1 = (uint32_t)(b1 << 24);
+ b2 = (uint32_t)(b2 << 16);
+ b3 = (uint32_t)(b3 << 8);
+ b4 = (uint32_t)(b4 << 0);
+ return (uint32_t)(b1 | b2 | b3 | b4);
+}
+
+static uint64_t
+parse64(const char *data)
+{
+ uint64_t b1 = (uint64_t)((const uint8_t *)data)[0];
+ uint64_t b2 = (uint64_t)((const uint8_t *)data)[1];
+ uint64_t b3 = (uint64_t)((const uint8_t *)data)[2];
+ uint64_t b4 = (uint64_t)((const uint8_t *)data)[3];
+ uint64_t b5 = (uint64_t)((const uint8_t *)data)[4];
+ uint64_t b6 = (uint64_t)((const uint8_t *)data)[5];
+ uint64_t b7 = (uint64_t)((const uint8_t *)data)[6];
+ uint64_t b8 = (uint64_t)((const uint8_t *)data)[7];
+ b1 = (uint32_t)(b1 << 56);
+ b2 = (uint32_t)(b2 << 48);
+ b3 = (uint32_t)(b3 << 40);
+ b4 = (uint32_t)(b4 << 32);
+ b5 = (uint32_t)(b5 << 24);
+ b6 = (uint32_t)(b6 << 16);
+ b7 = (uint32_t)(b7 << 8);
+ b8 = (uint32_t)(b8 << 0);
+ return (uint32_t)(b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8);
+}
+
+
+static void
+sign8(union {uint8_t u; int8_t s;} *info)
+{
+ info->s = ((info->u >> 7) ? -(int8_t)(~info->u + 1) : (int8_t)info->u);
+}
+
+static void
+sign16(union {uint16_t u; int16_t s;} *info)
+{
+ info->s = ((info->u >> 15) ? -(int16_t)(~info->u + 1) : (int16_t)info->u);
+}
+
+static void
+sign32(union {uint32_t u; int32_t s;} *info)
+{
+ info->s = ((info->u >> 31) ? -(int32_t)(~info->u + 1) : (int32_t)info->u);
+}
+
+static void
+sign64(union {uint64_t u; int64_t s;} *info)
+{
+ info->s = ((info->u >> 63) ? -(int64_t)(~info->u + 1) : (int64_t)info->u);
+}
+
+
+int
+libparsesfnt_parse___(const char *data, size_t size, void *infop, size_t esize,
+ const char *fmt, size_t offset, size_t offset2, size_t offset3,
+ size_t first, size_t count, const struct libparsesfnt_tabdir_entry *tag)
+{
+ const char *s;
+ size_t tag_offset = 0;
+ size_t need = 0;
+ size_t padding = 0;
+ int is_signed = 0;
+ char *info = infop;
+
+ if (offset > size || offset2 > size - offset)
+ goto ebfont;
+ offset += offset2;
+ if (offset3 > size - offset)
+ goto ebfont;
+ offset += offset3;
+
+ if (tag)
+ tag_offset = offset - tag->offset;
+
+ for (s = fmt; *s; s++) {
+ if (*s == 'p')
+ padding += 1;
+ else if (*s == '1' || *s == '.')
+ need += 1;
+ else if (*s == '2')
+ need += 2;
+ else if (*s == '4')
+ need += 4;
+ else if (*s == '8')
+ need += 8;
+ }
+
+ if (count > SIZE_MAX - first ||
+ first > (SIZE_MAX - offset) / need)
+ goto efbig;
+ offset += first * need;
+
+ if (offset > size || need > size - offset)
+ goto ebfont;
+
+ if (count > (SIZE_MAX - offset) / need)
+ goto efbig;
+ if (offset + count * need > size ||
+ (tag && (tag->length < count * need ||
+ tag->length > size ||
+ tag_offset > tag->length ||
+ first + count > (tag->length - tag_offset) / need)))
+ goto ebfont;
+
+ data = &data[offset];
+
+ padding = esize - need - padding;
+ for (; count--; info = &info[padding]) {
+ for (s = fmt; *s; s++) {
+ if (*s == 'p') {
+ *info++ = 0;
+ } else if (*s == '.') {
+ *info++ = *data++;
+ } else if (*s == '1') {
+ *(uint8_t *)info = *(const uint8_t *)data;
+ if (is_signed)
+ sign8((void *)info);
+ data = &data[1];
+ info = &info[1];
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcast-align" /* in practice alignment will be correct */
+#endif
+ } else if (*s == '2') {
+ *(uint16_t *)info = parse16(data);
+ if (is_signed)
+ sign16((void *)info);
+ data = &data[2];
+ info = &info[2];
+ } else if (*s == '4') {
+ *(uint32_t *)info = parse32(data);
+ if (is_signed)
+ sign32((void *)info);
+ data = &data[4];
+ info = &info[4];
+ } else if (*s == '8') {
+ *(uint64_t *)info = parse64(data);
+ if (is_signed)
+ sign64((void *)info);
+ data = &data[8];
+ info = &info[8];
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+ } else if (*s == '-') {
+ is_signed = 1;
+ } else if (*s == '+') {
+ is_signed = 0;
+ } else {
+ abort();
+ }
+ }
+ }
+
+ return 0;
+
+efbig:
+ errno = EFBIG;
+ return -1;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsesfnt_parse_fontdir.c b/libparsesfnt_parse_fontdir.c
new file mode 100644
index 0000000..ce3085a
--- /dev/null
+++ b/libparsesfnt_parse_fontdir.c
@@ -0,0 +1,11 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_fontdir(
+ const char *data, size_t size,
+ struct libparsesfnt_fontdir *infop)
+{
+ return PARSE(LIBPARSESFNT_FONTDIR__, 0, 0, 0, 0, 1, NULL);
+}
diff --git a/libparsesfnt_parse_tabdir.c b/libparsesfnt_parse_tabdir.c
new file mode 100644
index 0000000..1302e3a
--- /dev/null
+++ b/libparsesfnt_parse_tabdir.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_tabdir(
+ const char *data, size_t size,
+ struct libparsesfnt_tabdir_entry *infop,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_TABDIR_ENTRY__, 12, 0, 0, first, count, NULL);
+}
diff --git a/loca.c b/loca.c
new file mode 100644
index 0000000..715f0ef
--- /dev/null
+++ b/loca.c
@@ -0,0 +1,24 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_loca_short(
+ const char *data, size_t size,
+ struct libparsesfnt_loca_short_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_LOCA_SHORT_ENTRY__, tag->offset, 0, 0, first, count, tag);
+}
+
+
+int
+libparsesfnt_parse_loca_long(
+ const char *data, size_t size,
+ struct libparsesfnt_loca_long_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_LOCA_LONG_ENTRY__, tag->offset, 0, 0, first, count, tag);
+}
diff --git a/ltag.c b/ltag.c
new file mode 100644
index 0000000..4831fb2
--- /dev/null
+++ b/ltag.c
@@ -0,0 +1,44 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_ltag(
+ const char *data, size_t size,
+ struct libparsesfnt_ltag *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ return PARSE(LIBPARSESFNT_LTAG__, tag->offset, 0, 0, 0, 1, tag);
+}
+
+
+int
+libparsesfnt_parse_ltag_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_ltag_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_LTAG_ENTRY__, tag->offset, 12, 0, first, count, tag);
+}
+
+
+int
+libparsesfnt_get_ltag_offset(
+ size_t size,
+ size_t *offsetp,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_ltag_entry *entry)
+{
+ size_t offset;
+ if ((size_t)entry->offset > size - (size_t)tag->offset) {
+ errno = EBFONT;
+ return -1;
+ }
+ offset = (size_t)tag->offset + (size_t)entry->offset;
+ if ((size_t)entry->length > size - offset) {
+ errno = EBFONT;
+ return -1;
+ }
+ *offsetp = offset;
+ return 0;
+}
diff --git a/maxp.c b/maxp.c
new file mode 100644
index 0000000..bd70477
--- /dev/null
+++ b/maxp.c
@@ -0,0 +1,34 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_maxp(
+ const char *data, size_t size,
+ struct libparsesfnt_maxp *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ uint8_t major_high, major_low;
+ const char *fmt;
+
+ major_high = *(const uint8_t *)&data[tag->offset + 0];
+ major_low = *(const uint8_t *)&data[tag->offset + 1];
+
+ if (major_high == 0 && major_low == 0) {
+ if (*(const uint8_t *)&data[tag->offset + 2] < 0x50U)
+ goto bfont;
+ fmt = LIBPARSESFNT_MAXP__""LIBPARSESFNT_MAXP_0_5__;
+
+ } else if (major_high && major_low == 1) {
+ fmt = LIBPARSESFNT_MAXP__""LIBPARSESFNT_MAXP_1_0__;
+
+ } else {
+ goto bfont;
+ }
+
+ return PARSE(fmt, tag->offset, 0, 0, 0, 1, tag);
+
+bfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/meta.c b/meta.c
new file mode 100644
index 0000000..ef666c7
--- /dev/null
+++ b/meta.c
@@ -0,0 +1,32 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_meta(
+ const char *data, size_t size,
+ struct libparsesfnt_meta *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ int ret;
+ ret = PARSE(LIBPARSESFNT_META__, tag->offset, 0, 0, 0, 1, tag);
+ if (!ret) {
+ if (infop->data_offset > size - tag->offset ||
+ infop->num_data_maps > (size - tag->offset - infop->data_offset) / 12) {
+ errno = EBFONT;
+ return -1;
+ }
+ }
+ return ret;
+}
+
+
+int
+libparsesfnt_parse_meta_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_meta_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_meta *meta,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_META_ENTRY__, tag->offset, meta->data_offset, 0, first, count, NULL);
+}
diff --git a/name.c b/name.c
new file mode 100644
index 0000000..bf0e859
--- /dev/null
+++ b/name.c
@@ -0,0 +1,33 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_name(
+ const char *data, size_t size,
+ struct libparsesfnt_name *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ if ((tag->length - 6) % 12)
+ goto ebfont;
+ if (PARSE(LIBPARSESFNT_NAME__, tag->offset, 0, 0, 0, 1, tag))
+ return -1;
+ if ((tag->length - 6) / 12 != infop->count)
+ goto ebfont;
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
+
+
+int
+libparsesfnt_parse_name_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_name_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_NAME_ENTRY__, tag->offset, 6, 0, first, count, tag);
+}
diff --git a/trak.c b/trak.c
new file mode 100644
index 0000000..731f683
--- /dev/null
+++ b/trak.c
@@ -0,0 +1,76 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_trak(
+ const char *data, size_t size,
+ struct libparsesfnt_trak *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ return PARSE(LIBPARSESFNT_TRAK__, tag->offset, 0, 0, 0, 1, tag);
+}
+
+
+int
+libparsesfnt_parse_trak_horiz(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_data *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak *trak)
+{
+ return PARSE(LIBPARSESFNT_TRAK_DATA__, tag->offset, trak->horiz_offset, 0, 0, 1, NULL);
+}
+
+
+int
+libparsesfnt_parse_trak_vert(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_data *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak *trak)
+{
+ return PARSE(LIBPARSESFNT_TRAK_DATA__, tag->offset, trak->vert_offset, 0, 0, 1, NULL);
+}
+
+
+int
+libparsesfnt_parse_trak_horiz_track_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_track_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak *trak,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_TRAK_TRACK_ENTRY__, tag->offset, trak->horiz_offset, 8, first, count, NULL);
+}
+
+
+int
+libparsesfnt_parse_trak_vert_track_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_track_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak *trak,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_TRAK_TRACK_ENTRY__, tag->offset, trak->vert_offset, 8, first, count, NULL);
+}
+
+
+int
+libparsesfnt_parse_trak_size_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_size_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak_data *trak_data,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_TRAK_SIZE_ENTRY__, tag->offset, trak_data->size_table_offset, 0, first, count, NULL);
+}
+
+
+int
+libparsesfnt_parse_trak_track_size_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_trak_size_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_trak_track_entry *track,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_TRAK_SIZE_ENTRY__, tag->offset, track->offset, 0, first, count, NULL);
+}
diff --git a/vhea.c b/vhea.c
new file mode 100644
index 0000000..e12edf7
--- /dev/null
+++ b/vhea.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_vhea(
+ const char *data, size_t size,
+ struct libparsesfnt_vhea *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ return PARSE(LIBPARSESFNT_VHEA__, tag->offset, 0, 0, 0, 1, tag);
+}
diff --git a/vmtx.c b/vmtx.c
new file mode 100644
index 0000000..e6c83fc
--- /dev/null
+++ b/vmtx.c
@@ -0,0 +1,44 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_vmtx(
+ const char *data, size_t size,
+ struct libparsesfnt_vmtx_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_VMTX_ENTRY__, tag->offset, 0, 0, first, count, tag);
+}
+
+
+int
+libparsesfnt_get_vmtx_tsb_subtable_length(
+ size_t *lengthp,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_vhea *vhea)
+{
+ size_t off;
+ /* vhea->num_advances_in_vmtx_table is uint16_t, so overflow is impossible */
+ off = (size_t)vhea->num_advances_in_vmtx_table * 4;
+ if (off > tag->length || (tag->length - off) % 2) {
+ errno = EBFONT;
+ return -1;
+ }
+ *lengthp = (tag->length - off) / 2;
+ return 0;
+}
+
+
+int
+libparsesfnt_parse_vmtx_tsb_subtable(
+ const char *data, size_t size,
+ struct libparsesfnt_vmtx_tsb_subtable_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_vhea *vhea,
+ size_t first, size_t count)
+{
+ size_t off;
+ /* vhea->num_advances_in_vmtx_table is uint16_t, so overflow is impossible */
+ off = (size_t)vhea->num_advances_in_vmtx_table * 4;
+ return PARSE(LIBPARSESFNT_VMTX_TSB_SUBTABLE_ENTRY__, tag->offset, off, 0, first, count, NULL);
+}
diff --git a/xref.c b/xref.c
new file mode 100644
index 0000000..edec384
--- /dev/null
+++ b/xref.c
@@ -0,0 +1,48 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsesfnt_parse_xref(
+ const char *data, size_t size,
+ struct libparsesfnt_xref *infop,
+ const struct libparsesfnt_tabdir_entry *tag)
+{
+ return PARSE(LIBPARSESFNT_XREF__, tag->offset, 0, 0, 0, 1, tag);
+}
+
+
+int
+libparsesfnt_parse_xref_entries(
+ const char *data, size_t size,
+ struct libparsesfnt_xref_entry *infop,
+ const struct libparsesfnt_tabdir_entry *tag,
+ size_t first, size_t count)
+{
+ return PARSE(LIBPARSESFNT_XREF_ENTRY__, tag->offset, 16, 0, first, count, tag);
+}
+
+
+int
+libparsesfnt_get_xref_offset(
+ size_t size,
+ size_t *offsetp,
+ const struct libparsesfnt_tabdir_entry *tag, const struct libparsesfnt_xref *xref,
+ const struct libparsesfnt_xref_entry *entry)
+{
+ size_t offset = (size_t)tag->offset;
+ if ((size_t)xref->string_offset > size - offset)
+ goto ebfont;
+ offset += (size_t)xref->string_offset;
+ if ((size_t)entry->string_offset > size - offset)
+ goto ebfont;
+ offset += (size_t)entry->string_offset;
+ if ((size_t)entry->string_length > size - offset)
+ goto ebfont;
+ *offsetp = offset;
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}