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"
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_width(unifont *u) {
190 unsigned int unifont_get_height(unifont *u) {
196 unsigned int unifont_get_stride(unifont *u) {
199 return u->header.glyph_stride;
202 int unifont_lookup(unifont *u, unifont_glyph *out, uint32_t ucs4) {
203 unifont_glyph_header h = { };
204 const void *b = NULL;
205 unifont_glyph g = { };
208 assert_return(u, -EINVAL);
210 r = unifont_fetch_glyph(u, &h, &b, ucs4);
214 g.width = h.width * 8U;
216 g.stride = u->header.glyph_stride;
221 memcpy(out, &g, sizeof(g));
225 void unifont_fallback(unifont_glyph *out) {
226 static const uint8_t fallback_data[] = {
227 /* unifont 0xfffd '�' (unicode replacement character) */
228 0x00, 0x00, 0x00, 0x7e,
229 0x66, 0x5a, 0x5a, 0x7a,
230 0x76, 0x76, 0x7e, 0x76,
231 0x76, 0x7e, 0x00, 0x00,
240 out->data = fallback_data;