bdf2sfd.c (5983B)
1 /* 2 * bdf2sfd 1.1.7 3 * Copyright (c) 2019-2022, Frederic Cambus 4 * https://github.com/fcambus/bdf2sfd 5 * 6 * Created: 2019-11-21 7 * Last Updated: 2022-02-10 8 * 9 * bdf2sfd is released under the BSD 2-Clause license. 10 * See LICENSE file for details. 11 * 12 * SPDX-License-Identifier: BSD-2-Clause 13 */ 14 15 #include <sys/stat.h> 16 #include <sys/time.h> 17 #include <err.h> 18 #include <getopt.h> 19 #include <inttypes.h> 20 #include <stdbool.h> 21 #include <stdlib.h> 22 #include <stdint.h> 23 #include <stdio.h> 24 #include <string.h> 25 #include <time.h> 26 27 #ifdef HAVE_SECCOMP 28 #include <sys/prctl.h> 29 #include <linux/seccomp.h> 30 #include "seccomp.h" 31 #endif 32 33 #include "compat.h" 34 #include "config.h" 35 #include "header.h" 36 #include "parse.h" 37 #include "polygon.h" 38 39 static void 40 usage() 41 { 42 printf("bdf2sfd [-hv] [-f name] [-p name] font.bdf\n\n" 43 "The options are as follows:\n\n" 44 " -f name Specify font name.\n" 45 " -p name Specify PostScript font name.\n" 46 " -h Display usage.\n" 47 " -v Display version.\n"); 48 } 49 50 static void 51 error(const char *str) 52 { 53 errx(EXIT_FAILURE, "%s", str); 54 } 55 56 int 57 main(int argc, char *argv[]) 58 { 59 struct timespec begin, current, elapsed; 60 struct stat bdf_stat; 61 62 float x = 0.0, y = 0.0; 63 float xlength = 64.0, ylength = 64.0; /* Default for 8x16 fonts */ 64 65 uint64_t glyphs = 0; 66 uint32_t height = 0, width = 0; 67 uint32_t ascent = 0, descent = 0; 68 uint32_t mask = 0; 69 70 int opt, key, stride; 71 72 const char *errstr = NULL; 73 char *input; 74 char *value = NULL; 75 char *linebuffer = NULL; 76 size_t linesize = 0; 77 78 bool readglyph = false; 79 bool name_allocated = false, psname_allocated = false; 80 81 FILE *bdf; 82 83 struct fontinfo font; 84 memset(&font, 0, sizeof(struct fontinfo)); 85 86 if (pledge("stdio rpath", NULL) == -1) { 87 err(EXIT_FAILURE, "pledge"); 88 } 89 90 #ifdef HAVE_SECCOMP 91 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 92 perror("Can't initialize seccomp"); 93 return EXIT_FAILURE; 94 } 95 96 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &bdf2sfd)) { 97 perror("Can't load seccomp filter"); 98 return EXIT_FAILURE; 99 } 100 #endif 101 102 while ((opt = getopt(argc, argv, "f:p:hv")) != -1) { 103 switch (opt) { 104 case 'f': 105 font.name = optarg; 106 break; 107 108 case 'p': 109 font.psname = optarg; 110 break; 111 112 case 'h': 113 usage(); 114 return EXIT_SUCCESS; 115 116 case 'v': 117 printf("%s\n", VERSION); 118 return EXIT_SUCCESS; 119 } 120 } 121 122 if (optind < argc) { 123 input = argv[optind]; 124 } else { 125 usage(); 126 return EXIT_SUCCESS; 127 } 128 129 /* Starting timer */ 130 clock_gettime(CLOCK_MONOTONIC, &begin); 131 132 /* Open BDF file */ 133 if (!strcmp(input, "-")) { 134 /* Read from standard input */ 135 bdf = stdin; 136 } else { 137 /* Attempt to read from file */ 138 if (!(bdf = fopen(input, "r"))) { 139 perror("Can't open BDF file"); 140 return EXIT_FAILURE; 141 } 142 } 143 144 /* Get BDF file size */ 145 if (fstat(fileno(bdf), &bdf_stat)) { 146 perror("Can't stat BDF file"); 147 return EXIT_FAILURE; 148 } 149 150 while (getline(&linebuffer, &linesize, bdf) != -1) { 151 if (!*linebuffer) 152 continue; 153 154 key = parseLine(linebuffer); 155 156 switch(key) { 157 case FAMILY_NAME: 158 case COPYRIGHT: 159 case FONT_ASCENT: 160 case FONT_DESCENT: 161 case FONT_VERSION: 162 case CHARS: 163 case STARTCHAR: 164 case ENCODING: 165 value = strtok(NULL, "\n"); 166 167 if (!value) 168 continue; 169 } 170 171 switch(key) { 172 case FAMILY_NAME: 173 if (!font.name) { 174 if ((font.name = strdup(value)) == NULL) 175 error("Memory allocation error."); 176 177 name_allocated = true; 178 } 179 180 if (!font.psname) { 181 if ((font.psname = strdup(value)) == NULL) 182 error("Memory allocation error."); 183 184 psname_allocated = true; 185 } 186 187 continue; 188 189 case COPYRIGHT: 190 if ((font.copyright = strdup(value)) == NULL) 191 error("Memory allocation error."); 192 193 continue; 194 195 case FONTBOUNDINGBOX: 196 value = strtok(NULL, " \t"); 197 198 if (value) 199 width = strtonum(value, 0, 32, &errstr); 200 201 if (errstr) 202 error("Invalid value for FONTBOUNDINGBOX."); 203 204 value = strtok(NULL, " \t"); 205 206 if (value) 207 height = strtonum(value, 0, 64, &errstr); 208 209 if (errstr) 210 error("Invalid value for FONTBOUNDINGBOX."); 211 212 if (!width || !height) 213 error("Invalid value for FONTBOUNDINGBOX."); 214 215 xlength = 512.0 / width; 216 ylength = 1024.0 / height; 217 218 stride = (width + 7) / 8; 219 mask = 1 << (stride * 8 - 1); 220 221 continue; 222 223 case FONT_ASCENT: 224 ascent = strtonum(value, 0, 64, &errstr); 225 226 if (!errstr) 227 font.ascent = ascent * ylength; 228 else 229 error("Invalid value for FONT_ASCENT."); 230 231 continue; 232 233 case FONT_DESCENT: 234 descent = strtonum(value, 0, 64, &errstr); 235 236 if (!errstr) 237 font.descent = descent * ylength; 238 else 239 error("Invalid value for FONT_DESCENT."); 240 241 continue; 242 243 case FONT_VERSION: 244 if ((font.version = strdup(value)) == NULL) 245 error("Memory allocation error."); 246 247 continue; 248 249 case CHARS: 250 font.chars = value; 251 252 if (font.chars) 253 header(stdout, &font); 254 else 255 error("Invalid value for CHARS."); 256 257 continue; 258 259 case STARTCHAR: 260 fprintf(stdout, "StartChar: %s", value); 261 262 continue; 263 264 case ENCODING: 265 fprintf(stdout, "\nEncoding: %s %s %s\n", 266 value, value, value); 267 268 continue; 269 270 case BITMAP: 271 fprintf(stdout, "Width: 512\n" 272 "Flags: HW\n" 273 "LayerCount: 2\n" 274 "Fore\n" 275 "SplineSet\n"); 276 277 y = font.ascent; 278 readglyph = true; 279 glyphs++; 280 281 continue; 282 283 case ENDCHAR: 284 fprintf(stdout, "EndSplineSet\n" 285 "EndChar\n\n"); 286 287 readglyph = false; 288 continue; 289 } 290 291 if (readglyph) { 292 uint32_t row = strtoul(linebuffer, NULL, 16); 293 294 polygon(row, mask, width, x, y, xlength, ylength); 295 296 y -= ylength; 297 } 298 } 299 300 fprintf(stdout, "EndChars\n" 301 "EndSplineFont\n"); 302 303 /* Stopping timer */ 304 clock_gettime(CLOCK_MONOTONIC, ¤t); 305 306 timespecsub(¤t, &begin, &elapsed); 307 308 /* Printing results */ 309 fprintf(stderr, "Processed %" PRIu64 " glyphs in %f seconds.\n", 310 glyphs, elapsed.tv_sec + elapsed.tv_nsec / 1E9); 311 312 /* Clean up */ 313 free(linebuffer); 314 fclose(bdf); 315 316 if (name_allocated) 317 free(font.name); 318 319 if (psname_allocated) 320 free(font.psname); 321 322 free(font.copyright); 323 free(font.version); 324 325 return EXIT_SUCCESS; 326 }