/src/ghostpdl/base/gsdevmem.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-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 | | |
17 | | /* Memory device creation for Ghostscript library */ |
18 | | #include "math_.h" /* for fabs */ |
19 | | #include "memory_.h" |
20 | | #include "gx.h" |
21 | | #include "gserrors.h" |
22 | | #include "gsdevice.h" /* for prototypes */ |
23 | | #include "gxarith.h" |
24 | | #include "gxdevice.h" |
25 | | #include "gxdevmem.h" |
26 | | |
27 | | /* Make a memory (image) device. */ |
28 | | /* If colors_size = -16, -24, or -32, this is a true-color device; */ |
29 | | /* otherwise, colors_size is the size of the palette in bytes */ |
30 | | /* (2^N for gray scale, 3*2^N for RGB color). */ |
31 | | /* We separate device allocation and initialization at customer request. */ |
32 | | int |
33 | | gs_initialize_wordimagedevice(gx_device_memory * new_dev, const gs_matrix * pmat, |
34 | | uint width, uint height, const byte * colors, int colors_size, |
35 | | bool word_oriented, bool page_device, gs_memory_t * mem) |
36 | 0 | { |
37 | 0 | const gx_device_memory *proto_dev; |
38 | 0 | int palette_count = colors_size; |
39 | 0 | int num_components = 1; |
40 | 0 | int pcount; |
41 | 0 | int bits_per_pixel; |
42 | 0 | float x_pixels_per_unit, y_pixels_per_unit; |
43 | 0 | byte palette[256 * 3]; |
44 | 0 | bool has_color; |
45 | 0 | int code; |
46 | 0 | gs_rect bbox; |
47 | |
|
48 | 0 | bbox.p.x = 0; |
49 | 0 | bbox.p.y = 0; |
50 | 0 | bbox.q.x = width; |
51 | 0 | bbox.q.y = height; |
52 | 0 | code = gs_bbox_transform_inverse(&bbox, pmat, &bbox); |
53 | 0 | if (code < 0) |
54 | 0 | return code; |
55 | | |
56 | 0 | switch (colors_size) { |
57 | 0 | case 3 * 2: |
58 | 0 | palette_count = 2; |
59 | 0 | num_components = 3; |
60 | | /* fall through */ |
61 | 0 | case 2: |
62 | 0 | bits_per_pixel = 1; |
63 | 0 | break; |
64 | 0 | case 3 * 4: |
65 | 0 | palette_count = 4; |
66 | 0 | num_components = 3; |
67 | | /* fall through */ |
68 | 0 | case 4: |
69 | 0 | bits_per_pixel = 2; |
70 | 0 | break; |
71 | 0 | case 3 * 16: |
72 | 0 | palette_count = 16; |
73 | 0 | num_components = 3; |
74 | | /* fall through */ |
75 | 0 | case 16: |
76 | 0 | bits_per_pixel = 4; |
77 | 0 | break; |
78 | 0 | case 3 * 256: |
79 | 0 | palette_count = 256; |
80 | 0 | num_components = 3; |
81 | | /* fall through */ |
82 | 0 | case 256: |
83 | 0 | bits_per_pixel = 8; |
84 | 0 | break; |
85 | 0 | case -16: |
86 | 0 | bits_per_pixel = 16; |
87 | 0 | palette_count = 0; |
88 | 0 | break; |
89 | 0 | case -24: |
90 | 0 | bits_per_pixel = 24; |
91 | 0 | palette_count = 0; |
92 | 0 | break; |
93 | 0 | case -32: |
94 | 0 | bits_per_pixel = 32; |
95 | 0 | palette_count = 0; |
96 | 0 | break; |
97 | 0 | default: |
98 | 0 | return_error(gs_error_rangecheck); |
99 | 0 | } |
100 | 0 | proto_dev = (word_oriented ? |
101 | 0 | gdev_mem_word_device_for_bits(bits_per_pixel) : |
102 | 0 | gdev_mem_device_for_bits(bits_per_pixel)); |
103 | 0 | if (proto_dev == 0) /* no suitable device */ |
104 | 0 | return_error(gs_error_rangecheck); |
105 | 0 | pcount = palette_count * 3; |
106 | | /* Check to make sure the palette contains white and black, */ |
107 | | /* and, if it has any colors, the six primaries. */ |
108 | 0 | if (bits_per_pixel <= 8) { |
109 | 0 | const byte *p; |
110 | 0 | byte *q; |
111 | 0 | int primary_mask = 0; |
112 | 0 | int i; |
113 | |
|
114 | 0 | has_color = false; |
115 | 0 | for (i = 0, p = colors, q = palette; |
116 | 0 | i < palette_count; i++, q += 3 |
117 | 0 | ) { |
118 | 0 | int mask = 1; |
119 | |
|
120 | 0 | switch (num_components) { |
121 | 0 | case 1: /* gray */ |
122 | 0 | q[0] = q[1] = q[2] = *p++; |
123 | 0 | break; |
124 | 0 | default /* case 3 */ : /* RGB */ |
125 | 0 | q[0] = p[0], q[1] = p[1], q[2] = p[2]; |
126 | 0 | p += 3; |
127 | 0 | } |
128 | 0 | #define shift_mask(b,n)\ |
129 | 0 | switch ( b ) { case 0xff: mask <<= n; case 0: break; default: mask = 0; } |
130 | 0 | shift_mask(q[0], 4); |
131 | 0 | shift_mask(q[1], 2); |
132 | 0 | shift_mask(q[2], 1); |
133 | 0 | #undef shift_mask |
134 | 0 | primary_mask |= mask; |
135 | 0 | if (q[0] != q[1] || q[0] != q[2]) |
136 | 0 | has_color = true; |
137 | 0 | } |
138 | 0 | switch (primary_mask) { |
139 | 0 | case 129: /* just black and white */ |
140 | 0 | if (has_color) /* color but no primaries */ |
141 | 0 | return_error(gs_error_rangecheck); |
142 | 0 | case 255: /* full color */ |
143 | 0 | break; |
144 | 0 | default: |
145 | 0 | return_error(gs_error_rangecheck); |
146 | 0 | } |
147 | 0 | } else |
148 | 0 | has_color = true; |
149 | | /* |
150 | | * The initial transformation matrix must map 1 user unit to |
151 | | * 1/72". Let W and H be the width and height in pixels, and |
152 | | * assume the initial matrix is of the form [A 0 0 B X Y]. |
153 | | * Then the size of the image in user units is (W/|A|,H/|B|), |
154 | | * hence the size in inches is ((W/|A|)/72,(H/|B|)/72), so |
155 | | * the number of pixels per inch is |
156 | | * (W/((W/|A|)/72),H/((H/|B|)/72)), or (|A|*72,|B|*72). |
157 | | * Similarly, if the initial matrix is [0 A B 0 X Y] for a 90 |
158 | | * or 270 degree rotation, the size of the image in user |
159 | | * units is (W/|B|,H/|A|), so the pixels per inch are |
160 | | * (|B|*72,|A|*72). We forbid non-orthogonal transformation |
161 | | * matrices. |
162 | | */ |
163 | 0 | if (is_fzero2(pmat->xy, pmat->yx)) |
164 | 0 | x_pixels_per_unit = pmat->xx, y_pixels_per_unit = pmat->yy; |
165 | 0 | else if (is_fzero2(pmat->xx, pmat->yy)) |
166 | 0 | x_pixels_per_unit = pmat->yx, y_pixels_per_unit = pmat->xy; |
167 | 0 | else |
168 | 0 | return_error(gs_error_undefinedresult); |
169 | | /* All checks done, initialize the device. */ |
170 | 0 | if (bits_per_pixel == 1) { |
171 | | /* Determine the polarity from the palette. */ |
172 | 0 | gs_make_mem_device(new_dev, proto_dev, mem, |
173 | 0 | (page_device ? 1 : -1), 0); |
174 | | /* This is somewhat bogus, but does the right thing */ |
175 | | /* in the only cases we care about. */ |
176 | 0 | gdev_mem_mono_set_inverted(new_dev, |
177 | 0 | (palette[0] | palette[1] | palette[2]) != 0); |
178 | 0 | } else { |
179 | 0 | byte *dev_palette = gs_alloc_string(mem, pcount, |
180 | 0 | "gs_makeimagedevice(palette)"); |
181 | |
|
182 | 0 | if (dev_palette == 0) |
183 | 0 | return_error(gs_error_VMerror); |
184 | 0 | gs_make_mem_device(new_dev, proto_dev, mem, |
185 | 0 | (page_device ? 1 : -1), 0); |
186 | 0 | new_dev->palette.size = pcount; |
187 | 0 | new_dev->palette.data = dev_palette; |
188 | 0 | memcpy(dev_palette, palette, pcount); |
189 | 0 | if (!has_color) { |
190 | 0 | new_dev->color_info.num_components = 1; |
191 | 0 | new_dev->color_info.max_color = 0; |
192 | 0 | new_dev->color_info.dither_colors = 0; |
193 | 0 | new_dev->color_info.gray_index = 0; |
194 | 0 | } |
195 | 0 | } |
196 | | /* Memory defice is always initialised as an internal device but */ |
197 | | /* this is an external device */ |
198 | 0 | new_dev->retained = true; |
199 | 0 | rc_init(new_dev, new_dev->memory, 1); |
200 | |
|
201 | 0 | new_dev->initial_matrix = *pmat; |
202 | 0 | new_dev->HWResolution[0] = fabs(x_pixels_per_unit) * 72; |
203 | 0 | new_dev->HWResolution[1] = fabs(y_pixels_per_unit) * 72; |
204 | 0 | gx_device_set_width_height((gx_device *) new_dev, width, height); |
205 | | /* Set the ImagingBBox so we get a correct clipping region. */ |
206 | 0 | { |
207 | 0 | new_dev->ImagingBBox[0] = bbox.p.x; |
208 | 0 | new_dev->ImagingBBox[1] = bbox.p.y; |
209 | 0 | new_dev->ImagingBBox[2] = bbox.q.x; |
210 | 0 | new_dev->ImagingBBox[3] = bbox.q.y; |
211 | 0 | new_dev->ImagingBBox_set = true; |
212 | 0 | } |
213 | | /* The bitmap will be allocated when the device is opened. */ |
214 | 0 | new_dev->is_open = false; |
215 | 0 | new_dev->bitmap_memory = mem; |
216 | 0 | return 0; |
217 | 0 | } |
218 | | |
219 | | int |
220 | | gs_makewordimagedevice(gx_device ** pnew_dev, const gs_matrix * pmat, |
221 | | uint width, uint height, const byte * colors, int num_colors, |
222 | | bool word_oriented, bool page_device, gs_memory_t * mem) |
223 | 0 | { |
224 | 0 | int code; |
225 | 0 | gx_device_memory *pnew = |
226 | 0 | gs_alloc_struct_immovable(mem, gx_device_memory, &st_device_memory, |
227 | 0 | "gs_makeimagedevice(device)"); |
228 | |
|
229 | 0 | if (pnew == 0) |
230 | 0 | return_error(gs_error_VMerror); |
231 | | |
232 | | /* Bug #697450 "Null pointer dereference in gx_device_finalize()" |
233 | | * If we have incorrect data passed to gs_initialise_wordimagedevice() then the |
234 | | * initialisation will fail, crucially it will fail *before* it calls |
235 | | * gs_make_mem_device() which initialises the device. This means that the |
236 | | * icc_struct member will be uninitialsed, but the device finalise method |
237 | | * will unconditionally free that memory. Since its a garbage pointer, bad things happen. |
238 | | * Apparently we do still need makeimagedevice to be available from |
239 | | * PostScript, so in here just zero the device memory, which means that |
240 | | * the finalise routine won't have a problem. |
241 | | */ |
242 | 0 | memset(pnew, 0x00, st_device_memory.ssize); |
243 | 0 | code = gs_initialize_wordimagedevice(pnew, pmat, width, height, |
244 | 0 | colors, num_colors, word_oriented, |
245 | 0 | page_device, mem); |
246 | 0 | if (code < 0) { |
247 | 0 | gs_free_object(mem, pnew, "gs_makeimagedevice(device)"); |
248 | 0 | return code; |
249 | 0 | } |
250 | 0 | *pnew_dev = (gx_device *) pnew; |
251 | 0 | return 0; |
252 | 0 | } |