/src/ghostpdl/base/gsserial.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 | | /* some utilities useful for converting objects to serial form */ |
17 | | |
18 | | #include "stdpre.h" |
19 | | #include "gstypes.h" |
20 | | #include "gsserial.h" |
21 | | |
22 | | /* |
23 | | * Procedures for converint between integers and a variable-length, |
24 | | * little-endian string representation thereof. This scheme uses a |
25 | | * base-128 format with the high-order bit of each byte used as a |
26 | | * continuation flag ((b & 0x80) == 0 ==> this is the last byte of the |
27 | | * current number). See gsserial.h for complete information. |
28 | | */ |
29 | | |
30 | | /* |
31 | | * Determine the size of the string representation of an unsigned or |
32 | | * signed integer. |
33 | | */ |
34 | | int |
35 | | enc_u_size_uint(uint uval) |
36 | 2.90k | { |
37 | 2.90k | int i = 1; |
38 | | |
39 | 8.82k | while ((uval >>= enc_u_shift) > 0) |
40 | 5.91k | ++i; |
41 | 2.90k | return i; |
42 | 2.90k | } |
43 | | |
44 | | int |
45 | | enc_s_size_int(int ival) |
46 | 0 | { |
47 | | /* MIN_INT must be handled specially */ |
48 | 0 | if (ival < 0) { |
49 | 0 | if (ival == enc_s_min_int) |
50 | 0 | return enc_s_sizew_max; |
51 | 0 | ival = -ival; |
52 | 0 | } |
53 | 0 | return enc_u_sizew((uint)ival << 1); |
54 | 0 | } |
55 | | |
56 | | /* |
57 | | * Encode a signed or unsigned integer. The array pointed to by ptr is |
58 | | * assumed to be large enough. The returned pointer immediately follows |
59 | | * the encoded number. |
60 | | */ |
61 | | byte * |
62 | | enc_u_put_uint(uint uval, byte * ptr) |
63 | 1.42k | { |
64 | 1.42k | int tmp_v; |
65 | | |
66 | 4.30k | for (;;) { |
67 | 4.30k | tmp_v = uval & (enc_u_lim_1b - 1); |
68 | 4.30k | if ((uval >>= enc_u_shift) == 0) |
69 | 1.42k | break; |
70 | 2.88k | *ptr++ = tmp_v | enc_u_lim_1b; |
71 | 2.88k | } |
72 | 1.42k | *ptr++ = tmp_v; |
73 | 1.42k | return ptr; |
74 | 1.42k | } |
75 | | |
76 | | byte * |
77 | | enc_s_put_int(int ival, byte * ptr) |
78 | 0 | { |
79 | 0 | uint uval, tmp_v; |
80 | | |
81 | | /* MIN_INT must be handled specially */ |
82 | 0 | if (ival < 0 && ival != enc_s_min_int) |
83 | 0 | uval = (uint)-ival; |
84 | 0 | else |
85 | 0 | uval = (uint)ival; |
86 | |
|
87 | 0 | tmp_v = (uval & enc_s_max_1b) | (ival < 0 ? enc_s_max_1b + 1 : 0); |
88 | 0 | if (uval > enc_s_max_1b) { |
89 | 0 | *ptr++ = tmp_v | enc_u_lim_1b; |
90 | 0 | return enc_u_put_uint(uval >> enc_s_shift0, ptr); |
91 | 0 | } else { |
92 | 0 | *ptr++ = tmp_v; |
93 | 0 | return ptr; |
94 | 0 | } |
95 | 0 | } |
96 | | |
97 | | /* |
98 | | * Decode an integer string for a signed or unsigned integer. Note that |
99 | | * two forms of this procedure are provide, to allow both const and non- |
100 | | * const byte pointers to be handled (the former is far more common). |
101 | | */ |
102 | | const byte * |
103 | | enc_u_get_uint(uint * pval, const byte * ptr) |
104 | 305k | { |
105 | 305k | uint uval = 0, tmp_val; |
106 | 305k | int shift = 0; |
107 | | |
108 | 886k | while (((tmp_val = *ptr++) & enc_u_lim_1b) != 0) { |
109 | 581k | uval |= (tmp_val & (enc_u_lim_1b - 1)) << shift; |
110 | 581k | shift += enc_u_shift; |
111 | 581k | } |
112 | 305k | *pval = uval | (tmp_val << shift); |
113 | | |
114 | 305k | return ptr; |
115 | 305k | } |
116 | | |
117 | | byte * |
118 | | enc_u_get_uint_nc(uint * pval, byte * ptr) |
119 | 0 | { |
120 | 0 | const byte * tmp_ptr = ptr; |
121 | |
|
122 | 0 | tmp_ptr = enc_u_get_uint(pval, tmp_ptr); |
123 | 0 | return ptr += tmp_ptr - ptr; |
124 | 0 | } |
125 | | |
126 | | const byte * |
127 | | enc_s_get_int(int * pval, const byte * ptr) |
128 | 0 | { |
129 | 0 | int ival = *ptr++; |
130 | 0 | bool neg = false; |
131 | |
|
132 | 0 | if ((ival & (enc_s_max_1b + 1)) != 0) { |
133 | 0 | ival ^= enc_s_max_1b + 1; |
134 | 0 | neg = true; |
135 | 0 | } |
136 | 0 | if ((ival & enc_u_lim_1b) != 0) { |
137 | 0 | uint tmp_val; |
138 | |
|
139 | 0 | ival ^= enc_u_lim_1b; |
140 | 0 | ptr = enc_u_get_uint(&tmp_val, ptr); |
141 | 0 | ival |= tmp_val << enc_s_shift0; |
142 | 0 | } |
143 | 0 | if (neg && ival >= 0) /* >= check required for enc_s_min_int */ |
144 | 0 | ival = -ival; |
145 | |
|
146 | 0 | *pval = ival; |
147 | 0 | return ptr; |
148 | 0 | } |
149 | | |
150 | | byte * |
151 | | enc_s_get_int_nc(int * pval, byte * ptr) |
152 | 0 | { |
153 | 0 | const byte * tmp_ptr = ptr; |
154 | |
|
155 | 0 | tmp_ptr = enc_s_get_int(pval, tmp_ptr); |
156 | 0 | return ptr += tmp_ptr - ptr; |
157 | 0 | } |
158 | | |
159 | | #ifdef UNIT_TEST |
160 | | |
161 | | #include <stdio.h> |
162 | | #include <string.h> |
163 | | |
164 | | /* |
165 | | * Encoding and decoding of integers is verified using a round-trip process, |
166 | | * integer ==> string ==> integer. The string size is separately checked to |
167 | | * verify that it is not too large (it can't be too small if the round-trip |
168 | | * check works). If an integer x is represented by nbytes, then it must be |
169 | | * that x >= 1U << (7 * (n - 1)) (unsigned; 1U << (7 * (n - 2) + 6) for |
170 | | * signed integers; there is no need to check 1-byte encodings). |
171 | | * |
172 | | * It is possible to check every value, but this is not necessary. Any |
173 | | * failures that arise will do so in the vicinty of powers of 2. |
174 | | */ |
175 | | |
176 | | /* check the length of an encoded string */ |
177 | | void |
178 | | check_u_sizew(uint uval, int len) |
179 | | { |
180 | | if (len != enc_u_sizew(uval)) |
181 | | fprintf( stderr, |
182 | | "Size calculation error for (usigned) %u (%d != %d)\n", |
183 | | uval, |
184 | | len, |
185 | | enc_u_sizew(uval) ); |
186 | | if ( len > 1 && |
187 | | (len > enc_u_sizew_max || uval < 1U << (enc_u_shift * (len - 1))) ) |
188 | | fprintf( stderr, "unsigned encoding too large for %u (%d bytes)\n", |
189 | | uval, |
190 | | len ); |
191 | | } |
192 | | |
193 | | void |
194 | | check_s_sizew(int ival, int len) |
195 | | { |
196 | | uint uval; |
197 | | |
198 | | if (len != enc_s_sizew(ival)) |
199 | | fprintf( stderr, |
200 | | "Size calculation error for (signed) %d (%d != %d)\n", |
201 | | ival, |
202 | | len, |
203 | | enc_s_sizew(ival) ); |
204 | | if (len <= 1) |
205 | | return; |
206 | | if (ival < 0 && ival != enc_s_min_int) |
207 | | uval = (uint)-ival; |
208 | | else |
209 | | uval = (uint)ival; |
210 | | if ( len > enc_s_sizew_max || |
211 | | uval < 1U << (enc_s_shift1 * (len - 2) + enc_s_shift0) ) |
212 | | fprintf( stderr, |
213 | | "signed encoding too large for %d (%d bytes)\n", |
214 | | ival, |
215 | | len ); |
216 | | } |
217 | | |
218 | | /* check the encode and decode procedures on a value */ |
219 | | void |
220 | | check_u(uint uval) |
221 | | { |
222 | | byte buff[32]; /* generous size */ |
223 | | byte * cp0 = buff; |
224 | | const byte * cp1 = buff; |
225 | | byte * cp2 = buff; |
226 | | uint res_val; |
227 | | |
228 | | memset(buff, 0, sizeof(buff)); |
229 | | enc_u_putw(uval, cp0); |
230 | | check_u_sizew(uval, cp0 - buff); |
231 | | memset(cp0, (uval == 0 ? 0x7f : 0), sizeof(buff) - (cp0 - buff)); |
232 | | |
233 | | enc_u_getw(res_val, cp1); |
234 | | if (cp1 != cp0) |
235 | | fprintf( stderr, |
236 | | "encoded length disparity (const) for " |
237 | | "(unsigned) %u (%d != %d)\n", |
238 | | uval, |
239 | | cp0 - buff, |
240 | | cp1 - buff ); |
241 | | if (res_val != uval) |
242 | | fprintf( stderr, |
243 | | "decode error (const) for (unsigned) %u (!= %u)\n", |
244 | | uval, |
245 | | res_val ); |
246 | | |
247 | | enc_u_getw_nc(res_val, cp2); |
248 | | if (cp2 != cp0) |
249 | | fprintf( stderr, |
250 | | "encoded length disparity (non-const) for " |
251 | | "(unsigned) %u (%d != %d)\n", |
252 | | uval, |
253 | | cp0 - buff, |
254 | | cp1 - buff ); |
255 | | if (res_val != uval) |
256 | | fprintf( stderr, |
257 | | "decode error (non-const) for (unsigned) %u (!= %u)\n", |
258 | | uval, |
259 | | res_val ); |
260 | | } |
261 | | |
262 | | void |
263 | | check_s(int ival) |
264 | | { |
265 | | byte buff[32]; /* generous size */ |
266 | | byte * cp0 = buff; |
267 | | const byte * cp1 = buff; |
268 | | byte * cp2 = buff; |
269 | | int res_val; |
270 | | |
271 | | memset(buff, 0, sizeof(buff)); |
272 | | enc_s_putw(ival, cp0); |
273 | | check_s_sizew(ival, cp0 - buff); |
274 | | memset(cp0, (ival == 0 ? 0x7f : 0), sizeof(buff) - (cp0 - buff)); |
275 | | |
276 | | enc_s_getw(res_val, cp1); |
277 | | if (cp1 != cp0) |
278 | | fprintf( stderr, |
279 | | "encoded length disparity (const) for " |
280 | | "(signed) %d (%d != %d)\n", |
281 | | ival, |
282 | | cp0 - buff, |
283 | | cp1 - buff ); |
284 | | if (res_val != ival) |
285 | | fprintf( stderr, |
286 | | "decode error (const) for (signed) %d (!= %d)\n", |
287 | | ival, |
288 | | res_val ); |
289 | | |
290 | | enc_s_getw_nc(res_val, cp2); |
291 | | if (cp1 != cp0) |
292 | | fprintf( stderr, |
293 | | "encoded length disparity (non-const) for " |
294 | | "(signed) %d (%d != %d)\n", |
295 | | ival, |
296 | | cp0 - buff, |
297 | | cp1 - buff ); |
298 | | if (res_val != ival) |
299 | | fprintf( stderr, |
300 | | "decode error (non-const) for (unsigned) %d (!= %d)\n", |
301 | | ival, |
302 | | res_val ); |
303 | | } |
304 | | |
305 | | /* test the provided value and some surrounding values */ |
306 | | void |
307 | | check_u_vals(uint uval) |
308 | | { |
309 | | uint diff = 1; |
310 | | |
311 | | check_u(uval); |
312 | | do { |
313 | | check_u(uval - diff); |
314 | | check_u(uval + diff); |
315 | | } while ((diff <<= 1) < uval); |
316 | | } |
317 | | |
318 | | void |
319 | | check_s_vals(int ival) |
320 | | { |
321 | | int diff = 1; |
322 | | |
323 | | check_s(ival); |
324 | | if (ival == enc_s_min_int) { |
325 | | do { |
326 | | check_s(ival - diff); |
327 | | check_s(ival + diff); |
328 | | } while ((diff <<= 1) != enc_s_min_int); |
329 | | } else { |
330 | | int abs_val = (ival < 0 ? -ival : ival); |
331 | | |
332 | | do { |
333 | | check_s(ival - diff); |
334 | | check_s(ival + diff); |
335 | | } while ((diff <<= 1) < abs_val); |
336 | | } |
337 | | } |
338 | | |
339 | | int |
340 | | main(void) |
341 | | { |
342 | | uint uval; |
343 | | int ival; |
344 | | |
345 | | check_u_vals(0); |
346 | | for (uval = 1; uval != 0; uval <<= 1) |
347 | | check_u_vals(uval); |
348 | | |
349 | | check_s_vals(0); |
350 | | for (ival = 1; ival != 0; ival <<= 1) { |
351 | | check_s_vals(ival); |
352 | | if (ival != enc_s_min_int) |
353 | | check_s_vals(-ival); |
354 | | } |
355 | | |
356 | | fprintf(stderr, "all done\n"); |
357 | | return 0; |
358 | | } |
359 | | |
360 | | #endif /* UNIT_TEST */ |