Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1997, 1998, 1999, 2000 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: zfcmap.c,v 1.17 2005/10/04 06:30:02 ray Exp $ */
18
/* CMap creation operator */
19
#include "memory_.h"
20
#include "ghost.h"
21
#include "oper.h"
22
#include "gsmatrix.h"		/* for gxfont.h */
23
#include "gsstruct.h"
24
#include "gsutil.h"		/* for bytes_compare */
25
#include "gxfcmap1.h"
26
#include "gxfont.h"
27
#include "ialloc.h"
28
#include "icid.h"
29
#include "iddict.h"
30
#include "idparam.h"
31
#include "ifont.h"		/* for zfont_mark_glyph_name */
32
#include "iname.h"
33
#include "store.h"
34
 
35
/* Exported for zfont0.c */
36
int ztype0_get_cmap(const gs_cmap_t ** ppcmap, const ref * pfdepvector,
37
		    const ref * op, gs_memory_t *imem);
38
 
39
/*
40
 * Define whether to check the compatibility of CIDSystemInfo between the
41
 * CMap and the composite font.  PLRM2 says compatibility is required, but
42
 * PLRM3 says the interpreter doesn't check it.
43
 */
44
/*#define CHECK_CID_SYSTEM_INFO_COMPATIBILITY*/
45
 
46
/* ---------------- Internal procedures ---------------- */
47
 
48
/* Free a code map in case of VMerror. */
49
private void
50
free_code_map(gx_code_map_t * pcmap, gs_memory_t * mem)
51
{
52
    if (pcmap->lookup) {
53
	int i;
54
 
55
	for (i = 0; i < pcmap->num_lookup; ++i) {
56
	    gx_cmap_lookup_range_t *pclr = &pcmap->lookup[i];
57
 
58
	    if (pclr->value_type == CODE_VALUE_GLYPH)
59
		gs_free_string(mem, pclr->values.data, pclr->values.size,
60
			       "free_code_map(values)");
61
	}
62
	gs_free_object(mem, pcmap->lookup, "free_code_map(map)");
63
    }
64
}
65
 
66
/* Convert code ranges to internal form. */
67
private int
68
acquire_code_ranges(gs_cmap_adobe1_t *cmap, const ref *pref, gs_memory_t *mem)
69
{
70
    uint num_ranges = 0;
71
    gx_code_space_range_t *ranges;
72
    uint i, j, elem_sz;
73
    ref elem;
74
 
75
    if (!r_is_array(pref))
76
	return_error(e_rangecheck);
77
    for (i=0; i < r_size(pref); i++) {
78
        int code = array_get(mem, pref, i, &elem);
79
        if (code < 0)
80
            return code;
81
        elem_sz = r_size(&elem);
82
        if (elem_sz & 1)
83
	    return_error(e_rangecheck);
84
        num_ranges += elem_sz;
85
    }
86
    if (num_ranges == 0)
87
	return_error(e_rangecheck);
88
    num_ranges >>= 1;
89
 
90
    ranges = (gx_code_space_range_t *)
91
	gs_alloc_byte_array(mem, num_ranges, sizeof(gx_code_space_range_t),
92
			    "acquire_code_ranges");
93
    if (ranges == 0)
94
	return_error(e_VMerror);
95
    cmap->code_space.ranges = ranges;
96
    cmap->code_space.num_ranges = num_ranges;
97
 
98
    for (i = 0; i < r_size(pref); i++) {
99
        array_get(mem, pref, i, &elem);
100
        elem_sz = r_size(&elem);
101
        for (j = 0; j < elem_sz; j += 2) {
102
	ref rfirst, rlast;
103
	int size;
104
 
105
	    array_get(mem, &elem, j, &rfirst);
106
	    array_get(mem, &elem, j + 1, &rlast);
107
	if (!r_has_type(&rfirst, t_string) ||
108
	    !r_has_type(&rlast, t_string) ||
109
	    (size = r_size(&rfirst)) == 0 || size > MAX_CMAP_CODE_SIZE ||
110
	    r_size(&rlast) != size ||
111
	    memcmp(rfirst.value.bytes, rlast.value.bytes, size) > 0)
112
	    return_error(e_rangecheck);
113
	memcpy(ranges->first, rfirst.value.bytes, size);
114
	memcpy(ranges->last, rlast.value.bytes, size);
115
	ranges->size = size;
116
            ++ranges;
117
        }
118
    }
119
    return 0;
120
}
121
 
122
/* Convert a code map to internal form. */
123
private int
124
acquire_code_map(gx_code_map_t *pcmap, const ref *pref, gs_cmap_adobe1_t *root,
125
		 gs_memory_t *mem)
126
{
127
    uint num_lookup = 0;
128
    gx_cmap_lookup_range_t *pclr;
129
    long i;
130
    ref elem;
131
    uint elem_sz;
132
 
133
    if (!r_is_array(pref))
134
	return_error(e_rangecheck);
135
    for (i=0; i < r_size(pref); i++) {
136
        int code = array_get(mem, pref, i, &elem);
137
        if (code < 0)
138
            return code;
139
        elem_sz = r_size(&elem);
140
        if (elem_sz % 5 != 0)
141
	return_error(e_rangecheck);
142
        num_lookup += elem_sz;
143
    }
144
    num_lookup /= 5;
145
    pclr = gs_alloc_struct_array(mem, num_lookup, gx_cmap_lookup_range_t,
146
				 &st_cmap_lookup_range_element,
147
				 "acquire_code_map(lookup ranges)");
148
    if (pclr == 0)
149
	return_error(e_VMerror);
150
    memset(pclr, 0, sizeof(*pclr) * num_lookup);
151
    pcmap->lookup = pclr;
152
    pcmap->num_lookup = num_lookup;
153
 
154
 
155
    for (i = 0; i < r_size(pref); i++) {
156
        uint j;
157
        array_get(mem, pref, i, &elem);
158
        elem_sz = r_size(&elem);
159
        for (j = 0; j < elem_sz; j += 5) {
160
	ref rprefix, rmisc, rkeys, rvalues, rfxs;
161
 
162
	    array_get(mem, &elem, j, &rprefix);
163
	    array_get(mem, &elem, j + 1, &rmisc);
164
	    array_get(mem, &elem, j + 2, &rkeys);
165
	    array_get(mem, &elem, j + 3, &rvalues);
166
	    array_get(mem, &elem, j + 4, &rfxs);
167
 
168
	if (!r_has_type(&rprefix, t_string) ||
169
	    !r_has_type(&rmisc, t_string) ||
170
	    !r_has_type(&rkeys, t_string) ||
171
	    !(r_has_type(&rvalues, t_string) || r_is_array(&rvalues)) ||
172
	    !r_has_type(&rfxs, t_integer)
173
	    )
174
	    return_error(e_typecheck);
175
	if (r_size(&rmisc) != 4 ||
176
	    rmisc.value.bytes[0] > MAX_CMAP_CODE_SIZE - r_size(&rprefix) ||
177
	    rmisc.value.bytes[1] > 1 ||
178
	    rmisc.value.bytes[2] > CODE_VALUE_MAX ||
179
	    rmisc.value.bytes[3] == 0)
180
	    return_error(e_rangecheck);
181
	pclr->cmap = root;
182
	pclr->key_size = rmisc.value.bytes[0];
183
	pclr->key_prefix_size = r_size(&rprefix);
184
	memcpy(pclr->key_prefix, rprefix.value.bytes, pclr->key_prefix_size);
185
	pclr->key_is_range = rmisc.value.bytes[1];
186
	if (pclr->key_size == 0) {
187
	    /* This is a single entry consisting only of the prefix. */
188
	    if (r_size(&rkeys) != 0)
189
		return_error(e_rangecheck);
190
	    pclr->num_entries = 1;
191
	} else {
192
	    int step = pclr->key_size * (pclr->key_is_range ? 2 : 1);
193
 
194
	    if (r_size(&rkeys) % step != 0)
195
		return_error(e_rangecheck);
196
	    pclr->num_entries = r_size(&rkeys) / step;
197
	}
198
	pclr->keys.data = rkeys.value.bytes,
199
	    pclr->keys.size = r_size(&rkeys);
200
	pclr->value_type = rmisc.value.bytes[2];
201
	pclr->value_size = rmisc.value.bytes[3];
202
	if (r_has_type(&rvalues, t_string)) {
203
	    if (pclr->value_type == CODE_VALUE_GLYPH)
204
		return_error(e_rangecheck);
205
	    if (r_size(&rvalues) % pclr->num_entries != 0 ||
206
		r_size(&rvalues) / pclr->num_entries != pclr->value_size)
207
		return_error(e_rangecheck);
208
	    pclr->values.data = rvalues.value.bytes,
209
		pclr->values.size = r_size(&rvalues);
210
	} else {
211
	    uint values_size = pclr->num_entries * pclr->value_size;
212
	    long k;
213
	    byte *pvalue;
214
 
215
	    if (pclr->value_type != CODE_VALUE_GLYPH ||
216
		r_size(&rvalues) != pclr->num_entries ||
217
		pclr->value_size > sizeof(gs_glyph))
218
		return_error(e_rangecheck);
219
	    pclr->values.data = gs_alloc_string(mem, values_size,
220
						"acquire_code_map(values)");
221
	    if (pclr->values.data == 0)
222
		return_error(e_VMerror);
223
	    pclr->values.size = values_size;
224
	    pvalue = pclr->values.data;
225
	    for (k = 0; k < pclr->num_entries; ++k) {
226
		ref rvalue;
227
		gs_glyph value;
228
		int i;
229
 
230
		array_get(mem, &rvalues, k, &rvalue);
231
		if (!r_has_type(&rvalue, t_name))
232
		    return_error(e_rangecheck);
233
		value = name_index(mem, &rvalue);
234
		/*
235
		 * We need a special check here because some CPUs cannot
236
		 * shift by the full size of an int or long.
237
		 */
238
		if (pclr->value_size < sizeof(value) &&
239
		    (value >> (pclr->value_size * 8)) != 0
240
		    )
241
		    return_error(e_rangecheck);
242
		for (i = pclr->value_size; --i >= 0; )
243
		    *pvalue++ = (byte)(value >> (i * 8));
244
	    }
245
	}
246
	check_int_leu_only(rfxs, 0xff);
247
	pclr->font_index = (int)rfxs.value.intval;
248
            ++pclr;
249
        }
250
    }
251
    return 0;
252
}
253
 
254
/*
255
 * Acquire the CIDSystemInfo array from a dictionary.  If missing, fabricate
256
 * a 0-element array and return 1.
257
 */
258
private int
259
acquire_cid_system_info(ref *psia, const ref *op)
260
{
261
    ref *prcidsi;
262
 
263
    if (dict_find_string(op, "CIDSystemInfo", &prcidsi) <= 0) {
264
	make_empty_array(psia, a_readonly);
265
	return 1;
266
    }
267
    if (r_has_type(prcidsi, t_dictionary)) {
268
	make_array(psia, a_readonly, 1, prcidsi);
269
	return 0;
270
    }
271
    if (!r_is_array(prcidsi))
272
	return_error(e_typecheck);
273
    *psia = *prcidsi;
274
    return 0;
275
}
276
 
277
/*
278
 * Get one element of a CIDSystemInfo array.  If the element is missing or
279
 * null, return 1.
280
 */
281
private int
282
get_cid_system_info(const gs_memory_t *mem, gs_cid_system_info_t *pcidsi, const ref *psia, uint index)
283
{
284
    ref rcidsi;
285
    int code = array_get(mem, psia, (long)index, &rcidsi);
286
 
287
    if (code < 0 || r_has_type(&rcidsi, t_null)) {
288
	cid_system_info_set_null(pcidsi);
289
	return 1;
290
    }
291
    return cid_system_info_param(pcidsi, &rcidsi);
292
}
293
 
294
#ifdef CHECK_CID_SYSTEM_INFO_COMPATIBILITY
295
 
296
/* Check compatibility of CIDSystemInfo. */
297
private bool
298
bytes_eq(const gs_const_string *pcs1, const gs_const_string *pcs2)
299
{
300
    return !bytes_compare(pcs1->data, pcs1->size,
301
			  pcs2->data, pcs2->size);
302
}
303
private bool
304
cid_system_info_compatible(const gs_cid_system_info_t * psi1,
305
			   const gs_cid_system_info_t * psi2)
306
{
307
    return bytes_eq(&psi1->Registry, &psi2->Registry) &&
308
	bytes_eq(&psi1->Ordering, &psi2->Ordering);
309
}
310
 
311
#endif /* CHECK_CID_SYSTEM_INFO_COMPATIBILITY */
312
 
313
/* ---------------- (Semi-)public procedures ---------------- */
314
 
315
/* Get the CodeMap from a Type 0 font, and check the CIDSystemInfo of */
316
/* its subsidiary fonts. */
317
int
318
ztype0_get_cmap(const gs_cmap_t **ppcmap, const ref *pfdepvector,
319
		const ref *op, gs_memory_t *imem)
320
{
321
    ref *prcmap;
322
    ref *pcodemap;
323
    const gs_cmap_t *pcmap;
324
    int code;
325
    uint num_fonts;
326
    uint i;
327
 
328
    /*
329
     * We have no way of checking whether the CodeMap is a concrete
330
     * subclass of gs_cmap_t, so we just check that it is in fact a
331
     * t_struct and is large enough.
332
     */
333
    if (dict_find_string(op, "CMap", &prcmap) <= 0 ||
334
	!r_has_type(prcmap, t_dictionary) ||
335
	dict_find_string(prcmap, "CodeMap", &pcodemap) <= 0 ||
336
	!r_is_struct(pcodemap) ||
337
	gs_object_size(imem, r_ptr(pcodemap, gs_cmap_t)) < sizeof(gs_cmap_t)
338
	)
339
	return_error(e_invalidfont);
340
    pcmap = r_ptr(pcodemap, gs_cmap_t);
341
    num_fonts = r_size(pfdepvector);
342
    for (i = 0; i < num_fonts; ++i) {
343
	ref rfdep, rfsi;
344
 
345
	array_get(imem, pfdepvector, (long)i, &rfdep);
346
	code = acquire_cid_system_info(&rfsi, &rfdep);
347
	if (code < 0)
348
	    return code;
349
	if (code == 0) {
350
	    if (r_size(&rfsi) != 1)
351
		return_error(e_rangecheck);
352
#ifdef CHECK_CID_SYSTEM_INFO_COMPATIBILITY
353
	    {
354
		gs_cid_system_info_t cidsi;
355
 
356
		get_cid_system_info(&cidsi, &rfsi, 0);
357
		if (!cid_system_info_is_null(&cidsi) &&
358
		    !cid_system_info_compatible(&cidsi,
359
						pcmap->CIDSystemInfo + i))
360
		    return_error(e_rangecheck);
361
	    }
362
#endif
363
	}
364
    }
365
    *ppcmap = pcmap;
366
    return 0;
367
}
368
 
369
/* ---------------- Operators ---------------- */
370
 
371
/* <CMap> .buildcmap <CMap> */
372
/*
373
 * Create the internal form of a CMap.  The initial CMap must be read-write
374
 * and have an entry with key = CodeMap and value = null; the result is
375
 * read-only and has a real CodeMap.
376
 *
377
 * This operator reads the CMapType, CMapName, CIDSystemInfo, CMapVersion,
378
 * UIDOffset, XUID, WMode, and .CodeMapData elements of the CMap dictionary.
379
 * For details, see lib/gs_cmap.ps and the Adobe documentation.
380
 */
381
private int
382
zfcmap_glyph_name(const gs_memory_t *mem, 
383
		  gs_glyph glyph, gs_const_string *pstr, void *proc_data)
384
{
385
    ref nref, nsref;
386
    int code = 0;
387
 
388
    /*code = */name_index_ref(mem, (uint)glyph, &nref);
389
    if (code < 0)
390
	return code;
391
    name_string_ref(mem, &nref, &nsref);
392
    pstr->data = nsref.value.const_bytes;
393
    pstr->size = r_size(&nsref);
394
    return 0;
395
}
396
private int
397
zbuildcmap(i_ctx_t *i_ctx_p)
398
{
399
    os_ptr op = osp;
400
    int code;
401
    ref *pcmapname;
402
    ref *puidoffset;
403
    ref *pcodemapdata;
404
    ref *pcodemap;
405
    ref rname, rcidsi, rcoderanges, rdefs, rnotdefs;
406
    gs_cmap_adobe1_t *pcmap = 0;
407
    ref rcmap;
408
    uint i;
409
 
410
    check_type(*op, t_dictionary);
411
    check_dict_write(*op);
412
    if ((code = dict_find_string(op, "CMapName", &pcmapname)) <= 0) {
413
	code = gs_note_error(e_rangecheck);
414
	goto fail;
415
    }
416
    if (!r_has_type(pcmapname, t_name)) {
417
	code = gs_note_error(e_typecheck);
418
	goto fail;
419
    }
420
    name_string_ref(imemory, pcmapname, &rname);
421
    if (dict_find_string(op, ".CodeMapData", &pcodemapdata) <= 0 ||
422
	!r_has_type(pcodemapdata, t_array) ||
423
	r_size(pcodemapdata) != 3 ||
424
	dict_find_string(op, "CodeMap", &pcodemap) <= 0 ||
425
	!r_has_type(pcodemap, t_null)
426
	) {
427
	code = gs_note_error(e_rangecheck);
428
	goto fail;
429
    }
430
    if ((code = acquire_cid_system_info(&rcidsi, op)) < 0)
431
	goto fail;
432
    if ((code = gs_cmap_adobe1_alloc(&pcmap, 0, rname.value.const_bytes,
433
				     r_size(&rname), r_size(&rcidsi),
434
				     0, 0, 0, 0, 0, imemory)) < 0)
435
	goto fail;
436
    if ((code = dict_int_param(op, "CMapType", 0, 1, 0, &pcmap->CMapType)) < 0 ||
437
	(code = dict_float_param(op, "CMapVersion", 0.0, &pcmap->CMapVersion)) < 0 ||
438
	(code = dict_uid_param(op, &pcmap->uid, 0, imemory, i_ctx_p)) < 0 ||
439
	(code = dict_int_param(op, "WMode", 0, 1, 0, &pcmap->WMode)) < 0
440
	)
441
	goto fail;
442
    if (dict_find_string(op, "UIDOffset", &puidoffset) > 0) {
443
	if (!r_has_type(puidoffset, t_integer)) {
444
	    code = gs_note_error(e_typecheck);
445
	    goto fail;
446
	}
447
	pcmap->UIDOffset = puidoffset->value.intval; /* long, not int */
448
    }
449
    for (i = 0; i < r_size(&rcidsi); ++i) {
450
        code = get_cid_system_info(imemory, pcmap->CIDSystemInfo + i, &rcidsi, i);
451
	if (code < 0)
452
	    goto fail;
453
    }
454
    array_get(imemory, pcodemapdata, 0L, &rcoderanges);
455
    array_get(imemory, pcodemapdata, 1L, &rdefs);
456
    array_get(imemory, pcodemapdata, 2L, &rnotdefs);
457
    if ((code = acquire_code_ranges(pcmap, &rcoderanges, imemory)) < 0)
458
	goto fail;
459
    if ((code = acquire_code_map(&pcmap->def, &rdefs, pcmap, imemory)) < 0)
460
	goto fail;
461
    if ((code = acquire_code_map(&pcmap->notdef, &rnotdefs, pcmap, imemory)) < 0)
462
	goto fail;
463
    pcmap->mark_glyph = zfont_mark_glyph_name;
464
    pcmap->mark_glyph_data = 0;
465
    pcmap->glyph_name = zfcmap_glyph_name;
466
    pcmap->glyph_name_data = 0;
467
    make_istruct_new(&rcmap, a_readonly, pcmap);
468
    code = idict_put_string(op, "CodeMap", &rcmap);
469
    if (code < 0)
470
	goto fail;
471
    return zreadonly(i_ctx_p);
472
fail:
473
    if (pcmap) {
474
	free_code_map(&pcmap->notdef, imemory);
475
	free_code_map(&pcmap->def, imemory);
476
	ifree_object(pcmap->CIDSystemInfo, "zbuildcmap(CIDSystemInfo)");
477
	ifree_object(pcmap, "zbuildcmap(cmap)");
478
    }
479
    return code;
480
}
481
 
482
/* ------ Initialization procedure ------ */
483
 
484
const op_def zfcmap_op_defs[] =
485
{
486
    {"1.buildcmap", zbuildcmap},
487
    op_def_end(0)
488
};