summaryrefslogtreecommitdiff
path: root/ucf.c
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2006-10-05 21:10:32 +0000
committerRich Felker <dalias@aerifal.cx>2006-10-05 21:10:32 +0000
commitcffa2eeb2052df70c52fc720add9fe7e31b314e7 (patch)
treed4c80a2f080f3419959e54a462f259776bb37ab4 /ucf.c
parentdc6a00a52f6df3c7e66c6535c2489f51fa1fa13a (diff)
the big UCF-font commit!
still a little bit messy, but it works quite well already more to come soon.
Diffstat (limited to 'ucf.c')
-rw-r--r--ucf.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/ucf.c b/ucf.c
new file mode 100644
index 0000000..baf9c48
--- /dev/null
+++ b/ucf.c
@@ -0,0 +1,133 @@
+/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */
+
+/* note: the following implementation of ucf is NOT SECURE. malicious or
+ * damaged files can cause it to crash or possibly enter into an infinite
+ * loop, or cause other parts of the process core to be read as a font,
+ * possibly leading to information leaks. however there is no possibility
+ * of privilege elevation as ucf never writes to memory.
+ *
+ * users needing a robust implementation would be advised to simply run a
+ * sanity check across the whole font file before accepting it, rather than
+ * incurring large bounds-checking penalties at each glyph lookup.
+ */
+
+#include <stddef.h>
+#include "ucf.h"
+
+#define U24(p) ( ((p)[0]<<16) | ((p)[1]<<8) | (p)[2] )
+#define U32(p) ( ((p)[0]<<24) | U24((p)+1) )
+
+int ucf_init(struct ucf *f, const unsigned char *map, size_t len)
+{
+ size_t n;
+ if (memcmp(map, "ucf\300\000\001\000\000", 8))
+ return -1;
+ f->w = map[8];
+ f->h = map[9];
+ f->s = (f->w+7)>>3;
+ f->S = f->s * f->h;
+ f->ranges = map + U32(map+20) + 4;
+ f->gmap = map + U32(map+24);
+ f->glyphs = map + U32(map+28);
+ f->ctab = f->ranges + 8*(f->nranges = U32(f->ranges - 4));
+ return 0;
+}
+
+#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
+
+int ucf_lookup(struct ucf *f, int idx, const unsigned *cc,
+ const unsigned *pc, const unsigned *nc, int width)
+{
+ unsigned ch = cc[idx];
+ unsigned a, l, x, i;
+ const unsigned *c;
+ const unsigned char *p;
+
+ for (p=f->ranges, a=0; ch>=(a+=U32(p)); p+=8) {
+ if (ch-a < (l=U32(p+4))) {
+ x = U32(f->ctab+4*(a-1));
+ if (x>>30 != width-1)
+ return -1;
+ return (x & 0x3fffffff) + (ch-a)*width;
+ }
+ ch -= l;
+ }
+ x = U32(f->ctab+4*ch);
+ if (!((x+1) & CTAB_INDIRECT)) {
+ if (x>>CTAB_WIDTH != width-1) return -1;
+ return x & CTAB_MASK;
+ }
+ x &= 0x7fffffff;
+ i = idx;
+ c = cc;
+ for (p=f->gmap+x; ; p+=4) {
+ if (*p <= GMAP_GLYPH2) {
+ if ((*p & GMAP_WIDTH) == width-1) break;
+ else if (*p <= GMAP_FINAL2) return -1;
+ i = idx; c = cc;
+ continue;
+ }
+ x = *p;
+ a = U24(p+1);
+ if (p[4] == RULE_RANGE) {
+ p += 4;
+ l = U24(p+1);
+ } else l = 1;
+ switch (x) {
+ case RULE_ATTACHED_TO:
+ if (i && c[--i]-a < l) continue;
+ break;
+ case RULE_WITH_ATTACHED:
+ if (c[++i]-a < l) continue;
+ break;
+ case RULE_FOLLOWS:
+ if ((c=pc)[i=0]-a < l) continue;
+ break;
+ case RULE_PRECEDES:
+ if ((c=nc)[i=0]-a < l) continue;
+ break;
+ }
+ /* Skip until the next mapping */
+ for (; *p > GMAP_GLYPH2; p+=4);
+ i = idx; c = cc;
+ }
+ return U24(p+1);
+}
+
+#if 0
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ int i, j;
+ struct ucf f;
+ static char tmp[1000000];
+ ucf_init(&f, tmp, fread(tmp, 1, sizeof tmp, stdin));
+ for (i=1; i<argc; i++) {
+ unsigned x[5] = { strtol(argv[i], NULL, 16), 0 };
+ int g;
+ if (i+1<argc) x[1] = strtol(argv[i+1], NULL, 16);
+ printf("char %.4x maps to glyph %d\n", x[1], g=ucf_lookup(&f, 1, x, x+4, x+4, 1));
+ if (g >= 0) for (j=0; j<16; j++)
+ printf("%.2X", f.glyphs[16*g+j]);
+ printf("\n");
+ }
+ return 0;
+}
+#endif