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