Commit | Line | Data |
---|---|---|
ddb56ffc WJ |
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 | } |