summaryrefslogtreecommitdiff
path: root/pcl/pcsymbol.c
blob: d46a661dcc221b1457deb0305a600fac36b385dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
/* Portions Copyright (C) 2001 artofcode LLC.
   Portions Copyright (C) 1996, 2001 Artifex Software Inc.
   Portions Copyright (C) 1988, 2000 Aladdin Enterprises.
   This software is based in part on the work of the Independent JPEG Group.
   All Rights Reserved.

   This software is distributed under license and may not be copied, modified
   or distributed except as expressly authorized under the terms of that
   license.  Refer to licensing information at http://www.artifex.com/ or
   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
   San Rafael, CA  94903, (415)492-9861, for further information. */
/*$Id$ */

/* pcsymbol.c */
/* PCL5 user-defined symbol set commands */
#include "stdio_.h"			/* std.h + NULL */
#include "plvalue.h"
#include "pcommand.h"
#include "pcstate.h"
#include "pcfont.h"
#include "pcsymbol.h"



/* HP printers will not convert MSL coded symbol table to unicode.  An
   MSL based font must be used with an MSL symbol set.  We think this
   is a bug.  The following definition can be uncommented to support
   the feature anyway */

/* #define SUPPORT_MSL_TO_UNICODE */

static int /* ESC * c <id> R */
pcl_symbol_set_id_code(pcl_args_t *pargs, pcl_state_t *pcs)
{	uint id = uint_arg(pargs);
	id_set_value(pcs->symbol_set_id, id);
	return 0;
}

#ifdef DEBUG
static void
dump_dl_symbol_set(const pl_symbol_map_t *psm)
{
    dprintf6("header size:%d id:%d format:%s type:%d first code:%d last code:%d\n",
             pl_get_uint16(psm->header_size),
             pl_get_uint16(psm->id),
             (psm->format == 1 ? "MSL" : (psm->format == 3 ? "Unicode" : "Unknown")),
             psm->type,
             pl_get_uint16(psm->first_code),
             pl_get_uint16(psm->last_code));
    {
        int i;
        int num_codes = pl_get_uint16(psm->last_code) - pl_get_uint16(psm->first_code) + 1;
        for (i = 0; i < num_codes; i++) {
            dprintf2("index=%d, code:%d\n", i, psm->codes[i]);
        }
    }
}
#endif

static int /* ESC ( f <count> W */
pcl_define_symbol_set(pcl_args_t *pargs, pcl_state_t *pcs)
{	uint count = uint_arg(pargs);
	const pl_symbol_map_t *psm = (pl_symbol_map_t *)arg_data(pargs);
	uint header_size;
	uint first_code, last_code;
	gs_memory_t *mem = pcs->memory;
	pl_symbol_map_t *header;
	pcl_symbol_set_t *symsetp;
	pl_glyph_vocabulary_t gv;

#define psm_header_size 18
	if ( count < psm_header_size )
	  return e_Range;
	header_size = pl_get_uint16(psm->header_size);
	if ( header_size < psm_header_size ||
	     psm->id[0] != id_key(pcs->symbol_set_id)[0] ||
	     psm->id[1] != id_key(pcs->symbol_set_id)[1] ||
	     psm->type > 2
	   )
	  return e_Range;
	switch ( psm->format )
	  {
	  case 1:
              gv = plgv_MSL;
              break;
	  case 3:
              gv = plgv_Unicode;
              break;
	  default:
	    return e_Range;
	  }
	first_code = pl_get_uint16(psm->first_code);
	last_code = pl_get_uint16(psm->last_code);
        /* NB fixme should check psm->Format to identify the vocabulary. */
	{ int num_codes = last_code - first_code + 1;
	  int i;

	  if ( num_codes <= 0 || last_code > 255 || (count != psm_header_size + num_codes * 2) ) 
	    return e_Range;

	  header =
	    (pl_symbol_map_t *)gs_alloc_bytes(mem,
					      sizeof(pl_symbol_map_t),
					      "pcl_font_header(header)");
	  if ( header == 0 )
	    return_error(e_Memory);
	  memcpy((void *)header, (void *)psm, psm_header_size);
	  /* allow mapping to and from msl and unicode */
          if (psm->format == 1)
#ifdef SUPPORT_MSL_TO_UNICODE
              header->mapping_type = PLGV_M2U_MAPPING;
#else
              header->mapping_type = PLGV_NO_MAPPING;
#endif
          else
              header->mapping_type = PLGV_U2M_MAPPING;

	  /*
	   * Byte swap the codes now, so that we don't have to byte swap
	   * them every time we access them.
	   */
	  for ( i = num_codes; --i >= 0; )
	    header->codes[i] =
	      pl_get_uint16((byte *)psm + psm_header_size + i * 2);
	}
#undef psm_header_size

#ifdef DEBUG
        if ( gs_debug_c('=') )
            dump_dl_symbol_set(psm);
#endif

	/* Symbol set may already exist; if so, we may be replacing one of
	 * its existing maps or adding one for a new glyph vocabulary. */
	if ( pl_dict_find(&pcs->soft_symbol_sets, id_key(pcs->symbol_set_id),
	    2, (void **)&symsetp) )
	  {
	    if ( symsetp->maps[gv] != NULL )
	      gs_free_object(mem, symsetp->maps[gv], "symset map");
	  }
	else
	  { pl_glyph_vocabulary_t gx;
	    symsetp = (pcl_symbol_set_t *)gs_alloc_bytes(mem,
		sizeof(pcl_symbol_set_t), "symset dict value");
	    if ( !symsetp )
	      return_error(e_Memory);
	    for ( gx = plgv_MSL; gx < plgv_next; gx++ )
	      symsetp->maps[gx] = NULL;
	    symsetp->storage = pcds_temporary;
	    pl_dict_put(&pcs->soft_symbol_sets, id_key(pcs->symbol_set_id),
		2, symsetp);
	  }
	symsetp->maps[gv] = header;

	return 0;
}

static int /* ESC * c <ssc_enum> S */
pcl_symbol_set_control(pcl_args_t *pargs, pcl_state_t *pcs)
{	gs_const_string key;
	void *value;
	pl_dict_enum_t denum;

	switch ( int_arg(pargs) )
	  {
	  case 0:
	    { /* Delete all user-defined symbol sets. */
	      /* Note: When deleting symbol set(s), it is easier (safer?)
	       * to decache and reselect fonts unconditionally.  (Consider,
	       * for example, deleting a downloaded overload of a built-in
	       * which might be the default ID.) */
	      pl_dict_release(&pcs->soft_symbol_sets);
	      pcl_decache_font(pcs, -1);
	    }
	    return 0;
	  case 1:
	    { /* Delete all temporary symbol sets. */
	      pl_dict_enum_stack_begin(&pcs->soft_symbol_sets, &denum, false);
	      while ( pl_dict_enum_next(&denum, &key, &value) )
		if ( ((pcl_symbol_set_t *)value)->storage == pcds_temporary )
		  pl_dict_undef(&pcs->soft_symbol_sets, key.data, key.size);
	      pcl_decache_font(pcs, -1);
	    }
	    return 0;
	  case 2:
	    { /* Delete symbol set <symbol_set_id>. */
	      pl_dict_undef(&pcs->soft_symbol_sets,
		  id_key(pcs->symbol_set_id), 2);
	      pcl_decache_font(pcs, -1);
	    }
	    return 0;
	  case 4:
	    { /* Make <symbol_set_id> temporary. */
	      if ( pl_dict_find(&pcs->soft_symbol_sets,
		  id_key(pcs->symbol_set_id), 2, &value) )
		((pcl_symbol_set_t *)value)->storage = pcds_temporary;
	    }
	    return 0;
	  case 5:
	    { /* Make <symbol_set_id> permanent. */
	      if ( pl_dict_find(&pcs->soft_symbol_sets,
		  id_key(pcs->symbol_set_id), 2, &value) )
		((pcl_symbol_set_t *)value)->storage = pcds_permanent;
	    }
	    return 0;
	  default:
	    return 0;
	  }
}

static void	/* free any symbol maps as well as dict value entry */
pcsymbol_dict_value_free(gs_memory_t *mem, void *value, client_name_t cname)
{	pcl_symbol_set_t *ssp = (pcl_symbol_set_t *)value;
	pl_glyph_vocabulary_t gx;

	if ( ssp->storage != pcds_internal )
	  {
	    for ( gx = plgv_MSL; gx < plgv_next; gx++ )
	      {
		if ( ssp->maps[gx] != NULL )
		  gs_free_object(mem, (void*)ssp->maps[gx], cname);
	      }
	  }
	gs_free_object(mem, value, cname);
}

static int
pcl_load_built_in_symbol_sets(pcl_state_t *pcs)
{
	const pl_symbol_map_t **maplp;
	pcl_symbol_set_t *symsetp;
	pl_glyph_vocabulary_t gv;

	for ( maplp = &pl_built_in_symbol_maps[0]; *maplp; maplp++ )
	  {
	    const pl_symbol_map_t *mapp = *maplp;
	    /* Create entry for symbol set if this is the first map for
	     * that set. */
	    if ( !pl_dict_find(&pcs->built_in_symbol_sets, mapp->id, 2,
		(void **)&symsetp) )
	      { pl_glyph_vocabulary_t gx;
		symsetp = (pcl_symbol_set_t *)gs_alloc_bytes(pcs->memory,
		    sizeof(pcl_symbol_set_t), "symset init dict value");
		if ( !symsetp )
		  return_error(e_Memory);
		for ( gx = plgv_MSL; gx < plgv_next; gx++ )
		  symsetp->maps[gx] = NULL;
		symsetp->storage = pcds_internal;
	      }
	    gv = (mapp->character_requirements[7] & 07)==1?
		plgv_Unicode: plgv_MSL;
	    pl_dict_put(&pcs->built_in_symbol_sets, mapp->id, 2, symsetp);
	    symsetp->maps[gv] = (pl_symbol_map_t *)mapp;
	  }
	return 0;
}

bool
pcl_check_symbol_support(const byte *symset_req, const byte *font_sup)
{	int i;

	/* if glyph vocabularies match, following will work on the
	 * last 3 bits of last byte.  Note that the font-support bits
	 * are inverted (0 means available). 
	 */
	for ( i = 0; i < 7; i++ )
	  if ( symset_req[i] & font_sup[i] )
	    return false;		/* something needed, not present */
	/* check the last byte but not the glyph vocabularies. */
	if ((symset_req[7] >> 3) & (font_sup[7] >> 3))
	    return false;

	return true;
}


/* Find the symbol map for a particular symbol set and glyph vocabulary,
 * if it exists.
 * There are two dictionaries--one for soft (downloaded) symbol sets and
 * one for built-ins.  These are searched separately.  The actual maps
 * present for a symbol set may overlap between soft and built-in. */
pl_symbol_map_t *
pcl_find_symbol_map(const pcl_state_t *pcs, const byte *id,
                    pl_glyph_vocabulary_t gv, bool wide16)
{	
    pcl_symbol_set_t *setp;
	

    if ( pl_dict_find((pl_dict_t *)&pcs->soft_symbol_sets,
		      id, 2, (void **)&setp) ||
         pl_dict_find((pl_dict_t *)&pcs->built_in_symbol_sets,
		      id, 2, (void**)&setp) ) {

        /* 16 bit sets are not supported, they aren't strictly
           necessary, yet. */
        if (wide16)
            return NULL;
	/* simple case we found a matching symbol set */
	if ( setp->maps[gv] != NULL )
	    return setp->maps[gv];
	/* we requested a unicode symbol set and found an msl
	   symbol set that can be mapped to unicode */
	if ( (gv == plgv_Unicode)  &&
	     (setp->maps[plgv_MSL]) &&
	     ((setp->maps[plgv_MSL])->mapping_type == PLGV_M2U_MAPPING) )
	    return setp->maps[plgv_MSL];
	/* we requested an msl symbol set and found a unicode
	   symbol set that can be mapped to msl */
	if ( (gv == plgv_MSL) &&
	     (setp->maps[plgv_Unicode]) &&
	     ((setp->maps[plgv_Unicode])->mapping_type == PLGV_U2M_MAPPING) )
	    return setp->maps[plgv_Unicode];
    }
    return NULL;
}

/* Initialization */
static int
pcsymbol_do_registration(
    pcl_parser_state_t *pcl_parser_state,
    gs_memory_t *mem
)
{		/* Register commands */
	DEFINE_CLASS_COMMAND_ARGS('*', 'c', 'R', "Symbol Set ID Code",
				  pcl_symbol_set_id_code,
				  pca_neg_error|pca_big_error)
	DEFINE_CLASS_COMMAND_ARGS('(', 'f', 'W', "Define Symbol Set",
				  pcl_define_symbol_set, pca_byte_data|pca_neg_error|pca_big_clamp)
	DEFINE_CLASS_COMMAND_ARGS('*', 'c', 'S', "Symbol Set Control",
				  pcl_symbol_set_control,
				  pca_neg_ignore|pca_big_ignore)
	return 0;
}

static void
pcsymbol_do_reset(pcl_state_t *pcs, pcl_reset_type_t type)
{	
    if ( type & (pcl_reset_initial | pcl_reset_printer | pcl_reset_overlay) ) {
	id_set_value(pcs->symbol_set_id, 0);
	if ( type & pcl_reset_initial ) {
	    /* Don't set a parent relationship from soft to built-in
	     * symbol sets.  Although it is arguably useful, it's
	     * better to avoid it and keep anyone who's looking at the
	     * soft symbol sets from mucking up the permanent ones. */
	    pl_dict_init(&pcs->soft_symbol_sets, pcs->memory,
			 pcsymbol_dict_value_free);
	    pl_dict_init(&pcs->built_in_symbol_sets, pcs->memory,
			 pcsymbol_dict_value_free);
	    /* NB.  Symbol sets are require for RTL/HPGL/2 mode for
	     * stickfonts but we shouldn't load all of them. */
	    if ( pcl_load_built_in_symbol_sets(pcs) < 0 )
		dprintf("Internal error, no symbol sets found");
	}
	else if ( type & pcl_reset_printer ) { 
	    pcl_args_t args;
	    arg_set_uint(&args, 1);	/* delete temporary symbol sets */
	    pcl_symbol_set_control(&args, pcs);
	}
    }
    if ( type & pcl_reset_permanent ) {
	pl_dict_release(&pcs->soft_symbol_sets);
	pl_dict_release(&pcs->built_in_symbol_sets);
    }
}

static int
pcsymbol_do_copy(pcl_state_t *psaved, const pcl_state_t *pcs,
  pcl_copy_operation_t operation)
{	if ( operation & pcl_copy_after )
	  { /* Don't restore the downloaded symbol set dictionary. */
	    psaved->built_in_symbol_sets = pcs->built_in_symbol_sets;
	  }
	return 0;
}

const pcl_init_t pcsymbol_init = {
  pcsymbol_do_registration, pcsymbol_do_reset, pcsymbol_do_copy
};