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