summaryrefslogtreecommitdiff
path: root/misc/ttf2woff/readwoff.c
blob: 566eaea3ed50cc348d46489fe259a52c6e33b7f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
 *	Copyright (C) 2013 Jan Bobrowski <jb@wizard.ae.krakow.pl>
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	version 2 as published by the Free Software Foundation.
 */

#include <string.h>
#include <stdlib.h>
#include <zlib.h>
#include "ttf2woff.h"

static struct buf get_or_inflate(u8 *p, size_t len, size_t orig_len)
{
	struct buf buf;
	uLongf blen;
	char *m;
	int v;

	if(len == orig_len) {
		buf.ptr = p;
		buf.len = len;
		return buf;
	}

	buf.len = orig_len;
	buf.ptr = my_alloc(orig_len);

	blen = buf.len;
	v = uncompress(buf.ptr, &blen, p, len);
	switch(v) {
	case Z_OK:
		if(blen==buf.len)
			return buf;
	case Z_MEM_ERROR: m = "BAD_FONT uncompressed length"; break;
	case Z_DATA_ERROR: m = "Data corrupted"; ; break;
	default: m = "Error";
	}

	errx(3, "zlib: %s", m);
}

void read_woff(struct ttf *ttf, u8 *data, size_t length)
{
	u8 *p;
	int i;

	if(length<=44+20) BAD_FONT;

	ttf->flavor = g32(data+4);

	if(g32(data+8) != length) BAD_FONT;

	ttf->ntables = g16(data+12);
	if(!ttf->ntables) BAD_FONT;

	{
		u32 len=g32(data+28), off;
		ttf->woff_meta.len = 0;
		if(len) {
			off = g32(data+24);
			if((off|len)>length || off+len>length)
				BAD_FONT;
			ttf->woff_meta = get_or_inflate(data+off, len, g32(data+32));
		}
	}

	ttf->woff_priv.len = g32(data+40);
	ttf->woff_priv.ptr = ttf->woff_priv.len ? data+g32(data+36) : 0;

	alloc_tables(ttf);

	p = data+44;
	for(i=0; i<ttf->ntables; i++) {
		struct table *t = &ttf->tables[i];
		u32 off=g32(p+4), len=g32(p+8);
		if((off|len)>length || off+len>length)
			BAD_FONT;
		t->tag = g32(p);
		t->csum = g32(p+16);
		t->pos = off;
		t->free_buf = 1;
		t->buf = get_or_inflate(data+off, len, g32(p+12));
		name_table(t);
		p += 20;
	}
}