diff options
Diffstat (limited to 'ucfcomp.c')
-rw-r--r-- | ucfcomp.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/ucfcomp.c b/ucfcomp.c new file mode 100644 index 0000000..d607a43 --- /dev/null +++ b/ucfcomp.c @@ -0,0 +1,210 @@ +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +struct gmap +{ + struct gmap *next, *prev; + int glyph; + int width; + unsigned char rules[4*8]; + int len; + int offset; +}; + +static struct gmap *ctab[0x30000]; + +#define GMAP_WIDTH 1 + +#define GMAP_FINAL1 0 +#define GMAP_FINAL2 1 +#define GMAP_GLYPH1 2 +#define GMAP_GLYPH2 3 + +#define RULE_RANGE 4 +#define RULE_ATTACHED_TO 5 +#define RULE_WITH_ATTACHED 6 +#define RULE_FOLLOWS 7 +#define RULE_PRECEDES 8 + +#define CTAB_MASK 0x3fffffff +#define CTAB_INDIRECT 0x80000000 +#define CTAB_WIDTH 30 + +static void put_u32(int n) +{ + putchar(n>>24); + putchar(n>>16); + putchar(n>>8); + putchar(n); +} + +int main() +{ + char buf[256], *s; + int i; + int ch; + struct gmap *gm; + int type, begin, len; + int w=8, h=16; + unsigned char gbuf[32]; + char tmp[3]; + int width; + int nglyphs = 0; + unsigned char *glyphs = 0; + struct { unsigned begin, len, rel; } *ranges = 0; + int nranges = 0; + int ctab_len = 0; + int gmap_len = 0; + + while ((s=fgets(buf, sizeof buf, stdin))) { + if (*s++ != ':') continue; + for (tmp[2]=i=0; i<sizeof gbuf && isxdigit(tmp[0]=*s++) && isxdigit(tmp[1]=*s++); i++) + gbuf[i] = strtol(tmp, NULL, 16); + if (i == 32) { + unsigned char gbuf_tmp[32]; + width = 2; + for (i=0; i<16; i++) gbuf_tmp[i] = gbuf[2*i]; + for (i=0; i<16; i++) gbuf_tmp[16+i] = gbuf[2*i+1]; + memcpy(gbuf, gbuf_tmp, 32); + } else if (i == 16) { width = 1; + } else exit(1); + glyphs = realloc(glyphs, 16*(width+nglyphs)); + memcpy(glyphs + 16*nglyphs, gbuf, 16*width); + nglyphs += width; + for (;;) { + for (; isspace(*s); s++); + if (!*s) break; + ch = strtol(s, &s, 16); + gm = calloc(1, sizeof(struct gmap)); + gm->glyph = nglyphs-width; + gm->width = width; + gm->next = 0; + gm->prev = ctab[ch]; + if (ctab[ch]) ctab[ch]->next = gm; + ctab[ch] = gm; + i=0; + while(i<sizeof(gm->rules)-12 && *s && !isspace(*s)) { + switch (*s++) { + case '+': type = RULE_WITH_ATTACHED; break; + case '-': type = RULE_ATTACHED_TO; break; + case '<': type = RULE_PRECEDES; break; + case '>': type = RULE_FOLLOWS; break; + default: exit(1); + } + if (*s == '[') { + begin = strtol(++s, &s, 16); + if (*s++ != '-') exit(1); + len = strtol(s, &s, 16) - begin + 1; + if (*s++ != ']') exit(1); + gm->rules[i++] = type; + gm->rules[i++] = begin>>16; + gm->rules[i++] = begin>>8; + gm->rules[i++] = begin; + gm->rules[i++] = RULE_RANGE; + gm->rules[i++] = len>>16; + gm->rules[i++] = len>>8; + gm->rules[i++] = len; + } else if (isxdigit(*s)) { + begin = strtol(s, &s, 16); + gm->rules[i++] = type; + gm->rules[i++] = begin>>16; + gm->rules[i++] = begin>>8; + gm->rules[i++] = begin; + } else exit(1); + } + gm->rules[i++] = GMAP_GLYPH1 | (gm->width-1); + gm->rules[i++] = (gm->glyph)>>16; + gm->rules[i++] = (gm->glyph)>>8; + gm->rules[i++] = (gm->glyph); + gm->len = i; + } + } + + /* Count total glyph mapping rules and figure the table offsets */ + for (ch=0; ch < sizeof(ctab)/sizeof(ctab[0]); ch++) { + for (gm = ctab[ch]; gm && gm->prev; gm = gm->prev); + /* Exclude rules that can be replaced by a trivial mapping */ + if (!gm || (!gm->next && gm->len == 4)) { + if (gm) gm->len = 0; + continue; + } + for (ctab[ch] = gm; gm; gm = gm->next) { + /* Terminate the rules list */ + if (!gm->next) gm->rules[gm->len-4] &= GMAP_WIDTH; + gm->offset = gmap_len; + gmap_len += gm->len; + } + } + + /* Compact empty intervals and intervals with trivial glyph mapping */ + begin = 1; + for (ch=1; ch <= sizeof(ctab)/sizeof(ctab[0]); ch++) { + if (ch == sizeof(ctab)/sizeof(ctab[0]) + || (ctab[ch-1] != ctab[ch] + &&(!ctab[ch-1] || !ctab[ch] + || ctab[ch-1]->prev || ctab[ch-1]->len > 4 + || ctab[ch]->prev || ctab[ch]->len > 4 + || ctab[ch]->glyph != ctab[ch-1]->glyph + ctab[ch-1]->width + || ctab[ch]->width != ctab[ch-1]->width))) { + if (ch - begin >= 1024) { + ranges = realloc(ranges, sizeof(ranges[0])*(nranges+1)); + ranges[nranges].begin = begin; + ranges[nranges++].len = ch-begin; + } + begin = ch+1; + } + } + ranges[nranges-1].len = 0x110000; + + /* Count total size of the character table */ + ranges[0].rel = ranges[0].begin; + ctab_len = 1 + nranges*2 + ranges[0].begin; + for (i=1; i<nranges; i++) + ctab_len += ranges[i].rel = ranges[i].begin - (ranges[i-1].begin+ranges[i-1].len); + ctab_len *= 4; + + // offset 0: magic and version (0.1.0.0) + fwrite("ucf\300\000\001\000\000", 1, 8, stdout); + // offset 8 + putchar(8); + putchar(16); + putchar(0); + putchar(0); + putchar(0); + putchar(0); + putchar(0); + putchar(0); + // offset 16 + put_u32(0); // metadata offset + put_u32(32); // ctab offset + put_u32(32+ctab_len); // gmap offset + put_u32(32+ctab_len+gmap_len); // glyph bitmaps + // offset 32 + put_u32(nranges); + for (i=0; i<nranges; i++) { + put_u32(ranges[i].rel); + put_u32(ranges[i].len); + } + for (i=ch=0; ch<sizeof(ctab)/sizeof(ctab[0]); ch++) { + if (ch == ranges[i].begin) { + ch += ranges[i++].len-1; + continue; + } + if (!ctab[ch]) + put_u32(-1); + else if (ctab[ch]->len == 0) + put_u32(ctab[ch]->glyph | ctab[ch]->width-1<<30); + else + put_u32(ctab[ch]->offset | 0x80000000); + } + // offset 32 + ctab_len + for (ch=0; ch < sizeof(ctab)/sizeof(ctab[0]); ch++) + for (gm = ctab[ch]; gm; gm = gm->next) + fwrite(gm->rules, 1, gm->len, stdout); + // offset 30 + ctab_len + gmap_len + fwrite(glyphs, 16, nglyphs, stdout); + + return 0; +} |