--- src/usr.bin/vtfontcvt.c.orig +++ src/usr.bin/vtfontcvt.c @@ -44,11 +44,13 @@ #include #include -#define VFNT_MAPS 4 -#define VFNT_MAP_NORMAL 0 -#define VFNT_MAP_NORMAL_RH 1 -#define VFNT_MAP_BOLD 2 -#define VFNT_MAP_BOLD_RH 3 +#define VFNT_MAPS 4 +#define VFNT_MAP_NORMAL 0 +#define VFNT_MAP_NORMAL_RIGHT 1 +#define VFNT_MAP_BOLD 2 +#define VFNT_MAP_BOLD_RIGHT 3 +#define VFNT_MAXGLYPHS 131072 +#define VFNT_MAXDIMENSION 128 static unsigned int width = 8, wbytes, height = 16; @@ -63,10 +65,10 @@ TAILQ_HEAD(glyph_list, glyph); static SLIST_HEAD(, glyph) glyph_hash[FONTCVT_NHASH]; static struct glyph_list glyphs[VFNT_MAPS] = { - TAILQ_HEAD_INITIALIZER(glyphs[0]), - TAILQ_HEAD_INITIALIZER(glyphs[1]), - TAILQ_HEAD_INITIALIZER(glyphs[2]), - TAILQ_HEAD_INITIALIZER(glyphs[3]), + TAILQ_HEAD_INITIALIZER(glyphs[0]), + TAILQ_HEAD_INITIALIZER(glyphs[1]), + TAILQ_HEAD_INITIALIZER(glyphs[2]), + TAILQ_HEAD_INITIALIZER(glyphs[3]), }; static unsigned int glyph_total, glyph_count[4], glyph_unique, glyph_dupe; @@ -79,13 +81,13 @@ TAILQ_HEAD(mapping_list, mapping); static struct mapping_list maps[VFNT_MAPS] = { - TAILQ_HEAD_INITIALIZER(maps[0]), - TAILQ_HEAD_INITIALIZER(maps[1]), - TAILQ_HEAD_INITIALIZER(maps[2]), - TAILQ_HEAD_INITIALIZER(maps[3]), + TAILQ_HEAD_INITIALIZER(maps[0]), + TAILQ_HEAD_INITIALIZER(maps[1]), + TAILQ_HEAD_INITIALIZER(maps[2]), + TAILQ_HEAD_INITIALIZER(maps[3]), }; static unsigned int mapping_total, map_count[4], map_folded_count[4], - mapping_unique, mapping_dupe; + mapping_unique, mapping_dupe; static void usage(void) @@ -103,13 +105,15 @@ if ((m = malloc(size)) == NULL) errx(1, "memory allocation failure"); + memset(m, 0, size); + return (m); } static int add_mapping(struct glyph *gl, unsigned int c, unsigned int map_idx) { - struct mapping *mp; + struct mapping *mp, *mp_temp = NULL; struct mapping_list *ml; mapping_total++; @@ -120,10 +124,14 @@ mp->m_length = 0; ml = &maps[map_idx]; - if (TAILQ_LAST(ml, mapping_list) != NULL && - TAILQ_LAST(ml, mapping_list)->m_char >= c) - errx(1, "Bad ordering at character %u", c); - TAILQ_INSERT_TAIL(ml, mp, m_list); + TAILQ_FOREACH(mp_temp, ml, m_list) { + if (mp_temp->m_char >= c) + break; + } + if (mp_temp == NULL) + TAILQ_INSERT_TAIL(ml, mp, m_list); + else + TAILQ_INSERT_BEFORE(mp_temp, mp, m_list); map_count[map_idx]++; mapping_unique++; @@ -137,7 +145,7 @@ struct mapping *mp_bold, *mp_normal, *mp_temp; unsigned normal_map_idx = map_idx - VFNT_MAP_BOLD; - assert(map_idx == VFNT_MAP_BOLD || map_idx == VFNT_MAP_BOLD_RH); + assert(map_idx == VFNT_MAP_BOLD || map_idx == VFNT_MAP_BOLD_RIGHT); mp_normal = TAILQ_FIRST(&maps[normal_map_idx]); TAILQ_FOREACH_SAFE(mp_bold, &maps[map_idx], m_list, mp_temp) { while (mp_normal->m_char < mp_bold->m_char) @@ -153,6 +161,7 @@ free(mp_bold); mapping_dupe++; } + return (0); } @@ -183,6 +192,10 @@ SLIST_INSERT_HEAD(&glyph_hash[hash], gl, g_hash); glyph_unique++; + + if (glyph_unique > VFNT_MAXGLYPHS) + errx(1, "Too large number of glyphs %u!", glyph_unique); + return (gl); } @@ -201,120 +214,244 @@ return (1); if (bytes_r != NULL) { gl = add_glyph(bytes_r, map_idx + 1, 0); - if (add_mapping(gl, curchar, - map_idx + 1) != 0) + if (add_mapping(gl, curchar, map_idx + 1) != 0) return (1); } } + return (0); } - static int -parse_bitmap_line(uint8_t *left, uint8_t *right, unsigned int line, - unsigned int dwidth) +rshift_bitmap_line(uint8_t *line, size_t size, size_t len, size_t shift) { - uint8_t *p; - unsigned int i, subline; + size_t d, s, i; + uint16_t t; - if (dwidth != width && dwidth != width * 2) - errx(1, "Bitmap with unsupported width %u!", dwidth); + assert(size > 0 && len > 0); + assert(size * 8 >= len); - /* Move pixel data right to simplify splitting double characters. */ - line >>= (howmany(dwidth, 8) * 8) - dwidth; + if (shift == 0) + return (0); - for (i = dwidth / width; i > 0; i--) { - p = (i == 2) ? right : left; + d = shift / 8; + s = 8 - shift % 8; + i = howmany(len, 8); - subline = line & ((1 << width) - 1); - subline <<= (howmany(width, 8) * 8) - width; + while (i > 0) { + i--; - if (wbytes == 1) { - *p = subline; - } else if (wbytes == 2) { - *p++ = subline >> 8; - *p = subline; - } else { - errx(1, "Unsupported wbytes %u!", wbytes); - } + t = *(line + i); + *(line + i) = 0; - line >>= width; + t <<= s; + + if (i + d + 1 < size) + *(line + i + d + 1) |= (uint8_t) t; + if (i + d < size) + *(line + i + d) = t >> 8; } return (0); } static int +split_bitmap_line(uint8_t *left, uint8_t *right, uint8_t *line, size_t w) +{ + size_t s, i; + + s = wbytes * 8 - width; + + memcpy(left, line, wbytes); + *(left + wbytes - 1) &= 0xFF << s; + + if (w > width) { // Double-width character + uint8_t t; + + for (i = 0; i < wbytes; i++) { + t = *(line + wbytes + i - 1); + t <<= 8 - s; + t |= *(line + wbytes + i) >> s; + *(right + i) = t; + } + *(right + wbytes - 1) &= 0xFF << s; + } + + return (0); +} + +static void +set_width(int v) +{ + if (v < 1 || v > VFNT_MAXDIMENSION) + errx(1, "invalid width %d", v); + width = v; + wbytes = howmany(width, 8); +} + +static void +set_height(int v) +{ + if (v < 1 || v > VFNT_MAXDIMENSION) + errx(1, "invalid height %d", v); + height = v; +} + +static int parse_bdf(FILE *fp, unsigned int map_idx) { - char *ln; + char *ln, *p;; size_t length; - uint8_t bytes[wbytes * height], bytes_r[wbytes * height]; - unsigned int curchar = 0, dwidth = 0, i, line; + unsigned int linenum = 0, i, j; + int rv = 0; + char spacing = '\0'; + int fbbw, fbbh, fbbox, fbboy, dwx, dwy; + + fbbw = fbbh = fbbox = fbboy = dwx = dwy = 0; + while ((ln = fgetln(fp, &length)) != NULL) { + linenum++; ln[length - 1] = '\0'; - if (strncmp(ln, "ENCODING ", 9) == 0) { - curchar = atoi(ln + 9); + if (strncmp(ln, "FONT ", 5) == 0) { + p = ln + 5; i = 0; + while ((p = strchr(p, '-')) != NULL) { + p++; i++; + if (i == 11) { + spacing = *p; + break; + } + } + } else if (strncmp(ln, "FONTBOUNDINGBOX ", 16) == 0 && + sscanf(ln + 16, "%d %d %d %d", + &fbbw, &fbbh, &fbbox, &fbboy) == 4) { + set_width(fbbw); + set_height(fbbh); + break; } + } - if (strncmp(ln, "DWIDTH ", 7) == 0) { - dwidth = atoi(ln + 7); + if (fbbw == 0 && fbbh == 0) + errx(1, "Broken font header!"); + if (spacing != 'c' && spacing != 'C') + errx(1, "Font spacing \"C\" (Character cell) required"); + + while ((ln = fgetln(fp, &length)) != NULL) { + linenum++; + ln[length - 1] = '\0'; + + if (strncmp(ln, "DWIDTH ", 7) == 0 && + sscanf(ln + 7, "%d %d", &dwx, &dwy) == 2) { + if (dwy != 0 || (dwx != fbbw && dwx * 2 != fbbw)) + errx(1, "Bitmap with unsupported " + "DWIDTH %d %d at line %u", + dwx, dwy, linenum); + if (dwx < fbbw) + set_width(dwx); } + } - if (strncmp(ln, "BITMAP", 6) == 0 && + uint8_t *bytes = NULL, *bytes_r = NULL, *line = NULL; + unsigned int curchar = 0, bbwbytes; + int bbw, bbh, bbox, bboy; + + linenum = 0; + dwx = bbw = bbh = 0; + rewind(fp); + while ((ln = fgetln(fp, &length)) != NULL) { + linenum++; + ln[length - 1] = '\0'; + + if (strncmp(ln, "ENCODING ", 9) == 0) + curchar = atoi(ln + 9); + else if (strncmp(ln, "DWIDTH ", 7) == 0) + dwx = atoi(ln + 7); + else if (strncmp(ln, "BBX ", 4) == 0 && + sscanf(ln + 4, "%d %d %d %d", + &bbw, &bbh, &bbox, &bboy) == 4) { + if (bbw < 1 || bbh < 1 || bbw > fbbw || bbh > fbbh || + bbox < fbbox || bboy < fbboy) + errx(1, "Broken bitmap with " + "BBX %d %d %d %d at line %u", + bbw, bbh, bbox, bboy, linenum); + bbwbytes = howmany(bbw, 8); + } else if (strncmp(ln, "BITMAP", 6) == 0 && (ln[6] == ' ' || ln[6] == '\0')) { + if (dwx == 0 || bbw == 0 || bbh == 0) + errx(1, "Broken char header at line %u!", + linenum); + if (bytes == NULL) { + bytes = xmalloc(wbytes * height); + bytes_r = xmalloc(wbytes * height); + line = xmalloc(wbytes * 2); + } else { + memset(bytes, 0, wbytes * height); + memset(bytes_r, 0, wbytes * height); + } + /* - * Assume that the next _height_ lines are bitmap - * data. ENDCHAR is allowed to terminate the bitmap + * Assume that the next _bbh_ lines are bitmap data. + * ENDCHAR is allowed to terminate the bitmap * early but is not otherwise checked; any extra data * is ignored. */ - for (i = 0; i < height; i++) { + for (i = (fbbh + fbboy) - (bbh + bboy); + i < (unsigned int) ((fbbh + fbboy) - bboy); i++) { if ((ln = fgetln(fp, &length)) == NULL) errx(1, "Unexpected EOF!"); + linenum++; ln[length - 1] = '\0'; - if (strcmp(ln, "ENDCHAR") == 0) { - memset(bytes + i * wbytes, 0, - (height - i) * wbytes); - memset(bytes_r + i * wbytes, 0, - (height - i) * wbytes); + + if (strcmp(ln, "ENDCHAR") == 0) break; + + if (strlen(ln) < bbwbytes * 2) + errx(1, "Broken bitmap at line %u!", + linenum); + memset(line, 0, wbytes * 2); + for (j = 0; j < bbwbytes; j++) { + unsigned int val; + if (sscanf(ln + j * 2, "%2x", &val) == 0) + break; + *(line + j) = (uint8_t) val; } - sscanf(ln, "%x", &line); - if (parse_bitmap_line(bytes + i * wbytes, - bytes_r + i * wbytes, line, dwidth) != 0) - return (1); + + rv = rshift_bitmap_line(line, wbytes * 2, + bbw, bbox - fbbox); + if (rv != 0) + goto out; + + rv = split_bitmap_line(bytes + i * wbytes, + bytes_r + i * wbytes, line, dwx); + if (rv != 0) + goto out; } - if (add_char(curchar, map_idx, bytes, - dwidth == width * 2 ? bytes_r : NULL) != 0) - return (1); + rv = add_char(curchar, map_idx, bytes, + dwx > (int) width ? bytes_r : NULL); + if (rv != 0) + goto out; + + dwx = bbw = bbh = 0; } } - return (0); -} +out: + free(bytes); + free(bytes_r); + free(line); -static void -set_width(int w) -{ - - if (w <= 0 || w > 128) - errx(1, "invalid width %d", w); - width = w; - wbytes = howmany(width, 8); + return (rv); } static int parse_hex(FILE *fp, unsigned int map_idx) { char *ln, *p; - char fmt_str[8]; size_t length; - uint8_t *bytes = NULL, *bytes_r = NULL; - unsigned curchar = 0, i, line, chars_per_row, dwidth; + uint8_t *bytes = NULL, *bytes_r = NULL, *line = NULL; + unsigned int curchar = 0, gwidth, gwbytes, i, j, chars_per_row; int rv = 0; while ((ln = fgetln(fp, &length)) != NULL) { @@ -322,46 +459,61 @@ if (strncmp(ln, "# Height: ", 10) == 0) { if (bytes != NULL) - errx(1, "malformed input: Height tag after font data"); - height = atoi(ln + 10); + errx(1, "malformed input: " + "Height tag after font data"); + set_height(atoi(ln + 10)); } else if (strncmp(ln, "# Width: ", 9) == 0) { if (bytes != NULL) - errx(1, "malformed input: Width tag after font data"); + errx(1, "malformed input: " + "Width tag after font data"); set_width(atoi(ln + 9)); } else if (sscanf(ln, "%6x:", &curchar)) { if (bytes == NULL) { bytes = xmalloc(wbytes * height); bytes_r = xmalloc(wbytes * height); + line = xmalloc(wbytes * 2); } + /* ln is guaranteed to have a colon here. */ p = strchr(ln, ':') + 1; chars_per_row = strlen(p) / height; - dwidth = width; - if (chars_per_row / 2 > (width + 7) / 8) - dwidth *= 2; /* Double-width character. */ - snprintf(fmt_str, sizeof(fmt_str), "%%%ux", - chars_per_row); + if (chars_per_row < wbytes * 2) + errx(1, "malformed input: " + "Broken bitmap, character %06x", + curchar); + gwidth = width * 2; + gwbytes = howmany(gwidth, 8); + if (chars_per_row < gwbytes * 2 || gwidth <= 8) { + gwidth = width; // Single-width character + gwbytes = wbytes; + } for (i = 0; i < height; i++) { - sscanf(p, fmt_str, &line); - p += chars_per_row; - if (parse_bitmap_line(bytes + i * wbytes, - bytes_r + i * wbytes, line, dwidth) != 0) { - rv = 1; - goto out; + for (j = 0; j < gwbytes; j++) { + unsigned int val; + if (sscanf(p + j * 2, "%2x", &val) == 0) + break; + *(line + j) = (uint8_t) val; } + rv = split_bitmap_line(bytes + i * wbytes, + bytes_r + i * wbytes, line, gwidth); + if (rv != 0) + goto out; + p += gwbytes * 2; } - if (add_char(curchar, map_idx, bytes, - dwidth == width * 2 ? bytes_r : NULL) != 0) { - rv = 1; + rv = add_char(curchar, map_idx, bytes, + gwidth != width ? bytes_r : NULL); + if (rv != 0) goto out; - } } } + out: free(bytes); free(bytes_r); + free(line); + return (rv); } @@ -383,6 +535,7 @@ else rv = parse_bdf(fp, map_idx); fclose(fp); + return (rv); } @@ -454,7 +607,9 @@ return (1); } } + assert(i == j); + return (0); } @@ -496,9 +651,9 @@ if (write_glyphs(fp) != 0 || write_mappings(fp, VFNT_MAP_NORMAL) != 0 || - write_mappings(fp, 1) != 0 || + write_mappings(fp, VFNT_MAP_NORMAL_RIGHT) != 0 || write_mappings(fp, VFNT_MAP_BOLD) != 0 || - write_mappings(fp, 3) != 0) { + write_mappings(fp, VFNT_MAP_BOLD_RIGHT) != 0) { perror(filename); fclose(fp); return (1); @@ -512,43 +667,47 @@ print_font_info(void) { printf( -"Statistics:\n" -"- glyph_total: %6u\n" -"- glyph_normal: %6u\n" -"- glyph_normal_right: %6u\n" -"- glyph_bold: %6u\n" -"- glyph_bold_right: %6u\n" -"- glyph_unique: %6u\n" -"- glyph_dupe: %6u\n" -"- mapping_total: %6u\n" -"- mapping_normal: %6u\n" -"- mapping_normal_folded: %6u\n" -"- mapping_normal_right: %6u\n" -"- mapping_normal_right_folded: %6u\n" -"- mapping_bold: %6u\n" -"- mapping_bold_folded: %6u\n" -"- mapping_bold_right: %6u\n" -"- mapping_bold_right_folded: %6u\n" -"- mapping_unique: %6u\n" -"- mapping_dupe: %6u\n", - glyph_total, - glyph_count[0], - glyph_count[1], - glyph_count[2], - glyph_count[3], - glyph_unique, glyph_dupe, - mapping_total, - map_count[0], map_folded_count[0], - map_count[1], map_folded_count[1], - map_count[2], map_folded_count[2], - map_count[3], map_folded_count[3], - mapping_unique, mapping_dupe); + "Statistics:\n" + "- font_width: %6u\n" + "- font_height: %6u\n" + "- glyph_total: %6u\n" + "- glyph_normal: %6u\n" + "- glyph_normal_right: %6u\n" + "- glyph_bold: %6u\n" + "- glyph_bold_right: %6u\n" + "- glyph_unique: %6u\n" + "- glyph_dupe: %6u\n" + "- mapping_total: %6u\n" + "- mapping_normal: %6u\n" + "- mapping_normal_folded: %6u\n" + "- mapping_normal_right: %6u\n" + "- mapping_normal_right_folded: %6u\n" + "- mapping_bold: %6u\n" + "- mapping_bold_folded: %6u\n" + "- mapping_bold_right: %6u\n" + "- mapping_bold_right_folded: %6u\n" + "- mapping_unique: %6u\n" + "- mapping_dupe: %6u\n", + width, height, + glyph_total, + glyph_count[0], + glyph_count[1], + glyph_count[2], + glyph_count[3], + glyph_unique, glyph_dupe, + mapping_total, + map_count[0], map_folded_count[0], + map_count[1], map_folded_count[1], + map_count[2], map_folded_count[2], + map_count[3], map_folded_count[3], + mapping_unique, mapping_dupe + ); } int main(int argc, char *argv[]) { - int ch, val, verbose = 0; + int ch, verbose = 0; assert(sizeof(struct file_header) == 32); assert(sizeof(struct file_mapping) == 8); @@ -556,16 +715,13 @@ while ((ch = getopt(argc, argv, "h:vw:")) != -1) { switch (ch) { case 'h': - val = atoi(optarg); - if (val <= 0 || val > 128) - errx(1, "Invalid height %d", val); - height = val; + height = atoi(optarg); break; case 'v': verbose = 1; break; case 'w': - set_width(atoi(optarg)); + width = atoi(optarg); break; case '?': default: @@ -578,7 +734,8 @@ if (argc < 2 || argc > 3) usage(); - wbytes = howmany(width, 8); + set_width(width); + set_height(height); if (parse_file(argv[0], VFNT_MAP_NORMAL) != 0) return (1); @@ -592,7 +749,7 @@ } number_glyphs(); dedup_mapping(VFNT_MAP_BOLD); - dedup_mapping(VFNT_MAP_BOLD_RH); + dedup_mapping(VFNT_MAP_BOLD_RIGHT); fold_mappings(0); fold_mappings(1); fold_mappings(2);