/* Copyright (C) 2000 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: zfcid0.c,v 1.7.2.3.2.1 2003/01/17 00:49:06 giles Exp $ */ /* CIDFontType 0 operators */ #include "memory_.h" #include "ghost.h" #include "oper.h" #include "gsmatrix.h" #include "gsccode.h" #include "gsstruct.h" #include "gxfcid.h" #include "gxfont1.h" #include "gxalloc.h" /* for gs_ref_memory_t */ #include "stream.h" /* for files.h */ #include "bfont.h" #include "files.h" #include "ichar.h" #include "ichar1.h" #include "icid.h" #include "idict.h" #include "idparam.h" #include "ifcid.h" #include "ifont1.h" #include "ifont2.h" #include "ifont42.h" #include "store.h" /* Type 1 font procedures (defined in zchar1.c) */ font_proc_glyph_outline(zcharstring_glyph_outline); /* ---------------- CIDFontType 0 (FontType 9) ---------------- */ /* ------ Accessing ------ */ /* Parse a multi-byte integer from a string. */ private int get_index(gs_const_string *pgstr, int count, ulong *pval) { int i; if (pgstr->size < count) return_error(e_rangecheck); *pval = 0; for (i = 0; i < count; ++i) *pval = (*pval << 8) + pgstr->data[i]; pgstr->data += count; pgstr->size -= count; return 0; } /* Get bytes from GlyphData or DataSource. */ private int cid0_read_bytes(gs_font_cid0 *pfont, ulong base, uint count, byte *buf, gs_const_string *pstr) { const font_data *pfdata = pfont_data(pfont); byte *data = buf; int code = 0; /* Check for overflow. */ if (base != (long)base || base > base + count) return_error(e_rangecheck); if (r_has_type(&pfdata->u.cid0.DataSource, t_null)) { /* Get the bytes from GlyphData (a string or array of strings). */ const ref *pgdata = &pfdata->u.cid0.GlyphData; if (r_has_type(pgdata, t_string)) { /* single string */ uint size = r_size(pgdata); if (base >= size || count > size - base) return_error(e_rangecheck); data = pgdata->value.bytes + base; } else { /* array of strings */ /* * The algorithm is similar to the one in * string_array_access_proc in zfont42.c, but it also has to * deal with the case where the requested string crosses array * elements. */ ulong skip = base; uint copied = 0; uint index = 0; ref rstr; uint size; for (;; skip -= size, ++index) { int code = array_get(pgdata, index, &rstr); if (code < 0) return code; if (!r_has_type(&rstr, t_string)) return_error(e_typecheck); size = r_size(&rstr); if (skip < size) break; } size -= skip; if (count <= size) { data = rstr.value.bytes + skip; } else { /* multiple strings needed */ if (data == 0) { /* no buffer provided */ data = gs_alloc_string(pfont->memory, count, "cid0_read_bytes"); if (data == 0) return_error(e_VMerror); code = 1; } memcpy(data, rstr.value.bytes + skip, size); copied = size; while (copied < count) { int code = array_get(pgdata, ++index, &rstr); if (code < 0) goto err; if (!r_has_type(&rstr, t_string)) { code = gs_note_error(e_typecheck); goto err; } size = r_size(&rstr); if (size > count - copied) size = count - copied; memcpy(data + copied, rstr.value.bytes, size); copied += size; } } } } else { /* Get the bytes from DataSource (a stream). */ stream *s; uint nread; check_read_known_file(s, &pfdata->u.cid0.DataSource, return_error); if (sseek(s, base) < 0) return_error(e_ioerror); if (data == 0) { /* no buffer provided */ data = gs_alloc_string(pfont->memory, count, "cid0_read_bytes"); if (data == 0) return_error(e_VMerror); code = 1; } if (sgets(s, data, count, &nread) < 0 || nread != count) { code = gs_note_error(e_ioerror); goto err; } } pstr->data = data; pstr->size = count; return code; err: if (data != buf) gs_free_string(pfont->memory, data, count, "cid0_read_bytes"); return code; } /* Get the CharString data for a CIDFontType 0 font. */ /* This is the glyph_data procedure in the font itself. */ /* Note that pgstr may be NULL. */ private int z9_glyph_data(gs_font_base *pbfont, gs_glyph glyph, gs_const_string *pgstr, int *pfidx) { gs_font_cid0 *pfont = (gs_font_cid0 *)pbfont; const font_data *pfdata = pfont_data(pfont); long glyph_index = (long)(glyph - gs_min_cid_glyph); gs_const_string gstr; ulong fidx; int code; if (!r_has_type(&pfdata->u.cid0.GlyphDirectory, t_null)) { code = font_gdir_get_outline(&pfdata->u.cid0.GlyphDirectory, glyph_index, &gstr); if (code < 0) return code; /* Get the definition from GlyphDirectory. */ if (gstr.data) { code = get_index(&gstr, pfont->cidata.FDBytes, &fidx); if (code < 0) return code; if (fidx >= pfont->cidata.FDArray_size) return_error(e_rangecheck); if (pgstr) *pgstr = gstr; *pfidx = (int)fidx; return code; } } /* Get the definition from the binary data (GlyphData or DataSource). */ if (glyph_index < 0 || glyph_index >= pfont->cidata.common.CIDCount) { *pfidx = 0; if (pgstr) pgstr->data = 0, pgstr->size = 0; return_error(e_undefined); } { byte fd_gd[(MAX_FDBytes + MAX_GDBytes) * 2]; uint num_bytes = pfont->cidata.FDBytes + pfont->cidata.common.GDBytes; ulong base = pfont->cidata.CIDMapOffset + glyph_index * num_bytes; ulong gidx, fidx_next, gidx_next; int rcode = cid0_read_bytes(pfont, base, (ulong)(num_bytes * 2), fd_gd, &gstr); gs_const_string orig_str; if (rcode < 0) return rcode; orig_str = gstr; if ((code = get_index(&gstr, pfont->cidata.FDBytes, &fidx)) < 0 || (code = get_index(&gstr, pfont->cidata.common.GDBytes, &gidx)) < 0 || (code = get_index(&gstr, pfont->cidata.FDBytes, &fidx_next)) < 0 || (code = get_index(&gstr, pfont->cidata.common.GDBytes, &gidx_next)) < 0 ) DO_NOTHING; if (rcode > 0) gs_free_const_string(pfont->memory, orig_str.data, orig_str.size, "z9_glyph_data"); if (code < 0) return code; /* * Some CID fonts (from Adobe!) have invalid font indexes for * missing glyphs. Handle this now. */ if (gidx_next <= gidx) { /* missing glyph */ *pfidx = 0; if (pgstr) pgstr->data = 0, pgstr->size = 0; return_error(e_undefined); } if (fidx >= pfont->cidata.FDArray_size) return_error(e_rangecheck); *pfidx = (int)fidx; if (pgstr == 0) return 0; return cid0_read_bytes(pfont, gidx, gidx_next - gidx, NULL, pgstr); } } /* Get the outline of a CIDFontType 0 glyph. */ private int z9_glyph_outline(gs_font *font, gs_glyph glyph, const gs_matrix *pmat, gx_path *ppath) { gs_font_cid0 *const pfcid = (gs_font_cid0 *)font; ref gref; gs_const_string gstr; int code, fidx, ocode; code = pfcid->cidata.glyph_data((gs_font_base *)pfcid, glyph, &gstr, &fidx); if (code < 0) return code; glyph_ref(glyph, &gref); ocode = zcharstring_outline(pfcid->cidata.FDArray[fidx], &gref, &gstr, pmat, ppath); if (code > 0) gs_free_const_string(font->memory, gstr.data, gstr.size, "z9_glyph_outline"); return ocode; } /* * The "fonts" in the FDArray don't have access to their outlines -- the * outlines are always provided externally. Replace the accessor procedures * with ones that will give an error if called. */ private int z9_FDArray_glyph_data(gs_font_type1 * pfont, gs_glyph glyph, gs_const_string * pgdata) { return_error(e_invalidfont); } private int z9_FDArray_seac_data(gs_font_type1 *pfont, int ccode, gs_glyph *pglyph, gs_const_string *pstr) { return_error(e_invalidfont); } /* ------ Defining ------ */ /* Get one element of a FDArray. */ private int fd_array_element(i_ctx_t *i_ctx_p, gs_font_type1 **ppfont, ref *prfd) { charstring_font_refs_t refs; gs_type1_data data1; build_proc_refs build; gs_font_base *pbfont; gs_font_type1 *pfont; /* * Standard CIDFontType 0 fonts have Type 1 fonts in the FDArray, but * CFF CIDFontType 0 fonts have Type 2 fonts there. */ int fonttype = 1; /* default */ int code = charstring_font_get_refs(prfd, &refs); if (code < 0 || (code = dict_int_param(prfd, "FontType", 1, 2, 1, &fonttype)) < 0 ) return code; /* * We don't handle the alternate Subr representation (SubrCount, * SDBytes, SubrMapOffset) here: currently that is handled in * PostScript code (lib/gs_cidfn.ps). */ switch (fonttype) { case 1: data1.interpret = gs_type1_interpret; data1.subroutineNumberBias = 0; data1.lenIV = DEFAULT_LENIV_1; code = charstring_font_params(prfd, &refs, &data1); if (code < 0) return code; code = build_proc_name_refs(&build, "%Type1BuildChar", "%Type1BuildGlyph"); break; case 2: code = type2_font_params(prfd, &refs, &data1); if (code < 0) return code; code = charstring_font_params(prfd, &refs, &data1); if (code < 0) return code; code = build_proc_name_refs(&build, "%Type2BuildChar", "%Type2BuildGlyph"); break; default: /* can't happen */ return_error(e_Fatal); } if (code < 0) return code; code = build_gs_FDArray_font(i_ctx_p, prfd, &pbfont, fonttype, &st_gs_font_type1, &build); if (code < 0) return code; pfont = (gs_font_type1 *)pbfont; charstring_font_init(pfont, &refs, &data1); pfont->data.procs.glyph_data = z9_FDArray_glyph_data; pfont->data.procs.seac_data = z9_FDArray_seac_data; *ppfont = pfont; return 0; } /* .buildfont9 */ gs_private_st_ptr(st_gs_font_type1_ptr, gs_font_type1 *, "gs_font_type1 *", font1_ptr_enum_ptrs, font1_ptr_reloc_ptrs); gs_private_st_element(st_gs_font_type1_ptr_element, gs_font_type1 *, "gs_font_type1 *[]", font1_ptr_element_enum_ptrs, font1_ptr_element_reloc_ptrs, st_gs_font_type1_ptr); private int zbuildfont9(i_ctx_t *i_ctx_p) { os_ptr op = osp; build_proc_refs build; int code = build_proc_name_refs(&build, NULL, "%Type9BuildGlyph"); gs_font_cid_data common; ref GlyphDirectory, GlyphData, DataSource; ref *prfda; gs_font_type1 **FDArray; uint FDArray_size; int FDBytes; uint CIDMapOffset; gs_font_base *pfont; gs_font_cid0 *pfcid; uint i; /* * If the CIDFont's data have been loaded into VM, GlyphData will be * a string or an array of strings; if they are loaded incrementally * from a file, GlyphData will be an integer, and DataSource will be * a (reusable) stream. */ if (code < 0 || (code = cid_font_data_param(op, &common, &GlyphDirectory)) < 0 || (code = dict_find_string(op, "FDArray", &prfda)) < 0 || (code = dict_int_param(op, "FDBytes", 0, MAX_FDBytes, -1, &FDBytes)) < 0 ) return code; if (r_has_type(&GlyphDirectory, t_null)) { /* Standard CIDFont, require GlyphData and CIDMapOffset. */ ref *pGlyphData; if ((code = dict_find_string(op, "GlyphData", &pGlyphData)) < 0 || (code = dict_uint_param(op, "CIDMapOffset", 0, max_uint - 1, max_uint, &CIDMapOffset)) < 0) return code; GlyphData = *pGlyphData; if (r_has_type(&GlyphData, t_integer)) { ref *pds; stream *ignore_s; if ((code = dict_find_string(op, "DataSource", &pds)) < 0) return code; check_read_file(ignore_s, pds); DataSource = *pds; } else { if (!r_has_type(&GlyphData, t_string) && !r_is_array(&GlyphData)) return_error(e_typecheck); make_null(&DataSource); } } else { make_null(&GlyphData); make_null(&DataSource); CIDMapOffset = 0; } if (!r_is_array(prfda)) return_error(e_invalidfont); FDArray_size = r_size(prfda); if (FDArray_size == 0) return_error(e_invalidfont); FDArray = ialloc_struct_array(FDArray_size, gs_font_type1 *, &st_gs_font_type1_ptr_element, "buildfont9(FDarray)"); if (FDArray == 0) return_error(e_VMerror); memset(FDArray, 0, sizeof(gs_font_type1 *) * FDArray_size); for (i = 0; i < FDArray_size; ++i) { ref rfd; array_get(prfda, (long)i, &rfd); code = fd_array_element(i_ctx_p, &FDArray[i], &rfd); if (code < 0) goto fail; } code = build_gs_simple_font(i_ctx_p, op, &pfont, ft_CID_encrypted, &st_gs_font_cid0, &build, bf_Encoding_optional | bf_UniqueID_ignored); if (code < 0) goto fail; pfont->procs.enumerate_glyph = gs_font_cid0_enumerate_glyph; pfont->procs.glyph_outline = z9_glyph_outline; pfcid = (gs_font_cid0 *)pfont; pfcid->cidata.common = common; pfcid->cidata.CIDMapOffset = CIDMapOffset; pfcid->cidata.FDArray = FDArray; pfcid->cidata.FDArray_size = FDArray_size; pfcid->cidata.FDBytes = FDBytes; pfcid->cidata.glyph_data = z9_glyph_data; pfcid->cidata.proc_data = 0; /* for GC */ ref_assign(&pfont_data(pfont)->u.cid0.GlyphDirectory, &GlyphDirectory); ref_assign(&pfont_data(pfont)->u.cid0.GlyphData, &GlyphData); ref_assign(&pfont_data(pfont)->u.cid0.DataSource, &DataSource); code = define_gs_font((gs_font *)pfont); if (code >= 0) return code; fail: ifree_object(FDArray, "buildfont9(FDarray)"); return code; } /* .type9mapcid */ private int ztype9mapcid(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_font *pfont; gs_font_cid0 *pfcid; int code = font_param(op - 1, &pfont); gs_const_string gstr; int fidx; if (code < 0) return code; if (pfont->FontType != ft_CID_encrypted) return_error(e_invalidfont); check_type(*op, t_integer); pfcid = (gs_font_cid0 *)pfont; code = pfcid->cidata.glyph_data((gs_font_base *)pfcid, (gs_glyph)(gs_min_cid_glyph + op->value.intval), &gstr, &fidx); /* return code; original error-sensitive & fragile code */ if (code < 0) { /* failed to load glyph data, put CID 0 */ int default_fallback_CID = 0 ; if_debug2('J', "[J]ztype9cidmap() use CID %d instead of glyph-missing CID %d\n", default_fallback_CID, op->value.intval); op->value.intval = default_fallback_CID; /* reload glyph for default_fallback_CID */ code = pfcid->cidata.glyph_data((gs_font_base *)pfcid, (gs_glyph)(gs_min_cid_glyph + default_fallback_CID), &gstr, &fidx); if (code < 0) { if_debug1('J', "[J]ztype9cidmap() could not load default glyph (CID %d)\n", op->value.intval); return_error(e_invalidfont); } } make_const_string(op - 1, a_readonly | imemory_space((gs_ref_memory_t *)pfont->memory), gstr.size, gstr.data); make_int(op, fidx); return code; } #if defined(DEBUG) || defined(PROFILE) #include "gdevpsf.h" /* .writefont9 - */ private int zwritefont9(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_font *pfont; gs_font_cid0 *pfcid; int code = font_param(op, &pfont); stream *s; if (code < 0) return code; if (pfont->FontType != ft_CID_encrypted) return_error(e_invalidfont); check_write_file(s, op - 1); pfcid = (gs_font_cid0 *)pfont; code = psf_write_cid0_font(s, pfcid, WRITE_TYPE2_NO_LENIV | WRITE_TYPE2_CHARSTRINGS, NULL, 0, NULL); if (code >= 0) pop(2); return code; } #endif /* ------ Initialization procedure ------ */ const op_def zfcid0_op_defs[] = { {"2.buildfont9", zbuildfont9}, {"2.type9mapcid", ztype9mapcid}, #if defined(DEBUG) || defined(PROFILE) {"2.writefont9", zwritefont9}, #endif op_def_end(0) };