| 1 | /* Copyright (C) 1990, 1991 Aladdin Enterprises. All rights reserved. |
| 2 | Distributed by Free Software Foundation, Inc. |
| 3 | |
| 4 | This file is part of Ghostscript. |
| 5 | |
| 6 | Ghostscript is distributed in the hope that it will be useful, but |
| 7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility |
| 8 | to anyone for the consequences of using it or for whether it serves any |
| 9 | particular purpose or works at all, unless he says so in writing. Refer |
| 10 | to the Ghostscript General Public License for full details. |
| 11 | |
| 12 | Everyone is granted permission to copy, modify and redistribute |
| 13 | Ghostscript, but only under the conditions described in the Ghostscript |
| 14 | General Public License. A copy of this license is supposed to have been |
| 15 | given to you along with Ghostscript so you can know your rights and |
| 16 | responsibilities. It should be in a file named COPYING. Among other |
| 17 | things, the copyright notice and this notice must be preserved on all |
| 18 | copies. */ |
| 19 | |
| 20 | /* ibnum.c */ |
| 21 | /* Level 2 encoded number reading utilities for Ghostscript */ |
| 22 | #include "ghost.h" |
| 23 | #include "errors.h" |
| 24 | #include "stream.h" |
| 25 | #include "bnum.h" |
| 26 | #include "btoken.h" |
| 27 | |
| 28 | /* ------ Encoded number reading ------ */ |
| 29 | |
| 30 | /* Set up to read from an encoded number array/string. */ |
| 31 | int |
| 32 | sread_num_array(stream *s, ref *op) |
| 33 | { switch ( r_type(op) ) |
| 34 | { |
| 35 | case t_string: |
| 36 | { /* Check that this is a legitimate encoded number array */ |
| 37 | byte *bp = op->value.bytes; |
| 38 | short count; |
| 39 | int nshift; |
| 40 | if ( r_size(op) < 4 || (bt_type)bp[0] != bt_num_array || |
| 41 | !num_is_valid(bp[1]) |
| 42 | ) |
| 43 | return e_typecheck; |
| 44 | sread_string(s, bp + 2, r_size(op) - 2); |
| 45 | s->num_format = bp[1]; |
| 46 | sgetshort(s, &count); |
| 47 | nshift = ((bp[1] & 0x70) == 0x20 ? 1 : 2); |
| 48 | if ( count != (r_size(op) - 4) >> nshift ) |
| 49 | return e_typecheck; |
| 50 | } break; |
| 51 | case t_array: |
| 52 | sread_string(s, (byte *)op->value.refs, r_size(op) * sizeof(ref)); |
| 53 | s->num_format = num_array; |
| 54 | break; |
| 55 | default: |
| 56 | return e_typecheck; |
| 57 | } |
| 58 | return 0; |
| 59 | } |
| 60 | |
| 61 | /* Get the number of elements in an encoded number stream. */ |
| 62 | uint |
| 63 | scount_num_stream(stream *s) |
| 64 | { long avlong; |
| 65 | savailable(s, &avlong); |
| 66 | switch ( s->num_format & 0x170 ) |
| 67 | { |
| 68 | case num_int16: |
| 69 | return (uint)(avlong >> 1); |
| 70 | case num_array: |
| 71 | return (uint)(avlong / sizeof(ref)); |
| 72 | default: /* num_int32, num_float */ |
| 73 | return (uint)(avlong >> 2); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | /* Read an encoded number from a stream according to its num_format. */ |
| 78 | /* Put the value in np->value.{intval,realval}. Return t_int, t_real, */ |
| 79 | /* t_null if end of stream, or e_syntaxerror or e_typecheck. */ |
| 80 | static double binary_scale[32] = { |
| 81 | #define expn2(n) (0.5 / (1L << (n-1))) |
| 82 | 1.0, expn2(1), expn2(2), expn2(3), |
| 83 | expn2(4), expn2(5), expn2(6), expn2(7), |
| 84 | expn2(8), expn2(9), expn2(10), expn2(11), |
| 85 | expn2(12), expn2(13), expn2(14), expn2(15), |
| 86 | expn2(16), expn2(17), expn2(18), expn2(19), |
| 87 | expn2(20), expn2(21), expn2(22), expn2(23), |
| 88 | expn2(24), expn2(25), expn2(26), expn2(27), |
| 89 | expn2(28), expn2(29), expn2(30), expn2(31) |
| 90 | #undef expn2 |
| 91 | }; |
| 92 | int |
| 93 | sget_encoded_number(stream *s, ref *np) |
| 94 | { int format = s->num_format; |
| 95 | short snum; |
| 96 | long lnum; |
| 97 | int code, type; |
| 98 | switch ( format & 0x170 ) |
| 99 | { |
| 100 | case num_int32: case num_int32 + 16: |
| 101 | if ( (format & 31) == 0 ) |
| 102 | type = t_integer, |
| 103 | code = sgetlong(s, &np->value.intval); |
| 104 | else |
| 105 | { type = t_real; |
| 106 | code = sgetlong(s, &lnum); |
| 107 | if ( !code ) |
| 108 | np->value.realval = |
| 109 | (double)lnum * binary_scale[format & 31]; |
| 110 | } |
| 111 | break; |
| 112 | case num_int16: |
| 113 | code = sgetshort(s, &snum); |
| 114 | if ( (format & 15) == 0 ) |
| 115 | { type = t_integer; |
| 116 | np->value.intval = snum; |
| 117 | } |
| 118 | else |
| 119 | { type = t_real; |
| 120 | if ( !code ) |
| 121 | np->value.realval = |
| 122 | (double)snum * binary_scale[format & 15]; |
| 123 | } |
| 124 | break; |
| 125 | case num_float: |
| 126 | type = t_real; |
| 127 | code = sgetfloat(s, &np->value.realval); |
| 128 | break; |
| 129 | case num_array: |
| 130 | { uint count = sgets(s, (byte *)np, sizeof(ref)); |
| 131 | code = (count == 0 ? 1 : count == sizeof(ref) ? 0 : |
| 132 | e_syntaxerror); |
| 133 | if ( !code ) |
| 134 | switch ( r_type(np) ) |
| 135 | { |
| 136 | case t_integer: return t_integer; |
| 137 | case t_real: return t_real; |
| 138 | default: return e_typecheck; |
| 139 | } |
| 140 | } break; |
| 141 | default: |
| 142 | return e_syntaxerror; /* invalid num_format?? */ |
| 143 | } |
| 144 | switch ( code ) |
| 145 | { |
| 146 | case 0: return type; |
| 147 | case 1: return t_null; /* end of stream */ |
| 148 | default: return code; |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | /* ------ Get/put number ------ */ |
| 153 | |
| 154 | /* Get/put encoded numbers on a stream according to num_format. */ |
| 155 | /* 1 means end of stream, 0 means not end, <0 means error. */ |
| 156 | |
| 157 | /* Get/put a short. */ |
| 158 | int |
| 159 | sgetshort(register stream *s, short *p) |
| 160 | { int a = sgetc(s), b; |
| 161 | if ( a < 0 ) return 1; |
| 162 | b = sgetc(s); |
| 163 | if ( b < 0 ) return e_syntaxerror; |
| 164 | *p = (short)(s_is_lsb(s) ? (b << 8) + a : (a << 8) + b); |
| 165 | return 0; |
| 166 | } |
| 167 | void |
| 168 | sputshort(register stream *s, short num) |
| 169 | { byte a = num & 0xff; |
| 170 | byte b = (byte)(num >> 8); |
| 171 | if ( s_is_msb(s) ) |
| 172 | { byte t = a; a = b; b = t; |
| 173 | } |
| 174 | sputc(s, a); |
| 175 | sputc(s, b); |
| 176 | } |
| 177 | |
| 178 | /* Get/put a long. */ |
| 179 | int |
| 180 | sgetlong(register stream *s, long *p) |
| 181 | { int a = sgetc(s), b, c, d; |
| 182 | if ( a < 0 ) return 1; |
| 183 | b = sgetc(s); |
| 184 | c = sgetc(s); |
| 185 | d = sgetc(s); |
| 186 | if ( (b | c | d) < 0 ) return e_syntaxerror; |
| 187 | *p = (long)(s_is_lsb(s) ? |
| 188 | ((long)d << 24) + ((long)c << 16) + (b << 8) + a : |
| 189 | ((long)a << 24) + ((long)b << 16) + (c << 8) + d); |
| 190 | return 0; |
| 191 | } |
| 192 | void |
| 193 | sputlong(register stream *s, long num) |
| 194 | { byte a = num & 0xff; |
| 195 | byte b = (byte)(num >> 8); |
| 196 | byte c = (byte)(num >> 16); |
| 197 | byte d = (byte)(num >> 24); |
| 198 | if ( s_is_msb(s) ) |
| 199 | { byte t = a; a = d; d = t; |
| 200 | t = b; b = c; c = t; |
| 201 | } |
| 202 | sputc(s, a); |
| 203 | sputc(s, b); |
| 204 | sputc(s, c); |
| 205 | sputc(s, d); |
| 206 | } |
| 207 | |
| 208 | /* Get/put a float. We don't handle non-IEEE native representations yet. */ |
| 209 | int |
| 210 | sgetfloat(register stream *s, float *p) |
| 211 | { if ( s->num_format == num_float_native ) |
| 212 | { uint len = sgets(s, (byte *)p, sizeof(float)); |
| 213 | return (len == sizeof(float) ? 0 : |
| 214 | len == 0 && seofp(s) ? 1 : |
| 215 | e_syntaxerror); |
| 216 | } |
| 217 | else |
| 218 | { /* Hack: we know floats and longs are the same size. */ |
| 219 | return sgetlong(s, (long *)p); |
| 220 | } |
| 221 | } |
| 222 | void |
| 223 | sputfloat(register stream *s, floatp num) |
| 224 | { float f = num; /* coerce from double */ |
| 225 | if ( s->num_format == num_float_native ) |
| 226 | sputs(s, (byte *)&f, sizeof(float)); |
| 227 | else |
| 228 | { /* Hack: we know floats and longs are the same size. */ |
| 229 | sputlong(s, *(long *)&f); |
| 230 | } |
| 231 | } |