Commit | Line | Data |
---|---|---|
35b68964 WJ |
1 | /* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved. |
2 | Distributed by Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of Ghostscript. | |
5 | ||
6 | Ghostscript is distributed in the hope that it will be useful, but | |
7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
8 | to anyone for the consequences of using it or for whether it serves any | |
9 | particular purpose or works at all, unless he says so in writing. Refer | |
10 | to the Ghostscript General Public License for full details. | |
11 | ||
12 | Everyone is granted permission to copy, modify and redistribute | |
13 | Ghostscript, but only under the conditions described in the Ghostscript | |
14 | General Public License. A copy of this license is supposed to have been | |
15 | given to you along with Ghostscript so you can know your rights and | |
16 | responsibilities. It should be in a file named COPYING. Among other | |
17 | things, the copyright notice and this notice must be preserved on all | |
18 | copies. */ | |
19 | ||
20 | /* gsmisc.c */ | |
21 | /* Miscellaneous utilities for Ghostscript library */ | |
22 | #include "gx.h" | |
23 | #include "malloc_.h" | |
24 | #include "memory_.h" | |
25 | ||
26 | /* Ghostscript writes to gs_out instead of stdout, */ | |
27 | /* and writes debugging output to gs_debug_out. */ | |
28 | FILE *gs_out; | |
29 | /* We define gs_debug and gs_debug_out even if DEBUG isn't defined, */ | |
30 | /* so that we can compile individual modules with DEBUG set. */ | |
31 | char gs_debug[128]; | |
32 | FILE *gs_debug_out; | |
33 | /* We define gs_log_errors here for the same reason. */ | |
34 | int gs_log_errors = 0; | |
35 | ||
36 | /* We can turn on allocator debugging even if DEBUG isn't defined. */ | |
37 | int gs_alloc_debug = 0; | |
38 | byte gs_alloc_fill_alloc = 0xa1; | |
39 | byte gs_alloc_fill_free = 0xf1; | |
40 | ||
41 | /* Generate a block of unique IDs. */ | |
42 | static ulong gs_next_id = 0; | |
43 | ulong | |
44 | gs_next_ids(uint count) | |
45 | { ulong id; | |
46 | if ( gs_next_id == 0 ) gs_next_id++; | |
47 | id = gs_next_id; | |
48 | gs_next_id += count; | |
49 | return id; | |
50 | } | |
51 | ||
52 | /* Versions of malloc and free compatible with Ghostscript's */ | |
53 | /* model of memory management. We keep track of all allocated */ | |
54 | /* blocks so we can free them at cleanup time. */ | |
55 | /* We must make sure that malloc_blocks leave the block aligned. */ | |
56 | typedef struct malloc_block_s malloc_block; | |
57 | #define malloc_block_data\ | |
58 | malloc_block *next;\ | |
59 | uint size;\ | |
60 | const char *cname | |
61 | struct malloc_block_data_s { malloc_block_data; }; | |
62 | struct malloc_block_s { | |
63 | malloc_block_data; | |
64 | byte _pad[-sizeof(struct malloc_block_data_s) & 7]; /* pad to double */ | |
65 | }; | |
66 | private malloc_block *malloc_list = 0; | |
67 | char * | |
68 | gs_malloc(uint num_elts, uint elt_size, const char *client_name) | |
69 | { char *ptr; | |
70 | const char *msg = ""; | |
71 | if ( num_elts > (max_uint - sizeof(malloc_block)) / elt_size ) | |
72 | { /* Can't represent the size in a uint! */ | |
73 | msg = "too large for size_t"; | |
74 | ptr = 0; | |
75 | } | |
76 | else | |
77 | { uint size = num_elts * elt_size; | |
78 | ptr = malloc(size + sizeof(malloc_block)); | |
79 | if ( ptr == 0 ) | |
80 | msg = "failed"; | |
81 | else | |
82 | { malloc_block *bp = (malloc_block *)ptr; | |
83 | bp->next = malloc_list; | |
84 | bp->size = size; | |
85 | bp->cname = client_name; | |
86 | malloc_list = bp; | |
87 | msg = "OK"; | |
88 | ptr = (char *)(bp + 1); | |
89 | if ( gs_alloc_debug ) | |
90 | { /* Clear the block in an attempt to track down */ | |
91 | /* uninitialized data errors. */ | |
92 | memset(ptr, gs_alloc_fill_alloc, size); | |
93 | } | |
94 | } | |
95 | } | |
96 | if ( gs_alloc_debug || !*msg ) | |
97 | dprintf5("gs_malloc(%s)(%u, %u) = 0x%lx: %s\n", client_name, | |
98 | num_elts, elt_size, (ulong)ptr, msg); | |
99 | return ptr; | |
100 | } | |
101 | void | |
102 | gs_free(char *ptr, uint num_elts, uint elt_size, const char *client_name) | |
103 | { malloc_block *bp = malloc_list; | |
104 | if ( gs_alloc_debug ) | |
105 | dprintf4("gs_free(%s)(0x%lx, %u, %u)\n", client_name, | |
106 | (ulong)ptr, num_elts, elt_size); | |
107 | if ( ptr == (char *)(bp + 1) ) | |
108 | { | |
109 | #ifdef DEBUG | |
110 | if ( bp->size != num_elts * elt_size ) | |
111 | lprintf5("%s: free 0x%lx(%u,%u) size ~= %u\n", | |
112 | client_name, (ulong)ptr, num_elts, elt_size, | |
113 | bp->size); | |
114 | #endif | |
115 | malloc_list = bp->next; | |
116 | if ( gs_alloc_debug ) | |
117 | memset((char *)(bp + 1), gs_alloc_fill_free, bp->size); | |
118 | free(bp); | |
119 | } | |
120 | else | |
121 | { malloc_block *np; | |
122 | for ( ; (np = bp->next) != 0; bp = np ) | |
123 | { if ( ptr == (char *)(np + 1) ) | |
124 | { | |
125 | #ifdef DEBUG | |
126 | if ( np->size != num_elts * elt_size ) | |
127 | lprintf5("%s: free 0x%lx(%u,%u) size ~= %u\n", | |
128 | client_name, (ulong)ptr, num_elts, elt_size, | |
129 | np->size); | |
130 | #endif | |
131 | bp->next = np->next; | |
132 | if ( gs_alloc_debug ) | |
133 | memset((char *)(np + 1), gs_alloc_fill_free, np->size); | |
134 | free(np); | |
135 | return; | |
136 | } | |
137 | } | |
138 | lprintf4("%s: free 0x%lx(%u,%u) not found\n", | |
139 | client_name, (ulong)ptr, num_elts, elt_size); | |
140 | free((char *)((malloc_block *)ptr - 1)); | |
141 | } | |
142 | } | |
143 | void | |
144 | gs_malloc_release() | |
145 | { malloc_block *bp = malloc_list; | |
146 | malloc_block *np; | |
147 | for ( ; bp != 0; bp = np ) | |
148 | { np = bp->next; | |
149 | if ( gs_alloc_debug ) | |
150 | memset((char *)(bp + 1), gs_alloc_fill_free, bp->size); | |
151 | free(bp); | |
152 | } | |
153 | malloc_list = 0; | |
154 | } | |
155 | ||
156 | /* Swap even and odd bytes. */ | |
157 | /* This routine may be supplanted by assembly code. */ | |
158 | #if !USE_ASM | |
159 | #undef memswab /* see memory_.h */ | |
160 | void | |
161 | memswab(const char *src, char *dest, int count) | |
162 | { register const uint *sptr = (const uint *)src; | |
163 | register uint *dptr = (uint *)dest; | |
164 | register int x; | |
165 | register uint w; | |
166 | for ( x = count >> 3; --x >= 0; ) | |
167 | { w = *sptr; | |
168 | #if arch_ints_are_short | |
169 | *dptr = (w >> 8) + (w << 8); | |
170 | w = sptr[1]; | |
171 | dptr[1] = (w >> 8) + (w << 8); | |
172 | w = sptr[2]; | |
173 | dptr[2] = (w >> 8) + (w << 8); | |
174 | w = sptr[3]; | |
175 | dptr[3] = (w >> 8) + (w << 8); | |
176 | sptr += 4, dptr += 4; | |
177 | #else | |
178 | *dptr = ((w << 8) & 0xff00ff00) + ((w >> 8) & 0x00ff00ff); | |
179 | w = sptr[1]; | |
180 | dptr[1] = ((w << 8) & 0xff00ff00) + ((w >> 8) & 0x00ff00ff); | |
181 | sptr += 2, dptr += 2; | |
182 | #endif | |
183 | } | |
184 | switch ( count & 6 ) | |
185 | { | |
186 | case 6: | |
187 | w = ((const ushort *)sptr)[2]; | |
188 | ((ushort *)dptr)[2] = (w >> 8) + (w << 8); | |
189 | case 4: | |
190 | w = ((const ushort *)sptr)[1]; | |
191 | ((ushort *)dptr)[1] = (w >> 8) + (w << 8); | |
192 | case 2: | |
193 | w = ((const ushort *)sptr)[0]; | |
194 | ((ushort *)dptr)[0] = (w >> 8) + (w << 8); | |
195 | case 0: | |
196 | ; | |
197 | } | |
198 | } | |
199 | #endif /* !USE_ASM */ | |
200 | ||
201 | /* Transpose an 8 x 8 block of bits. line_size is the raster of */ | |
202 | /* the input data. dist is the distance between output bytes. */ | |
203 | /* This routine may be supplanted by assembly code. */ | |
204 | #if !USE_ASM | |
205 | ||
206 | #if 1 /* This is the better of the two algorithms. */ | |
207 | ||
208 | void | |
209 | memflip8x8(const byte *inp, int line_size, byte *outp, int dist) | |
210 | { register uint ae, bf, cg, dh; | |
211 | { const byte *ptr4 = inp + (line_size << 2); | |
212 | ae = ((uint)*inp << 8) + *ptr4; | |
213 | inp += line_size, ptr4 += line_size; | |
214 | bf = ((uint)*inp << 8) + *ptr4; | |
215 | inp += line_size, ptr4 += line_size; | |
216 | cg = ((uint)*inp << 8) + *ptr4; | |
217 | inp += line_size, ptr4 += line_size; | |
218 | dh = ((uint)*inp << 8) + *ptr4; | |
219 | } | |
220 | ||
221 | /* Check for all 8 bytes being the same. */ | |
222 | /* This is especially worth doing for the case where all are zero. */ | |
223 | if ( ae == bf && ae == cg && ae == dh && (ae >> 8) == (ae & 0xff) ) | |
224 | { if ( ae == 0 ) goto store; | |
225 | *outp = -((ae >> 7) & 1); | |
226 | outp += dist; | |
227 | *outp = -((ae >> 6) & 1); | |
228 | outp += dist; | |
229 | *outp = -((ae >> 5) & 1); | |
230 | outp += dist; | |
231 | *outp = -((ae >> 4) & 1); | |
232 | outp += dist; | |
233 | *outp = -((ae >> 3) & 1); | |
234 | outp += dist; | |
235 | *outp = -((ae >> 2) & 1); | |
236 | outp += dist; | |
237 | *outp = -((ae >> 1) & 1); | |
238 | outp += dist; | |
239 | *outp = -(ae & 1); | |
240 | return; | |
241 | } | |
242 | ||
243 | { register uint temp; | |
244 | ||
245 | /* Transpose a block of bits between registers. */ | |
246 | #define transpose(r,s,mask,shift)\ | |
247 | r ^= (temp = ((s >> shift) ^ r) & mask);\ | |
248 | s ^= temp << shift | |
249 | ||
250 | /* Transpose blocks of 4 x 4 */ | |
251 | #define transpose4(r) transpose(r,r,0x00f0,4) | |
252 | transpose4(ae); | |
253 | transpose4(bf); | |
254 | transpose4(cg); | |
255 | transpose4(dh); | |
256 | ||
257 | /* Transpose blocks of 2 x 2 */ | |
258 | transpose(ae, cg, 0x3333, 2); | |
259 | transpose(bf, dh, 0x3333, 2); | |
260 | ||
261 | /* Transpose blocks of 1 x 1 */ | |
262 | transpose(ae, bf, 0x5555, 1); | |
263 | transpose(cg, dh, 0x5555, 1); | |
264 | ||
265 | } | |
266 | ||
267 | store: *outp = ae >> 8; | |
268 | outp += dist; | |
269 | *outp = bf >> 8; | |
270 | outp += dist; | |
271 | *outp = cg >> 8; | |
272 | outp += dist; | |
273 | *outp = dh >> 8; | |
274 | outp += dist; | |
275 | *outp = (byte)ae; | |
276 | outp += dist; | |
277 | *outp = (byte)bf; | |
278 | outp += dist; | |
279 | *outp = (byte)cg; | |
280 | outp += dist; | |
281 | *outp = (byte)dh; | |
282 | } | |
283 | ||
284 | #else /* This looked like a good idea, but it's no faster. */ | |
285 | ||
286 | /* Transpose an 8 x 8 block of bits. line_size is the raster of */ | |
287 | /* the input data. dist is the distance between output bytes. */ | |
288 | void | |
289 | memflip8x8(const byte *inp, int line_size, byte *outp, int dist) | |
290 | { /* Define a table that spreads the bits of its index as follows: */ | |
291 | /* 0->0-3, 1->8-11, 2->16-19, 3->24-27, */ | |
292 | /* 4->4-7, 5->12-15, 6->20-23, 7->28-31. */ | |
293 | #define b4(v) v,v+0xf,v+0xf00,v+0xf0f | |
294 | #define b8(v) b4(v),b4(v+0xf0000) | |
295 | #define b16(v) b8(v),b8(v+0xf000000) | |
296 | static const ulong spread[256] = | |
297 | { b16(0), b16(0xf0), b16(0xf000), b16(0xf0f0), | |
298 | b16(0xf00000), b16(0xf000f0), b16(0xf0f000), b16(0xf0f0f0), | |
299 | b16(0xf0000000), b16(0xf00000f0), b16(0xf000f000), b16(0xf000f0f0), | |
300 | b16(0xf0f00000), b16(0xf0f000f0), b16(0xf0f0f000), b16(0xf0f0f0f0) | |
301 | }; | |
302 | register ulong hi, lo, temp; | |
303 | hi = spread[*inp] & 0x88888888; | |
304 | inp += line_size; | |
305 | hi |= spread[*inp] & 0x44444444; | |
306 | inp += line_size; | |
307 | hi |= spread[*inp] & 0x22222222; | |
308 | inp += line_size; | |
309 | hi |= spread[*inp] & 0x11111111; | |
310 | inp += line_size; | |
311 | lo = spread[*inp] & 0x88888888; | |
312 | inp += line_size; | |
313 | lo |= spread[*inp] & 0x44444444; | |
314 | inp += line_size; | |
315 | lo |= spread[*inp] & 0x22222222; | |
316 | inp += line_size; | |
317 | lo |= spread[*inp] & 0x11111111; | |
318 | temp = (hi & 0xf0f0f0f0) | ((lo >> 4) & 0x0f0f0f0f); | |
319 | *outp = (byte)((uint)(temp >> 16) >> 8); outp += dist; | |
320 | *outp = (byte)(temp >> 16); outp += dist; | |
321 | *outp = (byte)((uint)temp >> 8); outp += dist; | |
322 | *outp = (byte)(temp); outp += dist; | |
323 | temp = ((hi << 4) & 0xf0f0f0f0) | (lo & 0x0f0f0f0f); | |
324 | *outp = (byte)((uint)(temp >> 16) >> 8); outp += dist; | |
325 | *outp = (byte)(temp >> 16); outp += dist; | |
326 | *outp = (byte)((uint)temp >> 8); outp += dist; | |
327 | *outp = (byte)(temp); | |
328 | } | |
329 | ||
330 | #endif /* memflip8x8 */ | |
331 | ||
332 | #endif /* !USE_ASM */ |