1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 * This implements the unifont glyph-array parser and provides it via a simple
25 * API to the caller. No heavy transformations are performed so glyph-lookups
26 * stay as fast as possible.
36 #include <sys/types.h>
39 #include "unifont-def.h"
40 #include "unifont-internal.h"
50 unifont_header header;
51 const void *glyphs; /* unaligned! */
56 static int unifont_fetch_header(unifont *u) {
57 unifont_header h = { };
60 if (u->size < UNIFONT_HEADER_SIZE_MIN)
63 assert_cc(sizeof(h) >= UNIFONT_HEADER_SIZE_MIN);
64 memcpy(&h, u->map, UNIFONT_HEADER_SIZE_MIN);
66 h.compatible_flags = le32toh(h.compatible_flags);
67 h.incompatible_flags = le32toh(h.incompatible_flags);
68 h.header_size = le32toh(h.header_size);
69 h.glyph_header_size = le16toh(h.glyph_header_size);
70 h.glyph_stride = le16toh(h.glyph_stride);
71 h.glyph_body_size = le64toh(h.glyph_body_size);
73 if (memcmp(h.signature, "DVDHRMUF", 8))
75 if (h.incompatible_flags != 0)
77 if (h.header_size < UNIFONT_HEADER_SIZE_MIN || h.header_size > u->size)
79 if (h.glyph_header_size + h.glyph_body_size < h.glyph_header_size)
81 if (h.glyph_stride * 16ULL > h.glyph_body_size)
84 glyphsize = h.glyph_header_size + h.glyph_body_size;
86 if (glyphsize == 0 || glyphsize > u->size - h.header_size) {
89 u->glyphs = u->map + h.header_size;
90 u->n_glyphs = (u->size - h.header_size) / glyphsize;
91 u->glyphsize = glyphsize;
94 memcpy(&u->header, &h, sizeof(h));
98 static int unifont_fetch_glyph(unifont *u, unifont_glyph_header *out_header, const void **out_body, uint32_t ucs4) {
99 unifont_glyph_header glyph_header = { };
100 const void *glyph_body = NULL;
103 if (ucs4 >= u->n_glyphs)
108 /* copy glyph-header data */
109 p += ucs4 * u->glyphsize;
110 memcpy(&glyph_header, p, MIN(sizeof(glyph_header), u->header.glyph_header_size));
112 /* copy glyph-body pointer */
113 p += u->header.glyph_header_size;
116 if (glyph_header.width < 1)
118 if (glyph_header.width > u->header.glyph_stride)
121 memcpy(out_header, &glyph_header, sizeof(glyph_header));
122 *out_body = glyph_body;
126 int unifont_new(unifont **out) {
127 _cleanup_(unifont_unrefp) unifont *u = NULL;
131 assert_return(out, -EINVAL);
133 u = new0(unifont, 1);
141 u->fd = open(UNIFONT_PATH, O_RDONLY | O_CLOEXEC | O_NOCTTY);
145 r = fstat(u->fd, &st);
149 u->size = st.st_size;
150 u->map = mmap(NULL, u->size, PROT_READ, MAP_PRIVATE, u->fd, 0);
151 if (u->map == MAP_FAILED)
154 r = unifont_fetch_header(u);
163 unifont *unifont_ref(unifont *u) {
172 unifont *unifont_unref(unifont *u) {
173 if (!u || !u->ref || --u->ref)
176 if (u->map != MAP_FAILED)
177 munmap((void*)u->map, u->size);
178 u->fd = safe_close(u->fd);
184 unsigned int unifont_get_stride(unifont *u) {
187 return u->header.glyph_stride;
190 int unifont_lookup(unifont *u, unifont_glyph *out, uint32_t ucs4) {
191 unifont_glyph_header h = { };
192 const void *b = NULL;
193 unifont_glyph g = { };
196 assert_return(u, -EINVAL);
198 r = unifont_fetch_glyph(u, &h, &b, ucs4);
202 g.width = h.width * 8U;
204 g.stride = u->header.glyph_stride;
209 memcpy(out, &g, sizeof(g));