ref: 83519f11fd26cd605dba45d9ce1fc0f39d467d40
dir: /otf.c.in/
/* this file is generated. do not modify. */
#include "otfsys.h"
#include "otf.h"
#define f2dot14(o) (f = b[2*o]<<8 | b[2*o+1], (f>>14)+(f&((1<<14)-1))/16384.0)
int indentΔ = 2;
typedef struct Range Range;
struct Otf {
Otfile *f;
Range *r;
u8int *buf;
int bufsz;
int off;
/* extra fields to simplify parsing */
TableDirectory td;
TableRecord glyf;
OTF_EXTRA_FIELDS
};
struct Range {
int start;
int len;
int prevoff;
Range *par;
};
#define rchr(s) (be ? ((s)[0]<<8 | (s)[1]) : ((s)[1]<<8 | (s)[0]))
static u8int mark[] = {0x00, 0x00, 0xc0, 0xe0, 0xf0};
static int
utf16to8(u8int *o, int osz, u8int *s, int sz)
{
u32int c, c2;
int i, wr, j, be;
i = 0;
be = 1;
if(s[0] == 0xfe && s[1] == 0xff)
i += 2;
else if(s[0] == 0xff && s[1] == 0xfe){
be = 0;
i += 2;
}
for(; i < sz-1 && osz > 1;){
c = rchr(&s[i]);
i += 2;
if(c >= 0xd800 && c <= 0xdbff && i < sz-1){
c2 = rchr(&s[i]);
if(c2 >= 0xdc00 && c2 <= 0xdfff){
c = 0x10000 | (c - 0xd800)<<10 | (c2 - 0xdc00);
i += 2;
}else
return -1;
}else if(c >= 0xdc00 && c <= 0xdfff)
return -1;
if(c < 0x80)
wr = 1;
else if(c < 0x800)
wr = 2;
else if(c < 0x10000)
wr = 3;
else
wr = 4;
osz -= wr;
if(osz < 1)
break;
o += wr;
for(j = wr; j > 1; j--){
*(--o) = (c & 0xbf) | 0x80;
c >>= 6;
}
*(--o) = (u8int)c | mark[wr];
o += wr;
}
*o = 0;
return i;
}
static char *
strtoutf8(Otf *o, u8int *in, int sz)
{
char *s;
// FIXME this is not sufficient, obviously - need more platform/encoding handling
if(o->platformID == 0 || (o->platformID == 3 && o->encodingID == 1)){
s = malloc(sz/2+1);
utf16to8((u8int*)s, sz/2+1, in, sz);
}else{
s = malloc(sz+1);
memcpy(s, in, sz);
s[sz] = 0;
}
return s;
}
Otf *
otfopen(Otfile *f)
{
Otf *o;
if((o = calloc(1, sizeof(*o))) == nil){
werrstr("no memory");
}else{
o->f = f;
if(read_TableDirectory(o, &o->td) != 0){
free(o);
o = nil;
}
}
return o;
}
void
otfprint(Otf *o, Otfile *out, int indent)
{
print_TableDirectory(out, indent, o, &o->td);
}
void
otfclose(Otf *o)
{
if(o == nil)
return;
// FIXME traverse and free everything
free(o);
}
static int
otfpushrange(Otf *o, int off, int len)
{
Range *r;
int x;
r = nil;
if(o->r != nil){
if(len < 0)
len = o->r->len - off;
if(len < 0 || off+len > o->r->len){
werrstr("range overflow (len %d) by %d bytes", len, off+len - o->r->len);
goto err;
}
off += o->r->start;
}else if(len < 0){
len = 0x7fffffff;
}
if((r = malloc(sizeof(*r))) == nil){
werrstr("no memory");
goto err;
}
r->par = o->r;
r->start = off;
r->len = len;
r->prevoff = o->off;
if((x = o->f->seek(o->f->aux, off, 0)) != off){
werrstr("seek offset: need %d, got %d", off, x);
goto err;
}
o->off = off;
o->r = r;
return 0;
err:
free(r);
return -1;
}
static int
otfpoprange(Otf *o)
{
Range *r;
int x;
r = o->r;
if(r == nil){
werrstr("pop without push");
goto err;
}
if((x = o->f->seek(o->f->aux, r->prevoff, 0)) != r->prevoff){
werrstr("seek offset: need %d, got %d", r->prevoff, x);
goto err;
}
o->off = r->prevoff;
o->r = r->par;
free(r);
return 0;
err:
return -1;
}
static void
otfpopranges(Otf *o)
{
while(o->r != nil)
otfpoprange(o);
}
static u8int *
otfreadn(Otf *o, int n)
{
Range *r;
u8int *b;
int x;
r = o->r;
if(r != nil && o->off+n > r->start+r->len){
werrstr("need %d at %d, have %d at %d", n, o->off, r->len, r->start);
goto err;
}
if(n > o->bufsz){
if((b = realloc(o->buf, n)) == nil){
werrstr("no memory");
goto err;
}
o->buf = b;
o->bufsz = n;
}
if((x = o->f->read(o->f->aux, o->buf, n)) != n){
werrstr("need %d, got %d; off %d", n, x, o->off);
goto err;
}
o->off += n;
return o->buf;
err:
return nil;
}
static int
otfarray(Otf *o, void **arr_, void *fun_, int elsz, int num)
{
int i;
int (*fun)(Otf*, void*);
u8int *arr;
if((arr = calloc(num, elsz)) == nil){
werrstr("no memory");
goto err;
}
fun = fun_;
for(i = 0; i < num; i++){
if(fun(o, arr + i*elsz) < 0)
goto err;
}
*arr_ = arr;
return 0;
err:
free(arr);
return -1;
}
enum {
CGLYPH_FL_WORD_ARGS = 1<<0,
CGLYPH_FL_SCALE = 1<<3,
CGLYPH_FL_OVERLAP_COMPOUND = 1<<10,
CGLYPH_FL_UNSCALED_COMPONENT_OFFSET = 1<<12,
};
static int
read_ComponentGlyph(Otf *o, ComponentGlyph **out, int instr)
{
ComponentGlyph *v;
u8int *b;
s16int f;
if((v = calloc(1, sizeof(*v))) == nil){
nomem:
werrstr("no memory");
goto err;
}
if((b = otfreadn(o, 2*2)) == nil)
goto err;
v->flags = (b[0]<<8 | b[1]) & ~CGLYPH_FL_OVERLAP_COMPOUND;
v->glyphIndex = b[2]<<8 | b[3];
instr |= v->flags & CGLYPH_FL_INSTRUCTIONS;
if(v->flags & CGLYPH_FL_UNSCALED_COMPONENT_OFFSET)
v->flags &= ~(CGLYPH_FL_UNSCALED_COMPONENT_OFFSET | CGLYPH_FL_SCALED_COMPONENT_OFFSET);
if((v->flags & CGLYPH_FL_WORD_ARGS) != 0 && (b = otfreadn(o, 2*2)) != nil){
if(v->flags & CGLYPH_FL_SIGNED_XY){
v->arg1 = (s16int)(b[0]<<8 | b[1]);
v->arg2 = (s16int)(b[2]<<8 | b[3]);
}else{
v->arg1 = b[0]<<8 | b[1];
v->arg1 = b[2]<<8 | b[3];
}
}else if((b = otfreadn(o, 2)) != nil){
if(v->flags & CGLYPH_FL_SIGNED_XY){
v->arg1 = (s8int)b[0];
v->arg2 = (s8int)b[1];
}else{
v->arg1 = b[0];
v->arg2 = b[1];
}
}
if(b == nil)
goto err;
v->scaleX = 1.0;
v->scaleY = 1.0;
if((v->flags & CGLYPH_FL_SCALE) != 0 && (b = otfreadn(o, 2)) != nil){
v->scaleX = f2dot14(0);
v->scaleY = v->scaleX;
v->flags &= ~CGLYPH_FL_SCALE;
v->flags |= CGLYPH_FL_SCALE_XY;
}else if((v->flags & CGLYPH_FL_SCALE_XY) != 0 && (b = otfreadn(o, 2*2)) != nil){
v->scaleX = f2dot14(0);
v->scaleY = f2dot14(1);
}else if((v->flags & CGLYPH_FL_2X2_TRANSFORM) != 0 && (b = otfreadn(o, 2*2*2)) != nil){
v->scaleX = f2dot14(0);
v->scale01 = f2dot14(1);
v->scale10 = f2dot14(2);
v->scaleY = f2dot14(3);
}
if(b == nil)
goto err;
if((v->flags & CGLYPH_FL_MORE_COMPONENTS) != 0){
if(read_ComponentGlyph(o, &v->next, instr) != 0){
free(v);
return -1;
}
}else if(instr != 0){
if((b = otfreadn(o, 2)) == nil)
goto err;
v->numInstr = b[0]<<8 | b[1];
if((v->instr = malloc(v->numInstr)) == nil)
goto nomem;
if(v->numInstr > 0 && (b = otfreadn(o, v->numInstr)) == nil)
goto err;
memcpy(v->instr, b, v->numInstr);
}
*out = v;
return 0;
err:
if(v != nil)
free(v->instr);
free(v);
werrstr("ComponentGlyph: %r");
return -1;
}
void
print_ComponentGlyph(Otfile *f, int indent, Otf *o, ComponentGlyph *v)
{
void *a = f->aux;
f->print(a, "%*s%s: %#"PRIx16"%s%s%s%s%s%s%s%s%s%s\n", indent, "", "flags", v->flags,
(v->flags&CGLYPH_FL_SIGNED_XY)?" CGLYPH_FL_SIGNED_XY":"",
(v->flags&CGLYPH_FL_ROUND_TO_GRID_XY)?" CGLYPH_FL_ROUND_TO_GRID_XY":"",
(v->flags&CGLYPH_FL_SCALE)?" CGLYPH_FL_SCALE":"",
(v->flags&CGLYPH_FL_MORE_COMPONENTS)?" CGLYPH_FL_MORE_COMPONENTS":"",
(v->flags&CGLYPH_FL_SCALE_XY)?" CGLYPH_FL_SCALE_XY":"",
(v->flags&CGLYPH_FL_2X2_TRANSFORM)?" CGLYPH_FL_2X2_TRANSFORM":"",
(v->flags&CGLYPH_FL_INSTRUCTIONS)?" CGLYPH_FL_INSTRUCTIONS":"",
(v->flags&CGLYPH_FL_METRICS)?" CGLYPH_FL_METRICS":"",
(v->flags&CGLYPH_FL_OVERLAP_COMPOUND)?" CGLYPH_FL_OVERLAP_COMPOUND":"",
(v->flags&CGLYPH_FL_SCALED_COMPONENT_OFFSET)?" CGLYPH_FL_SCALED_COMPONENT_OFFSET":""
);
f->print(a, "%*s%s: %"PRIu16"\n", indent, "", "glyphIndex", v->glyphIndex);
if(v->arg1 != 0 || v->arg2 != 0){
f->print(f->aux, "%*s%s: %d\n", indent, "", "arg1", v->arg1);
f->print(f->aux, "%*s%s: %d\n", indent, "", "arg2", v->arg2);
}
if(v->flags & CGLYPH_FL_SCALE_XY){
f->print(a, "%*s%s: %g\n", indent, "", "scaleX", v->scaleX);
f->print(a, "%*s%s: %g\n", indent, "", "scaleY", v->scaleY);
}else if(v->flags & CGLYPH_FL_2X2_TRANSFORM){
f->print(a, "%*s%s: %g\n", indent, "", "scaleX", v->scaleX);
f->print(a, "%*s%s: %g\n", indent, "", "scale01", v->scale01);
f->print(a, "%*s%s: %g\n", indent, "", "scale10", v->scale10);
f->print(a, "%*s%s: %g\n", indent, "", "scaleY", v->scaleY);
}
if(v->numInstr > 0 && v->instr != nil){
f->print(a, "%*s%s: %"PRIu16"\n", indent, "", "numInstr", v->numInstr);
f->print(a, "%*s%s:", indent, "", "instr");
for(int i = 0; i < v->numInstr; i++)
f->print(a, " %02"PRIx8, v->instr[i]);
f->print(a, "\n");
}
if(v->next != nil){
f->print(a, "%*s%s:\n", indent, "", "next");
print_ComponentGlyph(f, indent+indentΔ, o, v->next);
}
}
enum {
GLYPH_FL_ON_CURVE_POINT = 1<<0,
GLYPH_FL_X_SHORT_VECTOR = 1<<1,
GLYPH_FL_Y_SHORT_VECTOR = 1<<2,
GLYPH_FL_REPEAT = 1<<3,
GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR = 1<<4,
GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR = 1<<5,
GLYPH_FL_OVERLAP_SIMPLE = 1<<6,
};
static int
read_SimpleGlyph(Otf *o, SimpleGlyph **out)
{
SimpleGlyph *v;
u8int *b, *flags;
int i, n, nflags, c, nc;
flags = nil;
if((v = calloc(1, sizeof(*v))) == nil){
nomem:
werrstr("no memory");
goto err;
}
v->numEndPtsOfContours = o->numberOfContours;
n = o->numberOfContours;
if((b = otfreadn(o, 2*n+2)) == nil)
goto err;
if((v->endPtsOfContours = malloc(2*n)) == nil)
goto nomem;
for(int i = 0; i < n; i++)
v->endPtsOfContours[i] = b[2*i+0]<<8 | b[2*i+1];
v->numPoints = 1 + v->endPtsOfContours[o->numberOfContours-1];
v->instructionLength = b[2*n+0]<<8 | b[2*n+1];
n = v->instructionLength;
if((b = otfreadn(o, n)) == nil)
goto err;
if((v->instructions = malloc(n)) == nil)
goto nomem;
memcpy(v->instructions, b, n);
if((flags = malloc(v->numPoints)) == nil) /* not supposed to be more than that, 64Kb max */
goto nomem;
for(nflags = 0; nflags < v->numPoints;){
if((b = otfreadn(o, 1)) == nil)
goto err;
if((flags[nflags++] = *b) & GLYPH_FL_REPEAT){
flags[nflags-1] ^= GLYPH_FL_REPEAT;
if((b = otfreadn(o, 1)) == nil)
goto err;
if(nflags + *b > v->numPoints){
werrstr("repeat overflow (%d+%d > %d)", nflags, *b, v->numPoints);
goto err;
}
memset(flags+nflags, flags[nflags-1], *b);
nflags += *b;
}
}
if((v->points = calloc(v->numPoints, sizeof(*v->points))) == nil)
goto nomem;
/* flags first */
for(i = n = 0; i < nflags && n < v->numPoints; i++, n++)
v->points[n].onCurve = (flags[i] & GLYPH_FL_ON_CURVE_POINT) != 0;
/* read packed x coordinates */
c = 0;
for(i = n = 0; i < nflags && n < v->numPoints; i++){
if((flags[i] & GLYPH_FL_X_SHORT_VECTOR) != 0){
if((b = otfreadn(o, 1)) == nil)
goto err;
nc = *b;
if((flags[i] & GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) == 0)
nc = -nc;
c = v->points[n++].x = c + nc;
}else if((flags[i] & GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) != 0){
v->points[n++].x = c;
}else{
if((b = otfreadn(o, 2)) == nil)
goto err;
c += (s16int)(b[0]<<8 | b[1]);
v->points[n++].x = c;
}
}
/* read packed y coordinates */
c = 0;
for(i = n = 0; i < nflags && n < v->numPoints; i++){
if((flags[i] & GLYPH_FL_Y_SHORT_VECTOR) != 0){
if((b = otfreadn(o, 1)) == nil)
goto err;
nc = *b;
if((flags[i] & GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) == 0)
nc = -nc;
c = v->points[n++].y = c + nc;
}else if((flags[i] & GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) != 0){
v->points[n++].y = c;
}else{
if((b = otfreadn(o, 2)) == nil)
goto err;
c += (s16int)(b[0]<<8 | b[1]);
v->points[n++].y = c;
}
}
free(flags);
*out = v;
return 0;
err:
free(flags);
if(v != nil){
free(v->endPtsOfContours);
free(v->instructions);
free(v->points);
}
free(v);
werrstr("SimpleGlyph: %r");
return -1;
}
void
print_SimpleGlyph(Otfile *f, int indent, Otf *o, SimpleGlyph *v)
{
void *a = f->aux;
USED(o);
if(v->numEndPtsOfContours > 0){
f->print(a, "%*s%s:", indent, "", "endPtsOfContours");
for(int i = 0; i < v->numEndPtsOfContours; i++)
f->print(a, " %"PRId16, v->endPtsOfContours[i]);
f->print(a, "\n");
}
if(v->instructionLength > 0){
f->print(a, "%*s%s: %ud\n", indent, "", "instructionLength", v->instructionLength);
f->print(a, "%*s%s:", indent, "", "instructions");
for(int i = 0; i < v->instructionLength; i++)
f->print(a, " %02"PRIx8, v->instructions[i]);
f->print(a, "\n");
}
if(v->numPoints > 0){
f->print(a, "%*s%s: %d\n", indent, "", "numPoints", v->numPoints);
f->print(a, "%*s%s:", indent, "", "points");
for(int i = 0; i < v->numPoints; i++)
f->print(a, " (%d,%d,%s)", v->points[i].x, v->points[i].y, v->points[i].onCurve?"on":"off");
f->print(a, "\n");
}
}
Glyf *
otfglyf(Otf *o, int index)
{
Glyf *g;
int off, len, i;
if((g = calloc(1, sizeof(*g))) == nil){
werrstr("no memory");
goto err;
}
if(o->td.head == nil){
werrstr("no head table");
goto err;
}
if(o->td.loca == nil){
werrstr("no loca table");
goto err;
}
if(o->glyf.offset == 0){
for(i = 0; i < o->td.numTables; i++){
TableRecord *rec = o->td.tableRecords+i;
if(rec->tableTag == (u32int)('g'<<24|'l'<<16|'y'<<8|'f')){
o->glyf = *rec;
break;
}
}
if(o->glyf.offset == 0){
werrstr("no glyf table");
goto err;
}
}
if(index < 0 || index >= o->numGlyphs){
werrstr("index out of range");
goto err;
}
if(o->indexToLocFormat == 0){
off = (int)o->td.loca->shortOffsets[index]*2;
len = (int)o->td.loca->shortOffsets[index+1]*2 - off;
}else{
off = o->td.loca->longOffsets[index];
len = o->td.loca->longOffsets[index+1] - off;
}
if(len < 1) /* no outlines */
return g;
if(otfpushrange(o, o->glyf.offset, o->glyf.length) < 0)
goto err;
if(otfpushrange(o, off, len) < 0)
goto err;
if(read_Glyf(o, g) < 0){
free(g);
g = nil;
}
otfpoprange(o);
otfpoprange(o);
return g;
err:
free(g);
otfpopranges(o);
return nil;
}
int
otfglyfnum(Otf *o)
{
return o->numGlyphs;
}
int
otfupem(Otf *o)
{
return o->td.head->unitsPerEm;
}
int
otfrune2glyph(Otf *o, Rune r)
{
RuneMapper *m;
int i, g;
for(i = 0, m = o->td.cmap->mappers; i < o->td.cmap->numMappers; i++, m++){
if((g = m->rune2glyph(m->aux, r)) >= 0)
return g;
}
return -1;
}
Rune
otfglyph2rune(Otf *o, int g)
{
RuneMapper *m;
Rune r;
int i;
for(i = 0, m = o->td.cmap->mappers; i < o->td.cmap->numMappers; i++, m++){
if((r = m->glyph2rune(m->aux, g)) != NoRune)
return r;
}
return NoRune;
}
enum {
PLAT_UNICODE,
PLAT_MACINTOSH, /* "currently discouraged", unsupported */
PLAT_ISO, /* deprecated, unsupported */
PLAT_WINDOWS,
PLAT_CUSTOM, /* deprecated, unsupported */
};
/* supported subtable formats: 4, 10, 12 */
/* FIXME: need to implement (higher to lower prio): 6, 14, 13 */
enum {
ENC_UNICODE_1_0, /* deprecated, unsupported */
ENC_UNICODE_1_1, /* deprecated, unsupported */
ENC_UNICODE_ISO, /* deprecated, unsupported */
ENC_UNICODE_2_0_BMP, /* subtable format 4, 6 */
ENC_UNICODE_2_0_FULL, /* subtable format 10, 12 */
ENC_UNICODE_VAR_SEQ, /* subtable format 14 */
ENC_UNICODE_FULL, /* subtable format 13 (many-to-one) */
ENC_WINDOWS_SYMBOL = 0, /* unsupported */
ENC_WINDOWS_UNICODE_BMP, /* subtable format 4 */
ENC_WINDOWS_SHIFTJIS, /* unsupported */
ENC_WINDOWS_PRC, /* unsupported */
ENC_WINDOWS_BIG5, /* unsupported */
ENC_WINDOWS_WANSUNG, /* unsupported */
ENC_WINDOWS_JOHAB, /* unsupported */
ENC_WINDOWS_UNICODE_FULL = 10, /* subtable format 12 */
};
static int
cmap4rune2glyph(void *aux, Rune r)
{
SubtableCmap4 *sc;
int i, b, e, n, x, segC;
if(r > 0xffff)
return -1;
sc = aux;
segC = sc->segCountX2/2;
for(b = 0, e = segC-1; b <= e; ){
i = (b + e)/2;
if(sc->endCode[i] < r)
b = i + 1;
else if(sc->startCode[i] > r)
e = i - 1;
else if(sc->idRangeOffset[i] == 0){
x = r + sc->idDelta[i];
if(x < 0)
x += 65536;
return x;
}else{
x = i + sc->idRangeOffset[i]/2 + (r - sc->startCode[i]);
n = (sc->length-((8*2)+(sc->segCountX2*4)))/2;
if(x < 0 || x >= n)
break;
return sc->glyphIdArray[x];
}
}
return -1;
}
static Rune
cmap4glyph2rune(void *aux, int g)
{
USED(aux); USED(g);
/* FIXME - other mapper will hopefully pick up after */
return NoRune;
}
static int
cmap10rune2glyph(void *aux, Rune r)
{
SubtableCmap10 *sc;
sc = aux;
if(r >= sc->startCharCode){
r -= sc->startCharCode;
if(r < sc->numChars)
return sc->glyphIdArray[r];
}
return -1;
}
static Rune
cmap10glyph2rune(void *aux, int g)
{
SubtableCmap10 *sc;
sc = aux;
if(g >= 0 && g < sc->numChars)
return sc->startCharCode + g;
return NoRune;
}
static int
cmap12rune2glyph(void *aux, Rune r)
{
SubtableCmap12or13 *sc;
MapGroup *m;
int b, e, x;
sc = aux;
for(b = 0, e = sc->numGroups-1; b <= e; ){
x = (b + e)/2;
m = sc->groups + x;
if(m->endCharCode < r)
b = x + 1;
else if(m->startCharCode > r)
e = x - 1;
else
return m->startGlyphID + (r - m->startCharCode);
}
return -1;
}
static Rune
cmap12glyph2rune(void *aux, int g)
{
SubtableCmap12or13 *sc;
MapGroup *m;
int i;
sc = aux;
for(i = 0, m = sc->groups; i < sc->numGroups; i++, m++){
if(g >= m->startGlyphID && g <= m->startGlyphID+(m->endCharCode-m->startCharCode))
return m->startCharCode + (g - m->startGlyphID);
}
return NoRune;
}
static int
otfcmapUnicode(TableCmap *c, EncodingRecord *er, int *parsed, int *unsupported)
{
SubtableCmap *sc;
sc = er->subtable;
switch(er->encodingID){
case ENC_UNICODE_2_0_BMP:
if(sc->format != 4){
(*unsupported)++;
werrstr("2.0 bmp: fmt %d", sc->format);
goto err;
}
c->mappers[c->numMappers].rune2glyph = cmap4rune2glyph;
c->mappers[c->numMappers].glyph2rune = cmap4glyph2rune;
c->mappers[c->numMappers++].aux = &sc->sub4;
(*parsed)++;
break;
case ENC_UNICODE_2_0_FULL: /* this one is good */
if(sc->format == 10){
if(sc->sub10.numChars < 1){
werrstr("2.0 full: no chars");
goto err;
}
c->mappers[c->numMappers].rune2glyph = cmap10rune2glyph;
c->mappers[c->numMappers].glyph2rune = cmap10glyph2rune;
c->mappers[c->numMappers++].aux = &sc->sub10;
(*parsed)++;
break;
}
if(sc->format == 12){
if(sc->sub12or13.numGroups < 1){
werrstr("2.0 full: no groups");
goto err;
}
c->mappers[c->numMappers].rune2glyph = cmap12rune2glyph;
c->mappers[c->numMappers].glyph2rune = cmap12glyph2rune;
c->mappers[c->numMappers++].aux = &sc->sub12or13;
(*parsed)++;
break;
}
(*unsupported)++;
werrstr("2.0 full: fmt %d", sc->format);
goto err;
case ENC_UNICODE_VAR_SEQ:
/* FIXME */
break;
case ENC_UNICODE_FULL:
/* FIXME */
break;
case ENC_UNICODE_1_0:
case ENC_UNICODE_1_1:
case ENC_UNICODE_ISO:
(*unsupported)++;
werrstr("deprecated encoding: %d", er->encodingID);
goto err;
default:
(*unsupported)++;
werrstr("unknown encoding: %d", er->encodingID);
goto err;
}
return 0;
err:
werrstr("unicode: %r");
return -1;
}
static int
otfcmapWindows(TableCmap *c, EncodingRecord *er, int *parsed, int *unsupported)
{
SubtableCmap *sc;
sc = er->subtable;
switch(er->encodingID){
case ENC_WINDOWS_UNICODE_BMP:
if(sc->format != 4){
(*unsupported)++;
werrstr("unicode bmp: fmt %d", sc->format);
goto err;
}
c->mappers[c->numMappers].rune2glyph = cmap4rune2glyph;
c->mappers[c->numMappers].glyph2rune = cmap4glyph2rune;
c->mappers[c->numMappers++].aux = &sc->sub4;
(*parsed)++;
break;
case ENC_WINDOWS_UNICODE_FULL:
if(sc->format != 12){
(*unsupported)++;
werrstr("unicode full: fmt %d", sc->format);
goto err;
}
if(sc->sub12or13.numGroups < 1){
werrstr("unicode full: no groups");
goto err;
}
c->mappers[c->numMappers].rune2glyph = cmap12rune2glyph;
c->mappers[c->numMappers].glyph2rune = cmap12glyph2rune;
c->mappers[c->numMappers++].aux = &sc->sub12or13;
(*parsed)++;
break;
case ENC_WINDOWS_SYMBOL:
case ENC_WINDOWS_SHIFTJIS:
case ENC_WINDOWS_PRC:
case ENC_WINDOWS_BIG5:
case ENC_WINDOWS_WANSUNG:
case ENC_WINDOWS_JOHAB:
(*unsupported)++;
werrstr("unsupported encoding: %d", er->encodingID);
goto err;
default:
(*unsupported)++;
werrstr("unknown encoding: %d", er->encodingID);
goto err;
}
return 0;
err:
werrstr("windows: %r");
return -1;
}
static int
otfcmap(TableCmap *c)
{
int i, parsed, unsupported;
EncodingRecord *er;
parsed = 0;
unsupported = 0;
for(i = 0, er = c->encodingRecords; i < c->numTables; i++, er++){
if(c->numMappers >= nelem(c->mappers)) /* give up */
break;
switch(er->platformID){
case PLAT_UNICODE:
/* FIXME issue a warning if returned non-zero */
if(otfcmapUnicode(c, er, &parsed, &unsupported) != 0)
goto err;
break;
case PLAT_WINDOWS:
/* FIXME issue a warning if returned non-zero */
if(otfcmapWindows(c, er, &parsed, &unsupported) != 0)
goto err;
break;
case PLAT_MACINTOSH:
case PLAT_ISO:
case PLAT_CUSTOM:
default:
unsupported++;
break;
}
}
if(parsed > 0)
return 0;
if(unsupported > 0)
werrstr(" (%d unsupported)", unsupported);
else
werrstr("");
werrstr("no usable records%r");
/* FIXME - eventually this return should be removed */
return 0;
err:
werrstr("cmap: %r");
return -1;
}