/src/ghostpdl/pdf/pdf_misc.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | /* Miscellaneous routines */ |
17 | | |
18 | | #include "pdf_int.h" |
19 | | #include "pdf_stack.h" |
20 | | #include "pdf_misc.h" |
21 | | #include "pdf_font_types.h" |
22 | | #include "pdf_gstate.h" |
23 | | #include "gspath.h" /* For gs_strokepath() */ |
24 | | #include "gspaint.h" /* For gs_erasepage() */ |
25 | | #include "gsicc_manage.h" /* For gsicc_get_default_type() */ |
26 | | #include "gsstate.h" /* for gs_setrenderingintent() */ |
27 | | |
28 | | /* Get current bbox, possibly from stroking current path (utility function) */ |
29 | | int pdfi_get_current_bbox(pdf_context *ctx, gs_rect *bbox, bool stroked) |
30 | 17.1k | { |
31 | 17.1k | int code, code1; |
32 | | |
33 | 17.1k | if (stroked) { |
34 | 887 | code = pdfi_gsave(ctx); |
35 | 887 | if (code < 0) |
36 | 0 | return code; |
37 | 887 | code = gs_strokepath(ctx->pgs); |
38 | 887 | if (code < 0) |
39 | 0 | goto exit; |
40 | 887 | } |
41 | 17.1k | code = gs_upathbbox(ctx->pgs, bbox, false); |
42 | | |
43 | 17.1k | exit: |
44 | 17.1k | if (stroked) { |
45 | 887 | code1 = pdfi_grestore(ctx); |
46 | 887 | if (code == 0) |
47 | 239 | code = code1; |
48 | 887 | } |
49 | 17.1k | return code; |
50 | 17.1k | } |
51 | | |
52 | | /* Get the current color space (the base one) from a color space |
53 | | */ |
54 | | gs_color_space_index pdfi_get_color_space_index(pdf_context *ctx, const gs_color_space *pcs) |
55 | 144k | { |
56 | 144k | gs_color_space_index csi; |
57 | | |
58 | | /* Get the color space index */ |
59 | 144k | csi = gs_color_space_get_index(pcs); |
60 | | |
61 | | /* If its an Indexed space, then use the base space */ |
62 | 144k | if (csi == gs_color_space_index_Indexed) |
63 | 104 | csi = gs_color_space_get_index(pcs->base_space); |
64 | | |
65 | | /* If its ICC, see if its a substitution for one of the device |
66 | | * spaces. If so then we will want to behave as if we were using the |
67 | | * device space. |
68 | | */ |
69 | 144k | if (csi == gs_color_space_index_ICC && pcs->cmm_icc_profile_data) |
70 | 141k | csi = gsicc_get_default_type(pcs->cmm_icc_profile_data); |
71 | | |
72 | 144k | return csi; |
73 | 144k | } |
74 | | |
75 | | /* Get the current color space (the base one) from current graphics state. |
76 | | * index -- tells whether to pull from 0 or 1 (probably 0) |
77 | | */ |
78 | | gs_color_space_index pdfi_currentcolorspace(pdf_context *ctx, int index) |
79 | 144k | { |
80 | 144k | const gs_color_space *pcs; |
81 | | |
82 | 144k | pcs = ctx->pgs->color[index].color_space; |
83 | | |
84 | 144k | return pdfi_get_color_space_index(ctx, pcs); |
85 | 144k | } |
86 | | |
87 | | |
88 | | int |
89 | | pdfi_name_strcmp(const pdf_name *n, const char *s) |
90 | 33.3k | { |
91 | 33.3k | int len = strlen(s); |
92 | 33.3k | if (n->length == len) |
93 | 33.0k | return memcmp(n->data, s, len); |
94 | 348 | return -1; |
95 | 33.3k | } |
96 | | |
97 | | bool |
98 | | pdfi_string_is(const pdf_string *n, const char *s) |
99 | 1 | { |
100 | 1 | int len = strlen(s); |
101 | 1 | if (n->length == len) |
102 | 1 | return (memcmp(n->data, s, len) == 0); |
103 | 0 | return false; |
104 | 1 | } |
105 | | |
106 | | bool |
107 | | pdfi_name_is(const pdf_name *n, const char *s) |
108 | 19.1G | { |
109 | 19.1G | int len = strlen(s); |
110 | 19.1G | if (n->length == len) |
111 | 3.09G | return (memcmp(n->data, s, len) == 0); |
112 | 16.0G | return false; |
113 | 19.1G | } |
114 | | |
115 | | bool |
116 | | pdfi_name_or_string_is(const pdf_obj *n, char *s) |
117 | 0 | { |
118 | 0 | if (pdfi_type_of(n) == PDF_NAME) |
119 | 0 | return(pdfi_name_is((const pdf_name *)n, s)); |
120 | 0 | if (pdfi_type_of(n) == PDF_STRING) |
121 | 0 | return(pdfi_string_is((const pdf_string *)n, s)); |
122 | 0 | return false; |
123 | 0 | } |
124 | | |
125 | | int |
126 | | pdfi_name_cmp(const pdf_name *n1, const pdf_name *n2) |
127 | 92.5k | { |
128 | 92.5k | if (n1->length != n2->length) |
129 | 942 | return -1; |
130 | 91.6k | return memcmp(n1->data, n2->data, n1->length); |
131 | 92.5k | } |
132 | | |
133 | | int |
134 | | pdfi_string_cmp(const pdf_string *n1, const pdf_string *n2) |
135 | 0 | { |
136 | 0 | if (n1->length != n2->length) |
137 | 0 | return -1; |
138 | 0 | return memcmp(n1->data, n2->data, n1->length); |
139 | 0 | } |
140 | | |
141 | | /* Set rendering intent, translating from name to number */ |
142 | | int pdfi_setrenderingintent(pdf_context *ctx, pdf_name *n) |
143 | 80.1k | { |
144 | 80.1k | int code = 0; |
145 | | |
146 | 80.1k | if (pdfi_name_is(n, "Perceptual")) { |
147 | 65.0k | code = gs_setrenderingintent(ctx->pgs, 0); |
148 | 65.0k | } else if (pdfi_name_is(n, "Saturation")) { |
149 | 0 | code = gs_setrenderingintent(ctx->pgs, 2); |
150 | 15.1k | } else if (pdfi_name_is(n, "RelativeColorimetric")) { |
151 | 14.4k | code = gs_setrenderingintent(ctx->pgs, 1); |
152 | 14.4k | } else if (pdfi_name_is(n, "AbsoluteColorimetric")) { |
153 | 0 | code = gs_setrenderingintent(ctx->pgs, 3); |
154 | 688 | } else { |
155 | | /* PDF 1.7 Reference, bottom of page 260 if a PDF uses an unknown rendering intent |
156 | | * then use RelativeColoimetric. But flag a warning. |
157 | | */ |
158 | 688 | pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_RENDERINGINTENT, "pdfi_setrenderingintent", ""); |
159 | 688 | code = gs_setrenderingintent(ctx->pgs, 1); |
160 | 688 | } |
161 | 80.1k | return code; |
162 | 80.1k | } |
163 | | |
164 | | int pdfi_string_from_name(pdf_context *ctx, pdf_name *n, char **str, int *len) |
165 | 611k | { |
166 | 611k | if (pdfi_type_of(n) != PDF_NAME) |
167 | 0 | return gs_note_error(gs_error_typecheck); |
168 | | |
169 | 611k | *str = NULL; |
170 | 611k | *len = 0; |
171 | | |
172 | 611k | *str = (char *)gs_alloc_bytes(ctx->memory, (size_t)n->length + 1, "pdfi_string_from_name"); |
173 | 611k | if (*str == NULL) |
174 | 0 | return gs_note_error(gs_error_VMerror); |
175 | | |
176 | 611k | memcpy(*str, n->data, n->length); |
177 | 611k | (*str)[n->length] = 0x00; |
178 | 611k | *len = n->length; |
179 | | |
180 | 611k | return 0; |
181 | 611k | } |
182 | | |
183 | | int pdfi_free_string_from_name(pdf_context *ctx, char *str) |
184 | 733k | { |
185 | 733k | if (str != NULL) |
186 | 611k | gs_free_object(ctx->memory, str, "pdfi_free_string_from_name"); |
187 | 733k | return 0; |
188 | 733k | } |
189 | | |
190 | | void normalize_rectangle(double *d) |
191 | 98.1k | { |
192 | 98.1k | double d1[4]; |
193 | 98.1k | int i; |
194 | | |
195 | 98.1k | if (d[0] < d[2]) { |
196 | 98.1k | d1[0] = d[0]; |
197 | 98.1k | d1[2] = d[2]; |
198 | 98.1k | } else { |
199 | 41 | d1[0] = d[2]; |
200 | 41 | d1[2] = d[0]; |
201 | 41 | } |
202 | 98.1k | if (d[1] < d[3]) { |
203 | 98.1k | d1[1] = d[1]; |
204 | 98.1k | d1[3] = d[3]; |
205 | 98.1k | } else { |
206 | 32 | d1[1] = d[3]; |
207 | 32 | d1[3] = d[1]; |
208 | 32 | } |
209 | 490k | for (i=0;i<=3;i++){ |
210 | 392k | d[i] = d1[i]; |
211 | 392k | } |
212 | 98.1k | } |
213 | | |
214 | | /* Free an array of cstrings, sets the pointer to null */ |
215 | | void pdfi_free_cstring_array(pdf_context *ctx, char ***pstrlist) |
216 | 211k | { |
217 | 211k | char **ptr = *pstrlist; |
218 | | |
219 | 211k | if (ptr == NULL) |
220 | 211k | return; |
221 | | |
222 | 0 | while (*ptr) { |
223 | 0 | gs_free_object(ctx->memory, *ptr, "pdfi_free_cstring_array(item)"); |
224 | 0 | ptr ++; |
225 | 0 | } |
226 | 0 | gs_free_object(ctx->memory, *pstrlist, "pdfi_free_cstring_array(array)"); |
227 | 0 | *pstrlist = NULL; |
228 | 0 | } |
229 | | |
230 | | /* Parse an argument string of names into an array of cstrings */ |
231 | | /* Format: /Item1,/Item2,/Item3 (no white space) */ |
232 | | int pdfi_parse_name_cstring_array(pdf_context *ctx, char *data, uint64_t size, char ***pstrlist) |
233 | 0 | { |
234 | 0 | char **strlist = NULL; |
235 | 0 | char **templist = NULL; |
236 | 0 | int numitems = 0, item; |
237 | 0 | int strnum; |
238 | 0 | uint64_t i; |
239 | 0 | char *strptr; |
240 | 0 | int code = 0; |
241 | | |
242 | | /* Free it if it already exists */ |
243 | 0 | if (*pstrlist != NULL) |
244 | 0 | pdfi_free_cstring_array(ctx, pstrlist); |
245 | | |
246 | | /* find out how many '/' characters there are -- this is the max possible number |
247 | | * of items in the list |
248 | | */ |
249 | 0 | for (i=0, strptr = data; i<size; i++,strptr++) { |
250 | 0 | if (*strptr == '/') |
251 | 0 | numitems ++; |
252 | | /* early exit if we hit a null */ |
253 | 0 | if (*strptr == 0) |
254 | 0 | break; |
255 | 0 | } |
256 | | |
257 | | /* Allocate space for the array of char * (plus one extra for null termination) */ |
258 | 0 | strlist = (char **)gs_alloc_bytes(ctx->memory, ((size_t)numitems+1)*sizeof(char *), |
259 | 0 | "pdfi_parse_cstring_array(strlist)"); |
260 | 0 | if (strlist == NULL) |
261 | 0 | return_error(gs_error_VMerror); |
262 | | |
263 | 0 | memset(strlist, 0, (numitems+1)*sizeof(char *)); |
264 | | |
265 | | /* Allocate a temp array */ |
266 | 0 | templist = (char **)gs_alloc_bytes(ctx->memory, ((size_t)numitems+1)*sizeof(char *), |
267 | 0 | "pdfi_parse_cstring_array(templist)"); |
268 | 0 | if (templist == NULL) { |
269 | 0 | code = gs_note_error(gs_error_VMerror); |
270 | 0 | goto exit; |
271 | 0 | } |
272 | | |
273 | 0 | memset(templist, 0, (numitems+1)*sizeof(char *)); |
274 | | |
275 | | /* Find start ptr of each string */ |
276 | 0 | item = 0; |
277 | 0 | for (i=0, strptr = data; i<size; i++,strptr++) { |
278 | 0 | if (*strptr == '/') { |
279 | 0 | templist[item] = strptr+1; |
280 | 0 | item++; |
281 | 0 | } |
282 | 0 | } |
283 | | |
284 | | /* Find each substring, alloc, copy into string array */ |
285 | 0 | strnum = 0; |
286 | 0 | for (i=0; i<numitems; i++) { |
287 | 0 | char *curstr, *nextstr; |
288 | 0 | int length; |
289 | 0 | char *newstr; |
290 | |
|
291 | 0 | curstr = templist[i]; |
292 | 0 | nextstr = templist[i+1]; |
293 | 0 | if (!curstr) |
294 | 0 | break; |
295 | 0 | if (*curstr == '/' || *curstr == ',') { |
296 | | /* Empty string, skip it */ |
297 | 0 | continue; |
298 | 0 | } |
299 | 0 | if (nextstr == NULL) { |
300 | 0 | length = size-(curstr-data); |
301 | 0 | } else { |
302 | 0 | length = nextstr - curstr - 1; |
303 | 0 | } |
304 | 0 | if (curstr[length-1] == ',') |
305 | 0 | length --; |
306 | | |
307 | | /* Allocate the string and copy it */ |
308 | 0 | newstr = (char *)gs_alloc_bytes(ctx->memory, (size_t)length+1, |
309 | 0 | "pdfi_parse_cstring_array(newstr)"); |
310 | 0 | if (newstr == NULL) { |
311 | 0 | code = gs_note_error(gs_error_VMerror); |
312 | 0 | goto exit; |
313 | 0 | } |
314 | 0 | memcpy(newstr, curstr, length); |
315 | 0 | newstr[length+1] = 0; /* Null terminate */ |
316 | 0 | strlist[strnum] = newstr; |
317 | 0 | strnum ++; |
318 | 0 | } |
319 | | |
320 | 0 | *pstrlist = strlist; |
321 | |
|
322 | 0 | exit: |
323 | 0 | if (code < 0) |
324 | 0 | pdfi_free_cstring_array(ctx, &strlist); |
325 | 0 | if (templist) |
326 | | gs_free_object(ctx->memory, templist, "pdfi_parse_cstring_array(templist(array))"); |
327 | 0 | return code; |
328 | 0 | } |