aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2021-10-29 23:00:19 +0200
committerMattias Andrée <maandree@kth.se>2021-10-29 23:00:19 +0200
commit52f4424f2dcffa5e20e55c52a5777ce9212d05c5 (patch)
tree74bde882b97c6cdd5e8fdfd1342fbb5dcef0d00b
downloadlibparsepcf-52f4424f2dcffa5e20e55c52a5777ce9212d05c5.tar.gz
libparsepcf-52f4424f2dcffa5e20e55c52a5777ce9212d05c5.tar.bz2
libparsepcf-52f4424f2dcffa5e20e55c52a5777ce9212d05c5.tar.xz
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--.gitignore15
-rw-r--r--LICENSE15
-rw-r--r--Makefile94
-rw-r--r--common.h54
-rw-r--r--config.mk8
-rw-r--r--demo.c580
-rw-r--r--libparsepcf.h234
-rw-r--r--libparsepcf_destroy_preparsed_font.c10
-rw-r--r--libparsepcf_get_accelerators.c83
-rw-r--r--libparsepcf_get_bitmap_offsets.c28
-rw-r--r--libparsepcf_get_bitmaps.c52
-rw-r--r--libparsepcf_get_encoding.c44
-rw-r--r--libparsepcf_get_glyph_index.c36
-rw-r--r--libparsepcf_get_glyph_indices.c22
-rw-r--r--libparsepcf_get_glyph_name_subtable.c34
-rw-r--r--libparsepcf_get_glyph_names.c43
-rw-r--r--libparsepcf_get_metrics.c50
-rw-r--r--libparsepcf_get_metrics_count.c38
-rw-r--r--libparsepcf_get_properties.c46
-rw-r--r--libparsepcf_get_property_subtable.c47
-rw-r--r--libparsepcf_get_swidth_count.c31
-rw-r--r--libparsepcf_get_swidths.c20
-rw-r--r--libparsepcf_get_table_count.c23
-rw-r--r--libparsepcf_get_tables.c39
-rw-r--r--libparsepcf_parse_int16_from_unsigned__.c13
-rw-r--r--libparsepcf_parse_int32_from_unsigned__.c13
-rw-r--r--libparsepcf_parse_lsb_uint16__.c12
-rw-r--r--libparsepcf_parse_lsb_uint32__.c14
-rw-r--r--libparsepcf_parse_msb_uint16__.c12
-rw-r--r--libparsepcf_parse_msb_uint32__.c14
-rw-r--r--libparsepcf_preparse_font.c104
-rw-r--r--mk/linux.mk4
-rw-r--r--mk/macos.mk4
-rw-r--r--mk/windows.mk4
34 files changed, 1840 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9e13a6f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+*\#*
+*~
+*.o
+*.a
+*.lo
+*.su
+*.so
+*.so.*
+*.dll
+*.dylib
+*.gch
+*.gcov
+*.gcno
+*.gcda
+/demo
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c44b2d9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+© 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..0c406ea
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,94 @@
+.POSIX:
+
+CONFIGFILE = config.mk
+include $(CONFIGFILE)
+
+OS = linux
+# Linux: linux
+# Mac OS: macos
+# Windows: windows
+include mk/$(OS).mk
+
+
+LIB_MAJOR = 1
+LIB_MINOR = 0
+LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR)
+LIB_NAME = parsepcf
+
+
+OBJ =\
+ libparsepcf_destroy_preparsed_font.o\
+ libparsepcf_get_accelerators.o\
+ libparsepcf_get_bitmap_offsets.o\
+ libparsepcf_get_bitmaps.o\
+ libparsepcf_get_encoding.o\
+ libparsepcf_get_glyph_indices.o\
+ libparsepcf_get_glyph_name_subtable.o\
+ libparsepcf_get_glyph_names.o\
+ libparsepcf_get_metrics.o\
+ libparsepcf_get_metrics_count.o\
+ libparsepcf_get_properties.o\
+ libparsepcf_get_property_subtable.o\
+ libparsepcf_get_swidth_count.o\
+ libparsepcf_get_swidths.o\
+ libparsepcf_get_table_count.o\
+ libparsepcf_get_tables.o\
+ libparsepcf_parse_int16_from_unsigned__.o\
+ libparsepcf_parse_int32_from_unsigned__.o\
+ libparsepcf_parse_lsb_uint16__.o\
+ libparsepcf_parse_lsb_uint32__.o\
+ libparsepcf_parse_msb_uint16__.o\
+ libparsepcf_parse_msb_uint32__.o\
+ libparsepcf_preparse_font.o
+
+HDR =\
+ libparsepcf.h\
+ common.h
+
+LOBJ = $(OBJ:.o=.lo)
+
+
+all: libparsepcf.a libparsepcf.$(LIBEXT) demo
+$(OBJ): $(HDR)
+$(LOBJ): $(HDR)
+
+demo: demo.o libparsepcf.a
+ $(CC) -o $@ demo.o libparsepcf.a $(LDFLAGS)
+
+.c.o:
+ $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+
+.c.lo:
+ $(CC) -fPIC -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+
+libparsepcf.a: $(OBJ)
+ @rm -f -- $@
+ $(AR) rc $@ $(OBJ)
+
+libparsepcf.$(LIBEXT): $(LOBJ)
+ $(CC) $(LIBFLAGS) -o $@ $(LOBJ) $(LDFLAGS)
+
+install: libparsepcf.a libparsepcf.$(LIBEXT)
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/lib"
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/include"
+ cp -- libparsepcf.a "$(DESTDIR)$(PREFIX)/lib/"
+ cp -- libparsepcf.$(LIBEXT) "$(DESTDIR)$(PREFIX)/lib/libparsepcf.$(LIBMINOREXT)"
+ ln -sf -- libparsepcf.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/libparsepcf.$(LIBMAJOREXT)"
+ ln -sf -- libparsepcf.$(LIBMAJOREXT) "$(DESTDIR)$(PREFIX)/lib/libparsepcf.$(LIBEXT)"
+ cp -- libparsepcf.h "$(DESTDIR)$(PREFIX)/include/"
+
+uninstall:
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libparsepcf.a"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libparsepcf.$(LIBMAJOREXT)"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libparsepcf.$(LIBMINOREXT)"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libparsepcf.$(LIBEXT)"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/include/libparsepcf.h"
+
+clean:
+ -rm -f -- *.o *.a *.lo *.su *.so *.so.* *.dll *.dylib
+ -rm -f -- *.gch *.gcov *.gcno *.gcda *.$(LIBEXT) demo
+
+.SUFFIXES:
+.SUFFIXES: .lo .o .c
+
+.PHONY: all install uninstall clean
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..f81a098
--- /dev/null
+++ b/common.h
@@ -0,0 +1,54 @@
+/* See LICENSE file for copyright and license details. */
+#include "libparsepcf.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#if defined(__GNUC__)
+# define PURE __attribute__((__pure__))
+# define CONST __attribute__((__const__))
+#else
+# define PURE
+# define CONST
+#endif
+
+
+/* Table formats: */
+#define LIBPARSEPCF_DEFAULT_FORMAT UINT32_C(0x00000000)
+#define LIBPARSEPCF_INKBOUNDS UINT32_C(0x00000200)
+#define LIBPARSEPCF_ACCELERATOR_WITH_INK_BOUNDS UINT32_C(0x00000100)
+#define LIBPARSEPCF_COMPRESSED_METRICS UINT32_C(0x00000100)
+
+/* Table format modifiers: */
+#define LIBPARSEPCF_GLYPH_PAD_MASK (UINT32_C(3) << 0)
+#define LIBPARSEPCF_BYTE (UINT32_C(1) << 2)
+#define LIBPARSEPCF_BIT (UINT32_C(1) << 3)
+#define LIBPARSEPCF_SCAN_UNIT_MASK (UINT32_C(3) << 4)
+
+
+PURE uint32_t libparsepcf_parse_lsb_uint32__(const void *);
+PURE uint32_t libparsepcf_parse_msb_uint32__(const void *);
+
+PURE uint16_t libparsepcf_parse_lsb_uint16__(const void *);
+PURE uint16_t libparsepcf_parse_msb_uint16__(const void *);
+
+CONST int16_t libparsepcf_parse_int16_from_unsigned__(uint16_t);
+CONST int32_t libparsepcf_parse_int32_from_unsigned__(uint32_t);
+
+#define PARSE_UINT32(TEXT, MSB)\
+ ((MSB) ? libparsepcf_parse_msb_uint32__(TEXT) : libparsepcf_parse_lsb_uint32__(TEXT))
+
+#define PARSE_UINT16(TEXT, MSB)\
+ ((MSB) ? libparsepcf_parse_msb_uint16__(TEXT) : libparsepcf_parse_lsb_uint16__(TEXT))
+
+#define PARSE_INT32(TEXT, MSB)\
+ (libparsepcf_parse_int32_from_unsigned__(PARSE_UINT32(TEXT, MSB)))
+
+#define PARSE_INT16(TEXT, MSB)\
+ (libparsepcf_parse_int16_from_unsigned__(PARSE_UINT16(TEXT, MSB)))
+
+
+#undef PURE
+#undef CONST
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..9b16e1d
--- /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 -g
+LDFLAGS =
diff --git a/demo.c b/demo.c
new file mode 100644
index 0000000..c277da2
--- /dev/null
+++ b/demo.c
@@ -0,0 +1,580 @@
+#include "libparsepcf.h"
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static char *file = NULL;
+static size_t len = 0;
+
+static size_t table_n;
+static size_t table_i;
+static struct libparsepcf_table *tables;
+
+static struct libparsepcf_font font;
+
+
+static void
+load_file(void)
+{
+ size_t size = 0;
+ ssize_t r;
+
+ if (isatty(STDIN_FILENO)) {
+ fprintf(stderr, "An uncompressed PCF file is required as standard input\n");
+ exit(1);
+ }
+
+ for (;;) {
+ if (size == len) {
+ file = realloc(file, size += 8096);
+ if (!file) {
+ perror("realloc");
+ exit(1);
+ }
+ }
+ r = read(STDIN_FILENO, &file[len], size - len);
+ if (r <= 0) {
+ if (!r)
+ break;
+ perror("read");
+ exit(1);
+ }
+ len += (size_t)r;
+ }
+}
+
+
+static void
+print_properties(void)
+{
+ size_t prop_i;
+ struct libparsepcf_properties props;
+ struct libparsepcf_property_subtable *proptab;
+
+ if (libparsepcf_get_properties(file, len, &tables[table_i], &props)) {
+ perror("libparsepcf_get_properties");
+ exit(1);
+ }
+ printf(" PROPERTIES:\n");
+ printf("\tnprops: %zu\n", props.property_count);
+ printf("\tstrlen: %zu\n", props.strings_size);
+ if (!props.property_count)
+ return;
+ proptab = calloc(props.property_count, sizeof(*proptab));
+ if (!proptab) {
+ perror("calloc");
+ exit(1);
+ }
+ if (libparsepcf_get_property_subtable(file, len, &tables[table_i], &props,
+ proptab, 0, props.property_count)) {
+ perror("libparsepcf_get_property_subtable");
+ exit(1);
+ }
+ for (prop_i = 0; prop_i < props.property_count; prop_i++) {
+ printf("\t #%zu\n", prop_i);
+ printf("\t\tname: %s\n", proptab[prop_i].name);
+ if (proptab[prop_i].is_string_property)
+ printf("\t\tvalue: \"%s\"\n", proptab[prop_i].value.string_value);
+ else
+ printf("\t\tvalue: %i\n", proptab[prop_i].value.signed_value);
+ }
+ free(proptab);
+}
+
+
+static void
+print_metrics(const char *header)
+{
+ struct libparsepcf_metrics *metrics;
+ size_t mtx_i, mtx_n;
+
+ if (libparsepcf_get_metrics_count(file, len, &tables[table_i], &mtx_n)) {
+ perror("libparsepcf_get_metrics_count");
+ exit(1);
+ }
+ metrics = calloc(mtx_n, sizeof(*metrics));
+ if (!metrics) {
+ perror("calloc");
+ exit(1);
+ }
+ if (libparsepcf_get_metrics(file, len, &tables[table_i], metrics, 0, mtx_n)) {
+ perror("libparsepcf_get_metrics");
+ exit(1);
+ }
+ printf(" %s:\n", header);
+ printf("\tcount: %zu\n", mtx_n);
+ for (mtx_i = 0; mtx_i < mtx_n; mtx_i++) {
+ printf("\t#%zu: lsb=%i, rsb=%i, width=%i, ascent=%i, descent=%i, attributes=%x\n",
+ mtx_i, metrics[mtx_i].left_side_bearing, metrics[mtx_i].right_side_bearing,
+ metrics[mtx_i].character_width, metrics[mtx_i].character_ascent,
+ metrics[mtx_i].character_descent, metrics[mtx_i].character_attributes);
+ }
+ free(metrics);
+}
+
+
+static void
+print_glyph_names(void)
+{
+ size_t name_i;
+ struct libparsepcf_glyph_names names;
+ const char **nametab;
+
+ if (libparsepcf_get_glyph_names(file, len, &tables[table_i], &names)) {
+ perror("libparsepcf_get_glyph_names");
+ exit(1);
+ }
+ printf(" GLYPH NAMES:\n");
+ printf("\tnglyph: %zu\n", names.glyph_count);
+ printf("\tstrlen: %zu\n", names.strings_size);
+ if (!names.glyph_count)
+ return;
+ nametab = calloc(names.glyph_count, sizeof(*nametab));
+ if (!nametab) {
+ perror("calloc");
+ exit(1);
+ }
+ if (libparsepcf_get_glyph_name_subtable(file, len, &tables[table_i], &names,
+ nametab, 0, names.glyph_count)) {
+ perror("libparsepcf_get_glyph_name_subtable");
+ exit(1);
+ }
+ for (name_i = 0; name_i < names.glyph_count; name_i++)
+ printf("\t #%zu: %s\n", name_i, nametab[name_i]);
+ free(nametab);
+}
+
+
+static void
+print_bitmaps(void)
+{
+ size_t bitmap_i;
+ struct libparsepcf_bitmaps bitmaps;
+ size_t *bitmaptab;
+
+ if (libparsepcf_get_bitmaps(file, len, &tables[table_i], &bitmaps)) {
+ perror("libparsepcf_get_bitmaps");
+ exit(1);
+ }
+ printf(" BITMAPS:\n");
+ printf("\tnglyph: %zu\n", bitmaps.glyph_count);
+ printf("\tsize: %zu\n", bitmaps.bitmap_size);
+ printf("\tpacking: %zu\n", bitmaps.bit_packing);
+ printf("\tpadding: %zu\n", bitmaps.row_padding);
+ printf("\tlsbyte: %i\n", bitmaps.lsbyte);
+ printf("\tlsbit: %i\n", bitmaps.lsbit);
+ if (!bitmaps.glyph_count)
+ return;
+ bitmaptab = calloc(bitmaps.glyph_count, sizeof(*bitmaptab));
+ if (!bitmaptab) {
+ perror("calloc");
+ exit(1);
+ }
+ if (libparsepcf_get_bitmap_offsets(file, len, &tables[table_i], &bitmaps,
+ bitmaptab, 0, bitmaps.glyph_count)) {
+ perror("libparsepcf_get_bitmap_offsets");
+ exit(1);
+ }
+ for (bitmap_i = 0; bitmap_i < bitmaps.glyph_count; bitmap_i++) {
+ printf("\t #%zu: %zu -> %p (maxsize=%zu)\n",
+ bitmap_i, bitmaptab[bitmap_i],
+ (const void *)&bitmaps.bitmap_data[bitmaptab[bitmap_i]],
+ bitmaps.bitmap_size - bitmaptab[bitmap_i]);
+ }
+ free(bitmaptab);
+}
+
+
+static void
+print_bdf_encodings(void)
+{
+ struct libparsepcf_encoding encoding;
+ size_t *indices;
+ size_t index_i;
+
+ if (libparsepcf_get_encoding(file, len, &tables[table_i], &encoding)) {
+ perror("libparsepcf_get_encoding:");
+ exit(1);
+ }
+ printf(" BDF ENCODINGS:\n");
+ printf("\trange2: [%u, %u]\n", encoding.min_byte2, encoding.max_byte2);
+ printf("\trange1: [%u, %u]\n", encoding.min_byte1, encoding.max_byte1);
+ printf("\tdefault: %u\n", encoding.default_char);
+ printf("\tnglyph: %zu\n", encoding.glyph_count);
+ if (!encoding.glyph_count)
+ return;
+ indices = calloc(encoding.glyph_count, sizeof(*indices));
+ if (libparsepcf_get_glyph_indices(file, len, &tables[table_i], &encoding,
+ indices, 0, encoding.glyph_count)) {
+ perror("libparsepcf_get_glyph_indices");
+ exit(1);
+ }
+ for (index_i = 0; index_i < encoding.glyph_count; index_i++) {
+ if (indices[index_i] == LIBPARSEPCF_NOT_ENCODED)
+ printf("\t#%#zx: not encoded\n", index_i);
+ else
+ printf("\t#%#zx: %zu\n", index_i, indices[index_i]);
+ }
+ free(indices);
+}
+
+
+static void
+print_accelerators(const char *header)
+{
+ struct libparsepcf_accelerators accel;
+
+ if (libparsepcf_get_accelerators(file, len, &tables[table_i], &accel)) {
+ perror("libparsepcf_get_accelerators:");
+ exit(1);
+ }
+ printf(" %s:\n", header);
+ printf("\tno overlap: %i\n", accel.no_overlap);
+ printf("\tconstant metrics: %i\n", accel.constant_metrics);
+ printf("\tterminal font: %i\n", accel.terminal_font);
+ printf("\tconstant width: %i\n", accel.constant_width);
+ printf("\tink inside: %i\n", accel.ink_inside);
+ printf("\tink metrics: %i\n", accel.ink_metrics);
+ printf("\tdraw rtl: %i\n", accel.draw_rtl);
+ printf("\thave ink bounds: %i\n", accel.have_ink_bounds);
+ printf("\tfont ascent: %i\n", accel.font_ascent);
+ printf("\tfont descent: %i\n", accel.font_descent);
+ printf("\tmax overlap: %i\n", accel.max_overlap);
+ printf("\tmin bounds: lsb=%i, rsb=%i, width=%i, ascent=%i, descent=%i, attributes=%x\n",
+ accel.min_bounds.left_side_bearing, accel.min_bounds.right_side_bearing,
+ accel.min_bounds.character_width, accel.min_bounds.character_ascent,
+ accel.min_bounds.character_descent, accel.min_bounds.character_attributes);
+ printf("\tmax bounds: lsb=%i, rsb=%i, width=%i, ascent=%i, descent=%i, attributes=%x\n",
+ accel.max_bounds.left_side_bearing, accel.max_bounds.right_side_bearing,
+ accel.max_bounds.character_width, accel.max_bounds.character_ascent,
+ accel.max_bounds.character_descent, accel.max_bounds.character_attributes);
+ if (accel.have_ink_bounds) {
+ printf("\tmin ink bounds: lsb=%i, rsb=%i, width=%i, ascent=%i, descent=%i, attributes=%x\n",
+ accel.min_ink_bounds.left_side_bearing, accel.min_ink_bounds.right_side_bearing,
+ accel.min_ink_bounds.character_width, accel.min_ink_bounds.character_ascent,
+ accel.min_ink_bounds.character_descent, accel.min_ink_bounds.character_attributes);
+ printf("\tmax ink bounds: lsb=%i, rsb=%i, width=%i, ascent=%i, descent=%i, attributes=%x\n",
+ accel.max_ink_bounds.left_side_bearing, accel.max_ink_bounds.right_side_bearing,
+ accel.max_ink_bounds.character_width, accel.max_ink_bounds.character_ascent,
+ accel.max_ink_bounds.character_descent, accel.max_ink_bounds.character_attributes);
+ }
+}
+
+
+static void
+print_swidths(void)
+{
+ size_t sw_i, sw_n;
+ int32_t *swidths;
+
+ if (libparsepcf_get_swidth_count(file, len, &tables[table_i], &sw_n)) {
+ perror("libparsepcf_get_swidth_count");
+ exit(1);
+ }
+ printf(" SWIDTHS:\n");
+ printf("\tnglyph: %zu\n", sw_n);
+ if (!sw_n)
+ return;
+ swidths = calloc(sw_n, sizeof(*swidths));
+ if (libparsepcf_get_swidths(file, len, &tables[table_i], swidths, 0, sw_n)) {
+ perror("libparsepcf_get_swidths");
+ exit(1);
+ }
+ for (sw_i = 0; sw_i < sw_n; sw_i++)
+ printf("\t#%zu: %i milli-ems\n", sw_i, swidths[sw_i]);
+}
+
+
+static void
+print_font(void)
+{
+ if (libparsepcf_get_table_count(file, len, &table_n)) {
+ perror("libparsepcf_get_table_count");
+ exit(1);
+ }
+ fprintf(stderr, "size: %zu\n", len);
+ fprintf(stderr, "ntables: %zu\n", table_n);
+
+ tables = calloc(table_n, sizeof(*tables));
+ if (!tables) {
+ perror("calloc");
+ exit(1);
+ }
+ if (libparsepcf_get_tables(file, len, tables, 0, table_n)) {
+ perror("libparsepcf_get_tables");
+ exit(1);
+ }
+
+ for (table_i = 0; table_i < table_n; table_i++) {
+ printf("table #%zu: type=%#x, format=%#x, offset=%u, size=%u, (end=%u)\n",
+ table_i, tables[table_i].type, tables[table_i].format,
+ tables[table_i].offset, tables[table_i].size,
+ tables[table_i].offset + tables[table_i].size);
+
+ switch (tables[table_i].type) {
+#if 1
+ case LIBPARSEPCF_PROPERTIES: /* X font atoms */
+ print_properties();
+ break;
+#endif
+#if 0
+ case LIBPARSEPCF_METRICS: /* bitmap size */
+ print_metrics("METRICS");
+ break;
+#endif
+#if 0
+ case LIBPARSEPCF_INK_METRICS: /* minimium bounding box metrics */
+ print_metrics("INK METRICS");
+ break;
+#endif
+#if 0
+ case LIBPARSEPCF_GLYPH_NAMES: /* PostScript names */
+ print_glyph_names();
+ break;
+#endif
+#if 0
+ case LIBPARSEPCF_BITMAPS:
+ print_bitmaps();
+ break;
+#endif
+#if 0
+ case LIBPARSEPCF_BDF_ENCODINGS:
+ print_bdf_encodings();
+ break;
+#endif
+#if 1
+ case LIBPARSEPCF_ACCELERATORS:
+ print_accelerators("ACCELERATORS");
+ break;
+#endif
+#if 1
+ case LIBPARSEPCF_BDF_ACCELERATORS: /* prefered over LIBPARSEPCF_ACCELERATORS */
+ print_accelerators("BDF ACCELERATORS");
+ break;
+#endif
+#if 0
+ case LIBPARSEPCF_SWIDTHS:
+ print_swidths();
+ break;
+#endif
+ default:
+ (void) print_properties;
+ (void) print_metrics;
+ (void) print_glyph_names;
+ (void) print_bitmaps;
+ (void) print_bdf_encodings;
+ (void) print_accelerators;
+ (void) print_swidths;
+ break;
+ }
+ }
+
+ free(tables);
+}
+
+
+static void
+print_glyph_info(size_t glyph, const struct libparsepcf_metrics *mtx)
+{
+ struct libparsepcf_metrics inkmtx;
+ const char *name;
+ int32_t s32;
+
+ if (font.name_table) {
+ if (libparsepcf_get_glyph_name_subtable(file, len, font.name_table, &font.names, &name, glyph, 1)) {
+ perror("libparsepcf_get_glyph_name_subtable");
+ exit(1);
+ }
+ printf("glyph name: %s\n", name);
+ }
+ if (font.swidth_table) {
+ if (libparsepcf_get_swidths(file, len, font.swidth_table, &s32, glyph, 1)) {
+ perror("libparsepcf_get_swidths");
+ exit(1);
+ }
+ printf("scalable width: %i milli-ems\n", s32);
+ }
+ printf("metrics:\n");
+ printf(" left side bearing: %i\n", mtx->left_side_bearing);
+ printf(" right side bearing: %i\n", mtx->right_side_bearing);
+ printf(" character width: %i\n", mtx->character_width);
+ printf(" character ascent: %i\n", mtx->character_ascent);
+ printf(" character descent: %i\n", mtx->character_descent);
+ printf(" character attributes: %u\n", mtx->character_attributes);
+ if (font.inkmtx_table) {
+ if (libparsepcf_get_metrics(file, len, font.inkmtx_table, &inkmtx, glyph, 1)) {
+ perror("libparsepcf_get_metrics");
+ exit(1);
+ }
+ printf("ink metrics:\n");
+ printf(" left side bearing: %i\n", inkmtx.left_side_bearing);
+ printf(" right side bearing: %i\n", inkmtx.right_side_bearing);
+ printf(" character width: %i\n", inkmtx.character_width);
+ printf(" character ascent: %i\n", inkmtx.character_ascent);
+ printf(" character descent: %i\n", inkmtx.character_descent);
+ printf(" character attributes: %u\n", inkmtx.character_attributes);
+ }
+ if (font.accel_table) {
+ printf("font ascent: %i\n", font.accels.font_ascent);
+ printf("font descent: %i\n", font.accels.font_descent);
+ }
+}
+
+
+static void
+print_glyph(size_t glyph)
+{
+ struct libparsepcf_metrics mtx;
+ size_t width, height, bitmap_size, bitmap_offset;
+ size_t row_size, padding, y, x, bit, byte, packing;
+ int32_t font_ascent, font_descent;
+ size_t extra_left, extra_right, print_width;
+ const uint8_t *bitmap;
+ const char *pixel;
+
+ if (glyph >= font.glyph_count) {
+ fprintf(stderr, "specified glyph does not exist\n");
+ exit(1);
+ }
+ if (libparsepcf_get_metrics(file, len, font.mtx_table, &mtx, glyph, 1)) {
+ perror("libparsepcf_get_metrics");
+ exit(1);
+ }
+ padding = font.bitmaps.row_padding - 1;
+ packing = font.bitmaps.bit_packing - 1;
+ width = (size_t)((int32_t)mtx.right_side_bearing - (int32_t)mtx.left_side_bearing);
+ height = (size_t)((int32_t)mtx.character_ascent + (int32_t)mtx.character_descent);
+ row_size = width / 8 + !!(width & 7);
+ row_size = row_size + ((font.bitmaps.row_padding - (row_size & padding)) & padding);
+ if (font.accel_table) {
+ font_ascent = font.accels.font_ascent;
+ font_descent = font.accels.font_descent;
+ } else {
+ font_ascent = mtx.character_ascent;
+ font_descent = mtx.character_descent;
+ }
+
+ print_glyph_info(glyph, &mtx);
+
+ if (libparsepcf_get_bitmap_offsets(file, len, font.bitmap_table, &font.bitmaps, &bitmap_offset, glyph, 1)) {
+ perror("libparsepcf_get_bitmap_offsets");
+ exit(1);
+ }
+ bitmap_size = font.bitmaps.bitmap_size - bitmap_offset;
+ bitmap = &font.bitmaps.bitmap_data[bitmap_offset];
+ if (height && row_size > bitmap_size / height) {
+ perror("bitmap is smaller than expected");
+ exit(1);
+ }
+ printf("\n");
+
+ font_ascent = 15;
+ font_descent = 5;
+
+ extra_left = mtx.left_side_bearing > 0 ? (size_t)mtx.left_side_bearing : 0;
+ extra_right = mtx.character_width > mtx.right_side_bearing ? (size_t)(mtx.character_width - mtx.right_side_bearing) : 0;
+ print_width = extra_left + width + extra_right;
+
+ /* If the font's ascent is greater than the character's, print the excees in black */
+ if (font_ascent > mtx.character_ascent) {
+ for (y = 0; y < (size_t)(font_ascent - mtx.character_ascent); y++) {
+ for (x = 0; x < print_width; x++)
+ printf("\033[1;30m[]");
+ printf("\033[0m\n");
+ }
+ }
+
+ for (y = 0; y < height; y++, bitmap += row_size) {
+ /* Draw baseline */
+ if (y + 1 == mtx.character_ascent)
+ printf("\033[4m");
+
+ /* If glyph is offset for caret, print offset in black */
+ for (x = 0; x < extra_left; x++)
+ printf("\033[1;30m[]");
+
+ /* Draw glyph */
+ for (x = 0; x < width; x++) {
+ bit = font.bitmaps.lsbit ? 7 - x % 8 : x % 8;
+ byte = x / 8;
+ if (!font.bitmaps.lsbyte)
+ byte = ((byte & ~packing) | (packing - (byte & packing)));
+
+ /* Use <> to mark dots outside of the glyph box */
+ if (mtx.left_side_bearing < 0 &&
+ x < (size_t)-mtx.left_side_bearing) {
+ pixel = "<>";
+ } else if (mtx.right_side_bearing > mtx.character_width &&
+ x >= mtx.character_width + mtx.left_side_bearing) {
+ pixel = "<>";
+ } else if (mtx.character_ascent > font_ascent &&
+ y < (size_t)(mtx.character_ascent - font_ascent)) {
+ pixel = "<>";
+ } else if (mtx.character_descent > font_descent &&
+ y >= (size_t)(mtx.character_ascent + font_descent)) {
+ pixel = "<>";
+ } else {
+ pixel = "[]";
+ }
+
+ printf("\033[%sm%s", ((bitmap[byte] >> bit) & 1) ? "1;37" : "2;37", pixel);
+ }
+
+ /* If horizontal advance is larger than character width, print extent in black */
+ for (x = 0; x < extra_right; x++)
+ printf("\033[1;30m[]");
+
+ printf("\033[0m\n");
+ }
+
+ /* If the font's descent is greater than the character's, print the excees in black */
+ if (font_descent > mtx.character_descent) {
+ for (y = 0; y < (size_t)(font_descent - mtx.character_descent); y++) {
+ for (x = 0; x < print_width; x++)
+ printf("\033[1;30m[]");
+ printf("\033[0m\n");
+ }
+ }
+}
+
+
+static void
+print_line(const char *str, size_t strlen) /* TODO */
+{
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ size_t glyph;
+ if (argc) {
+ argc--;
+ argv++;
+ }
+ load_file();
+ if (!argc) {
+ print_font();
+ } else {
+ if (libparsepcf_preparse_font(file, len, &font)) {
+ perror("libparsepcf_preparse_font");
+ exit(1);
+ }
+ if (argc == 2 && !strcmp(argv[0], "-g")) {
+ glyph = (size_t)strtoul(argv[1], NULL, 0);
+ print_glyph(glyph);
+ } else if (argc == 2 && !strcmp(argv[0], "-x")) {
+ glyph = (size_t)strtoul(argv[1], NULL, 16);
+ print_glyph(glyph);
+ } else {
+ for (; argc--; argv++)
+ print_line(*argv, strlen(*argv));
+ }
+ libparsepcf_destroy_preparsed_font(&font);
+ }
+ free(file);
+ return 0;
+}
diff --git a/libparsepcf.h b/libparsepcf.h
new file mode 100644
index 0000000..b3731d6
--- /dev/null
+++ b/libparsepcf.h
@@ -0,0 +1,234 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBPARSEPCF_H
+#define LIBPARSEPCF_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+
+/* Based on documentation from FontForge: https://fontforge.org/docs/techref/pcf-format.html */
+
+
+struct libparsepcf_table {
+ uint32_t type;
+ uint32_t format;
+ uint32_t size;
+ uint32_t offset;
+};
+
+/* Table types: */
+#define LIBPARSEPCF_PROPERTIES (UINT32_C(1) << 0)
+#define LIBPARSEPCF_ACCELERATORS (UINT32_C(1) << 1)
+#define LIBPARSEPCF_METRICS (UINT32_C(1) << 2)
+#define LIBPARSEPCF_BITMAPS (UINT32_C(1) << 3)
+#define LIBPARSEPCF_INK_METRICS (UINT32_C(1) << 4)
+#define LIBPARSEPCF_BDF_ENCODINGS (UINT32_C(1) << 5)
+#define LIBPARSEPCF_SWIDTHS (UINT32_C(1) << 6)
+#define LIBPARSEPCF_GLYPH_NAMES (UINT32_C(1) << 7)
+#define LIBPARSEPCF_BDF_ACCELERATORS (UINT32_C(1) << 8)
+
+int libparsepcf_get_table_count(const char *, size_t, size_t *countp);
+int libparsepcf_get_tables(const char *, size_t, struct libparsepcf_table *tables, size_t first, size_t count);
+
+
+
+struct libparsepcf_properties {
+ size_t property_count;
+ size_t strings_size;
+ const char *strings;
+};
+
+struct libparsepcf_property_subtable {
+ const char *name;
+ int is_string_property;
+ union {
+ int32_t signed_value;
+ const char *string_value;
+ } value;
+};
+
+int libparsepcf_get_properties(const char *, size_t,
+ const struct libparsepcf_table *,
+ struct libparsepcf_properties *);
+
+int libparsepcf_get_property_subtable(const char *, size_t,
+ const struct libparsepcf_table *,
+ const struct libparsepcf_properties *,
+ struct libparsepcf_property_subtable *, size_t, size_t);
+
+
+
+struct libparsepcf_metrics {
+ int16_t left_side_bearing;
+ int16_t right_side_bearing;
+ int16_t character_width;
+ int16_t character_ascent;
+ int16_t character_descent;
+ uint16_t character_attributes;
+};
+
+int libparsepcf_get_metrics_count(const char *, size_t, const struct libparsepcf_table *, size_t *);
+
+int libparsepcf_get_metrics(const char *, size_t,
+ const struct libparsepcf_table *,
+ struct libparsepcf_metrics *, size_t, size_t);
+
+
+
+struct libparsepcf_glyph_names {
+ size_t glyph_count;
+ size_t strings_size;
+ const char *strings;
+};
+
+int libparsepcf_get_glyph_names(const char *, size_t,
+ const struct libparsepcf_table *,
+ struct libparsepcf_glyph_names *);
+
+int libparsepcf_get_glyph_name_subtable(const char *, size_t,
+ const struct libparsepcf_table *,
+ const struct libparsepcf_glyph_names *,
+ const char **, size_t, size_t);
+
+
+
+struct libparsepcf_bitmaps {
+ size_t glyph_count;
+ size_t bitmap_size;
+ size_t bit_packing;
+ size_t row_padding;
+ int lsbyte;
+ int lsbit;
+ const uint8_t *bitmap_data;
+};
+
+int libparsepcf_get_bitmaps(const char *, size_t,
+ const struct libparsepcf_table *,
+ struct libparsepcf_bitmaps *);
+
+int libparsepcf_get_bitmap_offsets(const char *, size_t,
+ const struct libparsepcf_table *,
+ const struct libparsepcf_bitmaps *,
+ size_t *, size_t, size_t);
+
+
+
+struct libparsepcf_encoding {
+ uint16_t min_byte2;
+ uint16_t max_byte2;
+ uint16_t min_byte1;
+ uint16_t max_byte1;
+ uint16_t default_char;
+ size_t glyph_count;
+ /* If min_byte1 == 0 and max_byte1 == 0 (single byte encoding):
+ * glyph_index = glyph_indices[encoding - min_char_or_byte2]
+ * not included if encoding > max_byte2 or glyph_index == 0xFFFF
+ *
+ * Otherwise (dual byte encoding):
+ * [min_byte1, max_byte1] = allowed range of the more signficant of the 2 bytes (the first byte)
+ * [min_byte2, max_byte2] = allowed range of the less signficant of the 2 bytes (the second byte)
+ * e1 = encoding[0] - min_byte1
+ * e2 = encoding[1] - min_byte2
+ * glyph_index = glyph_indices[e1 * (max_byte2 - min_byte2 + 1) + e2]
+ * not included if out of range or or glyph_index == 0xFFFF
+ */
+};
+
+#define LIBPARSEPCF_NOT_ENCODED ((size_t)0xFFFFUL)
+
+int libparsepcf_get_encoding(const char *, size_t,
+ const struct libparsepcf_table *,
+ struct libparsepcf_encoding *);
+
+int libparsepcf_get_glyph_indices(const char *, size_t,
+ const struct libparsepcf_table *,
+ const struct libparsepcf_encoding *,
+ size_t *, size_t, size_t);
+
+
+
+struct libparsepcf_accelerators {
+ /**
+ * Whether metrics[i].right_side_bearing - metrics[i].character_width
+ * less than or equal to .min_bounds.left_side_bearing for all i
+ */
+ uint8_t no_overlap : 1;
+ uint8_t constant_metrics : 1;
+ /**
+ * .constant_metrics and, for all characters, left side bearing = 0,
+ * right side bearing = character width, ascent = .font_ascent, and
+ * descent = .font_descent
+ */
+ uint8_t terminal_font : 1;
+ uint8_t constant_width : 1;
+ /**
+ * Whether all inked bits are inside the glyph's box
+ */
+ uint8_t ink_inside : 1;
+ /**
+ * Whether the ink metrics differ from the metrics for some glyph
+ */
+ uint8_t ink_metrics : 1;
+ uint8_t draw_rtl : 1;
+ /**
+ * If 0, .ink_min_bounds and .ink_max_bounds are just copies of
+ * .min_bounds and max_bounds
+ */
+ uint8_t have_ink_bounds : 1;
+ int32_t font_ascent;
+ int32_t font_descent;
+ int32_t max_overlap;
+ struct libparsepcf_metrics min_bounds;
+ struct libparsepcf_metrics max_bounds;
+ struct libparsepcf_metrics min_ink_bounds;
+ struct libparsepcf_metrics max_ink_bounds;
+};
+
+int libparsepcf_get_accelerators(const char *, size_t,
+ const struct libparsepcf_table *,
+ struct libparsepcf_accelerators *);
+
+
+
+int libparsepcf_get_swidth_count(const char *, size_t, const struct libparsepcf_table *, size_t *);
+
+int libparsepcf_get_swidths(const char *, size_t, const struct libparsepcf_table *, int32_t *, size_t, size_t);
+
+
+
+struct libparsepcf_font {
+ const struct libparsepcf_table *prob_table;
+ struct libparsepcf_properties props;
+
+ const struct libparsepcf_table *accel_table;
+ struct libparsepcf_accelerators accels;
+
+ const struct libparsepcf_table *mtx_table;
+ size_t metrics;
+
+ const struct libparsepcf_table *inkmtx_table;
+ size_t ink_metrics;
+
+ const struct libparsepcf_table *enc_table;
+ struct libparsepcf_encoding encoding;
+
+ const struct libparsepcf_table *bitmap_table;
+ struct libparsepcf_bitmaps bitmaps;
+
+ const struct libparsepcf_table *swidth_table;
+ size_t swidths;
+
+ const struct libparsepcf_table *name_table;
+ struct libparsepcf_glyph_names names;
+
+ size_t glyph_count;
+ struct libparsepcf_table *_tables;
+};
+
+int libparsepcf_preparse_font(const char *, size_t, struct libparsepcf_font *);
+
+void libparsepcf_destroy_preparsed_font(struct libparsepcf_font *);
+
+
+
+#endif
diff --git a/libparsepcf_destroy_preparsed_font.c b/libparsepcf_destroy_preparsed_font.c
new file mode 100644
index 0000000..36ec493
--- /dev/null
+++ b/libparsepcf_destroy_preparsed_font.c
@@ -0,0 +1,10 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+void
+libparsepcf_destroy_preparsed_font(struct libparsepcf_font *font)
+{
+ free(font->_tables);
+ memset(font, 0, sizeof(*font));
+}
diff --git a/libparsepcf_get_accelerators.c b/libparsepcf_get_accelerators.c
new file mode 100644
index 0000000..af3224a
--- /dev/null
+++ b/libparsepcf_get_accelerators.c
@@ -0,0 +1,83 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+
+int
+libparsepcf_get_accelerators(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ struct libparsepcf_accelerators *out)
+{
+ int msb = table->format & LIBPARSEPCF_BYTE;
+ int with_ink_bounds = table->format & LIBPARSEPCF_ACCELERATOR_WITH_INK_BOUNDS;
+ size_t pos;
+
+ (void) size;
+
+ if (table->size < 24 + (with_ink_bounds ? 4 : 2) * 12)
+ goto ebfont;
+
+ pos = table->offset;
+
+ if (table->format != libparsepcf_parse_lsb_uint32__(&file[pos]))
+ goto ebfont;
+ pos += 4;
+
+ out->no_overlap = !!file[pos + 0];
+ out->constant_metrics = !!file[pos + 1];
+ out->terminal_font = !!file[pos + 2];
+ out->constant_width = !!file[pos + 3];
+ out->ink_inside = !!file[pos + 4];
+ out->ink_metrics = !!file[pos + 5];
+ out->draw_rtl = !!file[pos + 6];
+ out->have_ink_bounds = !!with_ink_bounds;
+ pos += 8;
+
+ out->font_ascent = PARSE_INT32(&file[pos + 0], msb);
+ out->font_descent = PARSE_INT32(&file[pos + 4], msb);
+ out->max_overlap = PARSE_INT32(&file[pos + 8], msb);
+ pos += 12;
+
+ out->min_bounds.left_side_bearing = PARSE_INT16(&file[pos + 0], msb);
+ out->min_bounds.right_side_bearing = PARSE_INT16(&file[pos + 2], msb);
+ out->min_bounds.character_width = PARSE_INT16(&file[pos + 4], msb);
+ out->min_bounds.character_ascent = PARSE_INT16(&file[pos + 6], msb);
+ out->min_bounds.character_descent = PARSE_INT16(&file[pos + 8], msb);
+ out->min_bounds.character_attributes = PARSE_UINT16(&file[pos + 10], msb);
+ pos += 12;
+
+ out->max_bounds.left_side_bearing = PARSE_INT16(&file[pos + 0], msb);
+ out->max_bounds.right_side_bearing = PARSE_INT16(&file[pos + 2], msb);
+ out->max_bounds.character_width = PARSE_INT16(&file[pos + 4], msb);
+ out->max_bounds.character_ascent = PARSE_INT16(&file[pos + 6], msb);
+ out->max_bounds.character_descent = PARSE_INT16(&file[pos + 8], msb);
+ out->max_bounds.character_attributes = PARSE_UINT16(&file[pos + 10], msb);
+ pos += 12;
+
+ if (with_ink_bounds) {
+ out->min_ink_bounds.left_side_bearing = PARSE_INT16(&file[pos + 0], msb);
+ out->min_ink_bounds.right_side_bearing = PARSE_INT16(&file[pos + 2], msb);
+ out->min_ink_bounds.character_width = PARSE_INT16(&file[pos + 4], msb);
+ out->min_ink_bounds.character_ascent = PARSE_INT16(&file[pos + 6], msb);
+ out->min_ink_bounds.character_descent = PARSE_INT16(&file[pos + 8], msb);
+ out->min_ink_bounds.character_attributes = PARSE_UINT16(&file[pos + 10], msb);
+ pos += 12;
+
+ out->max_ink_bounds.left_side_bearing = PARSE_INT16(&file[pos + 0], msb);
+ out->max_ink_bounds.right_side_bearing = PARSE_INT16(&file[pos + 2], msb);
+ out->max_ink_bounds.character_width = PARSE_INT16(&file[pos + 4], msb);
+ out->max_ink_bounds.character_ascent = PARSE_INT16(&file[pos + 6], msb);
+ out->max_ink_bounds.character_descent = PARSE_INT16(&file[pos + 8], msb);
+ out->max_ink_bounds.character_attributes = PARSE_UINT16(&file[pos + 10], msb);
+ pos += 12;
+ } else {
+ memcpy(&out->min_ink_bounds, &out->min_bounds, sizeof(out->min_bounds));
+ memcpy(&out->max_ink_bounds, &out->max_bounds, sizeof(out->max_bounds));
+ }
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_bitmap_offsets.c b/libparsepcf_get_bitmap_offsets.c
new file mode 100644
index 0000000..192b07b
--- /dev/null
+++ b/libparsepcf_get_bitmap_offsets.c
@@ -0,0 +1,28 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_bitmap_offsets(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ const struct libparsepcf_bitmaps *meta,
+ size_t *out, size_t first, size_t count)
+{
+ int msb = table->format & LIBPARSEPCF_BYTE;
+ size_t pos = table->offset + 8 + first * 4;
+ size_t i;
+
+ (void) size;
+
+ for (i = 0; i < count; i++, pos += 4) {
+ out[i] = (size_t)PARSE_UINT32(&file[pos + 0], msb);
+ if (out[i] > meta->bitmap_size)
+ goto ebfont;
+ }
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_bitmaps.c b/libparsepcf_get_bitmaps.c
new file mode 100644
index 0000000..961da96
--- /dev/null
+++ b/libparsepcf_get_bitmaps.c
@@ -0,0 +1,52 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_bitmaps(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ struct libparsepcf_bitmaps *out)
+{
+ size_t pos, glyph_pad;
+ int msb = table->format & LIBPARSEPCF_BYTE;
+
+ (void) size;
+
+ if (table->size < 8)
+ goto ebfont;
+
+ pos = table->offset;
+
+ if (table->format != libparsepcf_parse_lsb_uint32__(&file[pos]))
+ goto ebfont;
+ pos += 4;
+
+ out->glyph_count = (size_t)PARSE_UINT32(&file[pos], msb);
+ pos += 4;
+
+ if (16 > table->size - (pos - table->offset) ||
+ out->glyph_count > (table->size - (pos - table->offset) - 16) / 4)
+ goto ebfont;
+ pos += out->glyph_count * 4;
+ glyph_pad = (size_t)(table->format & LIBPARSEPCF_GLYPH_PAD_MASK);
+ out->bitmap_size = (size_t)PARSE_UINT32(&file[pos + 4 * glyph_pad], msb);
+ pos += 16;
+
+ out->bitmap_data = (const void *)&file[pos];
+ if (out->bitmap_size > table->size - (pos - table->offset))
+ goto ebfont;
+
+ out->bit_packing = (size_t)1 << ((table->format & LIBPARSEPCF_SCAN_UNIT_MASK) >> 4);
+ out->row_padding = (size_t)1 << ((table->format & LIBPARSEPCF_GLYPH_PAD_MASK) >> 0);
+ out->lsbyte = !!(table->format & LIBPARSEPCF_BYTE);
+ out->lsbit = !!(table->format & LIBPARSEPCF_BIT);
+
+ if (out->row_padding < out->bit_packing)
+ goto ebfont;
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_encoding.c b/libparsepcf_get_encoding.c
new file mode 100644
index 0000000..34ccd9b
--- /dev/null
+++ b/libparsepcf_get_encoding.c
@@ -0,0 +1,44 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_encoding(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ struct libparsepcf_encoding *out)
+{
+ int msb = table->format & LIBPARSEPCF_BYTE;
+ size_t pos;
+
+ (void) size;
+
+ if (table->size < 14)
+ goto ebfont;
+
+ pos = table->offset;
+
+ if (table->format != libparsepcf_parse_lsb_uint32__(&file[pos]))
+ goto ebfont;
+ pos += 4;
+
+ out->min_byte2 = PARSE_UINT16(&file[pos + 0], msb);
+ out->max_byte2 = PARSE_UINT16(&file[pos + 2], msb);
+ out->min_byte1 = PARSE_UINT16(&file[pos + 4], msb);
+ out->max_byte1 = PARSE_UINT16(&file[pos + 6], msb);
+ out->default_char = PARSE_UINT16(&file[pos + 8], msb);
+ pos += 10;
+
+ if (out->min_byte2 > out->max_byte2 || out->max_byte2 > 255 ||
+ out->min_byte1 > out->max_byte1 || out->max_byte1 > 255)
+ goto ebfont;
+
+ out->glyph_count = (size_t)(out->max_byte2 - out->min_byte2 + 1) * (size_t)(out->max_byte1 - out->min_byte1 + 1);
+ if (out->glyph_count > table->size - (pos - table->offset) / 2)
+ goto ebfont;
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_glyph_index.c b/libparsepcf_get_glyph_index.c
new file mode 100644
index 0000000..86150d6
--- /dev/null
+++ b/libparsepcf_get_glyph_index.c
@@ -0,0 +1,36 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_glyph_index(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ const struct libparsepcf_encoding *meta,
+ const char *text, size_t *out)
+{
+ int msb = table->format & LIBPARSEPCF_BYTE;
+ size_t pos, i, j;
+
+ (void) size;
+
+ i = (size_t)*(const uint8_t *)text;
+ if (i < (size_t)meta->min_byte1 || i > (size_t)meta->max_byte1)
+ goto not_encoded;
+ i -= (size_t)meta->min_byte1;
+
+ if (meta->min_byte2 | meta->max_byte2) {
+ j = (size_t)*(const uint8_t *)text;
+ if (j < (size_t)meta->min_byte2 || j > (size_t)meta->max_byte2)
+ goto not_encoded;
+ j -= (size_t)meta->min_byte2;
+ i = i * (meta->max_byte2 - meta->min_byte2 + 1) + j;
+ }
+
+ pos = table->offset + 14 + i * 2;
+ *out = (size_t)PARSE_UINT16(&file[pos], msb);
+ return 0;
+
+not_encoded:
+ *out = (size_t)0xFFFF;
+ return 0;
+}
diff --git a/libparsepcf_get_glyph_indices.c b/libparsepcf_get_glyph_indices.c
new file mode 100644
index 0000000..a1e7ed6
--- /dev/null
+++ b/libparsepcf_get_glyph_indices.c
@@ -0,0 +1,22 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_glyph_indices(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ const struct libparsepcf_encoding *meta,
+ size_t *out, size_t first, size_t count)
+{
+ int msb = table->format & LIBPARSEPCF_BYTE;
+ size_t pos = 14 + first * 2;
+ size_t i;
+
+ (void) size;
+ (void) meta;
+
+ for (i = 0; i < count; i++, pos += 2)
+ out[i] = (size_t)PARSE_UINT16(&file[pos], msb);
+
+ return 0;
+}
diff --git a/libparsepcf_get_glyph_name_subtable.c b/libparsepcf_get_glyph_name_subtable.c
new file mode 100644
index 0000000..578bf87
--- /dev/null
+++ b/libparsepcf_get_glyph_name_subtable.c
@@ -0,0 +1,34 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_glyph_name_subtable(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ const struct libparsepcf_glyph_names *meta,
+ const char **out, size_t first, size_t count)
+{
+ size_t pos, i, off;
+ int msb = table->format & LIBPARSEPCF_BYTE;
+
+ (void) size;
+
+ if (table->size < 8)
+ goto ebfont;
+
+ pos = table->offset + 8 + first * 4;
+ for (i = 0; i < count; i++, pos += 4) {
+ off = (size_t)PARSE_UINT32(&file[pos], msb);
+ if (off > meta->strings_size)
+ goto ebfont;
+ out[i] = &meta->strings[off];
+ if (!memchr(out[i], 0, meta->strings_size - off))
+ goto ebfont;
+ }
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_glyph_names.c b/libparsepcf_get_glyph_names.c
new file mode 100644
index 0000000..ca690a4
--- /dev/null
+++ b/libparsepcf_get_glyph_names.c
@@ -0,0 +1,43 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_glyph_names(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ struct libparsepcf_glyph_names *out)
+{
+ size_t pos;
+ int msb = table->format & LIBPARSEPCF_BYTE;
+
+ (void) size;
+
+ if (table->size < 8)
+ goto ebfont;
+
+ pos = table->offset;
+
+ if (table->format != libparsepcf_parse_lsb_uint32__(&file[pos]))
+ goto ebfont;
+ pos += 4;
+
+ out->glyph_count = (size_t)PARSE_UINT32(&file[pos], msb);
+ pos += 4;
+
+ if (4 > table->size - (pos - table->offset) ||
+ out->glyph_count > (table->size - (pos - table->offset) - 4) / 4)
+ goto ebfont;
+ pos += out->glyph_count * 4;
+ out->strings_size = (size_t)PARSE_UINT32(&file[pos], msb);
+ pos += 4;
+
+ out->strings = &file[pos];
+ if (out->strings_size > table->size - (pos - table->offset))
+ goto ebfont;
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_metrics.c b/libparsepcf_get_metrics.c
new file mode 100644
index 0000000..5e2fbe0
--- /dev/null
+++ b/libparsepcf_get_metrics.c
@@ -0,0 +1,50 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_metrics(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ struct libparsepcf_metrics *out, size_t first, size_t count)
+{
+ size_t pos, i;
+ int msb = table->format & LIBPARSEPCF_BYTE;
+ int compressed = table->format & LIBPARSEPCF_COMPRESSED_METRICS;
+
+ (void) size;
+
+ pos = table->offset + (compressed ? 6 : 8);
+ pos += first * (compressed ? 5 : 12);
+
+ if (compressed) {
+ for (i = 0; i < count; i++, pos += 5) {
+ out[i].left_side_bearing = (int16_t)((int)((const uint8_t *)file)[pos + 0] - 128);
+ out[i].right_side_bearing = (int16_t)((int)((const uint8_t *)file)[pos + 1] - 128);
+ out[i].character_width = (int16_t)((int)((const uint8_t *)file)[pos + 2] - 128);
+ out[i].character_ascent = (int16_t)((int)((const uint8_t *)file)[pos + 3] - 128);
+ out[i].character_descent = (int16_t)((int)((const uint8_t *)file)[pos + 4] - 128);
+ out[i].character_attributes = 0;
+ if (out[i].left_side_bearing > out[i].right_side_bearing ||
+ (int32_t)out[i].character_ascent < -(int32_t)out[i].character_descent)
+ goto ebfont;
+ }
+ } else {
+ for (i = 0; i < count; i++, pos += 12) {
+ out[i].left_side_bearing = PARSE_INT16(&file[pos + 0], msb);
+ out[i].right_side_bearing = PARSE_INT16(&file[pos + 2], msb);
+ out[i].character_width = PARSE_INT16(&file[pos + 4], msb);
+ out[i].character_ascent = PARSE_INT16(&file[pos + 6], msb);
+ out[i].character_descent = PARSE_INT16(&file[pos + 8], msb);
+ out[i].character_attributes = PARSE_UINT16(&file[pos + 10], msb);
+ if (out[i].left_side_bearing > out[i].right_side_bearing ||
+ (int32_t)out[i].character_ascent < -(int32_t)out[i].character_descent)
+ goto ebfont;
+ }
+ }
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_metrics_count.c b/libparsepcf_get_metrics_count.c
new file mode 100644
index 0000000..fab5544
--- /dev/null
+++ b/libparsepcf_get_metrics_count.c
@@ -0,0 +1,38 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_metrics_count(const char *file, size_t size, const struct libparsepcf_table *table, size_t *countp)
+{
+ size_t pos;
+ int msb = table->format & LIBPARSEPCF_BYTE;
+ int compressed = table->format & LIBPARSEPCF_COMPRESSED_METRICS;
+
+ if (table->size < (compressed ? 6 : 8))
+ goto ebfont;
+
+ pos = table->offset;
+
+ if (table->format != libparsepcf_parse_lsb_uint32__(&file[pos]))
+ goto ebfont;
+ pos += 4;
+
+ if (compressed) {
+ *countp = (size_t)PARSE_UINT16(&file[pos], msb);
+ pos += 2;
+ if (*countp > (size - pos) / 5)
+ goto ebfont;
+ } else {
+ *countp = (size_t)PARSE_UINT32(&file[pos], msb);
+ pos += 4;
+ if (*countp > (size - pos) / 12)
+ goto ebfont;
+ }
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_properties.c b/libparsepcf_get_properties.c
new file mode 100644
index 0000000..f586a5c
--- /dev/null
+++ b/libparsepcf_get_properties.c
@@ -0,0 +1,46 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_properties(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ struct libparsepcf_properties *out)
+{
+ size_t pos;
+ int msb = table->format & LIBPARSEPCF_BYTE;
+
+ (void) size;
+
+ if (table->size < 8)
+ goto ebfont;
+
+ pos = table->offset;
+
+ if (table->format != libparsepcf_parse_lsb_uint32__(&file[pos]))
+ goto ebfont;
+ pos += 4;
+
+ out->property_count = (size_t)PARSE_UINT32(&file[pos], msb);
+ pos += 4;
+
+ if (4 > table->size - (pos - table->offset) ||
+ out->property_count > (table->size - (pos - table->offset) - 4) / 9)
+ goto ebfont;
+ pos += out->property_count * 9;
+ pos += (4 - (out->property_count & 3)) & 3;
+ if (pos - table->offset > table->size - 4)
+ goto ebfont;
+ out->strings_size = (size_t)PARSE_UINT32(&file[pos], msb);
+ pos += 4;
+
+ out->strings = &file[pos];
+ if (out->strings_size > table->size - (pos - table->offset))
+ goto ebfont;
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_property_subtable.c b/libparsepcf_get_property_subtable.c
new file mode 100644
index 0000000..d19498c
--- /dev/null
+++ b/libparsepcf_get_property_subtable.c
@@ -0,0 +1,47 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_property_subtable(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ const struct libparsepcf_properties *meta,
+ struct libparsepcf_property_subtable *props,
+ size_t first, size_t count)
+{
+ int msb = table->format & LIBPARSEPCF_BYTE;
+ size_t pos = table->offset + 8 + first * 9;
+ size_t i, off, maxlen;
+
+ (void) size;
+
+ for (i = 0; i < count; i++, pos += 9) {
+ off = (size_t)PARSE_UINT32(&file[pos + 0], msb);
+ if (off > meta->strings_size)
+ goto ebfont;
+ maxlen = meta->strings_size - off;
+ props[i].name = &meta->strings[off];
+ if (!memchr(props[i].name, 0, maxlen))
+ goto ebfont;
+
+ props[i].is_string_property = !!file[pos + 4];
+
+ if (props[i].is_string_property) {
+ off = (size_t)PARSE_UINT32(&file[pos + 5], msb);
+ if (off > meta->strings_size)
+ goto ebfont;
+ maxlen = meta->strings_size - off;
+ props[i].value.string_value = &meta->strings[off];
+ if (!memchr(props[i].value.string_value, 0, maxlen))
+ goto ebfont;
+ } else {
+ props[i].value.signed_value = PARSE_INT32(&file[pos + 5], msb);
+ }
+ }
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_swidth_count.c b/libparsepcf_get_swidth_count.c
new file mode 100644
index 0000000..90a5f4a
--- /dev/null
+++ b/libparsepcf_get_swidth_count.c
@@ -0,0 +1,31 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_swidth_count(const char *file, size_t size, const struct libparsepcf_table *table, size_t *countp)
+{
+ size_t pos;
+ int msb = table->format & LIBPARSEPCF_BYTE;
+
+ if (table->size < 8)
+ goto ebfont;
+
+ pos = table->offset;
+
+ if (table->format != libparsepcf_parse_lsb_uint32__(&file[pos]))
+ goto ebfont;
+ pos += 4;
+
+ *countp = (size_t)PARSE_UINT32(&file[pos], msb);
+ pos += 4;
+
+ if (*countp > (size - pos) / 4)
+ goto ebfont;
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_swidths.c b/libparsepcf_get_swidths.c
new file mode 100644
index 0000000..d350b74
--- /dev/null
+++ b/libparsepcf_get_swidths.c
@@ -0,0 +1,20 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_swidths(const char *file, size_t size,
+ const struct libparsepcf_table *table,
+ int32_t *out, size_t first, size_t count)
+{
+ int msb = table->format & LIBPARSEPCF_BYTE;
+ size_t pos = table->offset + 8 + 4 * first;
+ size_t i;
+
+ (void) size;
+
+ for (i = 0; i < count; i++, pos += 4)
+ out[i] = PARSE_INT32(&file[pos], msb);
+
+ return 0;
+}
diff --git a/libparsepcf_get_table_count.c b/libparsepcf_get_table_count.c
new file mode 100644
index 0000000..0eb8741
--- /dev/null
+++ b/libparsepcf_get_table_count.c
@@ -0,0 +1,23 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_table_count(const char *file, size_t size, size_t *countp)
+{
+ uint32_t count;
+
+ if (size < 8 || file[0] != 1 || file[1] != 'f' || file[2] != 'c' || file[3] != 'p')
+ goto ebfont;
+
+ count = libparsepcf_parse_lsb_uint32__(&file[4]);
+ if (count > (size - 8) / 16)
+ goto ebfont;
+
+ *countp = (size_t)count;
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_get_tables.c b/libparsepcf_get_tables.c
new file mode 100644
index 0000000..56cffc2
--- /dev/null
+++ b/libparsepcf_get_tables.c
@@ -0,0 +1,39 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_get_tables(const char *file, size_t size, struct libparsepcf_table *tables, size_t first, size_t count)
+{
+ size_t pos = 8 + first * 16;
+ size_t i;
+
+ for (i = 0; i < count; i++, pos += 16) {
+ tables[i].type = libparsepcf_parse_lsb_uint32__(&file[pos + 0]);
+ tables[i].format = libparsepcf_parse_lsb_uint32__(&file[pos + 4]);
+ tables[i].size = libparsepcf_parse_lsb_uint32__(&file[pos + 8]);
+ tables[i].offset = libparsepcf_parse_lsb_uint32__(&file[pos + 12]);
+
+ if ((size_t)tables[i].offset > size)
+ goto ebfont;
+
+ /* For some reasons files specify table sizes such that they
+ * actually except the boundary of the file, despite not using
+ * that much data. Don't including this fix, but instead check
+ * that the table size is not too large, will break your
+ * favourite fonts. */
+ if ((size_t)tables[i].size > size - (size_t)tables[i].offset) {
+#if SIZE_MAX > UINT32_MAX
+ if (size - (size_t)tables[i].offset > (size_t)UINT32_MAX)
+ goto ebfont;
+#endif
+ tables[i].size = (uint32_t)(size - (size_t)tables[i].offset);
+ }
+ }
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+ return -1;
+}
diff --git a/libparsepcf_parse_int16_from_unsigned__.c b/libparsepcf_parse_int16_from_unsigned__.c
new file mode 100644
index 0000000..3d61ef8
--- /dev/null
+++ b/libparsepcf_parse_int16_from_unsigned__.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int16_t
+libparsepcf_parse_int16_from_unsigned__(uint16_t u)
+{
+ if (u & UINT16_C(0x8000)) {
+ return (int16_t)(uint16_t)~u - 1;
+ } else {
+ return (int16_t)u;
+ }
+}
diff --git a/libparsepcf_parse_int32_from_unsigned__.c b/libparsepcf_parse_int32_from_unsigned__.c
new file mode 100644
index 0000000..37de799
--- /dev/null
+++ b/libparsepcf_parse_int32_from_unsigned__.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int32_t
+libparsepcf_parse_int32_from_unsigned__(uint32_t u)
+{
+ if (u & UINT32_C(0x80000000)) {
+ return (int32_t)(uint32_t)~u - 1;
+ } else {
+ return (int32_t)u;
+ }
+}
diff --git a/libparsepcf_parse_lsb_uint16__.c b/libparsepcf_parse_lsb_uint16__.c
new file mode 100644
index 0000000..47d9a0d
--- /dev/null
+++ b/libparsepcf_parse_lsb_uint16__.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+uint16_t
+libparsepcf_parse_lsb_uint16__(const void *buf)
+{
+ const uint8_t *bs = buf;
+ uint16_t a = (uint16_t)bs[0] << 0;
+ uint16_t b = (uint16_t)bs[1] << 8;
+ return a | b;
+}
diff --git a/libparsepcf_parse_lsb_uint32__.c b/libparsepcf_parse_lsb_uint32__.c
new file mode 100644
index 0000000..6ea37ab
--- /dev/null
+++ b/libparsepcf_parse_lsb_uint32__.c
@@ -0,0 +1,14 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+uint32_t
+libparsepcf_parse_lsb_uint32__(const void *buf)
+{
+ const uint8_t *bs = buf;
+ uint32_t a = (uint32_t)bs[0] << 0;
+ uint32_t b = (uint32_t)bs[1] << 8;
+ uint32_t c = (uint32_t)bs[2] << 16;
+ uint32_t d = (uint32_t)bs[3] << 24;
+ return a | b | c | d;
+}
diff --git a/libparsepcf_parse_msb_uint16__.c b/libparsepcf_parse_msb_uint16__.c
new file mode 100644
index 0000000..9c899c4
--- /dev/null
+++ b/libparsepcf_parse_msb_uint16__.c
@@ -0,0 +1,12 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+uint16_t
+libparsepcf_parse_msb_uint16__(const void *buf)
+{
+ const uint8_t *bs = buf;
+ uint16_t a = (uint16_t)bs[0] << 8;
+ uint16_t b = (uint16_t)bs[1] << 0;
+ return a | b;
+}
diff --git a/libparsepcf_parse_msb_uint32__.c b/libparsepcf_parse_msb_uint32__.c
new file mode 100644
index 0000000..a3dfdc1
--- /dev/null
+++ b/libparsepcf_parse_msb_uint32__.c
@@ -0,0 +1,14 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+uint32_t
+libparsepcf_parse_msb_uint32__(const void *buf)
+{
+ const uint8_t *bs = buf;
+ uint32_t a = (uint32_t)bs[0] << 24;
+ uint32_t b = (uint32_t)bs[1] << 16;
+ uint32_t c = (uint32_t)bs[2] << 8;
+ uint32_t d = (uint32_t)bs[3] << 0;
+ return a | b | c | d;
+}
diff --git a/libparsepcf_preparse_font.c b/libparsepcf_preparse_font.c
new file mode 100644
index 0000000..5874b50
--- /dev/null
+++ b/libparsepcf_preparse_font.c
@@ -0,0 +1,104 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+int
+libparsepcf_preparse_font(const char *file, size_t size, struct libparsepcf_font *font)
+{
+ size_t min = SIZE_MAX, max = 0, table_i, table_n;
+ struct libparsepcf_table *tables = NULL;
+
+ if (libparsepcf_get_table_count(file, size, &table_n))
+ goto fail;
+ tables = calloc(table_n, sizeof(*tables));
+ if (!tables)
+ goto fail;
+ if (libparsepcf_get_tables(file, size, tables, 0, table_n))
+ goto fail;
+
+ for (table_i = 0; table_i < table_n; table_i++) {
+ if (tables[table_i].type == LIBPARSEPCF_PROPERTIES) {
+ font->prob_table = &tables[table_i];
+ if (libparsepcf_get_properties(file, size, &tables[table_i], &font->props))
+ goto fail;
+ } else if (tables[table_i].type == LIBPARSEPCF_ACCELERATORS && !font->accel_table) {
+ font->accel_table = &tables[table_i];
+ if (libparsepcf_get_accelerators(file, size, &tables[table_i], &font->accels))
+ goto fail;
+ } else if (tables[table_i].type == LIBPARSEPCF_BDF_ACCELERATORS) {
+ font->accel_table = &tables[table_i];
+ if (libparsepcf_get_accelerators(file, size, &tables[table_i], &font->accels))
+ goto fail;
+ } else if (tables[table_i].type == LIBPARSEPCF_METRICS) {
+ font->mtx_table = &tables[table_i];
+ if (libparsepcf_get_metrics_count(file, size, &tables[table_i], &font->metrics))
+ goto fail;
+ } else if (tables[table_i].type == LIBPARSEPCF_INK_METRICS) {
+ font->inkmtx_table = &tables[table_i];
+ if (libparsepcf_get_metrics_count(file, size, &tables[table_i], &font->ink_metrics))
+ goto fail;
+ } else if (tables[table_i].type == LIBPARSEPCF_BDF_ENCODINGS) {
+ font->enc_table = &tables[table_i];
+ if (libparsepcf_get_encoding(file, size, &tables[table_i], &font->encoding))
+ goto fail;
+ } else if (tables[table_i].type == LIBPARSEPCF_BITMAPS) {
+ font->bitmap_table = &tables[table_i];
+ if (libparsepcf_get_bitmaps(file, size, &tables[table_i], &font->bitmaps))
+ goto fail;
+ } else if (tables[table_i].type == LIBPARSEPCF_GLYPH_NAMES) {
+ font->name_table = &tables[table_i];
+ if (libparsepcf_get_glyph_names(file, size, &tables[table_i], &font->names))
+ goto fail;
+ } else if (tables[table_i].type == LIBPARSEPCF_SWIDTHS) {
+ font->swidth_table = &tables[table_i];
+ if (libparsepcf_get_swidth_count(file, size, &tables[table_i], &font->swidths))
+ goto fail;
+ }
+ }
+
+ if (font->mtx_table) {
+ if (font->metrics < min)
+ min = font->metrics;
+ if (font->metrics > max)
+ max = font->metrics;
+ }
+ if (font->inkmtx_table) {
+ if (font->ink_metrics < min)
+ min = font->ink_metrics;
+ if (font->ink_metrics > max)
+ max = font->ink_metrics;
+ }
+ if (font->bitmap_table) {
+ if (font->bitmaps.glyph_count < min)
+ min = font->bitmaps.glyph_count;
+ if (font->bitmaps.glyph_count > max)
+ max = font->bitmaps.glyph_count;
+ }
+ if (font->name_table) {
+ if (font->names.glyph_count < min)
+ min = font->names.glyph_count;
+ if (font->names.glyph_count > max)
+ max = font->names.glyph_count;
+ }
+ if (font->swidth_table) {
+ if (font->swidths < min)
+ min = font->swidths;
+ if (font->swidths > max)
+ max = font->swidths;
+ }
+
+ if (min != max || !font->mtx_table)
+ goto ebfont;
+ if (!font->inkmtx_table && font->accel_table && font->accels.ink_metrics)
+ goto ebfont;
+ font->glyph_count = min;
+ font->_tables = tables;
+
+ return 0;
+
+ebfont:
+ errno = EBFONT;
+fail:
+ free(tables);
+ return -1;
+}
diff --git a/mk/linux.mk b/mk/linux.mk
new file mode 100644
index 0000000..d016d31
--- /dev/null
+++ b/mk/linux.mk
@@ -0,0 +1,4 @@
+LIBEXT = so
+LIBFLAGS = -shared -Wl,-soname,lib$(LIB_NAME).$(LIBEXT).$(LIB_MAJOR)
+LIBMAJOREXT = $(LIBEXT).$(LIB_MAJOR)
+LIBMINOREXT = $(LIBEXT).$(LIB_VERSION)
diff --git a/mk/macos.mk b/mk/macos.mk
new file mode 100644
index 0000000..bd92de6
--- /dev/null
+++ b/mk/macos.mk
@@ -0,0 +1,4 @@
+LIBEXT = dylib
+LIBFLAGS = -dynamiclib
+LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT)
+LIBMINOREXT = $(LIB_VERSION).$(LIBEXT)
diff --git a/mk/windows.mk b/mk/windows.mk
new file mode 100644
index 0000000..e9602e1
--- /dev/null
+++ b/mk/windows.mk
@@ -0,0 +1,4 @@
+LIBEXT = dll
+LIBFLAGS = -mdll
+LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT)
+LIBMINOREXT = $(LIB_VERSION).$(LIBEXT)