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