386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / ibnum.c
CommitLineData
ddb56ffc
WJ
1/* Copyright (C) 1990, 1991 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
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. */
31int
32sread_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. */
62uint
63scount_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. */
80static 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};
92int
93sget_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. */
158int
159sgetshort(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}
167void
168sputshort(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. */
179int
180sgetlong(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}
192void
193sputlong(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. */
209int
210sgetfloat(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}
222void
223sputfloat(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}