int pdf_insert_utilstring(PDF *p, const char *utilstring, pdc_bool kdup) { static const char fn[] = "pdf_insert_utilstring"; char **utilstrlist; int i = 0; if (p->utilstrlist_index == -1) { utilstrlist = (char **) pdc_calloc(p->pdc, PDF_MAX_UTILSTRLISTS * sizeof (char *), fn); p->utilstrlist_index = pdf_insert_stringlist(p, utilstrlist, PDF_MAX_UTILSTRLISTS); } utilstrlist = p->stringlists[p->utilstrlist_index]; if (p->utilstring_number >= PDF_MAX_UTILSTRLISTS) p->utilstring_number = 0; i = p->utilstring_number; if (utilstrlist[i] != NULL) pdc_free(p->pdc, utilstrlist[i]); if (kdup) utilstrlist[i] = pdc_strdup_ext(p->pdc, utilstring, 0, fn); else utilstrlist[i] = (char *) utilstring; p->utilstring_number++; return i; }
void * pdc_calloc_tmp( pdc_core * pdc, size_t size, const char * caller, void * opaque, pdc_destructor destr) { void *memory = pdc_calloc(pdc, size, caller); pdc_insert_mem_tmp(pdc, memory, opaque, destr); return memory; }
void pdf__create_pvf(PDF *p, const char *filename, int reserved, const void *data, size_t size, const char *optlist) { static const char fn[] = "pdf__create_pvf"; pdc_bool iscopy = pdc_false; pdf_virtfile *vfile, *lastvfile = NULL; pdc_resopt *results; (void) reserved; /* Parse optlist */ results = pdc_parse_optionlist(p->pdc, optlist, pdf_create_pvf_options, NULL, pdc_true); pdc_get_optvalues(p->pdc, "copy", results, &iscopy, NULL); pdc_cleanup_optionlist(p->pdc, results); /* Find virtual file in file system */ vfile = pdf_find_pvf(p, filename, &lastvfile); /* Name already exists */ if (vfile != NULL) pdc_error(p->pdc, PDC_E_PVF_NAMEEXISTS, filename, 0, 0, 0); /* New virtual file */ vfile = (pdf_virtfile *) pdc_calloc(p->pdc, sizeof(pdf_virtfile), fn); if (lastvfile) lastvfile->next = vfile; else p->filesystem = vfile; /* Fill up file struct */ vfile->name = pdc_strdup(p->pdc, filename); if (iscopy == pdc_true) { vfile->data = (const void *) pdc_malloc(p->pdc, size, fn); memcpy((void *) vfile->data, data, size); } else { vfile->data = data; } vfile->size = size; vfile->iscopy = iscopy; vfile->lockcount = 0; vfile->next = NULL; }
static int pdf_insert_bookmark( PDF *p, const char *hypertext, pdf_outline *outline, int jndex) { static const char fn[] = "pdf_insert_bookmark"; pdf_outline *root, *self; int parent; int self_idx; int pageno = pdf_current_page(p); /* allocation */ if (p->outline_count == 0) { p->outline_capacity = OUTLINE_CHUNKSIZE; p->outlines = (pdf_outline *) pdc_calloc(p->pdc, sizeof(pdf_outline) * p->outline_capacity, fn); /* populate the root outline object */ root = &p->outlines[0]; pdf_init_outline(p, root); root->obj_id = pdc_alloc_id(p->out); root->open = pdc_true; /* set the open mode show bookmarks if we have at least one, * and the client didn't already set his own open mode. */ pdf_fix_openmode(p); } else if (p->outline_count + 1 >= p->outline_capacity) { p->outline_capacity *= 2; p->outlines = (pdf_outline *) pdc_realloc(p->pdc, p->outlines, sizeof(pdf_outline) * p->outline_capacity, fn); } /* copy */ self_idx = ++p->outline_count; self = &p->outlines[self_idx]; memcpy(self, outline, sizeof(pdf_outline)); self->obj_id = pdc_alloc_id(p->out); self->text = (char *) hypertext; self->page_id = pdf_get_page_id(p, 0); parent = self->parent; /* default destination */ if (self->action == NULL && self->dest == NULL) self->dest = pdf_init_destination(p); /* no destination */ if (self->dest != NULL && self->dest->name != NULL && !strlen(self->dest->name)) { pdf_cleanup_destination(p, self->dest); self->dest = NULL; } /* current page */ if (self->dest) { /* this ugly code is for compatibility with the ** obsolete "bookmarkdest" parameter. */ if (self->dest->pgnum == 0) self->dest->pgnum = pdf_current_page(p); if (self->dest->pgnum == 0) { self->dest->pgnum = 1; } else if (self->dest->page == PDC_BAD_ID) { self->dest->page = pdf_get_page_id(p, self->dest->pgnum); } } /* special case: empty list. */ if (FIRST(parent) == 0) { if (jndex > 0) pdc_error(p->pdc, PDC_E_OPT_ILLINTEGER, "index", pdc_errprintf(p->pdc, "%d", jndex), 0, 0); FIRST(parent) = LAST(parent) = self_idx; self->in_order = pdc_true; } else switch (jndex) { case -2: /* insert "in order" */ { /* the "natural" case: append to the end if appropriate. */ if (pageno >= search_backward(p, -1, LAST(parent))) { self->prev = LAST(parent); NEXT(LAST(parent)) = self_idx; LAST(parent) = self_idx; } else { int idx; int curr_pg = 1; int next_pg; for (idx = FIRST(parent); idx != 0; idx = NEXT(idx)) { if (!IN_ORDER(idx)) continue; next_pg = pdf_search_page_fwd(p, curr_pg, PAGE_ID(idx)); /* TODO: understand why this can happen. */ if (next_pg < 1) { idx = 0; break; } if (next_pg > pageno) { self->next = idx; self->prev = PREV(idx); PREV(idx) = self_idx; if (self->prev == 0) FIRST(parent) = self_idx; else NEXT(self->prev) = self_idx; break; } curr_pg = next_pg; } /* if there are no "in order" bookmarks yet, ** we simply append this one to the end. */ if (idx == 0) { self->prev = LAST(parent); NEXT(LAST(parent)) = self_idx; LAST(parent) = self_idx; } } self->in_order = pdc_true; break; } case -1: /* append to the end */ { self->prev = LAST(parent); NEXT(LAST(parent)) = self_idx; LAST(parent) = self_idx; self->in_order = (pageno >= search_backward(p, pageno, self->prev)); break; } case 0: /* insert at the beginning */ { self->next = FIRST(parent); PREV(FIRST(parent)) = self_idx; FIRST(parent) = self_idx; self->in_order = (pageno <= search_forward(p, pageno, self->next)); break; } default: /* insert before [1..LAST] */ { int i; int target = FIRST(parent); for (i = 0; i < jndex; ++i) { if (target == LAST(parent)) pdc_error(p->pdc, PDC_E_OPT_ILLINTEGER, "index", pdc_errprintf(p->pdc, "%d", jndex), 0, 0); target = NEXT(target); } self->next = target; self->prev = PREV(target); NEXT(self->prev) = PREV(self->next) = self_idx; self->in_order = ((pageno >= search_backward(p, pageno, self->prev)) && (pageno <= search_forward(p, pageno, self->next))); break; } } /* else switch */ /* increase the number of open sub-entries for all relevant ancestors */ do { COUNT(parent)++; } while (OPEN(parent) && (parent = PARENT(parent)) != 0); return (self_idx); /* caller may use this as handle */ }
static pdc_bool pdf_parse_pfm(PDF *p, pdc_file *fp, pdf_font *font) { static const char fn[] = "pdf_parse_pfm"; fnt_font_metric *ftm = &font->ft.m; size_t length; pdc_byte *pfm; pdc_bool ismem; int i, dfFirstChar, dfLastChar, default_width; unsigned long dfExtentTable; /* read whole file and close it */ pfm = (pdc_byte *) pdc_freadall(fp, &length, &ismem); pdc_fclose(fp); /* check whether this is really a valid PostScript PFM file */ if (pfm == NULL || (header_dfVersion != 0x100 && header_dfVersion != 0x200) || dfDevice > length || strncmp((const char *) pfm + dfDevice, PDF_STRING_PostScript, 10) || ext_dfDriverInfo > length) { if (!ismem) pdc_free(p->pdc, pfm); return pdc_false; } /* fetch relevant data from the PFM */ ftm->type = fnt_Type1; font->ft.name = pdc_strdup(p->pdc, (const char *)pfm + ext_dfDriverInfo); ftm->name = pdc_strdup(p->pdc, font->ft.name); pdc_logg_cond(p->pdc, 1, trc_font, "\tPostScript font name: \"%s\"\n", ftm->name); switch (header_dfPitchAndFamily & 0xF0) { case PDF_ROMAN: ftm->flags |= FNT_SERIF; break; case PDF_MODERN: /* Has to be ignored, contrary to MS's specs */ break; case PDF_SCRIPT: ftm->flags |= FNT_SCRIPT; break; case PDF_DECORATIVE: /* the dfCharSet flag lies in this case... */ header_dfCharSet = PFM_SYMBOL_CHARSET; break; case PDF_SWISS: case PDF_DONTCARE: default: break; } /* temporarily */ font->ft.enc = (pdc_encoding) header_dfCharSet; dfFirstChar = header_dfFirstChar; dfLastChar = header_dfLastChar; dfExtentTable = ext_dfExtentTable; /* * Some rare PFMs do not contain any ExtentTable if the fixed pitch flag * is set. Use the dfMaxWidth entry for all glyphs in this case. * If the user forced the font to be monospaced we use this value instead. */ if ((!(header_dfPitchAndFamily & PDF_FIXED_PITCH) && dfExtentTable == 0) || font->opt.monospace) { ftm->isFixedPitch = pdc_true; default_width = font->opt.monospace ? font->opt.monospace : (int) header_dfMaxWidth; } else { /* default values -- don't take the width of the default character */ default_width = FNT_DEFAULT_WIDTH; } font->ft.numcodes = 256; ftm->numwidths = font->ft.numcodes; ftm->widths = (int *) pdc_calloc(p->pdc, ftm->numwidths * sizeof(int), fn); for (i = 0; i < font->ft.numcodes; i++) ftm->widths[i] = default_width; if (!ftm->isFixedPitch) { if (ext_dfExtentTable == 0 || ext_dfExtentTable + 2 * (header_dfLastChar-header_dfFirstChar) + 1 > length) { if (!ismem) pdc_free(p->pdc, pfm); return pdc_false; } for (i = dfFirstChar; i <= dfLastChar; i++) ftm->widths[i] = (int) PFM_WORD(dfExtentTable + 2 * (i - dfFirstChar)); /* * Check whether the font is actually opt.monospaced * (the fixed pitch flag is not necessarily set) */ default_width = ftm->widths[dfFirstChar]; for (i = dfFirstChar+1; i <= dfLastChar; i++) if (default_width != ftm->widths[i]) break; if (i == dfLastChar + 1) ftm->isFixedPitch = pdc_true; } font->ft.weight = fnt_check_weight(header_dfWeight); ftm->defwidth = default_width; ftm->italicAngle = (header_dfItalic ? etmSlant/(10.0) : 0.0); ftm->capHeight = etmCapHeight; ftm->xHeight = etmXHeight; ftm->descender = -etmLowerCaseDescent; ftm->ascender = (int) header_dfAscent; ftm->underlinePosition = -etmUnderlineOffset; ftm->underlineThickness = etmUnderlineWidth; ftm->urx = header_dfMaxWidth; if (!ismem) pdc_free(p->pdc, pfm); return pdc_true; }
/* * Fill font metric struct from core metric struct */ void fnt_fill_font_metric(pdc_core *pdc, fnt_font *font, pdc_bool kerning, const fnt_font_metric *metric) { static const char fn[] = "fnt_fill_font_metric"; (void) kerning; /* Fill font metric struct. Font struct must be initialized */ font->m = *metric; font->m.charcoll = abs(font->m.charcoll); font->m.name = pdc_strdup(pdc, metric->name); font->name = pdc_strdup(pdc, metric->name); /* Fill glyph widths array (double mapping Unicode <-> code <-> width) */ if (font->m.numglwidths) { font->m.glw = (fnt_glyphwidth *) pdc_calloc(pdc, metric->numglwidths * sizeof(fnt_glyphwidth), fn); memcpy(font->m.glw, metric->glw, metric->numglwidths * sizeof(fnt_glyphwidth)); } /* Fill glyph width array (mapping Unicode interval <-> width) */ if (metric->numinters) { /* We must convert */ if (font->m.type == fnt_Type1) { int i, j, iw, iwe; pdc_ushort uv; for (i = 0; i < metric->numinters; i++) { if (i && metric->ciw[i-1].width != 0) font->m.numglwidths += metric->ciw[i].startcode - metric->ciw[i-1].startcode; } font->m.glw = (fnt_glyphwidth *) pdc_calloc(pdc, font->m.numglwidths * sizeof(fnt_glyphwidth), fn); j = 0; iw = 0; for (i = 0; i < metric->numinters; i++) { if (i && metric->ciw[j].width != 0) { uv = metric->ciw[j].startcode; iwe = iw + metric->ciw[i].startcode - uv; for (; iw < iwe; iw++) { font->m.glw[iw].unicode = uv; font->m.glw[iw].width = metric->ciw[j].width; uv++; } } j = i; } font->m.numinters = 0; font->m.ciw = NULL; } else { font->m.ciw = (fnt_interwidth *) pdc_calloc(pdc, font->m.numinters * sizeof(fnt_interwidth), fn); memcpy(font->m.ciw, metric->ciw, metric->numinters * sizeof(fnt_interwidth)); } } #ifdef PDF_CJKFONTWIDTHS_SUPPORTED /* Fill glyph width array (mapping CID -> width) */ if (font->m.type == fnt_CIDFontType0) fnt_parse_cid_widths(pdc, font); #endif /* PDF_CJKFONTWIDTHS_SUPPORTED */ /* Number of glyphs */ if (font->m.type == fnt_Type1) font->numglyphs = font->m.numglwidths; /* font weight */ font->weight = fnt_stemv2weight(font->m.StdVW); /* standard Adobe font */ font->isstdfont = pdc_true; /* symbol font */ if (!(font->m.flags & FNT_SYMBOL)) font->issymbfont = pdc_false; }
pdc_resopt * pdc_parse_optionlist(pdc_core *pdc, const char *optlist, const pdc_defopt *defopt, const pdc_clientdata *clientdata, pdc_bool verbose) { static const char *fn = "pdc_parse_optionlist"; pdc_bool logg5 = pdc_logg_is_enabled(pdc, 5, trc_optlist); const char *stemp1 = NULL, *stemp2 = NULL, *stemp3 = NULL, *s1, *s2; char **items = NULL, *keyword = NULL; char **values = NULL, *value = NULL, **strings = NULL; int i, j, k, nd, is, iss, it, iv, icoord; int numdef, nitems = 0, nvalues, ncoords = 0, errcode = 0; void *resval; double dz, maxval; int retval, iz; pdc_sint32 lz = 0; pdc_uint32 ulz = 0; size_t len; const pdc_defopt *dopt = NULL; pdc_resopt *resopt = NULL; pdc_bool ignore = pdc_false; pdc_bool boolval = pdc_false; pdc_bool tocheck = pdc_false; pdc_bool issorted = pdc_true; pdc_bool ishandle = pdc_true; pdc_bool isutf8 = pdc_false; pdc_logg_cond(pdc, 1, trc_optlist, "\n\tOption list: \"%T\"\n", optlist ? optlist : "", 0); /* split option list */ if (optlist != NULL) { nitems = pdc_split_stringlist(pdc, optlist, PDC_OPT_LISTSEPS, PDC_SPLIT_ISOPTLIST, &items); isutf8 = pdc_is_utf8_bytecode(optlist); } if (nitems < 0) { keyword = (char *) optlist; errcode = PDC_E_OPT_NOTBAL; goto PDC_OPT_SYNTAXERROR; } /* initialize result list */ for (numdef = 0; defopt[numdef].name != NULL; numdef++) { /* */ ; } /* allocate temporary memory for option parser result struct */ resopt = (pdc_resopt *) pdc_calloc_tmp(pdc, numdef * sizeof(pdc_resopt), fn, pdc, pdc_cleanup_optionlist_tmp); for (i = 0; i < numdef; i++) { resopt[i].numdef = numdef; resopt[i].defopt = &defopt[i]; if (defopt[i].flags & PDC_OPT_IGNOREIF1 || defopt[i].flags & PDC_OPT_IGNOREIF2 || defopt[i].flags & PDC_OPT_REQUIRIF1 || defopt[i].flags & PDC_OPT_REQUIRIF2 || defopt[i].flags & PDC_OPT_REQUIRED) tocheck = pdc_true; if (i && issorted) issorted = (strcmp(defopt[i-1].name, defopt[i].name) <= 0) ? pdc_true : pdc_false; } /* loop over all option list elements */ for (is = 0; is < nitems; is++) { pdc_bool isequal = pdc_false; /* search keyword */ boolval = pdc_undef; keyword = items[is]; for (it = 0; it < numdef; it++) { s1 = keyword; s2 = defopt[it].name; /* if (!pdc_stricmp(keyword, defopt[it].name)) * isequal = pdc_true; */ for (; *s1; ++s1, ++s2) { if (pdc_tolower(*s1) != pdc_tolower(*s2)) break; } if (pdc_tolower(*s1) == pdc_tolower(*s2)) isequal = pdc_true; /* special handling for booleans */ if (defopt[it].type == pdc_booleanlist) { if (isequal || (keyword[1] != 0 && !pdc_stricmp(&keyword[2], defopt[it].name))) { iss = is + 1; if (iss == nitems || (pdc_stricmp(items[iss], "true") && pdc_stricmp(items[iss], "false"))) { i = pdc_strincmp(defopt[it].name, "no", 2) ? 0 : 2; if (!pdc_strincmp(&keyword[i], "no", 2)) { boolval = pdc_false; break; } else if (isequal) { boolval = pdc_true; break; } } } } if (isequal) break; } if (logg5) pdc_logg(pdc, "\t\t\toption \"%s\" specified: ", keyword); if (it == numdef) { errcode = PDC_E_OPT_UNKNOWNKEY; goto PDC_OPT_SYNTAXERROR; } /* initialize */ dopt = &defopt[it]; ignore = pdc_false; nvalues = 1; values = NULL; ishandle = pdc_true; /* compatibility */ if (clientdata && clientdata->compatibility) { int compatibility = clientdata->compatibility; for (iv = PDC_1_3; iv <= PDC_X_X_LAST; iv++) { if (logg5 && (dopt->flags & (1L<<iv))) pdc_logg(pdc, "(compatibility >= %s) ", pdc_get_pdfversion(pdc, iv)); if ((dopt->flags & (1L<<iv)) && compatibility < iv) { if (logg5) pdc_logg(pdc, "\n"); stemp2 = pdc_get_pdfversion(pdc, compatibility); errcode = PDC_E_OPT_VERSION; goto PDC_OPT_SYNTAXERROR; } } } /* not supported */ if (dopt->flags & PDC_OPT_UNSUPP) { if (logg5) pdc_logg(pdc, "(unsupported)\n"); keyword = (char *) dopt->name; errcode = PDC_E_OPT_UNSUPP; goto PDC_OPT_SYNTAXERROR; } /* parse values */ if (boolval == pdc_undef) { is++; if (is == nitems) { errcode = PDC_E_OPT_NOVALUES; goto PDC_OPT_SYNTAXERROR; } if (!ignore) { if (dopt->type == pdc_stringlist && pdc_is_utf8_bytecode(items[is])) resopt[it].flags |= PDC_OPT_ISUTF8; if (dopt->type != pdc_stringlist || dopt->maxnum > 1) nvalues = pdc_split_stringlist(pdc, items[is], (dopt->flags & PDC_OPT_SUBOPTLIST) ? PDC_OPT_LISTSEPS : NULL, PDC_SPLIT_ISOPTLIST, &values); if (dopt->flags & PDC_OPT_DUPORIGVAL) resopt[it].origval = pdc_strdup(pdc, items[is]); } } /* ignore */ if (ignore) continue; /* number of values check */ if (nvalues < dopt->minnum) { stemp2 = pdc_errprintf(pdc, "%d", dopt->minnum); errcode = PDC_E_OPT_TOOFEWVALUES; goto PDC_OPT_SYNTAXERROR; } else if (nvalues > dopt->maxnum) { stemp2 = pdc_errprintf(pdc, "%d", dopt->maxnum); errcode = PDC_E_OPT_TOOMANYVALUES; goto PDC_OPT_SYNTAXERROR; } /* number of values must be even */ if (dopt->flags & PDC_OPT_EVENNUM && (nvalues % 2)) { errcode = PDC_E_OPT_ODDNUM; goto PDC_OPT_SYNTAXERROR; } /* number of values must be odd */ if (dopt->flags & PDC_OPT_ODDNUM && !(nvalues % 2)) { errcode = PDC_E_OPT_EVENNUM; goto PDC_OPT_SYNTAXERROR; } /* deprecated option since PDFlib 7 */ if (dopt->flags & PDC_OPT_PDFLIB_7) { pdc_logg_cond(pdc, 2, trc_api, "[Option \"%s\" is deprecated since PDFlib 7]\n", keyword); } /* option already exists */ if (resopt[it].num) { pdc_delete_optvalue(pdc, &resopt[it]); } /* no values */ if (!nvalues ) continue; /* maximal value */ switch (dopt->type) { case pdc_3ddatahandle: maxval = clientdata->max3ddata; break; case pdc_3dviewhandle: maxval = clientdata->max3dview; break; case pdc_actionhandle: maxval = clientdata->maxaction; break; case pdc_bookmarkhandle: maxval = clientdata->maxbookmark; break; case pdc_colorhandle: maxval = clientdata->maxcolor; break; case pdc_documenthandle: maxval = clientdata->maxdocument; break; case pdc_fonthandle: maxval = clientdata->maxfont; break; case pdc_gstatehandle: maxval = clientdata->maxgstate; break; case pdc_iccprofilehandle: maxval = clientdata->maxiccprofile; break; case pdc_imagehandle: maxval = clientdata->maximage; break; case pdc_layerhandle: maxval = clientdata->maxlayer; break; case pdc_pagehandle: maxval = clientdata->maxpage; break; case pdc_patternhandle: maxval = clientdata->maxpattern; break; case pdc_shadinghandle: maxval = clientdata->maxshading; break; case pdc_tablehandle: maxval = clientdata->maxtable; break; case pdc_templatehandle: maxval = clientdata->maxtemplate; break; case pdc_textflowhandle: maxval = clientdata->maxtextflow; break; case pdc_stringhandle: maxval = clientdata->maxstring; break; case pdc_polylinelist: ncoords = 0; default: maxval = dopt->maxval; ishandle = pdc_false; break; } /* allocate value array */ resopt[it].val = pdc_calloc(pdc, (size_t) (nvalues * pdc_typesizes[dopt->type]), fn); resopt[it].num = nvalues; resopt[it].currind = it; if (dopt->flags & PDC_OPT_PERCENT) memset(resopt[it].pcbits, 0, PDC_PCBITS_SIZE); if (logg5) pdc_logg(pdc, "{"); /* analyze type */ resval = resopt[it].val; for (iv = 0; iv < nvalues; iv++) { errcode = 0; if (dopt->maxnum > 1 && nvalues) value = values[iv]; else value = items[is]; if (logg5) pdc_logg(pdc, "%s{%T}", iv ? " " : "", value, 0); switch (dopt->type) { /* boolean list */ case pdc_booleanlist: if (boolval == pdc_true || !pdc_stricmp(value, "true")) { *(pdc_bool *) resval = pdc_true; } else if (boolval == pdc_false || !pdc_stricmp(value, "false")) { *(pdc_bool *) resval = pdc_false; } else { errcode = PDC_E_OPT_ILLBOOLEAN; } break; /* string list */ case pdc_stringlist: if (dopt->flags & PDC_OPT_NOSPACES) { if (pdc_split_stringlist(pdc, value, NULL, 0, &strings) > 1) errcode = PDC_E_OPT_ILLSPACES; pdc_cleanup_stringlist(pdc, strings); } if (!errcode) { len = strlen(value); dz = (double) len; if (dz < dopt->minval) { stemp3 = pdc_errprintf(pdc, "%d", (int) dopt->minval); errcode = PDC_E_OPT_TOOSHORTSTR; } else if (dz > maxval) { stemp3 = pdc_errprintf(pdc, "%d", (int) maxval); errcode = PDC_E_OPT_TOOLONGSTR; } if (dopt->flags & PDC_OPT_CONVUTF8) { int flags = PDC_CONV_EBCDIC | PDC_CONV_WITHBOM; if (isutf8 || (resopt[it].flags & PDC_OPT_ISUTF8)) flags |= PDC_CONV_ISUTF8; *((char **) resval) = pdc_convert_name(pdc, value, 0, flags); } else { *((char **) resval) = pdc_strdup(pdc, value); } } break; /* keyword list */ case pdc_keywordlist: if (dopt->flags & PDC_OPT_CASESENS) iz = pdc_get_keycode(value, dopt->keylist); else iz = pdc_get_keycode_ci(value, dopt->keylist); if (iz == PDC_KEY_NOTFOUND) { errcode = PDC_E_OPT_ILLKEYWORD; } else { *(int *) resval = iz; } break; /* character list */ case pdc_unicharlist: iz = pdc_string2unicode(pdc, value, dopt->flags, dopt->keylist, pdc_false); if (iz < 0) { errcode = PDC_E_OPT_ILLCHAR; break; } dz = iz; if (dz < dopt->minval) { stemp3 = pdc_errprintf(pdc, "%g", dopt->minval); errcode = PDC_E_OPT_TOOSMALLVAL; } else if (dz > maxval) { stemp3 = pdc_errprintf(pdc, "%g", maxval); errcode = PDC_E_OPT_TOOBIGVAL; } *(int *) resval = iz; break; /* string list */ case pdc_polylinelist: { int np = pdc_split_stringlist(pdc, value, NULL, 0, &strings); pdc_polyline *pl = (pdc_polyline *) resval; pl->np = np / 2; pl->p = NULL; /* number of coordinates must be even */ if (np % 2) { errcode = PDC_E_OPT_ODDNUM; np = 0; } /* polyline must be a box */ else if ((dopt->flags & PDC_OPT_ISBOX) && np != 4) { errcode = PDC_E_OPT_ILLBOX; np = 0; } /* polyline will be closed */ else if ((dopt->flags & PDC_OPT_CLOSEPOLY) && np <= 4) { errcode = PDC_E_OPT_ILLPOLYLINE; np = 0; } /* polyline not empty */ if (np) { if (dopt->flags & PDC_OPT_CLOSEPOLY) pl->np += 1; pl->p = (pdc_vector *) pdc_malloc(pdc, pl->np * sizeof(pdc_vector), fn); iz = PDC_KEY_NOTFOUND; j = 0; icoord = ncoords; for (i = 0; i < np; i++) { char *sk = strings[i]; if (dopt->keylist) { /* optional keyword list */ if (dopt->flags & PDC_OPT_CASESENS) iz = pdc_get_keycode(sk, dopt->keylist); else iz = pdc_get_keycode_ci(sk, dopt->keylist); } if (iz == PDC_KEY_NOTFOUND) { /* percentage */ if (dopt->flags & PDC_OPT_PERCENT) { k = (int) strlen(sk) - 1; if (sk[k] == '%') { sk[k] = 0; if (ncoords < PDC_MAX_PERCENTS) { pdc_setbit(resopt[it].pcbits, ncoords); } else { errcode = PDC_E_OPT_TOOMANYPERCVALS; } } } retval = pdc_str2double(sk, &dz); if (!retval) { errcode = PDC_E_OPT_ILLNUMBER; } else if (pdc_getbit(resopt[it].pcbits, ncoords)) { if (dopt->flags & PDC_OPT_PERCRANGE) { if (dz < 0) errcode = PDC_E_OPT_TOOSMALLPERCVAL; if (dz > 100) errcode = PDC_E_OPT_TOOBIGPERCVAL; } dz /= 100.0; } } else { dz = (double) iz; } if (!(i % 2)) { pl->p[j].x = dz; } else { pl->p[j].y = dz; j++; } ncoords++; } if (dopt->flags & PDC_OPT_CLOSEPOLY) { pl->p[pl->np - 1] = pl->p[0]; if (pdc_getbit(resopt[it].pcbits, icoord)) pdc_setbit(resopt[it].pcbits, ncoords); ncoords++; if (pdc_getbit(resopt[it].pcbits, icoord + 1)) pdc_setbit(resopt[it].pcbits, ncoords); ncoords++; } } pdc_cleanup_stringlist(pdc, strings); } break; /* number list */ case pdc_3ddatahandle: case pdc_3dviewhandle: case pdc_actionhandle: case pdc_bookmarkhandle: case pdc_colorhandle: case pdc_documenthandle: case pdc_fonthandle: case pdc_gstatehandle: case pdc_iccprofilehandle: case pdc_imagehandle: case pdc_layerhandle: case pdc_pagehandle: case pdc_patternhandle: case pdc_shadinghandle: case pdc_tablehandle: case pdc_templatehandle: case pdc_textflowhandle: case pdc_integerlist: case pdc_floatlist: case pdc_doublelist: case pdc_scalarlist: if (dopt->keylist && (!(dopt->flags & PDC_OPT_KEYLIST1) || !iv)) { /* optional keyword and/or allowed integer list */ if (dopt->flags & PDC_OPT_CASESENS) iz = pdc_get_keycode(value, dopt->keylist); else iz = pdc_get_keycode_ci(value, dopt->keylist); if (iz == PDC_KEY_NOTFOUND) { if (dopt->flags & PDC_OPT_INTLIST) { errcode = PDC_E_OPT_ILLINTEGER; break; } } else { switch (dopt->type) { default: case pdc_integerlist: *(int *) resval = iz; break; case pdc_floatlist: *(float *) resval = (float) iz; break; case pdc_doublelist: *(double *) resval = (double) iz; break; case pdc_scalarlist: *(pdc_scalar *) resval = (pdc_scalar) iz; break; } break; } } /* percentage */ if (dopt->flags & PDC_OPT_PERCENT) { i = (int) strlen(value) - 1; if (value[i] == '%') { value[i] = 0; if (iv < PDC_MAX_PERCENTS) { pdc_setbit(resopt[it].pcbits, iv); } else { errcode = PDC_E_OPT_TOOMANYPERCVALS; } } } case pdc_stringhandle: if (dopt->type == pdc_floatlist || dopt->type == pdc_doublelist || dopt->type == pdc_scalarlist) { retval = pdc_str2double(value, &dz); } else { if (dopt->minval >= 0) { retval = pdc_str2integer(value, PDC_INT_UNSIGNED, &ulz); dz = ulz; } else { retval = pdc_str2integer(value, 0, &lz); dz = lz; } if (retval && ishandle && pdc->hastobepos && dopt->type != pdc_bookmarkhandle && dopt->type != pdc_stringhandle) { dz -= 1; lz = (pdc_sint32) dz; ulz = (pdc_uint32) dz; } } if (!retval) { errcode = PDC_E_OPT_ILLNUMBER; } else { if (pdc_getbit(resopt[it].pcbits, iv)) { if (dopt->flags & PDC_OPT_PERCRANGE) { if (dz < 0) errcode = PDC_E_OPT_TOOSMALLPERCVAL; if (dz > 100) errcode = PDC_E_OPT_TOOBIGPERCVAL; } dz /= 100.0; } if (errcode == 0) { if (dz < dopt->minval) { if (ishandle) { stemp3 = pdc_get_keyword(dopt->type, pdc_handletypes); errcode = PDC_E_OPT_ILLHANDLE; } else { stemp3 = pdc_errprintf(pdc, "%g", dopt->minval); errcode = PDC_E_OPT_TOOSMALLVAL; } } else if (dz > maxval) { if (ishandle) { stemp3 = pdc_get_keyword(dopt->type, pdc_handletypes); errcode = PDC_E_OPT_ILLHANDLE; } else { stemp3 = pdc_errprintf(pdc, "%g", maxval); errcode = PDC_E_OPT_TOOBIGVAL; } } else if (dopt->flags & PDC_OPT_NOZERO && fabs(dz) < PDC_FLOAT_PREC) { errcode = PDC_E_OPT_ZEROVAL; } else if (dopt->type == pdc_scalarlist) { *(pdc_scalar *) resval = dz; } else if (dopt->type == pdc_doublelist) { *(double *) resval = dz; } else if (dopt->type == pdc_floatlist) { *(float *) resval = (float) dz; } else { if (dopt->minval >= 0) *(pdc_uint32 *) resval = ulz; else *(pdc_sint32 *) resval = lz; } } } break; } if (errcode) { stemp2 = pdc_errprintf(pdc, "%.*s", PDC_ERR_MAXSTRLEN, value); goto PDC_OPT_SYNTAXERROR; } /* increment value pointer */ resval = (void *) ((char *)(resval) + pdc_typesizes[dopt->type]); } pdc_cleanup_stringlist(pdc, values); values = NULL; if (logg5) pdc_logg(pdc, "}\n"); /* build OR bit pattern */ if (dopt->flags & PDC_OPT_BUILDOR && nvalues > 1) { int *bcode = (int *) resopt[it].val; for (iv = 1; iv < nvalues; iv++) { bcode[0] |= bcode[iv]; } resopt[it].num = 1; } } pdc_cleanup_stringlist(pdc, items); items = NULL; /* required and to be ignored options */ for (is = 0; tocheck && is < numdef; is++) { /* to be ignored option */ if (resopt[is].num) { nd = 0; if (defopt[is].flags & PDC_OPT_IGNOREIF1) nd = 1; if (defopt[is].flags & PDC_OPT_IGNOREIF2) nd = 2; for (it = is - 1; it >= is - nd && it >= 0; it--) { if (resopt[it].num) { pdc_delete_optvalue(pdc, &resopt[is]); if (verbose) pdc_warning(pdc, PDC_E_OPT_IGNORE, defopt[is].name, defopt[it].name, 0, 0); } } } /* required option */ if (!resopt[is].num && ((defopt[is].flags & PDC_OPT_REQUIRED) || (defopt[is].flags & PDC_OPT_REQUIRIF1 && resopt[is-1].num) || (defopt[is].flags & PDC_OPT_REQUIRIF2 && (resopt[is-1].num || resopt[is-2].num)))) { keyword = (char *) defopt[is].name; errcode = PDC_E_OPT_NOTFOUND; goto PDC_OPT_SYNTAXERROR; } } /* is no sorted */ if (!issorted) { qsort((void *)resopt, (size_t) numdef, sizeof(pdc_resopt), pdc_optname_compare); } /* global UTF-8 check after sort */ if (isutf8) resopt[0].isutf8 = pdc_true; /* index of last got option */ resopt[0].lastind = -1; /* protocol */ if (pdc_logg_is_enabled(pdc, 1, trc_optlist)) { for (is = 0; is < numdef; is++) { if (resopt[is].num) pdc_logg(pdc, "\tOption \"%s\": %d value%s found\n", resopt[is].defopt->name, resopt[is].num, resopt[is].num == 1 ? "" : "s"); else if (logg5) pdc_logg(pdc, "\t\t\toption \"%s\" not specified\n", resopt[is].defopt->name); for (iv = 0; iv < resopt[is].num; iv++) { switch (resopt[is].defopt->type) { case pdc_booleanlist: case pdc_keywordlist: case pdc_integerlist: case pdc_3ddatahandle: case pdc_3dviewhandle: case pdc_actionhandle: case pdc_bookmarkhandle: case pdc_colorhandle: case pdc_documenthandle: case pdc_fonthandle: case pdc_gstatehandle: case pdc_iccprofilehandle: case pdc_imagehandle: case pdc_layerhandle: case pdc_pagehandle: case pdc_patternhandle: case pdc_shadinghandle: case pdc_tablehandle: case pdc_templatehandle: case pdc_textflowhandle: case pdc_stringhandle: pdc_logg(pdc, "\tValue %d: %d\n", iv + 1, *((int *) resopt[is].val + iv)); break; case pdc_stringlist: pdc_logg(pdc, "\tValue %d: \"%T\"\n", iv + 1, *((char **) resopt[is].val + iv), 0); break; case pdc_floatlist: pdc_logg(pdc, "\tValue %d: %f\n", iv + 1, *((float *) resopt[is].val + iv)); break; case pdc_doublelist: pdc_logg(pdc, "\tValue %d: %f\n", iv + 1, *((double *) resopt[is].val + iv)); break; case pdc_scalarlist: pdc_logg(pdc, "\tValue %d: %f\n", iv + 1, *((pdc_scalar *) resopt[is].val + iv)); break; case pdc_unicharlist: pdc_logg(pdc, "\tValue %d: %d\n", iv + 1, *((int *) resopt[is].val + iv)); break; case pdc_polylinelist: pdc_logg(pdc, "\t\t#%d: ", iv + 1); { pdc_polyline *pl = (pdc_polyline *) resopt[is].val + iv; for (j = 0; j < pl->np; j++) pdc_logg(pdc, "%f,%f ", pl->p[j].x, pl->p[j].y); pdc_logg(pdc, "\n"); } break; } } } } return resopt; PDC_OPT_SYNTAXERROR: stemp1 = pdc_errprintf(pdc, "%.*s", PDC_ERR_MAXSTRLEN, keyword); pdc_cleanup_stringlist(pdc, items); pdc_cleanup_stringlist(pdc, values); pdc_set_errmsg(pdc, errcode, stemp1, stemp2, stemp3, 0); if (verbose) pdc_error(pdc, -1, 0, 0, 0, 0); return NULL; }
/* normalized file name according PDF specification */ void pdc_put_pdffilename(pdc_output *out, const char *text, int len) { static const char *fn = "pdc_put_pdffilename"; pdc_byte *btext = (pdc_byte *) text; pdc_bool isuni = pdc_is_utf16be_unicode(btext); char *ttext; pdc_byte c, cp, cpp; int i, ia = 0, j = 0; ttext = (char *) pdc_calloc(out->pdc, (size_t) (len + 4), fn); if (isuni) { ttext[0] = PDF_BOM0; ttext[1] = PDF_BOM1; ia = 2; j = 2; } /* absolute path name: * r:\pdfdocs\spec.pdf -> /r/pdfdocs/spec.pdf * pclib/eng:\pdfdocs\spec.pdf -> /pclib/eng/pdfdocs/spec.pdf */ cp = 0x7F; for (i = ia; i < len; i++) { c = btext[i]; if (c == PDF_COLON && (!isuni || cp == 0)) { if (isuni) { ttext[j] = 0; j++; } ttext[j] = PDF_SLASH; j++; break; } cp = c; } cp = 0x7F; cpp = 0x7F; for (i = ia; i < len; i++) { c = btext[i]; if ((c == PDF_BACKSLASH || c == PDF_SLASH || c == PDF_COLON) && (!isuni || cp == 0)) { /* convert to slash, but avoid multiple slashes */ if (cpp != PDF_SLASH) { c = PDF_SLASH; } else { if (isuni) j--; continue; } } ttext[j] = c; j++; cp = c; if (c) cpp = c; } len = j; pdc_put_pdfstring(out, ttext, len); pdc_free(out->pdc, ttext); }
pdc_bool pdf_handle_t3font(PDF *p, const char *fontname, pdc_encoding enc, pdf_font *font, int *slot) { static const char fn[] = "pdf_handle_t3font"; const char *encname; char *fname; size_t namlen; pdf_font *deffont = &p->fonts[*slot]; pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc); fnt_font_metric *ftm = &font->ft.m; size_t nalloc; int code, gid; pdc_bool newinst = pdc_false; /* font name incl. encoding name */ encname = pdc_get_user_encoding(p->pdc, enc); namlen = strlen(fontname) + strlen(encname) + 2; fname = (char *) pdc_malloc(p->pdc, namlen, fn); pdc_sprintf(p->pdc, pdc_false, fname, "%s.%s", fontname, encname); /* we have to copy the available font. * otherwise the original font will be changed */ newinst = deffont->ft.enc != pdc_invalidenc; pdc_logg_cond(p->pdc, 1, trc_font, "\n\tType3 font \"%s\" with %d glyphs found\n", fontname, deffont->t3font->next_glyph); if (newinst) { pdc_logg_cond(p->pdc, 1, trc_font, "\tInstance with specified encoding will be created\n"); } /* copy data from available font (see pdf__begin_font()) */ font->ft.m.type = fnt_Type3; font->ft.matrix = deffont->ft.matrix; font->ft.bbox = deffont->ft.bbox; font->t3font = deffont->t3font; font->ft.numglyphs = deffont->t3font->next_glyph; nalloc = (size_t) font->ft.numglyphs; ftm->name = fname; font->ft.name = pdc_strdup(p->pdc, fname); font->ft.enc = enc; font->ft.issymbfont = pdc_false; font->opt.embedding = pdc_true; if (enc >= pdc_winansi) { font->codesize = 1; font->ft.numcodes = 256; font->lastcode = -1; ftm->widths = (int *) pdc_calloc(p->pdc, (size_t) font->ft.numcodes * sizeof(int), fn); ftm->numwidths = font->ft.numcodes; } font->ft.code2gid = (pdc_ushort *) pdc_calloc(p->pdc, (size_t) font->ft.numcodes * sizeof(pdc_ushort), fn); font->ft.gid2code = (pdc_ushort *) pdc_calloc(p->pdc, nalloc * sizeof (pdc_ushort), fn); /* fill up font arrays */ for (gid = 0; gid < font->ft.numglyphs; gid++) { const char *str = NULL, *glyphname = font->t3font->glyphs[gid].name; if (enc >= pdc_winansi) { /* search for code */ for (code = 0; code < font->ft.numcodes; code++) { if (ev->chars[code] != NULL) str = ev->chars[code]; else if (ev->codes[code]) str = pdc_unicode2glyphname(p->pdc, ev->codes[code]); if (str != NULL && !pdc_strcmp(glyphname, str)) break; } /* code found */ if (code < font->ft.numcodes) { font->ft.code2gid[code] = gid; font->ft.gid2code[gid] = code; if (!gid) font->gid0code = code; if (font->opt.monospace) ftm->widths[code] = font->opt.monospace; else ftm->widths[code] = (int) (font->t3font->glyphs[gid].width + 0.5); } } } pdf_type3_protocol(p, font, ev); /* font flags */ if (!pdf_make_fontflag(p, font)) return pdc_false; if (newinst) { *slot = -1; } else { if (deffont->apiname != NULL) pdc_free(p->pdc, deffont->apiname); *deffont = *font; deffont->hasoriginal = pdc_true; } return pdc_true; }
pdc_bool pdf_process_metrics_data( PDF *p, pdf_font *font, const char *fontname) { static const char fn[] = "pdf_process_metrics_data"; fnt_font_metric *ftm = &font->ft.m; int width = 0; pdc_ushort uv; pdc_encoding enc = font->ft.enc; pdc_encodingvector *ev = NULL; int /* nalloc, */ foundglyphs = 0, i, j = 0, k; (void) j; /* Unallowed encoding */ if (enc == pdc_cid || enc < pdc_builtin) { pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0); return pdc_false; } /* Determine the default character width (width of space character) */ if (font->opt.monospace) { ftm->defwidth = font->opt.monospace; } else { width = fnt_get_glyphwidth((int) PDF_DEFAULT_CHAR, &font->ft); if (width != FNT_MISSING_WIDTH) ftm->defwidth = width; else ftm->defwidth = FNT_DEFAULT_WIDTH; } /* builtin font */ if (font->ft.issymbfont == pdc_true && enc != pdc_builtin && !strcmp(font->encapiname, "auto")) { enc = pdc_builtin; font->ft.enc = enc; } /* optimizing PDF output */ if (enc == pdc_ebcdic || enc == pdc_ebcdic_37 || enc == pdc_ebcdic_winansi) font->towinansi = pdc_winansi; /* glyph name list for incore fonts */ /* nalloc = font->ft.numglyphs + AFM_GLYPH_SUPPL; */ /* * Generate character width according to the chosen encoding */ { font->ft.numcodes = 256; font->ft.code2gid = (pdc_ushort *) pdc_calloc(p->pdc, font->ft.numcodes * sizeof (pdc_ushort), fn); ftm->numwidths = font->ft.numcodes; ftm->widths = (int *)pdc_calloc(p->pdc, font->ft.numcodes * sizeof(int), fn); /* Given 8-bit encoding */ if (enc >= 0) { ev = pdc_get_encoding_vector(p->pdc, enc); for (k = 0; k < font->ft.numcodes; k++) { uv = ev->codes[k]; ftm->widths[k] = ftm->defwidth; if (uv) { uv = pdc_get_alter_glyphname(uv, font->missingglyphs, NULL); if (uv) { for (i = 0; i < ftm->numglwidths; i++) { if (ftm->glw[i].unicode == uv) { j = i + 1; ftm->widths[k] = ftm->glw[i].width; font->ft.code2gid[k] = (pdc_ushort) j; foundglyphs++; } } } } } if (ftm->ciw != NULL) { pdc_free(p->pdc, ftm->ciw); ftm->ciw = NULL; } pdc_logg_cond(p->pdc, 2, trc_font, "\t\t%d glyphs could be mapped to Unicode\n", foundglyphs); /* No characters found */ if (!foundglyphs) { if (font->ft.issymbfont == pdc_false) { pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0); return pdc_false; } else { /* We enforce builtin encoding */ pdc_warning(p->pdc, PDF_E_FONT_FORCEENC, pdf_get_encoding_name(p, pdc_builtin, font), 0, 0, 0); enc = pdc_builtin; font->ft.enc = enc; font->towinansi = pdc_invalidenc; } } else if (foundglyphs < PDF_MIN_GLYPHS) { pdc_warning(p->pdc, PDF_E_FONT_INAPPROPENC, pdc_errprintf(p->pdc, "%d", foundglyphs), 0, 0, 0); } } /* built-in encoding */ if (enc == pdc_builtin) { if (ftm->glw == NULL) { pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0); return pdc_false; } /* encoding for builtin */ ev = pdf_create_font_encoding(p, enc, font, fontname, pdc_true); font->symenc = font->ft.enc; /***************************/ font->ft.enc = pdc_builtin; /***************************/ for (i = 0; i < font->ft.numcodes; i++) { ftm->widths[i] = ftm->defwidth; } for (i = 0; i < font->ft.numglyphs; i++) { pdc_short code = ftm->glw[i].code; if (code >= 0 && code < font->ft.numcodes) { j = i + 1; ftm->widths[code] = ftm->glw[i].width; font->ft.code2gid[code] = (pdc_ushort) j; if (ev != NULL) { ev->codes[code] = ftm->glw[i].unicode; } } } } } if (ftm->glw != NULL) { pdc_free(p->pdc, ftm->glw); ftm->glw = NULL; } return pdc_true; }
static pdc_bool pdf_parse_afm( PDF *p, pdc_file *fp, pdf_font *font, const char *fontname, const char *filename) { static const char fn[] = "pdf_parse_afm"; fnt_font_metric *ftm = &font->ft.m; const char *afmtype = NULL; char **wordlist = NULL, *keyword, *arg1; char line[AFM_LINEBUF]; int i, cmp, lo, hi, nwords, nglyphs = 0, nline = 0; int tablen = ((sizeof keyStrings) / (sizeof (char *))); pdc_sint32 iz; double dz; pdc_scalar charwidth = -1; pdf_afmkey keynumber; fnt_glyphwidth *glw; pdc_bool toskip = pdc_false; pdc_bool is_zadbfont = !strcmp(fontname, "ZapfDingbats"); /* all new glyph names of AGL 2.0 are missing */ font->missingglyphs = 0xFFFFFFFF; /* read loop. because of Mac files we use pdc_fgetline */ while (pdc_fgetline(line, AFM_LINEBUF, fp) != NULL) { /* split line */ nline++; nwords = pdc_split_stringlist(p->pdc, line, AFM_SEPARATORS, 0, &wordlist); if (!nwords) continue; keyword = wordlist[0]; /* find keynumber */ lo = 0; hi = tablen; keynumber = NOPE; while (lo < hi) { i = (lo + hi) / 2; cmp = strcmp(keyword, keyStrings[i]); if (cmp == 0) { keynumber = (pdf_afmkey) i; break; } if (cmp < 0) hi = i; else lo = i + 1; } /* unkown key */ if (keynumber == NOPE) { pdc_warning(p->pdc, PDF_E_T1_AFMBADKEY, keyword, filename, 0,0); goto PDF_PARSECONTD; } if (keynumber == ENDDIRECTION) toskip = pdc_false; if (nwords == 1 || toskip == pdc_true) goto PDF_PARSECONTD; /* key switch */ arg1 = wordlist[1]; switch (keynumber) { case STARTDIRECTION: if (pdc_str2integer(arg1, 0, &iz) != pdc_true) goto PDF_SYNTAXERROR; if (iz) toskip = pdc_true; break; case STARTCOMPFONTMETRICS: afmtype = "ACFM"; goto PDF_SYNTAXERROR; case STARTMASTERFONTMETRICS: afmtype = "AMFM"; goto PDF_SYNTAXERROR; case ISCIDFONT: afmtype = "CID font"; if (!strcmp(arg1, "true")) goto PDF_SYNTAXERROR; break; case FONTNAME: font->ft.name = pdc_strdup(p->pdc, arg1); ftm->name = pdc_strdup(p->pdc, arg1); pdc_logg_cond(p->pdc, 1, trc_font, "\tPostScript font name: \"%s\"\n", ftm->name); break; /* Recognize Multiple Master fonts by last part of name */ case FAMILYNAME: if (!strcmp(wordlist[nwords-1], "MM")) ftm->type = fnt_MMType1; else ftm->type = fnt_Type1; break; /* Default: FontSpecific */ case ENCODINGSCHEME: if (!pdc_stricmp(arg1, "StandardEncoding") || !pdc_stricmp(arg1, "AdobeStandardEncoding")) font->ft.issymbfont = pdc_false; break; case STDHW: if (pdc_str2double(arg1, &dz) != pdc_true) goto PDF_SYNTAXERROR; ftm->StdHW = (int) dz; break; case STDVW: if (pdc_str2double(arg1, &dz) != pdc_true) goto PDF_SYNTAXERROR; ftm->StdVW = (int) dz; break; case WEIGHT: font->ft.weight = fnt_check_weight(fnt_weightname2weight(arg1)); break; case ISFIXEDPITCH: if (!pdc_stricmp(arg1, "false")) ftm->isFixedPitch = pdc_false; else ftm->isFixedPitch = pdc_true; break; /* New AFM 4.1 keyword "CharWidth" implies fixed pitch */ case CHARWIDTH: if (pdc_str2double(arg1, &dz) != pdc_true) goto PDF_SYNTAXERROR; charwidth = dz; ftm->isFixedPitch = pdc_true; break; case ITALICANGLE: { if (pdc_str2double(arg1, &dz) != pdc_true) goto PDF_SYNTAXERROR; ftm->italicAngle = dz; } break; case UNDERLINEPOSITION: if (pdc_str2double(arg1, &dz) != pdc_true) goto PDF_SYNTAXERROR; ftm->underlinePosition = (int) dz; break; case UNDERLINETHICKNESS: if (pdc_str2double(arg1, &dz) != pdc_true) goto PDF_SYNTAXERROR; ftm->underlineThickness = (int) dz; break; case FONTBBOX: { if (nwords != 5) goto PDF_SYNTAXERROR; for (i = 1; i < nwords; i++) { if (pdc_str2double(wordlist[i], &dz) != pdc_true) goto PDF_SYNTAXERROR; if (i == 1) ftm->llx = dz; else if (i == 2) ftm->lly = dz; else if (i == 3) ftm->urx = dz; else if (i == 4) ftm->ury = dz; } } break; case CAPHEIGHT: if (pdc_str2double(arg1, &dz) != pdc_true) goto PDF_SYNTAXERROR; ftm->capHeight = (int) dz; break; case XHEIGHT: if (pdc_str2double(arg1, &dz) != pdc_true) goto PDF_SYNTAXERROR; ftm->xHeight = (int) dz; break; case DESCENDER: if (pdc_str2double(arg1, &dz) != pdc_true) goto PDF_SYNTAXERROR; ftm->descender = (int) dz; break; case ASCENDER: if (pdc_str2double(arg1, &dz) != pdc_true) goto PDF_SYNTAXERROR; ftm->ascender = (int) dz; break; /* Character widths */ case STARTCHARMETRICS: if (pdc_str2integer(arg1, PDC_INT_UNSIGNED, (pdc_sint32 *) &nglyphs) != pdc_true || nglyphs <= 0) goto PDF_SYNTAXERROR; ftm->glw = (fnt_glyphwidth *) pdc_calloc(p->pdc, (size_t) nglyphs * sizeof(fnt_glyphwidth), fn); break; /* Character code */ case CODE: case CODEHEX: if (!nglyphs || !ftm->glw) goto PDF_SYNTAXERROR; if (font->ft.numglyphs >= nglyphs) { nglyphs++; ftm->glw = (fnt_glyphwidth *) pdc_realloc(p->pdc, ftm->glw, (size_t) nglyphs * sizeof(fnt_glyphwidth), fn); } glw = &ftm->glw[font->ft.numglyphs]; if (keynumber == CODE) { if (pdc_str2integer(arg1, 0, &iz) != pdc_true) goto PDF_SYNTAXERROR; } else { if (pdc_str2integer(arg1, PDC_INT_HEXADEC, &iz) != pdc_true) goto PDF_SYNTAXERROR; } glw->code = (pdc_short) iz; glw->unicode = 0; glw->width = (pdc_ushort) (font->opt.monospace ? font->opt.monospace : charwidth); font->ft.numglyphs++; /* Character width and name */ for (i = 2; i < nwords; i++) { if (!strcmp(wordlist[i], "WX") || !strcmp(wordlist[i], "W0X") || !strcmp(wordlist[i], "W")) { i++; if (i == nwords) goto PDF_SYNTAXERROR; if (pdc_str2double(wordlist[i], &dz) != pdc_true) goto PDF_SYNTAXERROR; glw->width = (pdc_ushort) (font->opt.monospace ? font->opt.monospace : dz); } if (!strcmp(wordlist[i], "N")) { i++; if (i == nwords) goto PDF_SYNTAXERROR; /* Unicode value by means of AGL, * internal and private table */ glw->unicode = is_zadbfont ? (pdc_ushort) pdc_zadb2unicode(wordlist[i]): pdc_insert_glyphname(p->pdc, wordlist[i]); pdc_delete_missingglyph_bit(glw->unicode, &font->missingglyphs); } } break; default: break; } PDF_PARSECONTD: pdc_cleanup_stringlist(p->pdc, wordlist); wordlist = NULL; if (keynumber == ENDFONTMETRICS) break; } /* necessary font struct members */ if (font->ft.name == NULL || ftm->glw == NULL) goto PDF_SYNTAXERROR; pdc_fclose(fp); ftm->numglwidths = font->ft.numglyphs; return pdc_true; PDF_SYNTAXERROR: pdc_fclose(fp); pdc_cleanup_stringlist(p->pdc, wordlist); if (afmtype) pdc_set_errmsg(p->pdc, PDF_E_T1_UNSUPP_FORMAT, afmtype, 0, 0, 0); else pdc_set_errmsg(p->pdc, PDC_E_IO_ILLSYNTAX, "AFM ", filename, pdc_errprintf(p->pdc, "%d", nline), 0); return pdc_false; }
pdc_file * pdc_fopen(pdc_core *pdc, const char *filename, const char *qualifier, const pdc_byte *data, size_t size, int flags) { static const char fn[] = "pdc_fopen"; pdc_file *sfp; sfp = (pdc_file *) pdc_calloc(pdc, sizeof(pdc_file), fn); /* initialize */ sfp->pdc = pdc; sfp->filename = pdc_strdup_ext(pdc, filename, 0, fn); if (flags & PDC_FILE_WRITEMODE || flags & PDC_FILE_APPENDMODE) sfp->wrmode = pdc_true; if (data != NULL || size > 0) { /* virtual file */ if (sfp->wrmode) { sfp->data = (pdc_byte *) pdc_calloc(pdc, size, fn); if (data != NULL) { /* append mode */ memcpy(sfp->data, data, size); sfp->pos = sfp->data + size; } else { sfp->pos = sfp->data; } sfp->end = sfp->pos; sfp->limit = sfp->data + size; } else { sfp->data = (pdc_byte *) data; sfp->pos = sfp->data; sfp->end = sfp->data + size; } } else { const char *mode; /* disk file */ if (flags & PDC_FILE_BINARY) mode = READBMODE; else mode = READTMODE; if (flags & PDC_FILE_APPENDMODE) mode = APPENDMODE; else if (flags & PDC_FILE_WRITEMODE) mode = WRITEMODE; sfp->fp = pdc_fopen_logg(pdc, filename, mode); if (sfp->fp == NULL) { pdc_fclose(sfp); if (qualifier == NULL) qualifier = ""; pdc_set_fopen_errmsg(pdc, PDC_E_IO_RDOPEN, qualifier, filename); return NULL; } } return sfp; }
int pdc_read_textfile(pdc_core *pdc, pdc_file *sfp, int flags, char ***linelist) { static const char fn[] = "pdc_read_textfile"; char buf[PDC_BUFSIZE]; char *content = NULL; char **strlist = NULL; int nlines = 0; pdc_off_t filelen; size_t len = 0, sumlen = 0, maxl = 0; pdc_bool tocont = pdc_false; int i, nbs, is = -1; /* get file length */ filelen = pdc_file_size(sfp); if (filelen) { /* allocate content array */ content = (char *) pdc_calloc(pdc, (size_t) filelen, fn); /* read loop */ while (pdc_fgetline(buf, PDC_BUFSIZE, sfp) != NULL) { /* trim white spaces */ if (tocont) pdc_strtrim(buf); else pdc_str2trim(buf); /* skip blank and comment lines */ if (buf[0] == 0 || buf[0] == '%') { tocont = pdc_false; continue; } /* register new line */ if (!tocont) { if (nlines) pdc_logg_cond(pdc, 2, trc_filesearch, "\t\tLine %d; \"%s\"\n", nlines, strlist[nlines - 1]); if (nlines >= (int) maxl) { maxl += PDC_ARGV_CHUNKSIZE; strlist = (strlist == NULL) ? (char **)pdc_malloc(pdc, maxl * sizeof(char *), fn): (char **)pdc_realloc(pdc, strlist, maxl * sizeof(char *), fn); } is += sumlen + 1; strlist[nlines] = &content[is]; nlines++; sumlen = 0; } /* process new line */ nbs = 0; len = strlen(buf); for (i = 0; i < (int) len; i++) { /* backslash found */ if (buf[i] == '\\') { nbs++; } else { /* comment sign found */ if (buf[i] == '%') { if (nbs % 2) { /* masked */ memmove(&buf[i-1], &buf[i], (size_t) (len-i)); len--; buf[len] = 0; } else { buf[i] = 0; len = strlen(buf); } } nbs = 0; } } /* continuation line */ tocont = (nbs % 2) ? pdc_true : pdc_false; if (tocont) { if (flags & PDC_FILE_KEEPLF) buf[len - 1] = '\n'; else len--; } buf[len] = '\0'; /* backslash substitution */ if (flags & PDC_FILE_BSSUBST) { len = (size_t) pdc_subst_backslash(pdc, (pdc_byte *) buf, (int) len, NULL, pdc_bytes, pdc_true); } /* concatenate line */ strcat(&content[is], buf); sumlen += len; } if (!strlist) pdc_free(pdc, content); } if (nlines) pdc_logg_cond(pdc, 2, trc_filesearch, "\t\tLine %d; \"%s\"\n", nlines, strlist[nlines - 1]); *linelist = strlist; return nlines; }
void pdf_add_resource(PDF *p, const char *category, const char *resource) { static const char fn[] = "pdf_add_resource"; pdf_rescategory rescat; pdf_category *cat, *lastcat = NULL; pdf_res *res, *lastres = NULL; char *name; char *value; char *prefix = NULL; size_t len; int k, absolut; /* We no longer raise an error but silently ignore unknown categories */ k = pdc_get_keycode(category, pdf_rescategories); if (k == PDC_KEY_NOTFOUND) return; rescat = (pdf_rescategory) k; /* Read resource configuration file if it is pending */ if (p->resfilepending) { p->resfilepending = pdc_false; pdf_read_resourcefile(p, p->resourcefilename); } /* Find start of this category's resource list, if the category exists */ for (cat = p->resources; cat != (pdf_category *) NULL; cat = cat->next) { lastcat = cat; if (!strcmp(cat->category, category)) break; } if (cat == NULL) { cat = (pdf_category *) pdc_malloc(p->pdc, sizeof(pdf_category), fn); cat->category = pdc_strdup(p->pdc, category); cat->kids = NULL; cat->next = NULL; if (lastcat) lastcat->next = cat; else p->resources = cat; } /* Determine name and value of resource */ absolut = 0; len = strlen(resource); value = strchr(resource, '='); if (value) { len = (size_t) (value - resource); value++; if (*value == '=') { absolut = 1; value++; } /* file name is assumed */ if (value[0] != '\0' && value[0] == '.' && value[1] == '/') { value += 2; } } /* Copy resource name */ name = (char *) pdc_malloc(p->pdc, len + 1, fn); strncpy(name, resource, len); name[len] = 0; pdc_strtrim(name); /* Find resource name in resource list */ for (res = cat->kids; res != (pdf_res *) NULL; res = res->next) { if (!strcmp(res->name, name)) break; lastres = res; } /* New resource */ if (res) { pdc_free(p->pdc, name); } else { res = (pdf_res *) pdc_calloc(p->pdc, sizeof(pdf_res), fn); if (lastres) lastres->next = res; else cat->kids = res; res->prev = lastres; res->name = name; } /* New value */ if (res->value) pdc_free(p->pdc, res->value); res->value = NULL; if (!value) { value = ""; } else if (!absolut && p->prefix) { /* Directory prefix */ prefix = p->prefix; if (prefix[0] != '\0' && prefix[0] == '.' && prefix[1] == '/') prefix += 2; if (prefix) { len = strlen(prefix) + strlen(value) + 6; res->value = (char *) pdc_malloc(p->pdc, len, fn); pdc_file_fullname(prefix, value, res->value); } } if (!res->value) { res->value = pdc_strdup(p->pdc, value); pdc_str2trim(res->value); } #undef PDF_TEST_RESOURCE #ifdef PDF_TEST_RESOURCE printf("%s.%s: '%s'\n", category, res->name, res->value); #endif switch (rescat) { case pdf_FontOutline: case pdf_FontAFM: case pdf_FontPFM: case pdf_HostFont: case pdf_Encoding: case pdf_ICCProfile: if (!strlen(res->name) || !strlen(res->value)) pdc_error(p->pdc, PDF_E_RES_BADRES, resource, category, 0, 0); break; default: break; } }
int pdf_handle_t3font(PDF *p, const char *fontname, pdc_encoding enc, int oldslot) { static const char fn[] = "pdf_handle_t3font"; char *fname; int slot, i; unsigned int namlen; pdc_font *oldfont, *newfont; pdc_encodingvector *ev = p->encodings[enc].ev; oldfont = &p->fonts[oldslot]; /* slot of new font struct - initialized in pdf__load_font */ slot = p->fonts_number; newfont = &p->fonts[slot]; /* font name incl. encoding name */ namlen = strlen(fontname) + (int) strlen(ev->apiname) + 2; fname = (char *) pdc_malloc(p->pdc, namlen, fn); sprintf(fname, "%s.%s", fontname, ev->apiname); /* * This is a fresh font which has never been used. * Enter the new encoding, and we're done. */ if (oldfont->encoding == pdc_invalidenc) { oldfont->encoding = enc; for (i = 0; i < oldfont->numOfCodes; i++) { oldfont->widths[i] = name2width(oldfont->t3font, ev->chars[i]); if (newfont->monospace && oldfont->widths[i]) oldfont->widths[i] = newfont->monospace; } ev->flags |= PDC_ENC_USED; oldfont->name = fname; return oldslot; } p->fonts_number++; /* copy the complete font structure */ memcpy(newfont, oldfont, sizeof(pdc_font)); /* make copies of relevant strings to ensure correct cleanup */ newfont->name = fname; newfont->apiname = pdc_strdup(p->pdc, fontname); /* modify relevant entries */ newfont->used_on_current_page = pdc_false; newfont->encoding = enc; newfont->obj_id = pdc_alloc_id(p->out); newfont->t3font = (pdc_t3font*)pdc_malloc(p->pdc, sizeof(pdc_t3font), fn); pdf_init_t3font_struct(p, newfont->t3font, oldfont->t3font->capacity); /* copy relevant entries of Type 3 structure */ newfont->t3font->charprocs_id = oldfont->t3font->charprocs_id; newfont->t3font->res_id = oldfont->t3font->res_id; newfont->t3font->colorized = oldfont->t3font->colorized; memcpy(&newfont->t3font->matrix, &oldfont->t3font->matrix, sizeof(pdc_matrix)); memcpy(&newfont->t3font->bbox, &oldfont->t3font->bbox, sizeof(pdc_rectangle)); /* copy the glyph/width list from oldfont to newfont */ newfont->t3font->next_glyph = oldfont->t3font->next_glyph; for (i = 0; i < newfont->t3font->next_glyph; ++i) { newfont->t3font->glyphs[i].width = oldfont->t3font->glyphs[i].width; newfont->t3font->glyphs[i].charproc_id = oldfont->t3font->glyphs[i].charproc_id; newfont->t3font->glyphs[i].name = pdc_strdup(p->pdc, oldfont->t3font->glyphs[i].name); } newfont->widths = (int *) pdc_calloc(p->pdc, newfont->numOfCodes * sizeof(int), fn); for (i = 0; i < newfont->numOfCodes; i++) { newfont->widths[i] = name2width(newfont->t3font, p->encodings[enc].ev->chars[i]); if (newfont->monospace && oldfont->widths[i]) newfont->widths[i] = newfont->monospace; } p->encodings[enc].ev->flags |= PDC_ENC_USED; return slot; }
void pdf__begin_font( PDF *p, const char *fontname, float a, float b, float c, float d, float e, float f, const char *optlist) { static const char fn[] = "pdf__begin_font"; pdc_resopt *results; pdc_font *font; float det; int colorized = pdc_false; int slot; /* parsing optlist */ results = pdc_parse_optionlist(p->pdc, optlist, pdf_begin_font_options, NULL, pdc_true); pdc_get_optvalues(p->pdc, "colorized", results, &colorized, NULL); pdc_cleanup_optionlist(p->pdc, results); det = a*d - b*c; if (det == 0) pdc_error(p->pdc, PDC_E_ILLARG_MATRIX, pdc_errprintf(p->pdc, "%f %f %f %f %f %f", a, b, c, d, e, f), 0, 0, 0); /* look for an already existing font */ for (slot = 0; slot < p->fonts_number; slot++) { if (!strcmp(p->fonts[slot].apiname, fontname)) { pdc_error(p->pdc, PDF_E_T3_FONTEXISTS, fontname, 0, 0, 0); } } PDF_SET_STATE(p, pdf_state_font); pdf_init_tstate(p); pdf_init_gstate(p); pdf_init_cstate(p); /* slot for new font struct */ slot = pdf_init_newfont(p); font = &p->fonts[slot]; p->fonts_number++; /* * We store the new font in a font slot marked with "invalidenc" encoding. * When the font is used for the first time we modify the encoding. * Later uses will make a copy if the encoding is different. */ font->type = pdc_Type3; font->obj_id = pdc_alloc_id(p->out); font->name = NULL; font->apiname = pdc_strdup(p->pdc, fontname); font->encoding = pdc_invalidenc; /* initially there is no encoding */ font->widths = (int *) pdc_calloc(p->pdc, font->numOfCodes * sizeof(int), fn); font->t3font = (pdc_t3font*) pdc_malloc(p->pdc, sizeof(pdc_t3font), fn); pdf_init_t3font_struct(p, font->t3font, T3GLYPHS_CHUNKSIZE); font->t3font->fontname = pdc_strdup(p->pdc, fontname); font->t3font->colorized = colorized; /* the resource id is needed until the font dict is written */ font->t3font->res_id = pdc_alloc_id(p->out); font->t3font->matrix.a = a; font->t3font->matrix.b = b; font->t3font->matrix.c = c; font->t3font->matrix.d = d; font->t3font->matrix.e = e; font->t3font->matrix.f = f; /* We won't receive glyph bounding box values for colorized true, * so we use the font matrix to get an approximation instead. * * Writing the font matrix should be optional according to the * PDF reference, but we must write it in order to work around a * display bug in Acrobat. */ if (font->t3font->colorized == pdc_true) { font->t3font->bbox.llx = 0; font->t3font->bbox.lly = 0; font->t3font->bbox.urx = (d-b)/det; font->t3font->bbox.ury = (a-c)/det; } /* * We must store a pointer to the current font because its glyph * definitions may use other fonts and we would be unable to find * "our" current font again. This pointer lives throughout the * font definition, and will be reset in PDF_end_font() below. */ p->t3font = font->t3font; }