NetSurf
convert_font.c
Go to the documentation of this file.
1 /*
2  * Copyright 2014 Michael Drake <tlsa@netsurf-browser.org>
3  * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
4  *
5  * This file is part of the convert_font tool used to convert font
6  * glyph data into a compilable representation.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 #include <unistd.h>
34 #include <getopt.h>
35 
36 #define GLYPH_LEN 16
37 #define BUCKETS 512
38 #define CHUNK_SIZE (64 * 1024)
39 #define HEADER_MAX 2000
40 
41 #define SECTION_SIZE (sizeof(uint16_t) * 256)
42 
43 const char *labels[4] = {
44  " Regular",
45  " Italic",
46  " Bold",
47  "Bold & Italic"
48 };
49 
50 const char *var_lables[4] = {
51  "fb_regular",
52  "fb_italic",
53  "fb_bold",
54  "fb_bold_italic"
55 };
56 
57 const char *short_labels[4] = {
58  " ",
59  " i",
60  "b ",
61  "bi"
62 };
63 
64 enum font_style {
65  REGULAR = 0,
66  ITALIC = (1 << 0),
67  BOLD = (1 << 1),
68  ITALIC_BOLD = (1 << 2)
69 };
70 
71 enum log_level {
77 };
78 
80 
81 typedef struct glyph_entry {
82  union {
83  uint32_t u32[GLYPH_LEN / 4];
84  uint8_t u8[GLYPH_LEN];
85  } data;
86  uint32_t index;
87  struct glyph_entry *next;
88 } glyph_entry;
89 
90 /** Scratch glyph for generated code points */
92 
93 /** Hash table */
95 
96 #define LOG(lev, fmt, ...) \
97  if (lev >= level) \
98  printf(fmt, ##__VA_ARGS__);
99 
100 /**
101  * Get hash for glyph data
102  * \param g Glyph data (GLYPH_LEN bytes)
103  * \return glyph's hash
104  */
105 static inline uint32_t glyph_hash(const uint8_t *g)
106 {
107  uint32_t hash = 0x811c9dc5;
108  unsigned int len = GLYPH_LEN;
109 
110  while (len > 0) {
111  hash *= 0x01000193;
112  hash ^= *g++;
113  len--;
114  }
115 
116  return hash;
117 }
118 
119 
120 /**
121  * Check whether glyphs are identical (compares glyph data)
122  *
123  * \param g1 First glyph's data (GLYPH_LEN bytes)
124  * \param g2 Second glyph's data (GLYPH_LEN bytes)
125  * \return true iff both glyphs are identical, else false
126  */
127 static inline bool glyphs_match(const uint8_t *g1, const uint8_t *g2)
128 {
129  return (memcmp(g1, g2, GLYPH_LEN) == 0);
130 }
131 
132 
133 /**
134  * Add a glyph to a hash chain (or free, and return pointer to existing glyph)
135  *
136  * Note that if new glyph already exists in chain, it is freed and a pointer to
137  * the existing glyph is returned. If the glyph does not exist in the chain
138  * it is added and its pointer is returned.
139  *
140  * \param head Head of hash chain
141  * \param new New glyph to add (may be freed)
142  * \return pointer to glyph in hash chain
143  */
145 {
146  glyph_entry *e = *head;
147 
148  if (*head == NULL) {
149  new->next = NULL;
150  *head = new;
151  return new;
152  }
153 
154  do {
155  if (glyphs_match(new->data.u8, e->data.u8)) {
156  free(new);
157  return e;
158  }
159  if (e->next == NULL)
160  break;
161  e = e->next;
162  } while (1);
163 
164  new->next = e->next;
165  e->next = new;
166  return new;
167 }
168 
169 
170 /**
171  * Free a glyph entry chain
172  *
173  * \param head Head of hash chain
174  */
175 static void free_chain(glyph_entry *head)
176 {
177  glyph_entry *e = head;
178 
179  if (head == NULL)
180  return;
181 
182  while (e != NULL) {
183  head = e->next;
184  free(e);
185  e = head;
186  };
187 }
188 
189 
190 /**
191  * Add new glyph to hash table (or free, and return pointer to existing glyph)
192  *
193  * Note that if new glyph already exists in table, it is freed and a pointer to
194  * the existing glyph is returned. If the glyph does not exist in the table
195  * it is added and its pointer is returned.
196  *
197  * \param new New glyph to add (may be freed)
198  * \return pointer to glyph in hash table
199  */
201 {
202  uint32_t hash = glyph_hash(new->data.u8);
203 
204  return glyph_add_to_chain(&ht[hash % BUCKETS], new);
205 }
206 
207 
208 /**
209  * Free glyph table.
210  */
211 static void free_table(void)
212 {
213  int i;
214 
215  for (i = 0; i < BUCKETS; i++) {
216  free_chain(ht[i]);
217  }
218 }
219 
221  enum {
227  IN_GLYPH_DATA
228  } state; /**< Current parser state */
229 
230  union {
231  struct {
232  bool new_line;
233  } in_header;
234  struct {
235  bool new_line;
236  bool u;
237  } before_id;
238  struct {
239  int c;
240  } g_id;
241  struct {
242  bool new_line;
243  bool prev_h;
244  bool prev_s;
245  int c;
246  } before_gd;
247  struct {
248  int line;
249  int pos;
250  int styles;
252  glyph_entry *e[4];
253  } in_gd;
254  } data; /**< The state specific data */
255 
256  int id; /**< Current ID */
257 
258  int codepoints; /**< Glyphs containing codepoints */
259  int count[4]; /**< Count of glyphs in file */
260 };
261 
262 struct font_data {
263  char header[HEADER_MAX];
265 
266  uint8_t section_table[4][256];
267  uint8_t sec_count[4];
268  uint16_t *sections[4];
269 
270  glyph_entry *e[0xffff];
271  int glyphs;
272 };
273 
274 static bool generate_font_header(const char *path, struct font_data *data)
275 {
276  FILE *fp;
277  int s;
278 
279  fp = fopen(path, "wb");
280  if (fp == NULL) {
281  LOG(LOG_ERROR, "Couldn't open header file \"%s\"\n", path);
282  return false;
283  }
284 
285  fprintf(fp, "/*\n");
286  fwrite(data->header, 1, data->header_len, fp);
287  fprintf(fp, " */\n\n");
288  fprintf(fp, "/* Don't edit this file, it was generated from the "
289  "plain text source data. */\n\n");
290 
291 
292  for (s = 0; s < 4; s++) {
293  fprintf(fp, "const uint8_t *%s_section_table;\n",
294  var_lables[s]);
295  fprintf(fp, "const uint16_t *%s_sections;\n",
296  var_lables[s]);
297 
298  }
299 
300  fprintf(fp, "const uint8_t *font_glyph_data;\n");
301 
302  fprintf(fp, "\n\n");
303 
304  fclose(fp);
305 
306  return true;
307 
308 }
309 
310 static bool generate_font_source(const char *path, struct font_data *data)
311 {
312  int s, i, y;
313  int limit;
314  FILE *fp;
315 
316  fp = fopen(path, "wb");
317  if (fp == NULL) {
318  LOG(LOG_ERROR, "Couldn't open output file \"%s\"\n", path);
319  return false;
320  }
321 
322  fprintf(fp, "/*\n");
323  fwrite(data->header, 1, data->header_len, fp);
324  fprintf(fp, " */\n\n");
325  fprintf(fp, "/* Don't edit this file, it was generated from the "
326  "plain text source data. */\n\n");
327 
328  fprintf(fp, "#include <stdint.h>\n");
329  fprintf(fp, "\n");
330 
331  for (s = 0; s < 4; s++) {
332 
333  fprintf(fp, "static const uint8_t %s_section_table_c[256] = {\n",
334  var_lables[s]);
335 
336  for (i = 0; i < 256; i++) {
337  if (i == 255)
338  fprintf(fp, "0x%.2X\n",
339  data->section_table[s][i]);
340  else if (i % 8 == 7)
341  fprintf(fp, "0x%.2X,\n",
342  data->section_table[s][i]);
343  else if (i % 8 == 0)
344  fprintf(fp, "\t0x%.2X, ",
345  data->section_table[s][i]);
346  else
347  fprintf(fp, "0x%.2X, ",
348  data->section_table[s][i]);
349  }
350 
351  fprintf(fp, "};\nconst uint8_t *%s_section_table = &%s_section_table_c[0];\n\n",
352  var_lables[s], var_lables[s]);
353  fprintf(fp, "static const uint16_t %s_sections_c[%i] = {\n",
354  var_lables[s], data->sec_count[s] * 256);
355 
356  limit = data->sec_count[s] * 256;
357  for (i = 0; i < limit; i++) {
358  uint16_t offset = data->sections[s][i];
359  if (i == limit - 1)
360  fprintf(fp, "0x%.4X\n", offset);
361  else if (i % 4 == 3)
362  fprintf(fp, "0x%.4X,\n", offset);
363  else if (i % 4 == 0)
364  fprintf(fp, "\t0x%.4X, ", offset);
365  else
366  fprintf(fp, "0x%.4X, ", offset);
367  }
368 
369  fprintf(fp, "};\nconst uint16_t *%s_sections = &%s_sections_c[0];\n\n", var_lables[s], var_lables[s]);
370  }
371 
372  fprintf(fp, "static const uint8_t font_glyph_data_c[%i] = {\n",
373  (data->glyphs + 1) * 16);
374 
375  fprintf(fp, "\t0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n"
376  "\t0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n");
377 
378  limit = data->glyphs;
379  for (i = 0; i < limit; i++) {
380  glyph_entry *e = data->e[i];
381 
382  for (y = 0; y < 16; y++) {
383  if (i == limit - 1 && y == 15)
384  fprintf(fp, "0x%.2X\n", e->data.u8[y]);
385  else if (y % 8 == 7)
386  fprintf(fp, "0x%.2X,\n", e->data.u8[y]);
387  else if (y % 8 == 0)
388  fprintf(fp, "\t0x%.2X, ", e->data.u8[y]);
389  else
390  fprintf(fp, "0x%.2X, ", e->data.u8[y]);
391  }
392  }
393 
394  fprintf(fp, "};\n");
395  fprintf(fp, "const uint8_t *font_glyph_data = &font_glyph_data_c[0];\n\n");
396 
397  fclose(fp);
398 
399  return true;
400 }
401 
402 static bool add_glyph_to_data(glyph_entry *add, int id, int style,
403  struct font_data *d)
404 {
405  glyph_entry *e;
406  int offset;
407  int s;
408 
409  /* Find out if 'add' is unique, and get its unique table entry */
410  e = glyph_add_to_table(add);
411  if (e == add) {
412  /* Unique glyph */
413  d->e[d->glyphs++] = e;
414  e->index = d->glyphs;
415  if (d->glyphs >= 0xfffd) {
416  LOG(LOG_ERROR, " Too many glyphs for internal data "
417  "representation\n");
418  return false;
419  }
420  } else {
421  /* Duplicate glyph */
422  LOG(LOG_DEBUG, " U+%.4X (%s) is duplicate\n",
423  id, short_labels[style]);
424  }
425 
426  /* Find glyph's section */
427  s = id / 256;
428 
429  /* Allocate section if needed */
430  if ((s == 0 && d->sections[style] == NULL) ||
431  (s != 0 && d->section_table[style][s] == 0)) {
432  size_t size = (d->sec_count[style] + 1) * SECTION_SIZE;
433  uint16_t *temp = realloc(d->sections[style], size);
434  if (temp == NULL) {
435  LOG(LOG_ERROR, " Couldn't increase sections "
436  "allocation\n");
437  return false;
438  }
439  memset(temp + d->sec_count[style] * 256, 0,
440  SECTION_SIZE);
441  d->section_table[style][s] = d->sec_count[style];
442  d->sections[style] = temp;
443  d->sec_count[style]++;
444  }
445 
446  offset = d->section_table[style][s] * 256 + (id & 0xff);
447  d->sections[style][offset] = e->index;
448 
449  return true;
450 }
451 
452 
453 static bool check_glyph_data_valid(int pos, char c)
454 {
455  int offset = pos % 11;
456 
457  if (pos == 44) {
458  if (c != '\n') {
459  LOG(LOG_ERROR, " Invalid glyph data: "
460  "expecting '\\n', got '%c' (%i)\n",
461  c, c);
462  return false;
463  } else {
464  return true;
465  }
466  } else if (pos < 3) {
467  if (c != ' ') {
468  LOG(LOG_ERROR, " Invalid glyph data: "
469  "expecting ' ', got '%c' (%i)\n",
470  c, c);
471  return false;
472  } else {
473  return true;
474  }
475  } else if (offset == 0) {
476  if (c != '\n' && c != ' ') {
477  LOG(LOG_ERROR, " Invalid glyph data: "
478  "expecting '\\n' or ' ', "
479  "got '%c' (%i)\n",
480  c, c);
481  return false;
482  } else {
483  return true;
484  }
485  } else if (offset < 3) {
486  if (c != ' ') {
487  LOG(LOG_ERROR, " Invalid glyph data: "
488  "expecting ' ', got '%c' (%i)\n",
489  c, c);
490  return false;
491  } else {
492  return true;
493  }
494  } else if (offset >= 3 && pos < 11) {
495  if (c != '.' && c != '#') {
496  LOG(LOG_ERROR, " Invalid glyph data: "
497  "expecting '.' or '#', "
498  "got '%c' (%i)\n",
499  c, c);
500  return false;
501  } else {
502  return true;
503  }
504  }
505 
506  /* offset must be >=3 */
507  if (c != '.' && c != '#' && c != ' ') {
508  LOG(LOG_ERROR, " Invalid glyph data: "
509  "expecting '.', '#', or ' ', "
510  "got '%c' (%i)\n",
511  c, c);
512  return false;
513  }
514 
515  return true;
516 }
517 
518 #define SEVEN_SET ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | \
519  (1 << 4) | (1 << 5) | (1 << 6))
520 
521 #define THREE_SSS ((1 << 0) | (1 << 1) | (1 << 2))
522 #define THREE_S_S ((1 << 0) | (1 << 2))
523 #define THREE__SS ((1 << 0) | (1 << 1) )
524 #define THREE_SS_ ( (1 << 1) | (1 << 2))
525 #define THREE_S__ (1 << 2)
526 #define THREE__S_ (1 << 1)
527 #define THREE___S (1 << 0)
528 
529 uint8_t frag[16][5] = {
530  { THREE_SSS,
531  THREE_S_S,
532  THREE_S_S,
533  THREE_S_S,
534  THREE_SSS },
535 
536  { THREE__S_,
537  THREE_SS_,
538  THREE__S_,
539  THREE__S_,
540  THREE_SSS },
541 
542  { THREE_SS_,
543  THREE___S,
544  THREE__S_,
545  THREE_S__,
546  THREE_SSS },
547 
548  { THREE_SS_,
549  THREE___S,
550  THREE_SS_,
551  THREE___S,
552  THREE_SS_ },
553 
554  { THREE_S_S,
555  THREE_S_S,
556  THREE_SSS,
557  THREE___S,
558  THREE___S },
559 
560  { THREE_SSS,
561  THREE_S__,
562  THREE_SSS,
563  THREE___S,
564  THREE_SSS },
565 
566  { THREE__SS,
567  THREE_S__,
568  THREE_SSS,
569  THREE_S_S,
570  THREE_SSS },
571 
572  { THREE_SSS,
573  THREE___S,
574  THREE__S_,
575  THREE__S_,
576  THREE__S_ },
577 
578  { THREE_SSS,
579  THREE_S_S,
580  THREE_SSS,
581  THREE_S_S,
582  THREE_SSS },
583 
584  { THREE_SSS,
585  THREE_S_S,
586  THREE_SSS,
587  THREE___S,
588  THREE___S },
589 
590  { THREE__S_,
591  THREE_S_S,
592  THREE_SSS,
593  THREE_S_S,
594  THREE_S_S },
595 
596  { THREE_SS_,
597  THREE_S_S,
598  THREE_SS_,
599  THREE_S_S,
600  THREE_SS_ },
601 
602  { THREE__S_,
603  THREE_S_S,
604  THREE_S__,
605  THREE_S_S,
606  THREE__S_ },
607 
608  { THREE_SS_,
609  THREE_S_S,
610  THREE_S_S,
611  THREE_S_S,
612  THREE_SS_ },
613 
614  { THREE_SSS,
615  THREE_S__,
616  THREE_SS_,
617  THREE_S__,
618  THREE_SSS },
619 
620  { THREE_SSS,
621  THREE_S__,
622  THREE_SS_,
623  THREE_S__,
624  THREE_S__ }
625 };
626 
627 static void build_codepoint(int id, bool italic, uint8_t *code_point)
628 {
629  int shift = 0;
630  int l;
631  int r;
632 
633  if (!italic)
634  shift = 1;
635 
636  l = (id >> 12);
637  r = 0xf & (id >> 8);
638 
639  code_point[ 0] = 0;
640  code_point[ 1] = SEVEN_SET << shift;
641  code_point[ 2] = 0;
642 
643  code_point[ 3] = (frag[l][0] << (4 + shift)) | (frag[r][0] << shift);
644  code_point[ 4] = (frag[l][1] << (4 + shift)) | (frag[r][1] << shift);
645  code_point[ 5] = (frag[l][2] << (4 + shift)) | (frag[r][2] << shift);
646  code_point[ 6] = (frag[l][3] << (4 + shift)) | (frag[r][3] << shift);
647  code_point[ 7] = (frag[l][4] << (4 + shift)) | (frag[r][4] << shift);
648 
649  code_point[ 8] = 0;
650 
651  shift = 1;
652 
653  l = 0xf & (id >> 4);
654  r = 0xf & id ;
655 
656  code_point[ 9] = (frag[l][0] << (4 + shift)) | (frag[r][0] << shift);
657  code_point[10] = (frag[l][1] << (4 + shift)) | (frag[r][1] << shift);
658  code_point[11] = (frag[l][2] << (4 + shift)) | (frag[r][2] << shift);
659  code_point[12] = (frag[l][3] << (4 + shift)) | (frag[r][3] << shift);
660  code_point[13] = (frag[l][4] << (4 + shift)) | (frag[r][4] << shift);
661 
662  code_point[14] = 0;
663  code_point[15] = SEVEN_SET << shift;
664 }
665 
666 #undef SEVEN_SET
667 #undef THREE_SSS
668 #undef THREE_S_S
669 #undef THREE__SS
670 #undef THREE_SS_
671 #undef THREE_S__
672 #undef THREE__S_
673 #undef THREE___S
674 
675 static bool glyph_is_codepoint(const glyph_entry *e, int id, int style)
676 {
677  bool italic = false;
678 
679  if (style == 1 || style == 3) {
680  italic = true;
681  }
682 
683  build_codepoint(id, italic, code_point);
684 
685  return glyphs_match(code_point, e->data.u8);
686 }
687 
688 
689 static bool parse_glyph_data(struct parse_context *ctx, char c,
690  struct font_data *d)
691 {
692  int glyph = ctx->data.in_gd.pos / 11;
693  int g_pos = ctx->data.in_gd.pos % 11 - 3;
694  uint8_t *row;
695  bool ok;
696  int i;
697 
698  /* Check that character is valid */
699  if (check_glyph_data_valid(ctx->data.in_gd.pos, c) == false) {
700  LOG(LOG_ERROR, " Error in U+%.4X data: "
701  "glyph line: %i, pos: %i\n",
702  ctx->id,
703  ctx->data.in_gd.line,
704  ctx->data.in_gd.pos);
705  goto error;
706  }
707 
708  /* Allocate glyph data if needed */
709  if (ctx->data.in_gd.line == 0 &&
710  (c == '.' || c == '#')) {
711  if (ctx->data.in_gd.e[glyph] == NULL) {
712  ctx->data.in_gd.e[glyph] =
713  calloc(sizeof(struct glyph_entry), 1);
714  if (ctx->data.in_gd.e[glyph] == NULL) {
715  LOG(LOG_ERROR, " Couldn't allocate memory for "
716  "glyph entry\n");
717  goto error;
718  }
719 
720  ctx->data.in_gd.styles |= 1 << glyph;
721  }
722  }
723 
724  /* Build glyph data */
725  if (c == '#') {
726  row = &ctx->data.in_gd.e[glyph]->data.u8[ctx->data.in_gd.line];
727  *row += 1 << (7 - g_pos);
728 
729  ctx->data.in_gd.line_styles |= 1 << glyph;
730  } else if (c == '.') {
731  ctx->data.in_gd.line_styles |= 1 << glyph;
732  }
733 
734  /* Deal with current position */
735  if (c == '\n') {
736  if (ctx->data.in_gd.line == 0) {
737  if (ctx->data.in_gd.e[0] == NULL) {
738  LOG(LOG_ERROR, " Error in U+%.4X data: "
739  "\"Regular\" glyph style must "
740  "be present\n", ctx->id);
741  goto error;
742  }
743  } else if (ctx->data.in_gd.styles !=
744  ctx->data.in_gd.line_styles) {
745  LOG(LOG_ERROR, " Error in U+%.4X data: "
746  "glyph line: %i "
747  "styles don't match first line\n",
748  ctx->id,
749  ctx->data.in_gd.line);
750  goto error;
751  }
752 
753  ctx->data.in_gd.pos = 0;
754  ctx->data.in_gd.line++;
755  ctx->data.in_gd.line_styles = 0;
756  } else {
757  ctx->data.in_gd.pos++;
758  }
759 
760  /* If we've got all the glyph data, tidy up and advance state */
761  if (ctx->data.in_gd.line == 16) {
762  for (i = 0; i < 4; i++) {
763  if (ctx->data.in_gd.e[i] != NULL) {
764  ctx->count[i] += 1;
765  if (glyph_is_codepoint(ctx->data.in_gd.e[i],
766  ctx->id, i)) {
767  LOG(LOG_DEBUG, " U+%.4X (%s) is "
768  "codepoint\n",
769  ctx->id,
770  short_labels[i]);
771  ctx->codepoints += 1;
772  free(ctx->data.in_gd.e[i]);
773  ctx->data.in_gd.e[i] = NULL;
774  continue;
775  }
776 
777  ok = add_glyph_to_data(ctx->data.in_gd.e[i],
778  ctx->id, i, d);
779  if (!ok) {
780  goto error;
781  }
782  }
783  }
784 
785  ctx->data.before_id.new_line = false;
786  ctx->data.before_id.u = false;
787  ctx->state = BEFORE_ID;
788  }
789 
790  return true;
791 
792 error:
793 
794  for (i = 0; i < 4; i++) {
795  free(ctx->data.in_gd.e[i]);
796  }
797 
798  return false;
799 }
800 
801 static void parse_init(struct parse_context *ctx)
802 {
803  memset(ctx, 0, sizeof(struct parse_context));
804 }
805 
806 static bool get_hex_digit_value(char c, int *v)
807 {
808  if (c >= '0' && c <= '9')
809  *v = (c - '0');
810  else if (c >= 'A' && c <= 'F')
811  *v = (10 + c - 'A');
812  else {
813  LOG(LOG_ERROR, "Invalid hex digit '%c' (%i)\n", c, c);
814  return false;
815  }
816 
817  return true;
818 }
819 
820 static bool assemble_codepoint(const char* c, int n, int *id)
821 {
822  bool ok;
823  int v;
824 
825  ok = get_hex_digit_value(*c, &v);
826  if (!ok) {
827  return false;
828  }
829 
830  *id += v << (4 * (3 - n));
831 
832  return true;
833 }
834 
835 static bool parse_chunk(struct parse_context *ctx, const char *buf, size_t len,
836  struct font_data *d)
837 {
838  int i;
839  bool ok;
840  int count[4];
841  const char *pos = buf;
842  const char *end = buf + len;
843 
844  for (i = 0; i < 4; i++) {
845  count[i] = ctx->count[i];
846  }
847 
848  while (pos < end) {
849  if (*pos == '\r') {
850  LOG(LOG_ERROR, "Detected \'\\r\': Bad line ending\n");
851  return false;
852  }
853 
854  switch (ctx->state) {
855  case START:
856  if (*pos != '*') {
857  LOG(LOG_ERROR, "First character must be '*'\n");
858  printf("Got: %c (%i)\n", *pos, *pos);
859  return false;
860  }
861  d->header_len = 0;
862  ctx->data.in_header.new_line = true;
863  ctx->state = IN_HEADER;
864 
865  /* Fall through */
866  case IN_HEADER:
867  if (ctx->data.in_header.new_line == true) {
868  if (*pos != '*') {
869  LOG(LOG_INFO, " Got header "
870  "(%i bytes)\n",
871  d->header_len);
872  LOG(LOG_DEBUG, " Header:\n\n%.*s\n",
873  d->header_len,
874  d->header);
875  ctx->data.before_id.new_line = false;
876  ctx->data.before_id.u = false;
877  ctx->state = BEFORE_ID;
878  continue;
879  } else if (*pos == '*') {
880  d->header[d->header_len++] = ' ';
881  }
882  ctx->data.in_header.new_line = false;
883 
884  } else if (*pos == '\n') {
885  ctx->data.in_header.new_line = true;
886  }
887 
888  if (d->header_len == HEADER_MAX) {
889  LOG(LOG_ERROR, " Header too long "
890  "(>%i bytes)\n",
891  d->header_len);
892  return false;
893  }
894 
895  d->header[d->header_len++] = *pos;
896  break;
897 
898  case BEFORE_ID:
899  if (*pos == '+' &&
900  ctx->data.before_id.new_line == true &&
901  ctx->data.before_id.u == true) {
902  ctx->data.g_id.c = 0;
903  ctx->id = 0;
904  ctx->state = GLYPH_ID;
905  break;
906 
907  } else if (*pos == 'U' &&
908  ctx->data.before_id.new_line == true) {
909  ctx->data.before_id.u = true;
910 
911  } else if (*pos == '\n') {
912  ctx->data.before_id.new_line = true;
913  ctx->data.before_id.u = false;
914 
915  } else {
916  ctx->data.before_id.new_line = false;
917  ctx->data.before_id.u = false;
918  }
919  break;
920 
921  case GLYPH_ID:
922  ok = assemble_codepoint(pos, ctx->data.g_id.c++,
923  &ctx->id);
924  if (!ok) {
925  LOG(LOG_ERROR, " Invalid glyph ID\n");
926  return false;
927  }
928 
929  if (ctx->data.g_id.c == 4) {
930  ctx->data.before_gd.new_line = false;
931  ctx->data.before_gd.prev_h = false;
932  ctx->data.before_gd.prev_s = false;
933  ctx->data.before_gd.c = 0;
934  ctx->state = BEFORE_GLYPH_DATA;
935  break;
936  }
937  break;
938 
939  case BEFORE_GLYPH_DATA:
940  /* Skip until end of dashed line */
941  if (*pos == '\n' && ctx->data.before_gd.c == 53) {
942  ctx->state = IN_GLYPH_DATA;
943  ctx->data.in_gd.e[0] = NULL;
944  ctx->data.in_gd.e[1] = NULL;
945  ctx->data.in_gd.e[2] = NULL;
946  ctx->data.in_gd.e[3] = NULL;
947  ctx->data.in_gd.line = 0;
948  ctx->data.in_gd.pos = 0;
949  ctx->data.in_gd.line_styles = 0;
950  ctx->data.in_gd.styles = 0;
951  break;
952 
953  } else if (*pos == '\n') {
954  ctx->data.before_gd.new_line = true;
955  ctx->data.before_gd.prev_h = false;
956  ctx->data.before_gd.prev_s = false;
957  ctx->data.before_gd.c = 0;
958  } else if (*pos == '-' &&
959  ctx->data.before_gd.new_line == true) {
960  assert(ctx->data.before_gd.c == 0);
961  ctx->data.before_gd.new_line = false;
962  ctx->data.before_gd.c++;
963  ctx->data.before_gd.prev_h = true;
964  } else if (*pos == ' ' &&
965  ctx->data.before_gd.prev_h == true) {
966  assert(ctx->data.before_gd.prev_s == false);
967  ctx->data.before_gd.c++;
968  ctx->data.before_gd.prev_h = false;
969  ctx->data.before_gd.prev_s = true;
970  } else if (*pos == '-' &&
971  ctx->data.before_gd.prev_s == true) {
972  assert(ctx->data.before_gd.prev_h == false);
973  ctx->data.before_gd.c++;
974  ctx->data.before_gd.prev_h = true;
975  ctx->data.before_gd.prev_s = false;
976  } else {
977  ctx->data.before_gd.new_line = false;
978  ctx->data.before_gd.prev_h = false;
979  ctx->data.before_gd.prev_s = false;
980  ctx->data.before_gd.c = 0;
981  }
982  break;
983 
984  case IN_GLYPH_DATA:
985  ok = parse_glyph_data(ctx, *pos, d);
986  if (!ok) {
987  return false;
988  }
989 
990  break;
991  }
992 
993  pos++;
994  }
995 
996  for (i = 0; i < 4; i++) {
997  LOG(LOG_DEBUG, " %s: %i gylphs\n", labels[i],
998  ctx->count[i] - count[i]);
999  }
1000 
1001  return true;
1002 }
1003 
1004 
1005 static bool load_font(const char *path, struct font_data **data)
1006 {
1007  struct parse_context ctx;
1008  struct font_data *d;
1009  size_t file_len;
1010  size_t done;
1011  size_t len;
1012  int count;
1013  char *buf;
1014  FILE *fp;
1015  bool ok;
1016  int i;
1017 
1018  *data = NULL;
1019 
1020  fp = fopen(path, "rb");
1021  if (fp == NULL) {
1022  LOG(LOG_ERROR, "Couldn't open font data file\n");
1023  return false;
1024  }
1025 
1026  d = calloc(sizeof(struct font_data), 1);
1027  if (d == NULL) {
1028  LOG(LOG_ERROR, "Couldn't allocate memory for font data\n");
1029  fclose(fp);
1030  return false;
1031  }
1032 
1033  /* Find filesize */
1034  fseek(fp, 0L, SEEK_END);
1035  file_len = ftell(fp);
1036  if ((long)file_len == -1) {
1037  LOG(LOG_ERROR, "Could not size input file\n");
1038  free(d);
1039  fclose(fp);
1040  return false;
1041  }
1042  fseek(fp, 0L, SEEK_SET);
1043  LOG(LOG_DEBUG, "Input size: %zu bytes\n", file_len);
1044 
1045  /* Allocate buffer for data chunks */
1046  buf = malloc(CHUNK_SIZE);
1047  if (buf == NULL) {
1048  LOG(LOG_ERROR, "Couldn't allocate memory for input buffer\n");
1049  free(d);
1050  fclose(fp);
1051  return false;
1052  }
1053 
1054  /* Initialise parser */
1055  parse_init(&ctx);
1056 
1057  LOG(LOG_DEBUG, "Using chunk size of %i bytes\n", CHUNK_SIZE);
1058 
1059  /* Parse the input file in chunks */
1060  for (done = 0; done < file_len; done += CHUNK_SIZE) {
1061  LOG(LOG_INFO, "Parsing input chunk %zu\n", done / CHUNK_SIZE);
1062 
1063  /* Read chunk */
1064  len = fread(buf, 1, CHUNK_SIZE, fp);
1065  if (file_len - done < CHUNK_SIZE &&
1066  len != file_len - done) {
1067  LOG(LOG_WARNING, "Last chunk has suspicious size\n");
1068  } else if (file_len - done >= CHUNK_SIZE &&
1069  len != CHUNK_SIZE) {
1070  LOG(LOG_ERROR, "Problem reading file\n");
1071  free(buf);
1072  free(d);
1073  fclose(fp);
1074  return false;
1075  }
1076 
1077  /* Parse chunk */
1078  ok = parse_chunk(&ctx, buf, len, d);
1079  if (!ok) {
1080  free(buf);
1081  free(d);
1082  fclose(fp);
1083  return false;
1084  }
1085  LOG(LOG_DEBUG, "Parsed %zu bytes\n", done + len);
1086  }
1087 
1088  fclose(fp);
1089 
1090  if (ctx.state != BEFORE_ID) {
1091  LOG(LOG_ERROR, "Unexpected end of file\n");
1092  free(buf);
1093  free(d);
1094  return false;
1095  }
1096 
1097  LOG(LOG_INFO, "Parsing complete:\n");
1098  count = 0;
1099  for (i = 0; i < 4; i++) {
1100  LOG(LOG_INFO, " %s: %i gylphs\n", labels[i], ctx.count[i]);
1101  count += ctx.count[i];
1102  }
1103 
1104  LOG(LOG_RESULT, " Total %i gylphs "
1105  "(of which %i unique, %i codepoints, %i duplicates)\n",
1106  count, d->glyphs, ctx.codepoints,
1107  count - d->glyphs - ctx.codepoints);
1108 
1109  free(buf);
1110 
1111  *data = d;
1112  return true;
1113 }
1114 
1115 static void log_usage(const char *argv0)
1116 {
1117  level = LOG_INFO;
1118  LOG(LOG_INFO,
1119  "Usage:\n"
1120  "\t%s [options] <in_file> <out_file>\n"
1121  "\n"
1122  "Options:\n"
1123  "\t--help -h Display this text\n"
1124  "\t--quiet -q Don't show warnings\n"
1125  "\t--verbose -v Verbose output\n"
1126  "\t--debug -d Full debug output\n",
1127  argv0);
1128 }
1129 
1130 int main(int argc, char** argv)
1131 {
1132  const char *in_path = NULL;
1133  const char *out_path = NULL;
1134  char *header_path = NULL;
1135  struct font_data *data;
1136  bool ok;
1137  int i;
1138  int opt;
1139 
1140  level = LOG_RESULT;
1141 
1142  /* Handle program arguments */
1143  struct option long_options[] = {
1144  { "help", no_argument, NULL, 'h' },
1145  { "quiet", no_argument, NULL, 'q' },
1146  { "verbose", no_argument, NULL, 'v' },
1147  { "debug", no_argument, NULL, 'd' },
1148  { "header", required_argument, NULL, 'H' },
1149  };
1150 
1151  while ((opt = getopt_long(argc, argv, "hqvdH:", long_options, NULL)) != -1) {
1152  switch (opt) {
1153  case 'q':
1154  level = LOG_WARNING;
1155  break;
1156 
1157  case 'v':
1158  level = LOG_INFO;
1159  break;
1160 
1161  case 'd':
1162  level = LOG_DEBUG;
1163  break;
1164 
1165  case 'H':
1166  header_path = strdup(optarg);
1167  break;
1168 
1169  case 'h':
1170  log_usage(argv[0]);
1171  free(header_path);
1172  return EXIT_SUCCESS;
1173 
1174  default:
1175  log_usage(argv[0]);
1176  free(header_path);
1177  return EXIT_FAILURE;
1178  }
1179  }
1180 
1181  if ((argc - optind) < 2) {
1182  log_usage(argv[0]);
1183  free(header_path);
1184  return EXIT_FAILURE;
1185  }
1186 
1187  in_path = argv[optind];
1188  out_path = argv[optind + 1];
1189 
1190  LOG(LOG_DEBUG, "Using input path: \"%s\"\n", in_path);
1191  LOG(LOG_DEBUG, "Using output path: \"%s\"\n", out_path);
1192 
1193  ok = load_font(in_path, &data);
1194  if (!ok) {
1195  free_table();
1196  free(header_path);
1197  return EXIT_FAILURE;
1198  }
1199 
1200  ok = generate_font_source(out_path, data);
1201  if (ok && (header_path != NULL)) {
1202  ok = generate_font_header(header_path, data);
1203  }
1204  free(header_path);
1205  free_table();
1206  for (i = 0; i < 4; i++) {
1207  free(data->sections[i]);
1208  }
1209  free(data);
1210  if (!ok) {
1211  return EXIT_FAILURE;
1212  }
1213 
1214  return EXIT_SUCCESS;
1215 }
struct glyph_entry glyph_entry
log_level
Definition: convert_font.c:71
uint8_t sec_count[4]
Definition: convert_font.c:267
glyph_entry * ht[BUCKETS]
Hash table.
Definition: convert_font.c:94
struct parse_context::@148::@152 before_gd
Interface to utility string handling.
#define HEADER_MAX
Definition: convert_font.c:39
static bool generate_font_header(const char *path, struct font_data *data)
Definition: convert_font.c:274
uint8_t u8[GLYPH_LEN]
Definition: convert_font.c:84
#define THREE___S
Definition: convert_font.c:527
static bool get_hex_digit_value(char c, int *v)
Definition: convert_font.c:806
static glyph_entry * glyph_add_to_table(glyph_entry *new)
Add new glyph to hash table (or free, and return pointer to existing glyph)
Definition: convert_font.c:200
#define CHUNK_SIZE
Definition: convert_font.c:38
uint8_t section_table[4][256]
Definition: convert_font.c:266
int codepoints
Glyphs containing codepoints.
Definition: convert_font.c:258
uint32_t u32[GLYPH_LEN/4]
Definition: convert_font.c:83
static glyph_entry * glyph_add_to_chain(glyph_entry **head, glyph_entry *new)
Add a glyph to a hash chain (or free, and return pointer to existing glyph)
Definition: convert_font.c:144
#define THREE__SS
Definition: convert_font.c:523
static bool add_glyph_to_data(glyph_entry *add, int id, int style, struct font_data *d)
Definition: convert_font.c:402
static bool glyphs_match(const uint8_t *g1, const uint8_t *g2)
Check whether glyphs are identical (compares glyph data)
Definition: convert_font.c:127
font_style
Definition: convert_font.c:64
static void build_codepoint(int id, bool italic, uint8_t *code_point)
Definition: convert_font.c:627
const char * short_labels[4]
Definition: convert_font.c:57
enum log_level level
Definition: convert_font.c:79
union glyph_entry::@146 data
static void free_table(void)
Free glyph table.
Definition: convert_font.c:211
uint8_t frag[16][5]
Definition: convert_font.c:529
#define THREE_S__
Definition: convert_font.c:525
static bool assemble_codepoint(const char *c, int n, int *id)
Definition: convert_font.c:820
#define SEVEN_SET
Definition: convert_font.c:518
struct parse_context::@148::@150 before_id
static uint32_t glyph_hash(const uint8_t *g)
Get hash for glyph data.
Definition: convert_font.c:105
#define THREE_SSS
Definition: convert_font.c:521
const char * labels[4]
Definition: convert_font.c:43
static bool parse_chunk(struct parse_context *ctx, const char *buf, size_t len, struct font_data *d)
Definition: convert_font.c:835
#define THREE_S_S
Definition: convert_font.c:522
int count[4]
Count of glyphs in file.
Definition: convert_font.c:259
struct parse_context::@148::@151 g_id
const char * var_lables[4]
Definition: convert_font.c:50
static void free_chain(glyph_entry *head)
Free a glyph entry chain.
Definition: convert_font.c:175
#define THREE__S_
Definition: convert_font.c:526
static bool parse_glyph_data(struct parse_context *ctx, char c, struct font_data *d)
Definition: convert_font.c:689
uint16_t * sections[4]
Definition: convert_font.c:268
#define GLYPH_LEN
Definition: convert_font.c:36
glyph_entry * e[0xffff]
Definition: convert_font.c:270
#define THREE_SS_
Definition: convert_font.c:524
static bool load_font(const char *path, struct font_data **data)
static bool generate_font_source(const char *path, struct font_data *data)
Definition: convert_font.c:310
int main(int argc, char **argv)
Normal entry point from OS.
#define BUCKETS
Definition: convert_font.c:37
struct glyph_entry * next
Definition: convert_font.c:87
static void parse_init(struct parse_context *ctx)
Definition: convert_font.c:801
static bool glyph_is_codepoint(const glyph_entry *e, int id, int style)
Definition: convert_font.c:675
union parse_context::@148 data
The state specific data.
static nserror path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, const float transform[6])
Plots a path.
Definition: plot.c:821
uint32_t index
Definition: convert_font.c:86
uint8_t code_point[GLYPH_LEN]
Scratch glyph for generated code points.
Definition: convert_font.c:91
enum parse_context::@147 state
Current parser state.
#define SECTION_SIZE
Definition: convert_font.c:41
char header[HEADER_MAX]
Definition: convert_font.c:263
int header_len
Definition: convert_font.c:264
static uint32_t count(const http_directive *list, lwc_string *key)
struct parse_context::@148::@153 in_gd
static bool check_glyph_data_valid(int pos, char c)
Definition: convert_font.c:453
int id
Current ID.
Definition: convert_font.c:256
#define LOG(lev, fmt,...)
Definition: convert_font.c:96
Definition: convert_font.c:81
struct parse_context::@148::@149 in_header
static void log_usage(const char *argv0)