summaryrefslogtreecommitdiff
path: root/fitz/res_cmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fitz/res_cmap.c')
-rw-r--r--fitz/res_cmap.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/fitz/res_cmap.c b/fitz/res_cmap.c
new file mode 100644
index 00000000..577ba7c0
--- /dev/null
+++ b/fitz/res_cmap.c
@@ -0,0 +1,466 @@
+#include <fitz.h>
+
+typedef struct fz_range_s fz_range;
+
+enum { MAXCODESPACE = 10 };
+enum { SINGLE, RANGE, LOOKUP };
+
+struct fz_range_s
+{
+ int low;
+ int high;
+ int flag;
+ int offset;
+};
+
+struct fz_cmap_s
+{
+ int refs;
+ char cmapname[32];
+
+ char usecmapname[32];
+ fz_cmap *usecmap;
+
+ int wmode;
+
+ int ncspace;
+ struct {
+ int n;
+ unsigned char lo[4];
+ unsigned char hi[4];
+ } cspace[MAXCODESPACE];
+
+ int rlen, rcap;
+ fz_range *ranges;
+
+ int tlen, tcap;
+ int *lookup;
+};
+
+fz_error *
+fz_newcmap(fz_cmap **cmapp)
+{
+ fz_cmap *cmap;
+
+ cmap = *cmapp = fz_malloc(sizeof(fz_cmap));
+ if (!cmap)
+ return fz_outofmem;
+
+ cmap->refs = 1;
+ strcpy(cmap->cmapname, "");
+
+ strcpy(cmap->usecmapname, "");
+ cmap->usecmap = nil;
+
+ cmap->wmode = 0;
+
+ cmap->ncspace = 0;
+
+ cmap->rlen = 0;
+ cmap->rcap = 0;
+ cmap->ranges = nil;
+
+ cmap->tlen = 0;
+ cmap->tcap = 0;
+ cmap->lookup = nil;
+
+ return nil;
+}
+
+fz_cmap *
+fz_keepcmap(fz_cmap *cmap)
+{
+ cmap->refs ++;
+ return cmap;
+}
+
+void
+fz_dropcmap(fz_cmap *cmap)
+{
+ if (--cmap->refs == 0)
+ {
+ if (cmap->usecmap)
+ fz_dropcmap(cmap->usecmap);
+ fz_free(cmap->ranges);
+ fz_free(cmap->lookup);
+ fz_free(cmap);
+ }
+}
+
+char *
+fz_getcmapname(fz_cmap *cmap)
+{
+ if (cmap->cmapname[0])
+ return cmap->cmapname;
+ return nil;
+}
+
+void
+fz_setcmapname(fz_cmap *cmap, char *cmapname)
+{
+ strlcpy(cmap->cmapname, cmapname, sizeof cmap->cmapname);
+}
+
+char *
+fz_getusecmapname(fz_cmap *cmap)
+{
+ if (cmap->usecmapname[0])
+ return cmap->usecmapname;
+ return nil;
+}
+
+void
+fz_setusecmapname(fz_cmap *cmap, char *usecmap)
+{
+ strlcpy(cmap->usecmapname, usecmap, sizeof cmap->usecmapname);
+}
+
+fz_cmap *
+fz_getusecmap(fz_cmap *cmap)
+{
+ return cmap->usecmap;
+}
+
+void
+fz_setusecmap(fz_cmap *cmap, fz_cmap *usecmap)
+{
+ int i;
+
+ if (cmap->usecmap)
+ fz_dropcmap(cmap->usecmap);
+ cmap->usecmap = fz_keepcmap(usecmap);
+
+ if (cmap->ncspace == 0)
+ {
+ cmap->ncspace = usecmap->ncspace;
+ for (i = 0; i < usecmap->ncspace; i++)
+ cmap->cspace[i] = usecmap->cspace[i];
+ }
+}
+
+void
+fz_setwmode(fz_cmap *cmap, int wmode)
+{
+ cmap->wmode = wmode;
+}
+
+int
+fz_getwmode(fz_cmap *cmap)
+{
+ return cmap->wmode;
+}
+
+fz_error *
+fz_addcodespacerange(fz_cmap *cmap, unsigned lo, unsigned hi, int n)
+{
+ int i;
+
+ if (cmap->ncspace + 1 == MAXCODESPACE)
+ return fz_throw("rangelimit: too many code space ranges");
+
+ cmap->cspace[cmap->ncspace].n = n;
+
+ for (i = 0; i < n; i++)
+ {
+ int o = (n - i - 1) * 8;
+ cmap->cspace[cmap->ncspace].lo[i] = (lo >> o) & 0xFF;
+ cmap->cspace[cmap->ncspace].hi[i] = (hi >> o) & 0xFF;
+ }
+
+ cmap->ncspace ++;
+
+ return nil;
+}
+
+fz_error *
+fz_addcidrange(fz_cmap *cmap, int low, int high, int offset)
+{
+ if (cmap->rlen + 1 > cmap->rcap)
+ {
+ fz_range *newranges;
+ int newcap = cmap->rcap == 0 ? 256 : cmap->rcap * 2;
+ newranges = fz_realloc(cmap->ranges, newcap * sizeof(fz_range));
+ if (!newranges)
+ return fz_outofmem;
+ cmap->rcap = newcap;
+ cmap->ranges = newranges;
+ }
+
+ cmap->ranges[cmap->rlen].low = low;
+ cmap->ranges[cmap->rlen].high = high;
+ cmap->ranges[cmap->rlen].flag = high - low == 0 ? SINGLE : RANGE;
+ cmap->ranges[cmap->rlen].offset = offset;
+ cmap->rlen ++;
+
+ return nil;
+}
+
+static fz_error *
+addlookup(fz_cmap *cmap, int value)
+{
+ if (cmap->tlen + 1 > cmap->tcap)
+ {
+ int newcap = cmap->tcap == 0 ? 256 : cmap->tcap * 2;
+ int *newlookup = fz_realloc(cmap->lookup, newcap * sizeof(int));
+ if (!newlookup)
+ return fz_outofmem;
+ cmap->tcap = newcap;
+ cmap->lookup = newlookup;
+ }
+
+ cmap->lookup[cmap->tlen++] = value;
+
+ return nil;
+}
+
+static int compare(const void *va, const void *vb)
+{
+ return ((const fz_range*)va)->low - ((const fz_range*)vb)->low;
+}
+
+fz_error *
+fz_endcidrange(fz_cmap *cmap)
+{
+ fz_error *error;
+ fz_range *newranges;
+ int *newlookup;
+ fz_range *a; /* last written range on output */
+ fz_range *b; /* current range examined on input */
+
+ qsort(cmap->ranges, cmap->rlen, sizeof(fz_range), compare);
+
+ a = cmap->ranges;
+ b = cmap->ranges + 1;
+
+ while (b < cmap->ranges + cmap->rlen)
+ {
+ /* input contiguous */
+ if (a->high + 1 == b->low)
+ {
+ /* output contiguous */
+ if (a->high - a->low + a->offset + 1 == b->offset)
+ {
+ /* SR -> R and SS -> R and RR -> R and RS -> R */
+ if (a->flag == SINGLE || a->flag == RANGE)
+ {
+ a->flag = RANGE;
+ a->high = b->high;
+ }
+
+ /* LS -> L */
+ else if (a->flag == LOOKUP && b->flag == SINGLE)
+ {
+ a->high = b->high;
+ error = addlookup(cmap, b->offset);
+ if (error)
+ return error;
+ }
+
+ /* LR -> LR */
+ else if (a->flag == LOOKUP && b->flag == RANGE)
+ {
+ *(++a) = *b;
+ }
+ }
+
+ /* output separated */
+ else
+ {
+ /* SS -> L */
+ if (a->flag == SINGLE && b->flag == SINGLE)
+ {
+ a->flag = LOOKUP;
+ a->high = b->high;
+
+ error = addlookup(cmap, a->offset);
+ if (error)
+ return error;
+
+ error = addlookup(cmap, b->offset);
+ if (error)
+ return error;
+
+ a->offset = cmap->tlen - 2;
+ }
+
+ /* LS -> L */
+ else if (a->flag == LOOKUP && b->flag == SINGLE)
+ {
+ a->high = b->high;
+ error = addlookup(cmap, b->offset);
+ if (error)
+ return error;
+ }
+
+ /* XX -> XX */
+ else
+ {
+ *(++a) = *b;
+ }
+ }
+ }
+
+ /* input separated: XX -> XX */
+ else
+ {
+ *(++a) = *b;
+ }
+
+ b ++;
+ }
+
+ cmap->rlen = a - cmap->ranges + 1;
+
+ assert(cmap->rlen > 0);
+
+ newranges = fz_realloc(cmap->ranges, cmap->rlen * sizeof(fz_range));
+ if (!newranges)
+ return fz_outofmem;
+ cmap->rcap = cmap->rlen;
+ cmap->ranges = newranges;
+
+ if (cmap->tlen)
+ {
+ newlookup = fz_realloc(cmap->lookup, cmap->tlen * sizeof(int));
+ if (!newlookup)
+ return fz_outofmem;
+ cmap->tcap = cmap->tlen;
+ cmap->lookup = newlookup;
+ }
+
+ return nil;
+}
+
+fz_error *
+fz_setcidlookup(fz_cmap *cmap, int map[256])
+{
+ int i;
+
+ cmap->rlen = cmap->rcap = 1;
+ cmap->ranges = fz_malloc(sizeof (fz_range));
+ if (!cmap->ranges) {
+ return fz_outofmem;
+ }
+
+ cmap->tlen = cmap->tcap = 256;
+ cmap->lookup = fz_malloc(sizeof (int) * 256);
+ if (!cmap->lookup) {
+ fz_free(cmap->ranges);
+ return fz_outofmem;
+ }
+
+ cmap->ranges[0].low = 0;
+ cmap->ranges[0].high = 255;
+ cmap->ranges[0].flag = LOOKUP;
+ cmap->ranges[0].offset = 0;
+
+ for (i = 0; i < 256; i++)
+ cmap->lookup[i] = map[i];
+
+ return nil;
+}
+
+int
+fz_lookupcid(fz_cmap *cmap, int cpt)
+{
+ int l = 0;
+ int r = cmap->rlen - 1;
+ int m;
+
+ while (l <= r)
+ {
+ m = (l + r) >> 1;
+ if (cpt < cmap->ranges[m].low)
+ r = m - 1;
+ else if (cpt > cmap->ranges[m].high)
+ l = m + 1;
+ else
+ {
+ int i = cpt - cmap->ranges[m].low + cmap->ranges[m].offset;
+ if (cmap->ranges[m].flag == LOOKUP)
+ return cmap->lookup[i];
+ return i;
+ }
+ }
+
+ if (cmap->usecmap)
+ return fz_lookupcid(cmap->usecmap, cpt);
+
+ return -1;
+}
+
+unsigned char *
+fz_decodecpt(fz_cmap *cmap, unsigned char *buf, int *cpt)
+{
+ int i, k;
+
+ for (k = 0; k < cmap->ncspace; k++)
+ {
+ unsigned char *lo = cmap->cspace[k].lo;
+ unsigned char *hi = cmap->cspace[k].hi;
+ int n = cmap->cspace[k].n;
+ int c = 0;
+
+ for (i = 0; i < n; i++)
+ {
+ if (lo[i] <= buf[i] && buf[i] <= hi[i])
+ c = (c << 8) | buf[i];
+ else
+ break;
+ }
+
+ if (i == n) {
+ *cpt = c;
+ return buf + n;
+ }
+ }
+
+ *cpt = 0;
+ return buf + 1;
+}
+
+void
+fz_debugcmap(fz_cmap *cmap)
+{
+ int i, k;
+
+ printf("cmap $%p /%s {\n", cmap, cmap->cmapname);
+
+ if (cmap->usecmapname[0])
+ printf(" usecmap /%s\n", cmap->usecmapname);
+ if (cmap->usecmap)
+ printf(" usecmap $%p\n", cmap->usecmap);
+
+ printf(" wmode %d\n", cmap->wmode);
+
+ printf(" codespaces {\n");
+ for (i = 0; i < cmap->ncspace; i++)
+ {
+ printf(" <");
+ for (k = 0; k < cmap->cspace[i].n; k++)
+ printf("%02x", cmap->cspace[i].lo[k]);
+ printf("> <");
+ for (k = 0; k < cmap->cspace[i].n; k++)
+ printf("%02x", cmap->cspace[i].hi[k]);
+ printf(">\n");
+ }
+ printf(" }\n");
+
+ printf(" ranges (%d,%d) {\n", cmap->rlen, cmap->tlen);
+ for (i = 0; i < cmap->rlen; i++)
+ {
+ fz_range *r = &cmap->ranges[i];
+ printf(" <%04x> <%04x> ", r->low, r->high);
+ if (r->flag == LOOKUP)
+ {
+ printf("[ ");
+ for (k = 0; k < r->high - r->low + 1; k++)
+ printf("%d ", cmap->lookup[r->offset + k]);
+ printf("]\n");
+ }
+ else
+ printf("%d\n", r->offset);
+ }
+ printf(" }\n}\n");
+}
+