]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-terminal/unifont.c
resloved: transaction - unify IPv4 and IPv6 sockets
[thirdparty/systemd.git] / src / libsystemd-terminal / unifont.c
CommitLineData
86db5dfb
DH
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
7
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.
12
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.
17
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/>.
20***/
21
22/*
23 * Unifont
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.
27 */
28
29#include <endian.h>
30#include <fcntl.h>
86db5dfb
DH
31#include <stdint.h>
32#include <stdlib.h>
33#include <sys/mman.h>
34#include <sys/stat.h>
86db5dfb
DH
35#include "macro.h"
36#include "unifont-def.h"
c2977e5c 37#include "unifont.h"
86db5dfb
DH
38#include "util.h"
39
40struct unifont {
41 unsigned long ref;
42
43 int fd;
44 const uint8_t *map;
45 size_t size;
46
47 unifont_header header;
48 const void *glyphs; /* unaligned! */
49 size_t n_glyphs;
50 size_t glyphsize;
51};
52
53static int unifont_fetch_header(unifont *u) {
54 unifont_header h = { };
55 uint64_t glyphsize;
56
57 if (u->size < UNIFONT_HEADER_SIZE_MIN)
58 return -EBFONT;
59
60 assert_cc(sizeof(h) >= UNIFONT_HEADER_SIZE_MIN);
61 memcpy(&h, u->map, UNIFONT_HEADER_SIZE_MIN);
62
63 h.compatible_flags = le32toh(h.compatible_flags);
64 h.incompatible_flags = le32toh(h.incompatible_flags);
65 h.header_size = le32toh(h.header_size);
66 h.glyph_header_size = le16toh(h.glyph_header_size);
67 h.glyph_stride = le16toh(h.glyph_stride);
68 h.glyph_body_size = le64toh(h.glyph_body_size);
69
70 if (memcmp(h.signature, "DVDHRMUF", 8))
71 return -EBFONT;
72 if (h.incompatible_flags != 0)
73 return -EBFONT;
74 if (h.header_size < UNIFONT_HEADER_SIZE_MIN || h.header_size > u->size)
75 return -EBFONT;
76 if (h.glyph_header_size + h.glyph_body_size < h.glyph_header_size)
77 return -EBFONT;
78 if (h.glyph_stride * 16ULL > h.glyph_body_size)
79 return -EBFONT;
80
81 glyphsize = h.glyph_header_size + h.glyph_body_size;
82
83 if (glyphsize == 0 || glyphsize > u->size - h.header_size) {
84 u->n_glyphs = 0;
85 } else {
86 u->glyphs = u->map + h.header_size;
87 u->n_glyphs = (u->size - h.header_size) / glyphsize;
88 u->glyphsize = glyphsize;
89 }
90
91 memcpy(&u->header, &h, sizeof(h));
92 return 0;
93}
94
95static int unifont_fetch_glyph(unifont *u, unifont_glyph_header *out_header, const void **out_body, uint32_t ucs4) {
96 unifont_glyph_header glyph_header = { };
97 const void *glyph_body = NULL;
98 const uint8_t *p;
99
100 if (ucs4 >= u->n_glyphs)
101 return -ENOENT;
102
103 p = u->glyphs;
104
105 /* copy glyph-header data */
106 p += ucs4 * u->glyphsize;
107 memcpy(&glyph_header, p, MIN(sizeof(glyph_header), u->header.glyph_header_size));
108
109 /* copy glyph-body pointer */
110 p += u->header.glyph_header_size;
111 glyph_body = p;
112
113 if (glyph_header.width < 1)
114 return -ENOENT;
115 if (glyph_header.width > u->header.glyph_stride)
116 return -EBFONT;
117
118 memcpy(out_header, &glyph_header, sizeof(glyph_header));
119 *out_body = glyph_body;
120 return 0;
121}
122
123int unifont_new(unifont **out) {
124 _cleanup_(unifont_unrefp) unifont *u = NULL;
125 struct stat st;
126 int r;
127
128 assert_return(out, -EINVAL);
129
130 u = new0(unifont, 1);
131 if (!u)
132 return -ENOMEM;
133
134 u->ref = 1;
135 u->fd = -1;
136 u->map = MAP_FAILED;
137
138 u->fd = open(UNIFONT_PATH, O_RDONLY | O_CLOEXEC | O_NOCTTY);
139 if (u->fd < 0)
140 return -errno;
141
142 r = fstat(u->fd, &st);
143 if (r < 0)
144 return -errno;
145
146 u->size = st.st_size;
147 u->map = mmap(NULL, u->size, PROT_READ, MAP_PRIVATE, u->fd, 0);
148 if (u->map == MAP_FAILED)
149 return -errno;
150
151 r = unifont_fetch_header(u);
152 if (r < 0)
153 return r;
154
155 *out = u;
156 u = NULL;
157 return 0;
158}
159
160unifont *unifont_ref(unifont *u) {
161 if (!u || !u->ref)
162 return NULL;
163
164 ++u->ref;
165
166 return u;
167}
168
169unifont *unifont_unref(unifont *u) {
170 if (!u || !u->ref || --u->ref)
171 return NULL;
172
173 if (u->map != MAP_FAILED)
174 munmap((void*)u->map, u->size);
175 u->fd = safe_close(u->fd);
176 free(u);
177
178 return NULL;
179}
180
fa965345
DH
181unsigned int unifont_get_width(unifont *u) {
182 assert(u);
183
184 return 8U;
185}
186
187unsigned int unifont_get_height(unifont *u) {
188 assert(u);
189
190 return 16U;
191}
192
86db5dfb
DH
193unsigned int unifont_get_stride(unifont *u) {
194 assert(u);
195
196 return u->header.glyph_stride;
197}
198
199int unifont_lookup(unifont *u, unifont_glyph *out, uint32_t ucs4) {
200 unifont_glyph_header h = { };
201 const void *b = NULL;
202 unifont_glyph g = { };
203 int r;
204
205 assert_return(u, -EINVAL);
206
207 r = unifont_fetch_glyph(u, &h, &b, ucs4);
208 if (r < 0)
209 return r;
210
211 g.width = h.width * 8U;
212 g.height = 16U;
213 g.stride = u->header.glyph_stride;
214 g.cwidth = h.width;
215 g.data = b;
216
217 if (out)
218 memcpy(out, &g, sizeof(g));
219 return 0;
220}
61d0326a
DH
221
222void unifont_fallback(unifont_glyph *out) {
223 static const uint8_t fallback_data[] = {
224 /* unifont 0xfffd '�' (unicode replacement character) */
225 0x00, 0x00, 0x00, 0x7e,
226 0x66, 0x5a, 0x5a, 0x7a,
227 0x76, 0x76, 0x7e, 0x76,
228 0x76, 0x7e, 0x00, 0x00,
229 };
230
231 assert(out);
232
233 out->width = 8;
234 out->height = 16;
235 out->stride = 1;
236 out->cwidth = 1;
237 out->data = fallback_data;
238}