1 /* Copyright (C) 2001-2006 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, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 /* $Id: gsserial.h 8022 2007-06-05 22:23:38Z giles $ */
14 /* some general structures useful for converting objects to serial form */
15 
16 #ifndef gsserial_INCLUDED
17 #  define gsserial_INCLUDED
18 
19 /*
20  * A variable-length, little-endian format for encoding (unsigned)
21  * integers.
22  *
23  * This format represents integers is a base-128 form that is quite
24  * compact for parameters whose values are typically small.
25  *
26  * A number x is represented by the string of bytes s[0], ... s[n],
27  * where:
28  *
29  *    s[i] & 0x80 == 0x80 for i = 0, ..., n - 1,
30  *    s[n] & 0x80 == 0x00
31  *
32  * and
33  *
34  *    x == s[0] + (s[1] << 7) + (s[2] << 14) + ... (s[n] << (n * 7))
35  *
36  * In words, the high-order bit is used as a continue bit; it is off
37  * only for the last byte of the string. The low-order 7 bits of each
38  * byte for the base-128 digit, with the low-order digits preceding
39  * the high-order digits.
40  *
41  * The encoding considers all numbers as unsigned. It may be used with
42  * signed quantities (just change the interpretation), though obviously
43  * it is inefficient with negative numbers.
44  *
45  * This code was originally part of the command list device module.
46  * Though the names used here differ from those used from those used in
47  * that module, they follow the same pattern, which accounts for certain
48  * peculiarities.
49  */
50 #define enc_u_shift     7
51 #define enc_u_lim_1b    (1U << enc_u_shift)
52 #define enc_u_lim_2b    (1U << (2 * enc_u_shift))
53 
54 /* determine the encoded size of an (unsigned) integer */
55 extern  int     enc_u_size_uint(uint);
56 
57 #define enc_u_sizew(w)                                      \
58     ( (uint)(w) < enc_u_lim_1b                              \
59         ? 1                                                 \
60         : (uint)(w) < enc_u_lim_2b ? 2 : enc_u_size_uint(w) )
61 
62 /* similarly, for a pair of values (frequently used for points) */
63 #define enc_u_size2w(w1, w2)                        \
64     ( ((uint)(w1) | (uint)(w2)) < enc_u_lim_1b      \
65         ? 2                                         \
66         : enc_u_size_uint(w1) + enc_u_size_uint(w2) )
67 
68 #define enc_u_sizexy(xy)    enc_u_size2w((xy).x, (xy).y)
69 
70 /* the maximum size of an encoded uint */
71 #define enc_u_sizew_max ((8 * sizeof(uint) + enc_u_shift - 1) / enc_u_shift)
72 
73 /* encode and decode an unsigned integer; note special handling of const */
74 extern  byte *          enc_u_put_uint(uint, byte *);
75 extern  const byte *    enc_u_get_uint(uint *, const byte *);
76 extern  byte *          enc_u_get_uint_nc(uint *, byte *);
77 
78 #define enc_u_putw(w, p)                                        \
79     BEGIN                                                       \
80         if ((uint)(w) < enc_u_lim_1b)                           \
81             *(p)++ = (byte)(w);                                 \
82         else if ((uint)(w) < enc_u_lim_2b) {                    \
83             *(p)++ = enc_u_lim_1b | ((w) & (enc_u_lim_1b - 1)); \
84             *(p)++ = (w) >> enc_u_shift;                        \
85         } else                                                  \
86             (p) = enc_u_put_uint((w), (p));                     \
87     END
88 
89 /* encode a pair of integers; this is often used with points */
90 #define enc_u_put2w(w1, w2, p)                          \
91     BEGIN                                               \
92         if (((uint)(w1) | (uint)(w2)) < enc_u_lim_1b) { \
93             *(p)++ = (w1);                              \
94             *(p)++ = (w2);                              \
95         } else {                                        \
96             (p) = enc_u_put_uint((w1), (p));            \
97             (p) = enc_u_put_uint((w2), (p));            \
98         }                                               \
99     END
100 
101 #define enc_u_putxy(xy, p)    enc_u_put2w((xy).x, (xy).y, (p))
102 
103 
104 /* decode an unsigned integer */
105 #define enc_u_getw(w, p)                        \
106     BEGIN                                       \
107         if (((w) = *(p)) >= enc_u_lim_1b) {     \
108             uint    tmp_w;                      \
109                                                 \
110             (p) = enc_u_get_uint(&tmp_w, (p));  \
111             (w) = tmp_w;                        \
112         } else                                  \
113             ++(p);                              \
114     END
115 
116 #define enc_u_getw_nc(w, p)                         \
117     BEGIN                                           \
118         if (((w) = *(p)) >= enc_u_lim_1b) {         \
119             uint    tmp_w;                          \
120                                                     \
121             (p) = enc_u_get_uint_nc(&tmp_w, (p));   \
122             (w) = tmp_w;                            \
123         } else                                      \
124             ++(p);                                  \
125     END
126 
127 /* decode a pair of unsigned integers; this is often used for points */
128 #define enc_u_get2w(w1, w2, p)  \
129     BEGIN                       \
130         enc_u_getw((w1), (p));  \
131         enc_u_getw((w2), (p));  \
132     END
133 
134 #define enc_u_get2w_nc(w1, w2, p)   \
135     BEGIN                           \
136         enc_u_getw_nc((w1), (p));   \
137         enc_u_getw_nc((w2), (p));   \
138     END
139 
140 #define enc_u_getxy(xy, p)      enc_u_get2w((xy).x, (xy).y, (p))
141 #define enc_u_getxy_nc(xy, p)   enc_u_get2w_nc((xy).x, (xy).y, (p))
142 
143 
144 /*
145  * An encoding mechanism similar to that above for signed integers. This
146  * makes use of the next-to-highest order bit of the first byte to encode
147  * the sign of the number. Thus, the number x is represented by the bytes
148  * s[0], ... s[n], where:
149  *
150  *    s[i] & 0x80 == 0x80 for i = 0, ..., n - 1,
151  *    s[n] & 0x80 == 0x00,
152  *
153  *    s[0] & 0x40 == 0x40 if x < 0,
154  *    s[0] & 0x40 == 0x00 if x >- 0,
155  *
156  * and
157  *
158  *    abs(x) = s[0] + (s[1] << 6) + (s[2] << 13) + ... (s[n] * (n * 7 - 1))
159  *
160  * This encoding is less efficient than the unsigned encoding for non-
161  * negative numbers but is much more efficient for numbers that might be
162  * negative.
163  *
164  * There are no special 2-value versions of these macros, as it is not
165  * possible to test both values against the limit simultaneously. We do,
166  * however, provide point encoding macros.
167  */
168 #define enc_s_shift0    6
169 #define enc_s_shift1    (enc_s_shift0 + 1)
170 #define enc_s_max_1b    ((1U << enc_s_shift0) - 1)
171 #define enc_s_min_1b    (-(int)enc_s_max_1b)
172 #define enc_s_max_2b    ((1U << (enc_s_shift0 + enc_s_shift1) - 1))
173 #define enc_s_min_2b    (-enc_s_max_2b)
174 #define enc_s_min_int   ((int)(1U << (8 * sizeof(int) - 1)))
175 
176 /* determine the encoded size of a signed integer */
177 extern  int     enc_s_size_int(int);
178 
179 /* the maximum size of encoded integer */
180 #define enc_s_sizew_max   ((8 * sizeof(int)) / enc_s_shift1 + 1)
181 
182 #define enc_s_sizew(v)                                                  \
183     ( (v) >= 0 ? enc_u_sizew((uint)(v) << 1)                            \
184                : (v) != enc_s_min_int ? enc_u_sizew((uint)-(v) << 1)    \
185                                       : enc_s_sizew_max )
186 
187 #define enc_s_sizexy(xy)    (enc_s_sizew((xy).x) + enc_s_sizew((xy).y))
188 
189 
190 /* encode and decode a signed integfer; note special handling of const */
191 extern  byte *          enc_s_put_int(int, byte *);
192 extern  const byte *    enc_s_get_int(int *, const byte *);
193 extern  byte *          enc_s_get_int_nc(int *, byte *);
194 
195 #define enc_s_putw(v, p)                                            \
196     BEGIN                                                           \
197         if ((int)(v) <= enc_s_max_1b && (int)(v) >= enc_s_min_1b)   \
198             *(p)++ =  ((v) & enc_s_max_1b)                          \
199                     | ((v) < 0 ? (enc_s_max_1b + 1) : 0);           \
200         else                                                        \
201             (p) = enc_s_put_int((v), (p));                          \
202     END
203 
204 #define enc_s_putxy(xy, p)          \
205     BEGIN                           \
206         enc_s_putw((xy).x, (p));    \
207         enc_s_putw((xy).y, (p));    \
208     END
209 
210 #define enc_s_getw(v, p)                                \
211     BEGIN                                               \
212         if (((v = *p) & (1U << enc_s_shift1)) != 0) {   \
213             int     tmp_v;                              \
214                                                         \
215             (p) = enc_s_get_int(&tmp_v, (p));           \
216             (v) = tmp_v;                                \
217         } else {                                        \
218             if (((v) & (1U << enc_s_shift0)) != 0)      \
219                 (v) = -((v) & enc_s_max_1b);            \
220             ++(p);                                      \
221         }                                               \
222     END
223 
224 #define enc_s_getw_nc(v, p)                             \
225     BEGIN                                               \
226         if (((v = *p) & (1U << enc_s_shift1)) != 0) {   \
227             int     tmp_v;                              \
228                                                         \
229             (p) = enc_s_get_int_nc(&tmp_v, (p));        \
230             (v) = tmp_v;                                \
231         } else {                                        \
232             if (((v) & (1U << enc_s_shift0)) != 0)      \
233                 (v) = -((v) & enc_s_max_1b);            \
234             ++(p);                                      \
235         }                                               \
236     END
237 
238 #define enc_s_getxy(xy, p)          \
239     BEGIN                           \
240         enc_s_getw((xy).x, (p));    \
241         enc_s_getw((xy).y, (p));    \
242     END
243 
244 #define enc_s_getxy_nc(xy, p)       \
245     BEGIN                           \
246         enc_s_getw_nc((xy).x, (p)); \
247         enc_s_getw_nc((xy).y, (p)); \
248     END
249 
250 #endif  /* gsserial_INCLUDED */
251