xref: /titanic_51/usr/src/lib/libnsl/rpc/xdr_float.c (revision 1fb95e48b0ed76e2ce9a37cb14d82c1ad8e941f6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 /*
30  * Portions of this source code were derived from Berkeley
31  * 4.3 BSD under license from the Regents of the University of
32  * California.
33  */
34 /*
35  * Copyright 2011 Jason King.  All rights reserved
36  */
37 
38 /*
39  * Generic XDR routines impelmentation.
40  *
41  * These are the "floating point" xdr routines used to (de)serialize
42  * most common data items.  See xdr.h for more info on the interface to
43  * xdr.
44  */
45 
46 #include "mt.h"
47 #include <sys/types.h>
48 #include <stdio.h>
49 #include <rpc/types.h>
50 #include <rpc/xdr.h>
51 
52 #if defined(_IEEE_754)
53 static bool_t ieee_float_to_xdr(XDR *, float *);
54 static bool_t ieee_xdr_to_float(XDR *, float *);
55 static bool_t ieee_double_to_xdr(XDR *, double *);
56 static bool_t ieee_xdr_to_double(XDR *, double *);
57 #define	cvt_float_to_xdr ieee_float_to_xdr
58 #define	cvt_xdr_to_float ieee_xdr_to_float
59 #define	cvt_double_to_xdr ieee_double_to_xdr
60 #define	cvt_xdr_to_double ieee_xdr_to_double
61 #else
62 #warning No platform specific float and double conversion routines defined
63 static bool_t def_float_to_xdr(XDR *, float *);
64 static bool_t def_xdr_to_float(XDR *, float *);
65 static bool_t def_double_to_xdr(XDR *, double *);
66 static bool_t def_xdr_to_double(XDR *, double *);
67 #define	cvt_float_to_xdr def_float_to_xdr
68 #define	cvt_xdr_to_float def_xdr_to_float
69 #define	cvt_double_to_xdr def_double_to_xdr
70 #define	cvt_xdr_to_double def_xdr_to_double
71 #endif
72 
73 bool_t
74 xdr_float(XDR *xdrs, float *fp)
75 {
76 	switch (xdrs->x_op) {
77 
78 	case XDR_ENCODE:
79 		return (cvt_float_to_xdr(xdrs, fp));
80 
81 	case XDR_DECODE:
82 		return (cvt_xdr_to_float(xdrs, fp));
83 
84 	case XDR_FREE:
85 		return (TRUE);
86 	}
87 	return (FALSE);
88 }
89 
90 bool_t
91 xdr_double(XDR *xdrs, double *dp)
92 {
93 	switch (xdrs->x_op) {
94 
95 	case XDR_ENCODE:
96 		return (cvt_double_to_xdr(xdrs, dp));
97 
98 	case XDR_DECODE:
99 		return (cvt_xdr_to_double(xdrs, dp));
100 
101 	case XDR_FREE:
102 		return (TRUE);
103 	}
104 
105 	return (FALSE);
106 }
107 
108 /* ARGSUSED */
109 bool_t
110 xdr_quadruple(XDR *xdrs, long double *fp)
111 {
112 /*
113  * The Sparc uses IEEE FP encoding, so just do a byte copy
114  */
115 
116 #if !defined(sparc)
117 	return (FALSE);
118 #else
119 	switch (xdrs->x_op) {
120 	case XDR_ENCODE:
121 		return (XDR_PUTBYTES(xdrs, (char *)fp, sizeof (long double)));
122 	case XDR_DECODE:
123 		return (XDR_GETBYTES(xdrs, (char *)fp, sizeof (long double)));
124 	case XDR_FREE:
125 		return (TRUE);
126 	}
127 	return (FALSE);
128 #endif
129 }
130 
131 #if defined(_IEEE_754)
132 
133 /*
134  * Over-the-wire format is IEEE, so just copy.  Includes CPUs:
135  * amd64, i386, sparc, sparcv9
136  */
137 
138 static bool_t
139 ieee_float_to_xdr(XDR *xdrs, float *fp)
140 {
141 	return (XDR_PUTBYTES(xdrs, (char *)fp, sizeof (float)));
142 }
143 
144 static bool_t
145 ieee_xdr_to_float(XDR *xdrs, float *fp)
146 {
147 	return (XDR_GETBYTES(xdrs, (char *)fp, sizeof (float)));
148 }
149 
150 static bool_t
151 ieee_double_to_xdr(XDR *xdrs, double *dp)
152 {
153 	return (XDR_PUTBYTES(xdrs, (char *)dp, sizeof (double)));
154 }
155 
156 static bool_t
157 ieee_xdr_to_double(XDR *xdrs, double *dp)
158 {
159 	return (XDR_GETBYTES(xdrs, (char *)dp, sizeof (double)));
160 }
161 
162 #else /* !defined (_IEEE_794) */
163 
164 static bool_t
165 def_float_to_xdr(XDR *xdrs, float *fp)
166 {
167 	/*
168 	 * Every machine can do this, its just not very efficient.
169 	 * In addtion, some rounding errors may occur do to the
170 	 * calculations involved.
171 	 */
172 	float f;
173 	int neg = 0;
174 	int exp = 0;
175 	int32_t val;
176 
177 	f = *fp;
178 	if (f == 0) {
179 		val = 0;
180 		return (XDR_PUTINT32(xdrs, &val));
181 	}
182 	if (f < 0) {
183 		f = 0 - f;
184 		neg = 1;
185 	}
186 	while (f < 1) {
187 		f = f * 2;
188 		--exp;
189 	}
190 	while (f >= 2) {
191 		f = f/2;
192 		++exp;
193 	}
194 	if ((exp > 128) || (exp < -127)) {
195 		/* over or under flowing ieee exponent */
196 		return (FALSE);
197 	}
198 	val = neg;
199 	val = val << 8;		/* for the exponent */
200 	val += 127 + exp;	/* 127 is the bias */
201 	val = val << 23;	/* for the mantissa */
202 	val += (int32_t)((f - 1) * 8388608);	/* 2 ^ 23 */
203 	return (XDR_PUTINT32(xdrs, &val));
204 }
205 
206 static bool_t
207 def_xdr_to_float(XDR *xdrs, float *fp)
208 {
209 	/*
210 	 * Every machine can do this, its just not very
211 	 * efficient.  It assumes that the decoding machine's
212 	 * float can represent any value in the range of
213 	 *	ieee largest  float  = (2 ^ 128)  * 0x1.fffff
214 	 *	to
215 	 *	ieee smallest float  = (2 ^ -127) * 0x1.00000
216 	 * In addtion, some rounding errors may occur do to the
217 	 * calculations involved.
218 	 */
219 	float f;
220 	int neg = 0;
221 	int exp = 0;
222 	int32_t val;
223 
224 	if (!XDR_GETINT32(xdrs, (int32_t *)&val))
225 		return (FALSE);
226 	neg = val & 0x80000000;
227 	exp = (val & 0x7f800000) >> 23;
228 	exp -= 127;		/* subtract exponent base */
229 	f = (val & 0x007fffff) * 0.00000011920928955078125;
230 	/* 2 ^ -23 */
231 	f++;
232 
233 	while (exp != 0) {
234 		if (exp < 0) {
235 			f = f/2.0;
236 			++exp;
237 		} else {
238 			f = f * 2.0;
239 			--exp;
240 		}
241 	}
242 
243 	if (neg)
244 		f = 0 - f;
245 
246 	*fp = f;
247 	return (TRUE);
248 }
249 
250 static bool_t
251 def_double_to_xdr(XDR *xdrs, double *dp)
252 {
253 	/*
254 	 * Every machine can do this, its just not very efficient.
255 	 * In addtion, some rounding errors may occur do to the
256 	 * calculations involved.
257 	 */
258 
259 	int *lp;
260 	double d;
261 	int neg = 0;
262 	int exp = 0;
263 	int32_t val[2];
264 
265 	d = *dp;
266 	if (d == 0) {
267 		val[0] = 0;
268 		val[1] = 0;
269 		lp = val;
270 		return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
271 	}
272 	if (d < 0) {
273 		d = 0 - d;
274 		neg = 1;
275 	}
276 	while (d < 1) {
277 		d = d * 2;
278 		--exp;
279 	}
280 	while (d >= 2) {
281 		d = d/2;
282 		++exp;
283 	}
284 	if ((exp > 1024) || (exp < -1023)) {
285 		/* over or under flowing ieee exponent */
286 		return (FALSE);
287 	}
288 	val[0] = neg;
289 	val[0] = val[0] << 11;	/* for the exponent */
290 	val[0] += 1023 + exp;	/* 1023 is the bias */
291 	val[0] = val[0] << 20;	/* for the mantissa */
292 	val[0] += (int32_t)((d - 1) * 1048576);	/* 2 ^ 20 */
293 	val[1] += (int32_t)((((d - 1) * 1048576) - val[0]) * 4294967296);
294 	/* 2 ^ 32 */
295 	lp = val;
296 
297 	return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
298 }
299 
300 static bool_t
301 def_xdr_to_double(XDR *, double *dp)
302 {
303 	/*
304 	 * Every machine can do this, its just not very
305 	 * efficient.  It assumes that the decoding machine's
306 	 * double can represent any value in the range of
307 	 *	ieee largest  double  = (2 ^ 1024)  * 0x1.fffffffffffff
308 	 *	to
309 	 *	ieee smallest double  = (2 ^ -1023) * 0x1.0000000000000
310 	 * In addtion, some rounding errors may occur do to the
311 	 * calculations involved.
312 	 */
313 	int *lp;
314 	double d;
315 	int neg = 0;
316 	int exp = 0;
317 	int32_t val[2];
318 
319 	lp = val;
320 	if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
321 		return (FALSE);
322 	neg = val[0] & 0x80000000;
323 	exp = (val[0] & 0x7ff00000) >> 20;
324 	exp -= 1023;		/* subtract exponent base */
325 	d = (val[0] & 0x000fffff) * 0.00000095367431640625;
326 	/* 2 ^ -20 */
327 	d += (val[1] * 0.0000000000000002220446049250313);
328 	/* 2 ^ -52 */
329 	d++;
330 	while (exp != 0) {
331 		if (exp < 0) {
332 			d = d/2.0;
333 			++exp;
334 		} else {
335 			d = d * 2.0;
336 			--exp;
337 		}
338 	}
339 	if (neg)
340 		d = 0 - d;
341 
342 	*dp = d;
343 	return (TRUE);
344 }
345 
346 #endif /* _IEEE_794 */
347