xref: /plan9/sys/src/cmd/gs/src/gsutil.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1992, 1993, 1994, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gsutil.c,v 1.11 2005/09/14 07:13:51 ray Exp $ */
18 /* Utilities for Ghostscript library */
19 #include "string_.h"
20 #include "memory_.h"
21 #include "gstypes.h"
22 #include "gconfigv.h"		/* for USE_ASM */
23 #include "gserror.h"
24 #include "gserrors.h"
25 #include "gsmemory.h"		/* for init procedure */
26 #include "gsrect.h"		/* for prototypes */
27 #include "gsuid.h"
28 #include "gsutil.h"		/* for prototypes */
29 
30 /* ------ Unique IDs ------ */
31 
32 ulong
gs_next_ids(const gs_memory_t * mem,uint count)33 gs_next_ids(const gs_memory_t *mem, uint count)
34 {
35     ulong id = mem->gs_lib_ctx->gs_next_id;
36 
37     mem->gs_lib_ctx->gs_next_id += count;
38     return id;
39 }
40 
41 /* ------ Memory utilities ------ */
42 
43 /* Transpose an 8 x 8 block of bits.  line_size is the raster of */
44 /* the input data.  dist is the distance between output bytes. */
45 /* This routine may be supplanted by assembly code. */
46 #if !USE_ASM
47 
48 void
memflip8x8(const byte * inp,int line_size,byte * outp,int dist)49 memflip8x8(const byte * inp, int line_size, byte * outp, int dist)
50 {
51     uint aceg, bdfh;
52 
53     {
54 	const byte *ptr4 = inp + (line_size << 2);
55 	const int ls2 = line_size << 1;
56 
57 	aceg = ((uint)*inp) | ((uint)inp[ls2] << 8) |
58 	    ((uint)*ptr4 << 16) | ((uint)ptr4[ls2] << 24);
59 	inp += line_size, ptr4 += line_size;
60 	bdfh = ((uint)*inp) | ((uint)inp[ls2] << 8) |
61 	    ((uint)*ptr4 << 16) | ((uint)ptr4[ls2] << 24);
62     }
63 
64     /* Check for all 8 bytes being the same. */
65     /* This is especially worth doing for the case where all are zero. */
66     if (aceg == bdfh && (aceg >> 8) == (aceg & 0xffffff)) {
67 	if (aceg == 0 || aceg == 0xffffffff)
68 	    goto store;
69 	*outp = (byte)-(int)((aceg >> 7) & 1);
70 	outp[dist] = (byte)-(int)((aceg >> 6) & 1);
71 	outp += dist << 1;
72 	*outp = (byte)-(int)((aceg >> 5) & 1);
73 	outp[dist] = (byte)-(int)((aceg >> 4) & 1);
74 	outp += dist << 1;
75 	*outp = (byte)-(int)((aceg >> 3) & 1);
76 	outp[dist] = (byte)-(int)((aceg >> 2) & 1);
77 	outp += dist << 1;
78 	*outp = (byte)-(int)((aceg >> 1) & 1);
79 	outp[dist] = (byte)-(int)(aceg & 1);
80 	return;
81     } {
82 	register uint temp;
83 
84 /* Transpose a block of bits between registers. */
85 #define TRANSPOSE(r,s,mask,shift)\
86   (r ^= (temp = ((s >> shift) ^ r) & mask),\
87    s ^= temp << shift)
88 
89 /* Transpose blocks of 4 x 4 */
90 	TRANSPOSE(aceg, aceg, 0x00000f0f, 20);
91 	TRANSPOSE(bdfh, bdfh, 0x00000f0f, 20);
92 
93 /* Transpose blocks of 2 x 2 */
94 	TRANSPOSE(aceg, aceg, 0x00330033, 10);
95 	TRANSPOSE(bdfh, bdfh, 0x00330033, 10);
96 
97 /* Transpose blocks of 1 x 1 */
98 	TRANSPOSE(aceg, bdfh, 0x55555555, 1);
99 
100 #undef TRANSPOSE
101     }
102 
103   store:
104     *outp = (byte)aceg;
105     outp[dist] = (byte)bdfh;
106     outp += dist << 1;
107     *outp = (byte)(aceg >>= 8);
108     outp[dist] = (byte)(bdfh >>= 8);
109     outp += dist << 1;
110     *outp = (byte)(aceg >>= 8);
111     outp[dist] = (byte)(bdfh >>= 8);
112     outp += dist << 1;
113     *outp = (byte)(aceg >> 8);
114     outp[dist] = (byte)(bdfh >> 8);
115 }
116 
117 #endif /* !USE_ASM */
118 
119 /* Get an unsigned, big-endian 32-bit value. */
120 ulong
get_u32_msb(const byte * p)121 get_u32_msb(const byte *p)
122 {
123     return ((uint)p[0] << 24) + ((uint)p[1] << 16) + ((uint)p[2] << 8) + p[3];
124 }
125 
126 /* ------ String utilities ------ */
127 
128 /* Compare two strings, returning -1 if the first is less, */
129 /* 0 if they are equal, and 1 if first is greater. */
130 /* We can't use memcmp, because we always use unsigned characters. */
131 int
bytes_compare(const byte * s1,uint len1,const byte * s2,uint len2)132 bytes_compare(const byte * s1, uint len1, const byte * s2, uint len2)
133 {
134     register uint len = len1;
135 
136     if (len2 < len)
137 	len = len2;
138     {
139 	register const byte *p1 = s1;
140 	register const byte *p2 = s2;
141 
142 	while (len--)
143 	    if (*p1++ != *p2++)
144 		return (p1[-1] < p2[-1] ? -1 : 1);
145     }
146     /* Now check for differing lengths */
147     return (len1 == len2 ? 0 : len1 < len2 ? -1 : 1);
148 }
149 
150 /* Test whether a string matches a pattern with wildcards. */
151 /* '*' = any substring, '?' = any character, '\' quotes next character. */
152 const string_match_params string_match_params_default = {
153     '*', '?', '\\', false, false
154 };
155 
156 bool
string_match(const byte * str,uint len,const byte * pstr,uint plen,register const string_match_params * psmp)157 string_match(const byte * str, uint len, const byte * pstr, uint plen,
158 	     register const string_match_params * psmp)
159 {
160     const byte *pback = 0;
161     const byte *spback = 0;	/* initialized only to pacify gcc */
162     const byte *p = pstr, *pend = pstr + plen;
163     const byte *sp = str, *spend = str + len;
164 
165     if (psmp == 0)
166 	psmp = &string_match_params_default;
167   again:while (p < pend) {
168 	register byte ch = *p;
169 
170 	if (ch == psmp->any_substring) {
171 	    pback = ++p, spback = sp;
172 	    continue;
173 	} else if (ch == psmp->any_char) {
174 	    if (sp == spend)
175 		return false;	/* str too short */
176 	    p++, sp++;
177 	    continue;
178 	} else if (ch == psmp->quote_next) {
179 	    if (++p == pend)
180 		return true;	/* bad pattern */
181 	    ch = *p;
182 	}
183 	if (sp == spend)
184 	    return false;	/* str too short */
185 	if (*sp == ch ||
186 	    (psmp->ignore_case && (*sp ^ ch) == 0x20 &&
187 	     (ch &= ~0x20) >= 0x41 && ch <= 0x5a) ||
188 	     (psmp->slash_equiv && ((ch == '\\' && *sp == '/') ||
189 	     (ch == '/' && *sp == '\\')))
190 	    )
191 	    p++, sp++;
192 	else if (pback == 0)
193 	    return false;	/* no * to back up to */
194 	else {
195 	    sp = ++spback;
196 	    p = pback;
197 	}
198     }
199     if (sp < spend) {		/* We got a match, but there are chars left over. */
200 	/* If we can back up, back up to the only place that */
201 	/* could produce a complete match, otherwise fail. */
202 	if (pback == 0)
203 	    return false;
204 	p = pback;
205 	pback = 0;
206 	sp = spend - (pend - p);
207 	goto again;
208     }
209     return true;
210 }
211 
212 /* ------ UID utilities ------ */
213 
214 /* Compare two UIDs for equality. */
215 /* We know that at least one of them is valid. */
216 bool
uid_equal(register const gs_uid * puid1,register const gs_uid * puid2)217 uid_equal(register const gs_uid * puid1, register const gs_uid * puid2)
218 {
219     if (puid1->id != puid2->id)
220 	return false;
221     if (puid1->id >= 0)
222 	return true;		/* UniqueID */
223     return
224 	!memcmp((const char *)puid1->xvalues,
225 		(const char *)puid2->xvalues,
226 		(uint) - (puid1->id) * sizeof(long));
227 }
228 
229 /* Copy the XUID data for a uid, if needed, updating the uid in place. */
230 int
uid_copy(gs_uid * puid,gs_memory_t * mem,client_name_t cname)231 uid_copy(gs_uid *puid, gs_memory_t *mem, client_name_t cname)
232 {
233     if (uid_is_XUID(puid)) {
234 	uint xsize = uid_XUID_size(puid);
235 	long *xvalues = (long *)
236 	    gs_alloc_byte_array(mem, xsize, sizeof(long), cname);
237 
238 	if (xvalues == 0)
239 	    return_error(gs_error_VMerror);
240 	memcpy(xvalues, uid_XUID_values(puid), xsize * sizeof(long));
241 	puid->xvalues = xvalues;
242     }
243     return 0;
244 }
245 
246 /* ------ Rectangle utilities ------ */
247 
248 /*
249  * Calculate the difference of two rectangles, a list of up to 4 rectangles.
250  * Return the number of rectangles in the list, and set the first rectangle
251  * to the intersection.
252  */
253 int
int_rect_difference(gs_int_rect * outer,const gs_int_rect * inner,gs_int_rect * diffs)254 int_rect_difference(gs_int_rect * outer, const gs_int_rect * inner,
255 		    gs_int_rect * diffs /*[4] */ )
256 {
257     int x0 = outer->p.x, y0 = outer->p.y;
258     int x1 = outer->q.x, y1 = outer->q.y;
259     int count = 0;
260 
261     if (y0 < inner->p.y) {
262 	diffs[0].p.x = x0, diffs[0].p.y = y0;
263 	diffs[0].q.x = x1, diffs[0].q.y = min(y1, inner->p.y);
264 	outer->p.y = y0 = diffs[0].q.y;
265 	++count;
266     }
267     if (y1 > inner->q.y) {
268 	diffs[count].p.x = x0, diffs[count].p.y = max(y0, inner->q.y);
269 	diffs[count].q.x = x1, diffs[count].q.y = y1;
270 	outer->q.y = y1 = diffs[count].p.y;
271 	++count;
272     }
273     if (x0 < inner->p.x) {
274 	diffs[0].p.x = x0, diffs[0].p.y = y0;
275 	diffs[0].q.x = min(x1, inner->p.x), diffs[0].q.y = y1;
276 	outer->p.x = x0 = diffs[count].q.x;
277 	++count;
278     }
279     if (x1 > inner->q.x) {
280 	diffs[count].p.x = max(x0, inner->q.x), diffs[count].p.y = y0;
281 	diffs[count].q.x = x1, diffs[count].q.y = y1;
282 	outer->q.x = x1 = diffs[count].p.x;
283 	++count;
284     }
285     return count;
286 }
287