#include "libtexpdf.h"
#include <string.h>
#include "mem.h"
#include "error.h"
#include "dpxutil.h"
#include "pdfobj.h"
#include "pdfresource.h"
#include "cmap_p.h"
#include "cmap.h"
#include "cmap_write.h"
struct sbuf {
char *buf;
char *curptr;
char *limptr;
};
static int write_map (mapDef *mtab, int count,
unsigned char *codestr, int depth,
struct sbuf *wbuf, pdf_obj *stream);
#if 0#endif
static int
block_count (mapDef *mtab, int c)
{
int count = 0, n;
n = mtab[c].len - 1;
c += 1;
for (; c < 256; c++) {
if (LOOKUP_CONTINUE(mtab[c].flag) ||
!MAP_DEFINED(mtab[c].flag) ||
(MAP_TYPE(mtab[c].flag) != MAP_IS_CID &&
MAP_TYPE(mtab[c].flag) != MAP_IS_CODE) ||
mtab[c-1].len != mtab[c].len)
break;
else if (!memcmp(mtab[c-1].code, mtab[c].code, n) &&
mtab[c-1].code[n] < 255 &&
mtab[c-1].code[n] + 1 == mtab[c].code[n])
count++;
else {
break;
}
}
return count;
}
static int
write_map (mapDef *mtab, int count,
unsigned char *codestr, int depth,
struct sbuf *wbuf, pdf_obj *stream)
{
int c, i, block_length;
mapDef *mtab1;
#define BLOCK_LEN_MIN 2
struct {
int start, count;
} blocks[256/BLOCK_LEN_MIN+1];
int num_blocks = 0;
for (c = 0; c < 256; c++) {
codestr[depth] = (unsigned char) (c & 0xff);
if (LOOKUP_CONTINUE(mtab[c].flag)) {
mtab1 = mtab[c].next;
count = write_map(mtab1, count,
codestr, depth + 1, wbuf, stream);
} else {
if (MAP_DEFINED(mtab[c].flag)) {
switch (MAP_TYPE(mtab[c].flag)) {
case MAP_IS_CID: case MAP_IS_CODE:
block_length = block_count(mtab, c);
if (block_length >= BLOCK_LEN_MIN) {
blocks[num_blocks].start = c;
blocks[num_blocks].count = block_length;
num_blocks++;
c += block_length;
} else {
*(wbuf->curptr)++ = '<';
for (i = 0; i <= depth; i++)
sputx(codestr[i], &(wbuf->curptr), wbuf->limptr);
*(wbuf->curptr)++ = '>';
*(wbuf->curptr)++ = ' ';
*(wbuf->curptr)++ = '<';
for (i = 0; i < mtab[c].len; i++)
sputx(mtab[c].code[i], &(wbuf->curptr), wbuf->limptr);
*(wbuf->curptr)++ = '>';
*(wbuf->curptr)++ = '\n';
count++;
}
break;
case MAP_IS_NAME:
ERROR("%s: Unexpected error...", CMAP_DEBUG_STR);
break;
case MAP_IS_NOTDEF:
break;
default:
ERROR("%s: Unknown mapping type: %d",
CMAP_DEBUG_STR, MAP_TYPE(mtab[c].flag));
}
}
}
if (count >= 100 ||
wbuf->curptr >= wbuf->limptr ) {
char fmt_buf[32];
if (count > 100)
ERROR("Unexpected error....: %d", count);
sprintf(fmt_buf, "%d beginbfchar\n", count);
texpdf_add_stream(stream, fmt_buf, strlen(fmt_buf));
texpdf_add_stream(stream,
wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
wbuf->curptr = wbuf->buf;
texpdf_add_stream(stream,
"endbfchar\n", strlen("endbfchar\n"));
count = 0;
}
}
if (num_blocks > 0) {
char fmt_buf[32];
if (count > 0) {
sprintf(fmt_buf, "%d beginbfchar\n", count);
texpdf_add_stream(stream, fmt_buf, strlen(fmt_buf));
texpdf_add_stream(stream,
wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
wbuf->curptr = wbuf->buf;
texpdf_add_stream(stream,
"endbfchar\n", strlen("endbfchar\n"));
count = 0;
}
sprintf(fmt_buf, "%d beginbfrange\n", num_blocks);
texpdf_add_stream(stream, fmt_buf, strlen(fmt_buf));
for (i = 0; i < num_blocks; i++) {
int j;
c = blocks[i].start;
*(wbuf->curptr)++ = '<';
for (j = 0; j < depth; j++)
sputx(codestr[j], &(wbuf->curptr), wbuf->limptr);
sputx((unsigned char)c, &(wbuf->curptr), wbuf->limptr);
*(wbuf->curptr)++ = '>';
*(wbuf->curptr)++ = ' ';
*(wbuf->curptr)++ = '<';
for (j = 0; j < depth; j++)
sputx(codestr[j], &(wbuf->curptr), wbuf->limptr);
sputx((unsigned char)(c + blocks[i].count), &(wbuf->curptr), wbuf->limptr);
*(wbuf->curptr)++ = '>';
*(wbuf->curptr)++ = ' ';
*(wbuf->curptr)++ = '<';
for (j = 0; j < mtab[c].len; j++)
sputx(mtab[c].code[j], &(wbuf->curptr), wbuf->limptr);
*(wbuf->curptr)++ = '>';
*(wbuf->curptr)++ = '\n';
}
texpdf_add_stream(stream,
wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
wbuf->curptr = wbuf->buf;
texpdf_add_stream(stream,
"endbfrange\n", strlen("endbfrange\n"));
}
return count;
}
#define CMAP_BEGIN "\
/CIDInit /ProcSet findresource begin\n\
12 dict begin\n\
begincmap\n\
"
#define CMAP_END "\
endcmap\n\
CMapName currentdict /CMap defineresource pop\n\
end\n\
end\n\
"
pdf_obj *
CMap_create_stream (CMap *cmap)
{
pdf_obj *stream;
pdf_obj *stream_dict;
CIDSysInfo *csi;
struct sbuf wbuf;
struct rangeDef *ranges;
unsigned char *codestr;
int i, j, count = 0;
if (!cmap || !CMap_is_valid(cmap)) {
WARN("Invalid CMap");
return NULL;
}
if (cmap->type == CMAP_TYPE_IDENTITY)
return NULL;
stream = texpdf_new_stream(STREAM_COMPRESS);
stream_dict = texpdf_stream_dict(stream);
csi = CMap_get_CIDSysInfo(cmap);
if (!csi) {
csi = (cmap->type != CMAP_TYPE_TO_UNICODE) ?
&CSI_IDENTITY : &CSI_UNICODE;
}
if (cmap->type != CMAP_TYPE_TO_UNICODE) {
pdf_obj *csi_dict;
csi_dict = texpdf_new_dict();
texpdf_add_dict(csi_dict,
texpdf_new_name("Registry"),
texpdf_new_string(csi->registry, strlen(csi->registry)));
texpdf_add_dict(csi_dict,
texpdf_new_name("Ordering"),
texpdf_new_string(csi->ordering, strlen(csi->ordering)));
texpdf_add_dict(csi_dict,
texpdf_new_name("Supplement"),
texpdf_new_number(csi->supplement));
texpdf_add_dict(stream_dict,
texpdf_new_name("Type"),
texpdf_new_name("CMap"));
texpdf_add_dict(stream_dict,
texpdf_new_name("CMapName"),
texpdf_new_name(cmap->name));
texpdf_add_dict(stream_dict,
texpdf_new_name("CIDSystemInfo"), csi_dict);
if (cmap->wmode != 0)
texpdf_add_dict(stream_dict,
texpdf_new_name("WMode"),
texpdf_new_number(cmap->wmode));
}
if (cmap->useCMap) {
ERROR("UseCMap found (not supported yet)...");
if (CMap_is_Identity(cmap->useCMap)) {
if (CMap_get_wmode(cmap) == 1) {
texpdf_add_dict(stream_dict,
texpdf_new_name("UseCMap"),
texpdf_new_name("Identity-V"));
} else {
texpdf_add_dict(stream_dict,
texpdf_new_name("UseCMap"),
texpdf_new_name("Identity-H"));
}
} else {
long res_id;
pdf_obj *ucmap_ref;
res_id = pdf_findresource("CMap", CMap_get_name(cmap->useCMap));
if (res_id >= 0) {
ucmap_ref = texpdf_get_resource_reference(res_id);
} else {
pdf_obj *ucmap_obj;
ucmap_obj = CMap_create_stream(cmap->useCMap);
if (!ucmap_obj) {
ERROR("Uh ah. I cannot continue...");
}
res_id = pdf_defineresource("CMap",
CMap_get_name(cmap->useCMap),
ucmap_obj, PDF_RES_FLUSH_IMMEDIATE);
ucmap_ref = texpdf_get_resource_reference(res_id);
}
texpdf_add_dict(stream_dict, texpdf_new_name("UseCMap"), ucmap_ref);
}
}
#define WBUF_SIZE 4096
wbuf.buf = NEW(WBUF_SIZE, char);
codestr = NEW(cmap->profile.maxBytesIn, unsigned char);
memset(codestr, 0, cmap->profile.maxBytesIn);
wbuf.curptr = wbuf.buf;
wbuf.limptr = wbuf.buf + WBUF_SIZE -
2 * (cmap->profile.maxBytesIn + cmap->profile.maxBytesOut) + 16;
texpdf_add_stream(stream, (const void *) CMAP_BEGIN, strlen(CMAP_BEGIN));
wbuf.curptr += sprintf(wbuf.curptr, "/CMapName /%s def\n", cmap->name);
wbuf.curptr += sprintf(wbuf.curptr, "/CMapType %d def\n" , cmap->type);
if (cmap->wmode != 0 &&
cmap->type != CMAP_TYPE_TO_UNICODE)
wbuf.curptr += sprintf(wbuf.curptr, "/WMode %d def\n", cmap->wmode);
#define CMAP_CSI_FMT "/CIDSystemInfo <<\n\
/Registry (%s)\n\
/Ordering (%s)\n\
/Supplement %d\n\
>> def\n"
wbuf.curptr += sprintf(wbuf.curptr, CMAP_CSI_FMT,
csi->registry, csi->ordering, csi->supplement);
texpdf_add_stream(stream, wbuf.buf, (long)(wbuf.curptr - wbuf.buf));
wbuf.curptr = wbuf.buf;
ranges = cmap->codespace.ranges;
wbuf.curptr += sprintf(wbuf.curptr,
"%d begincodespacerange\n", cmap->codespace.num);
for (i = 0; i < cmap->codespace.num; i++) {
*(wbuf.curptr)++ = '<';
for (j = 0; j < ranges[i].dim; j++) {
sputx(ranges[i].codeLo[j], &(wbuf.curptr), wbuf.limptr);
}
*(wbuf.curptr)++ = '>';
*(wbuf.curptr)++ = ' ';
*(wbuf.curptr)++ = '<';
for (j = 0; j < ranges[i].dim; j++) {
sputx(ranges[i].codeHi[j], &(wbuf.curptr), wbuf.limptr);
}
*(wbuf.curptr)++ = '>';
*(wbuf.curptr)++ = '\n';
}
texpdf_add_stream(stream, wbuf.buf, (long)(wbuf.curptr - wbuf.buf));
wbuf.curptr = wbuf.buf;
texpdf_add_stream(stream,
"endcodespacerange\n", strlen("endcodespacerange\n"));
if (cmap->mapTbl) {
count = write_map(cmap->mapTbl,
0, codestr, 0, &wbuf, stream);
if (count > 0) {
char fmt_buf[32];
if (count > 100)
ERROR("Unexpected error....: %d", count);
sprintf(fmt_buf, "%d beginbfchar\n", count);
texpdf_add_stream(stream, fmt_buf, strlen(fmt_buf));
texpdf_add_stream(stream,
wbuf.buf, (long) (wbuf.curptr - wbuf.buf));
texpdf_add_stream(stream,
"endbfchar\n", strlen("endbfchar\n"));
count = 0;
wbuf.curptr = wbuf.buf;
}
}
texpdf_add_stream(stream, CMAP_END, strlen(CMAP_END));
RELEASE(codestr);
RELEASE(wbuf.buf);
return stream;
}
#if 0#endif