Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 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: gdevpsfm.c,v 1.15 2004/08/19 19:33:09 stefan Exp $ */
18
/* Write a CMap */
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gxfcmap.h"
22
#include "stream.h"
23
#include "spprint.h"
24
#include "spsdf.h"
25
#include "gdevpsf.h"
26
#include "memory_.h"
27
 
28
/* ---------------- Utilities ---------------- */
29
 
30
typedef struct cmap_operators_s {
31
    const char *beginchar;
32
    const char *endchar;
33
    const char *beginrange;
34
    const char *endrange;
35
} cmap_operators_t;
36
private const cmap_operators_t
37
  cmap_cid_operators = {
38
    "begincidchar\n", "endcidchar\n",
39
    "begincidrange\n", "endcidrange\n"
40
  },
41
  cmap_notdef_operators = {
42
    "beginnotdefchar\n", "endnotdefchar\n",
43
    "beginnotdefrange\n", "endnotdefrange\n"
44
  };
45
 
46
/* Write a gs_string with a prefix. */
47
private void
48
pput_string_entry(stream *s, const char *prefix, const gs_const_string *pstr)
49
{
50
    stream_puts(s, prefix);
51
    stream_write(s, pstr->data, pstr->size);
52
}
53
 
54
/* Write a hex string. */
55
private void
56
pput_hex(stream *s, const byte *pcid, int size)
57
{
58
    int i;
59
    static const char *const hex_digits = "0123456789abcdef";
60
 
61
    for (i = 0; i < size; ++i) {
62
	stream_putc(s, hex_digits[pcid[i] >> 4]);
63
	stream_putc(s, hex_digits[pcid[i] & 0xf]);
64
    }
65
}
66
 
67
/* Write a list of code space ranges. */
68
private void
69
cmap_put_ranges(stream *s, const gx_code_space_range_t *pcsr, int count)
70
{
71
    int i;
72
 
73
    pprintd1(s, "%d begincodespacerange\n", count);
74
    for (i = 0; i < count; ++i, ++pcsr) {
75
	stream_puts(s, "<");
76
	pput_hex(s, pcsr->first, pcsr->size);
77
	stream_puts(s, "><");
78
	pput_hex(s, pcsr->last, pcsr->size);
79
	stream_puts(s, ">\n");
80
    }
81
    stream_puts(s, "endcodespacerange\n");
82
}
83
 
84
/* Write one CIDSystemInfo dictionary. */
85
private void
86
cmap_put_system_info(stream *s, const gs_cid_system_info_t *pcidsi)
87
{
88
    if (cid_system_info_is_null(pcidsi)) {
89
	stream_puts(s, " null ");
90
    } else {
91
	stream_puts(s, " 3 dict dup begin\n");
92
	stream_puts(s, "/Registry ");
93
	s_write_ps_string(s, pcidsi->Registry.data, pcidsi->Registry.size, 0);
94
	stream_puts(s, " def\n/Ordering ");
95
	s_write_ps_string(s, pcidsi->Ordering.data, pcidsi->Ordering.size, 0);
96
	pprintd1(s, " def\n/Supplement %d def\nend ", pcidsi->Supplement);
97
    }
98
}
99
 
100
/* Write one code map. */
101
private int
102
cmap_put_code_map(const gs_memory_t *mem,
103
		  stream *s, int which, const gs_cmap_t *pcmap,
104
		  const cmap_operators_t *pcmo,
105
		  psf_put_name_chars_proc_t put_name_chars, 
106
		  int font_index_only)
107
{
108
    /* For simplicity, produce one entry for each lookup range. */
109
    gs_cmap_lookups_enum_t lenum;
110
    int font_index = (pcmap->num_fonts <= 1 ? 0 : -1);
111
    int code;
112
 
113
    for (gs_cmap_lookups_enum_init(pcmap, which, &lenum);
114
	 (code = gs_cmap_enum_next_lookup(&lenum)) == 0; ) {
115
	gs_cmap_lookups_enum_t counter;
116
	int num_entries = 0;
117
	int gi;
118
 
119
	if (font_index_only >= 0 && lenum.entry.font_index != font_index_only)
120
	    continue;
121
	if (font_index_only < 0 && lenum.entry.font_index != font_index) {
122
	    pprintd1(s, "%d usefont\n", lenum.entry.font_index);
123
	    font_index = lenum.entry.font_index;
124
	}
125
	/* Count the number of entries in this lookup range. */
126
	counter = lenum;
127
	while (gs_cmap_enum_next_entry(&counter) == 0)
128
	    ++num_entries;
129
	for (gi = 0; gi < num_entries; gi += 100) {
130
	    int i = gi, ni = min(i + 100, num_entries);
131
	    const char *end;
132
 
133
	    pprintd1(s, "%d ", ni - i);
134
	    if (lenum.entry.key_is_range) {
135
		if (lenum.entry.value_type == CODE_VALUE_CID || lenum.entry.value_type == CODE_VALUE_NOTDEF) {
136
		    stream_puts(s, pcmo->beginrange);
137
		    end = pcmo->endrange;
138
		} else {	/* must be def, not notdef */
139
		    stream_puts(s, "beginbfrange\n");
140
		    end = "endbfrange\n";
141
		}
142
	    } else {
143
		if (lenum.entry.value_type == CODE_VALUE_CID || lenum.entry.value_type == CODE_VALUE_NOTDEF) {
144
		    stream_puts(s, pcmo->beginchar);
145
		    end = pcmo->endchar;
146
		} else {	/* must be def, not notdef */
147
		    stream_puts(s, "beginbfchar\n");
148
		    end = "endbfchar\n";
149
		}
150
	    }
151
	    for (; i < ni; ++i) {
152
		int j;
153
		long value;
154
		int value_size;
155
 
156
		DISCARD(gs_cmap_enum_next_entry(&lenum)); /* can't fail */
157
		value_size = lenum.entry.value.size;
158
		for (j = 0; j <= lenum.entry.key_is_range; ++j) {
159
		    stream_putc(s, '<');
160
		    pput_hex(s, lenum.entry.key[j], lenum.entry.key_size);
161
		    stream_putc(s, '>');
162
		}
163
		for (j = 0, value = 0; j < value_size; ++j)
164
		    value = (value << 8) + lenum.entry.value.data[j];
165
		switch (lenum.entry.value_type) {
166
		case CODE_VALUE_CID:
167
		case CODE_VALUE_NOTDEF:
168
		    pprintld1(s, "%ld", value);
169
		    break;
170
		case CODE_VALUE_CHARS:
171
		    stream_putc(s, '<');
172
		    pput_hex(s, lenum.entry.value.data, value_size);
173
		    stream_putc(s, '>');
174
		    break;
175
		case CODE_VALUE_GLYPH: {
176
		    gs_const_string str;
177
		    int code = pcmap->glyph_name(mem, (gs_glyph)value, &str,
178
						 pcmap->glyph_name_data);
179
 
180
		    if (code < 0)
181
			return code;
182
		    stream_putc(s, '/');
183
		    code = put_name_chars(s, str.data, str.size);
184
		    if (code < 0)
185
			return code;
186
		}
187
		    break;
188
		default:	/* not possible */
189
		    return_error(gs_error_unregistered);
190
		}
191
		stream_putc(s, '\n');
192
	    }
193
	    stream_puts(s, end);
194
	}
195
    }
196
    return code;
197
}
198
 
199
/* ---------------- Main program ---------------- */
200
 
201
/* Write a CMap in its standard (source) format. */
202
int
203
psf_write_cmap(const gs_memory_t *mem, 
204
	       stream *s, const gs_cmap_t *pcmap,
205
	       psf_put_name_chars_proc_t put_name_chars,
206
	       const gs_const_string *alt_cmap_name, int font_index_only)
207
{
208
    const gs_const_string *const cmap_name =
209
	(alt_cmap_name ? alt_cmap_name : &pcmap->CMapName);
210
    const gs_cid_system_info_t *const pcidsi = pcmap->CIDSystemInfo;
211
 
212
    switch (pcmap->CMapType) {
213
    case 0: case 1: case 2:
214
	break;
215
    default:
216
	return_error(gs_error_rangecheck);
217
    }
218
 
219
    /* Write the header. */
220
 
221
    if (!pcmap->ToUnicode) {
222
	stream_puts(s, "%!PS-Adobe-3.0 Resource-CMap\n");
223
	stream_puts(s, "%%DocumentNeededResources: ProcSet (CIDInit)\n");
224
	stream_puts(s, "%%IncludeResource: ProcSet (CIDInit)\n");
225
	pput_string_entry(s, "%%BeginResource: CMap (", cmap_name);
226
	pput_string_entry(s, ")\n%%Title: (", cmap_name);
227
	pput_string_entry(s, " ", &pcidsi->Registry);
228
	pput_string_entry(s, " ", &pcidsi->Ordering);
229
	pprintd1(s, " %d)\n", pcidsi->Supplement);
230
	pprintg1(s, "%%%%Version: %g\n", pcmap->CMapVersion);
231
    }
232
    stream_puts(s, "/CIDInit /ProcSet findresource begin\n");
233
    stream_puts(s, "12 dict begin\nbegincmap\n");
234
 
235
    /* Write the fixed entries. */
236
 
237
    pprintd1(s, "/CMapType %d def\n", pcmap->CMapType);
238
    if (!pcmap->ToUnicode) {
239
	pprintg1(s, "/CMapVersion %g def\n", pcmap->CMapVersion);
240
	stream_puts(s, "/CMapName/");
241
	put_name_chars(s, cmap_name->data, cmap_name->size);
242
	stream_puts(s, " def\n");
243
	stream_puts(s, "/CIDSystemInfo");
244
	if (font_index_only >= 0 && font_index_only < pcmap->num_fonts) {
245
	    cmap_put_system_info(s, pcidsi + font_index_only);
246
	} else if (pcmap->num_fonts == 1) {
247
	    cmap_put_system_info(s, pcidsi);
248
	} else {
249
	    int i;
250
 
251
	    pprintd1(s, " %d array\n", pcmap->num_fonts);
252
	    for (i = 0; i < pcmap->num_fonts; ++i) {
253
		pprintd1(s, "dup %d", i);
254
		cmap_put_system_info(s, pcidsi + i);
255
		stream_puts(s, "put\n");
256
	    }
257
	}
258
	stream_puts(s, " def\n");
259
	if (uid_is_XUID(&pcmap->uid)) {
260
	    uint i, n = uid_XUID_size(&pcmap->uid);
261
	    const long *values = uid_XUID_values(&pcmap->uid);
262
 
263
	    stream_puts(s, "/XUID [");
264
	    for (i = 0; i < n; ++i)
265
		pprintld1(s, " %ld", values[i]);
266
	    stream_puts(s, "] def\n");
267
	}
268
	pprintld1(s, "/UIDOffset %ld def\n", pcmap->UIDOffset);
269
	pprintd1(s, "/WMode %d def\n", pcmap->WMode);
270
    }
271
 
272
    /* Write the code space ranges. */
273
 
274
    {
275
	gs_cmap_ranges_enum_t renum;
276
#define MAX_RANGES 100
277
	gx_code_space_range_t ranges[MAX_RANGES];
278
	int code, count = 0;
279
 
280
	for (gs_cmap_ranges_enum_init(pcmap, &renum);
281
	     (code = gs_cmap_enum_next_range(&renum)) == 0; ) {
282
	    if (count == MAX_RANGES) {
283
		cmap_put_ranges(s, ranges, count);
284
		count = 0;
285
	    }
286
	    ranges[count++] = renum.range;
287
	}
288
	if (code < 0)
289
	    return code;
290
	if (count)
291
	    cmap_put_ranges(s, ranges, count);
292
#undef MAX_RANGES
293
    }
294
 
295
    /* Write the code and notdef data. */
296
 
297
    {
298
	int code;
299
 
300
	code = cmap_put_code_map(mem, s, 1, pcmap, &cmap_notdef_operators,
301
			         put_name_chars, font_index_only);
302
	if (code < 0)
303
	    return code;
304
	code = cmap_put_code_map(mem, s, 0, pcmap, &cmap_cid_operators,
305
			         put_name_chars, font_index_only);
306
	if (code < 0)
307
	    return code;
308
    }
309
 
310
    /* Write the trailer. */
311
 
312
    stream_puts(s, "endcmap\n");
313
    stream_puts(s, "CMapName currentdict /CMap defineresource pop\nend end\n");
314
    if (!pcmap->ToUnicode) {
315
	stream_puts(s, "%%EndResource\n");
316
	stream_puts(s, "%%EOF\n");
317
    }
318
 
319
    return 0;
320
}
321