xref: /plan9/sys/src/cmd/gs/src/gsfcmap.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 /* Copyright (C) 1997, 2000 Aladdin Enterprises.  All rights reserved.
2 
3    This file is part of Aladdin Ghostscript.
4 
5    Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
6    or distributor accepts any responsibility for the consequences of using it,
7    or for whether it serves any particular purpose or works at all, unless he
8    or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
9    License (the "License") for full details.
10 
11    Every copy of Aladdin Ghostscript must include a copy of the License,
12    normally in a plain ASCII text file named PUBLIC.  The License grants you
13    the right to copy, modify and redistribute Aladdin Ghostscript, but only
14    under certain conditions described in the License.  Among other things, the
15    License requires that the copyright notice and this notice be preserved on
16    all copies.
17  */
18 
19 /*$Id: gsfcmap.c,v 1.2 2000/03/10 07:03:09 lpd Exp $ */
20 /* CMap character decoding */
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsstruct.h"
24 #include "gxfcmap.h"
25 
26 /* CMap structure descriptors */
27 public_st_cmap();
28 public_st_code_map();
29 public_st_code_map_element();
30 
31 /* Because code maps can be elements of arrays, */
32 /* their enum_ptrs procedure must never return 0 prematurely. */
33 private
34 ENUM_PTRS_WITH(code_map_enum_ptrs, gx_code_map *pcmap) return 0;
35 ENUM_PTR(0, gx_code_map, cmap);
36 case 1:
37 switch (pcmap->type)
38 {
39     case cmap_glyph:
40 	(*pcmap->cmap->mark_glyph)(pcmap->data.glyph,
41 				   pcmap->cmap->mark_glyph_data);
42     default:
43 	ENUM_RETURN(0);
44     case cmap_subtree:
45 	ENUM_RETURN_PTR(gx_code_map, data.subtree);
46 }
47 ENUM_PTRS_END
48 private RELOC_PTRS_WITH(code_map_reloc_ptrs, gx_code_map *pcmap);
49 switch (pcmap->type) {
50     case cmap_subtree:
51 	RELOC_PTR(gx_code_map, data.subtree);
52 	break;
53     default:
54 	;
55 }
56 RELOC_PTR(gx_code_map, cmap);
57 RELOC_PTRS_END
58 
59 /* CIDSystemInfo structure descriptors */
60 private_st_cid_system_info();
61 public_st_cid_system_info_element();
62 
63 /* ---------------- Procedures ---------------- */
64 
65 /*
66  * Decode a character from a string using a code map, updating the index.
67  * Return 0 for a CID or name, N > 0 for a character code where N is the
68  * number of bytes in the code, or an error.  Shift the decoded bytes into
69  * *pchr.  For undefined characters, set *pglyph = gs_no_glyph and return 0.
70  */
71 private int
72 code_map_decode_next(const gx_code_map * pcmap, const gs_const_string * str,
73 		     uint * pindex, uint * pfidx,
74 		     gs_char * pchr, gs_glyph * pglyph)
75 {
76     const gx_code_map *map = pcmap;
77     uint chr = 0;
78 
79     for (;;) {
80 	int result;
81 
82 	if_debug1('J', "[J]cmap char = 0x%x: ", chr);
83 	switch ((gx_code_map_type) map->type) {
84 	    case cmap_char_code:
85 		if_debug0('J', "char code");
86 		*pglyph = (gs_glyph)map->data.ccode;
87 		result = map->num_bytes1 + 1;
88 leaf:		if (chr > map->last)
89 		    goto undef;
90 		if (map->add_offset)
91 		    *pglyph += chr - map->first;
92 		*pfidx = map->byte_data.font_index;
93 		if_debug3('J', " 0x%lx, fidx %u, result %d\n",
94 			  *pglyph, *pfidx, result);
95 		return result;
96 	    case cmap_glyph:
97 		if_debug0('J', "glyph");
98 		*pglyph = map->data.glyph;
99 		result = 0;
100 		goto leaf;
101 	    case cmap_subtree:
102 		if_debug0('J', "subtree\n");
103 		if (*pindex >= str->size)
104 		    return_error(gs_error_rangecheck);
105 		chr = str->data[(*pindex)++];
106 		if (chr >= map->data.subtree[0].first) {
107 		    /* Invariant: map[lo].first <= chr < map[hi].first. */
108 		    uint lo = 0, hi = map->byte_data.count1 + 1;
109 
110 		    map = map->data.subtree;
111 		    while (lo + 1 < hi) {
112 			uint mid = (lo + hi) >> 1;
113 
114 			if (chr >= map[mid].first)
115 			    lo = mid;
116 			else
117 			    hi = mid;
118 		    }
119 		    *pchr = (*pchr << 8) | chr;
120 		    map = &map[lo];
121 		    continue;
122 		}
123 undef:		if_debug0('J', " undef\n");
124 		*pchr = 0;
125 		*pglyph = gs_no_glyph;
126 		return 0;
127 	    default:		/* (can't happen) */
128 		if_debug0('J', "error!\n");
129 		return_error(gs_error_invalidfont);
130 	}
131     }
132 }
133 
134 /*
135  * Decode a character from a string using a CMap.
136  * Return like code_map_decode_next.
137  */
138 int
139 gs_cmap_decode_next(const gs_cmap * pcmap, const gs_const_string * str,
140 		    uint * pindex, uint * pfidx,
141 		    gs_char * pchr, gs_glyph * pglyph)
142 {
143     uint save_index = *pindex;
144     int code;
145 
146     *pchr = 0;
147     code =
148 	code_map_decode_next(&pcmap->def, str, pindex, pfidx, pchr, pglyph);
149     if (code != 0 || *pglyph != gs_no_glyph)
150 	return code;
151     /* This is an undefined character.  Use the notdef map. */
152     {
153 	uint next_index = *pindex;
154 
155 	*pindex = save_index;
156 	*pchr = 0;
157 	code =
158 	    code_map_decode_next(&pcmap->notdef, str, pindex, pfidx,
159 				 pchr, pglyph);
160 	*pindex = next_index;
161     }
162     return code;
163 }
164