/src/ghostpdl/pdf/pdf_misc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2019-2023 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 | 23.6k | { |
31 | 23.6k | int code, code1; |
32 | | |
33 | 23.6k | if (stroked) { |
34 | 1.72k | code = pdfi_gsave(ctx); |
35 | 1.72k | if (code < 0) |
36 | 0 | return code; |
37 | 1.72k | code = gs_strokepath(ctx->pgs); |
38 | 1.72k | if (code < 0) |
39 | 0 | goto exit; |
40 | 1.72k | } |
41 | 23.6k | code = gs_upathbbox(ctx->pgs, bbox, false); |
42 | | |
43 | 23.6k | exit: |
44 | 23.6k | if (stroked) { |
45 | 1.72k | code1 = pdfi_grestore(ctx); |
46 | 1.72k | if (code == 0) |
47 | 528 | code = code1; |
48 | 1.72k | } |
49 | 23.6k | return code; |
50 | 23.6k | } |
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 | 235k | { |
56 | 235k | gs_color_space_index csi; |
57 | | |
58 | | /* Get the color space index */ |
59 | 235k | csi = gs_color_space_get_index(pcs); |
60 | | |
61 | | /* If its an Indexed space, then use the base space */ |
62 | 235k | if (csi == gs_color_space_index_Indexed) |
63 | 197 | 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 | 235k | if (csi == gs_color_space_index_ICC && pcs->cmm_icc_profile_data) |
70 | 230k | csi = gsicc_get_default_type(pcs->cmm_icc_profile_data); |
71 | | |
72 | 235k | return csi; |
73 | 235k | } |
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 | 235k | { |
80 | 235k | const gs_color_space *pcs; |
81 | | |
82 | 235k | pcs = ctx->pgs->color[index].color_space; |
83 | | |
84 | 235k | return pdfi_get_color_space_index(ctx, pcs); |
85 | 235k | } |
86 | | |
87 | | |
88 | | int |
89 | | pdfi_name_strcmp(const pdf_name *n, const char *s) |
90 | 35.6k | { |
91 | 35.6k | int len = strlen(s); |
92 | 35.6k | if (n->length == len) |
93 | 35.3k | return memcmp(n->data, s, len); |
94 | 351 | return -1; |
95 | 35.6k | } |
96 | | |
97 | | bool |
98 | | pdfi_string_is(const pdf_string *n, const char *s) |
99 | 0 | { |
100 | 0 | int len = strlen(s); |
101 | 0 | if (n->length == len) |
102 | 0 | return (memcmp(n->data, s, len) == 0); |
103 | 0 | return false; |
104 | 0 | } |
105 | | |
106 | | bool |
107 | | pdfi_name_is(const pdf_name *n, const char *s) |
108 | 20.2G | { |
109 | 20.2G | int len = strlen(s); |
110 | 20.2G | if (n->length == len) |
111 | 3.12G | return (memcmp(n->data, s, len) == 0); |
112 | 17.0G | return false; |
113 | 20.2G | } |
114 | | |
115 | | int |
116 | | pdfi_name_cmp(const pdf_name *n1, const pdf_name *n2) |
117 | 164k | { |
118 | 164k | if (n1->length != n2->length) |
119 | 784 | return -1; |
120 | 163k | return memcmp(n1->data, n2->data, n1->length); |
121 | 164k | } |
122 | | |
123 | | int |
124 | | pdfi_string_cmp(const pdf_string *n1, const pdf_string *n2) |
125 | 0 | { |
126 | 0 | if (n1->length != n2->length) |
127 | 0 | return -1; |
128 | 0 | return memcmp(n1->data, n2->data, n1->length); |
129 | 0 | } |
130 | | |
131 | | /* Set rendering intent, translating from name to number */ |
132 | | int pdfi_setrenderingintent(pdf_context *ctx, pdf_name *n) |
133 | 147k | { |
134 | 147k | int code = 0; |
135 | | |
136 | 147k | if (pdfi_name_is(n, "Perceptual")) { |
137 | 128k | code = gs_setrenderingintent(ctx->pgs, 0); |
138 | 128k | } else if (pdfi_name_is(n, "Saturation")) { |
139 | 0 | code = gs_setrenderingintent(ctx->pgs, 2); |
140 | 19.2k | } else if (pdfi_name_is(n, "RelativeColorimetric")) { |
141 | 18.1k | code = gs_setrenderingintent(ctx->pgs, 1); |
142 | 18.1k | } else if (pdfi_name_is(n, "AbsoluteColorimetric")) { |
143 | 0 | code = gs_setrenderingintent(ctx->pgs, 3); |
144 | 1.14k | } else { |
145 | | /* PDF 1.7 Reference, bottom of page 260 if a PDF uses an unknown rendering intent |
146 | | * then use RelativeColoimetric. But flag a warning. |
147 | | */ |
148 | 1.14k | pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_RENDERINGINTENT, "pdfi_setrenderingintent", ""); |
149 | 1.14k | code = gs_setrenderingintent(ctx->pgs, 1); |
150 | 1.14k | } |
151 | 147k | return code; |
152 | 147k | } |
153 | | |
154 | | int pdfi_string_from_name(pdf_context *ctx, pdf_name *n, char **str, int *len) |
155 | 638k | { |
156 | 638k | if (pdfi_type_of(n) != PDF_NAME) |
157 | 0 | return gs_note_error(gs_error_typecheck); |
158 | | |
159 | 638k | *str = NULL; |
160 | 638k | *len = 0; |
161 | | |
162 | 638k | *str = (char *)gs_alloc_bytes(ctx->memory, n->length + 1, "pdfi_string_from_name"); |
163 | 638k | if (*str == NULL) |
164 | 0 | return gs_note_error(gs_error_VMerror); |
165 | | |
166 | 638k | memcpy(*str, n->data, n->length); |
167 | 638k | (*str)[n->length] = 0x00; |
168 | 638k | *len = n->length; |
169 | | |
170 | 638k | return 0; |
171 | 638k | } |
172 | | |
173 | | int pdfi_free_string_from_name(pdf_context *ctx, char *str) |
174 | 767k | { |
175 | 767k | if (str != NULL) |
176 | 638k | gs_free_object(ctx->memory, str, "pdfi_free_string_from_name"); |
177 | 767k | return 0; |
178 | 767k | } |
179 | | |
180 | | void normalize_rectangle(double *d) |
181 | 103k | { |
182 | 103k | double d1[4]; |
183 | 103k | int i; |
184 | | |
185 | 103k | if (d[0] < d[2]) { |
186 | 103k | d1[0] = d[0]; |
187 | 103k | d1[2] = d[2]; |
188 | 103k | } else { |
189 | 46 | d1[0] = d[2]; |
190 | 46 | d1[2] = d[0]; |
191 | 46 | } |
192 | 103k | if (d[1] < d[3]) { |
193 | 103k | d1[1] = d[1]; |
194 | 103k | d1[3] = d[3]; |
195 | 103k | } else { |
196 | 39 | d1[1] = d[3]; |
197 | 39 | d1[3] = d[1]; |
198 | 39 | } |
199 | 519k | for (i=0;i<=3;i++){ |
200 | 415k | d[i] = d1[i]; |
201 | 415k | } |
202 | 103k | } |
203 | | |
204 | | /* Free an array of cstrings, sets the pointer to null */ |
205 | | void pdfi_free_cstring_array(pdf_context *ctx, char ***pstrlist) |
206 | 189k | { |
207 | 189k | char **ptr = *pstrlist; |
208 | | |
209 | 189k | if (ptr == NULL) |
210 | 189k | return; |
211 | | |
212 | 0 | while (*ptr) { |
213 | 0 | gs_free_object(ctx->memory, *ptr, "pdfi_free_cstring_array(item)"); |
214 | 0 | ptr ++; |
215 | 0 | } |
216 | 0 | gs_free_object(ctx->memory, *pstrlist, "pdfi_free_cstring_array(array)"); |
217 | 0 | *pstrlist = NULL; |
218 | 0 | } |
219 | | |
220 | | /* Parse an argument string of names into an array of cstrings */ |
221 | | /* Format: /Item1,/Item2,/Item3 (no white space) */ |
222 | | int pdfi_parse_name_cstring_array(pdf_context *ctx, char *data, uint64_t size, char ***pstrlist) |
223 | 0 | { |
224 | 0 | char **strlist = NULL; |
225 | 0 | char **templist = NULL; |
226 | 0 | int numitems = 0, item; |
227 | 0 | int strnum; |
228 | 0 | uint64_t i; |
229 | 0 | char *strptr; |
230 | 0 | int code = 0; |
231 | | |
232 | | /* Free it if it already exists */ |
233 | 0 | if (*pstrlist != NULL) |
234 | 0 | pdfi_free_cstring_array(ctx, pstrlist); |
235 | | |
236 | | /* find out how many '/' characters there are -- this is the max possible number |
237 | | * of items in the list |
238 | | */ |
239 | 0 | for (i=0, strptr = data; i<size; i++,strptr++) { |
240 | 0 | if (*strptr == '/') |
241 | 0 | numitems ++; |
242 | | /* early exit if we hit a null */ |
243 | 0 | if (*strptr == 0) |
244 | 0 | break; |
245 | 0 | } |
246 | | |
247 | | /* Allocate space for the array of char * (plus one extra for null termination) */ |
248 | 0 | strlist = (char **)gs_alloc_bytes(ctx->memory, (numitems+1)*sizeof(char *), |
249 | 0 | "pdfi_parse_cstring_array(strlist)"); |
250 | 0 | if (strlist == NULL) |
251 | 0 | return_error(gs_error_VMerror); |
252 | | |
253 | 0 | memset(strlist, 0, (numitems+1)*sizeof(char *)); |
254 | | |
255 | | /* Allocate a temp array */ |
256 | 0 | templist = (char **)gs_alloc_bytes(ctx->memory, (numitems+1)*sizeof(char *), |
257 | 0 | "pdfi_parse_cstring_array(templist)"); |
258 | 0 | if (templist == NULL) { |
259 | 0 | code = gs_note_error(gs_error_VMerror); |
260 | 0 | goto exit; |
261 | 0 | } |
262 | | |
263 | 0 | memset(templist, 0, (numitems+1)*sizeof(char *)); |
264 | | |
265 | | /* Find start ptr of each string */ |
266 | 0 | item = 0; |
267 | 0 | for (i=0, strptr = data; i<size; i++,strptr++) { |
268 | 0 | if (*strptr == '/') { |
269 | 0 | templist[item] = strptr+1; |
270 | 0 | item++; |
271 | 0 | } |
272 | 0 | } |
273 | | |
274 | | /* Find each substring, alloc, copy into string array */ |
275 | 0 | strnum = 0; |
276 | 0 | for (i=0; i<numitems; i++) { |
277 | 0 | char *curstr, *nextstr; |
278 | 0 | int length; |
279 | 0 | char *newstr; |
280 | |
|
281 | 0 | curstr = templist[i]; |
282 | 0 | nextstr = templist[i+1]; |
283 | 0 | if (!curstr) |
284 | 0 | break; |
285 | 0 | if (*curstr == '/' || *curstr == ',') { |
286 | | /* Empty string, skip it */ |
287 | 0 | continue; |
288 | 0 | } |
289 | 0 | if (nextstr == NULL) { |
290 | 0 | length = size-(curstr-data); |
291 | 0 | } else { |
292 | 0 | length = nextstr - curstr - 1; |
293 | 0 | } |
294 | 0 | if (curstr[length-1] == ',') |
295 | 0 | length --; |
296 | | |
297 | | /* Allocate the string and copy it */ |
298 | 0 | newstr = (char *)gs_alloc_bytes(ctx->memory, length+1, |
299 | 0 | "pdfi_parse_cstring_array(newstr)"); |
300 | 0 | if (newstr == NULL) { |
301 | 0 | code = gs_note_error(gs_error_VMerror); |
302 | 0 | goto exit; |
303 | 0 | } |
304 | 0 | memcpy(newstr, curstr, length); |
305 | 0 | newstr[length+1] = 0; /* Null terminate */ |
306 | 0 | strlist[strnum] = newstr; |
307 | 0 | strnum ++; |
308 | 0 | } |
309 | | |
310 | 0 | *pstrlist = strlist; |
311 | |
|
312 | 0 | exit: |
313 | 0 | if (code < 0) |
314 | 0 | pdfi_free_cstring_array(ctx, &strlist); |
315 | 0 | if (templist) |
316 | 0 | gs_free_object(ctx->memory, templist, "pdfi_parse_cstring_array(templist(array))"); |
317 | 0 | return code; |
318 | 0 | } |