xref: /illumos-gate/usr/src/lib/libnsl/rpc/xdr_float.c (revision 7f93f875)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55f9e186fSgt  * Common Development and Distribution License (the "License").
65f9e186fSgt  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
2061961e0fSrobinson  */
2161961e0fSrobinson 
2261961e0fSrobinson /*
23e8031f0aSraf  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
26e8031f0aSraf 
277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
287c478bd9Sstevel@tonic-gate /* All Rights Reserved */
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley
317c478bd9Sstevel@tonic-gate  * 4.3 BSD under license from the Regents of the University of
327c478bd9Sstevel@tonic-gate  * California.
337c478bd9Sstevel@tonic-gate  */
344b05e997SJason King /*
354b05e997SJason King  * Copyright 2011 Jason King.  All rights reserved
364b05e997SJason King  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
39e8031f0aSraf  * Generic XDR routines impelmentation.
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * These are the "floating point" xdr routines used to (de)serialize
427c478bd9Sstevel@tonic-gate  * most common data items.  See xdr.h for more info on the interface to
437c478bd9Sstevel@tonic-gate  * xdr.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
46e8031f0aSraf #include "mt.h"
477c478bd9Sstevel@tonic-gate #include <sys/types.h>
487c478bd9Sstevel@tonic-gate #include <stdio.h>
49*7f93f875SJason King #include <values.h>
507c478bd9Sstevel@tonic-gate #include <rpc/types.h>
517c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
52*7f93f875SJason King #include <sys/byteorder.h>
537c478bd9Sstevel@tonic-gate 
54*7f93f875SJason King #ifdef _IEEE_754
557c478bd9Sstevel@tonic-gate 
56*7f93f875SJason King /*
57*7f93f875SJason King  * The OTW format is IEEE 754 with big endian ordering.
58*7f93f875SJason King  */
597c478bd9Sstevel@tonic-gate bool_t
xdr_float(XDR * xdrs,float * fp)607c478bd9Sstevel@tonic-gate xdr_float(XDR *xdrs, float *fp)
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate 	switch (xdrs->x_op) {
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	case XDR_ENCODE:
65*7f93f875SJason King 		return (XDR_PUTINT32(xdrs, (int *)fp));
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	case XDR_DECODE:
68*7f93f875SJason King 		return (XDR_GETINT32(xdrs, (int *)fp));
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	case XDR_FREE:
717c478bd9Sstevel@tonic-gate 		return (TRUE);
727c478bd9Sstevel@tonic-gate 	}
737c478bd9Sstevel@tonic-gate 	return (FALSE);
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate bool_t
xdr_double(XDR * xdrs,double * dp)777c478bd9Sstevel@tonic-gate xdr_double(XDR *xdrs, double *dp)
787c478bd9Sstevel@tonic-gate {
79*7f93f875SJason King 	int64_t *i64p = (int64_t *)dp;
80*7f93f875SJason King 	int64_t val;
81*7f93f875SJason King 	bool_t ret;
82*7f93f875SJason King 
837c478bd9Sstevel@tonic-gate 	switch (xdrs->x_op) {
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	case XDR_ENCODE:
86*7f93f875SJason King 		val = BE_64(*i64p);
87*7f93f875SJason King 		return (XDR_PUTBYTES(xdrs, (char *)&val, sizeof (val)));
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	case XDR_DECODE:
90*7f93f875SJason King 		ret = XDR_GETBYTES(xdrs, (char *)dp, sizeof (double));
91*7f93f875SJason King 		if (ret)
92*7f93f875SJason King 			*i64p = BE_64(*i64p);
93*7f93f875SJason King 		return (ret);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	case XDR_FREE:
967c478bd9Sstevel@tonic-gate 		return (TRUE);
977c478bd9Sstevel@tonic-gate 	}
984b05e997SJason King 
997c478bd9Sstevel@tonic-gate 	return (FALSE);
1007c478bd9Sstevel@tonic-gate }
1017c478bd9Sstevel@tonic-gate 
10261961e0fSrobinson /* ARGSUSED */
1037c478bd9Sstevel@tonic-gate bool_t
xdr_quadruple(XDR * xdrs,long double * fp)1047c478bd9Sstevel@tonic-gate xdr_quadruple(XDR *xdrs, long double *fp)
1057c478bd9Sstevel@tonic-gate {
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate  * The Sparc uses IEEE FP encoding, so just do a byte copy
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate 
11061961e0fSrobinson #if !defined(sparc)
11161961e0fSrobinson 	return (FALSE);
11261961e0fSrobinson #else
1137c478bd9Sstevel@tonic-gate 	switch (xdrs->x_op) {
1147c478bd9Sstevel@tonic-gate 	case XDR_ENCODE:
11561961e0fSrobinson 		return (XDR_PUTBYTES(xdrs, (char *)fp, sizeof (long double)));
1167c478bd9Sstevel@tonic-gate 	case XDR_DECODE:
11761961e0fSrobinson 		return (XDR_GETBYTES(xdrs, (char *)fp, sizeof (long double)));
1187c478bd9Sstevel@tonic-gate 	case XDR_FREE:
1197c478bd9Sstevel@tonic-gate 		return (TRUE);
1207c478bd9Sstevel@tonic-gate 	}
1217c478bd9Sstevel@tonic-gate 	return (FALSE);
12261961e0fSrobinson #endif
1237c478bd9Sstevel@tonic-gate }
1244b05e997SJason King 
125*7f93f875SJason King #else
1264b05e997SJason King 
127*7f93f875SJason King #warn No platform specific implementation defined for floats
1284b05e997SJason King 
129*7f93f875SJason King bool_t
xdr_float(XDR * xdrs,float * fp)130*7f93f875SJason King xdr_float(XDR *xdrs, float *fp)
1314b05e997SJason King {
1324b05e997SJason King 	/*
1334b05e997SJason King 	 * Every machine can do this, its just not very efficient.
1344b05e997SJason King 	 * In addtion, some rounding errors may occur do to the
1354b05e997SJason King 	 * calculations involved.
1364b05e997SJason King 	 */
1374b05e997SJason King 	float f;
1384b05e997SJason King 	int neg = 0;
1394b05e997SJason King 	int exp = 0;
1404b05e997SJason King 	int32_t val;
1414b05e997SJason King 
142*7f93f875SJason King 	switch (xdrs->x_op) {
143*7f93f875SJason King 	case XDR_ENCODE:
144*7f93f875SJason King 		f = *fp;
145*7f93f875SJason King 		if (f == 0) {
146*7f93f875SJason King 			val = 0;
147*7f93f875SJason King 			return (XDR_PUTINT32(xdrs, &val));
148*7f93f875SJason King 		}
149*7f93f875SJason King 		if (f < 0) {
150*7f93f875SJason King 			f = 0 - f;
151*7f93f875SJason King 			neg = 1;
152*7f93f875SJason King 		}
153*7f93f875SJason King 		while (f < 1) {
154*7f93f875SJason King 			f = f * 2;
155*7f93f875SJason King 			--exp;
156*7f93f875SJason King 		}
157*7f93f875SJason King 		while (f >= 2) {
158*7f93f875SJason King 			f = f/2;
159*7f93f875SJason King 			++exp;
160*7f93f875SJason King 		}
161*7f93f875SJason King 		if ((exp > 128) || (exp < -127)) {
162*7f93f875SJason King 			/* over or under flowing ieee exponent */
163*7f93f875SJason King 			return (FALSE);
164*7f93f875SJason King 		}
165*7f93f875SJason King 		val = neg;
166*7f93f875SJason King 		val = val << 8;		/* for the exponent */
167*7f93f875SJason King 		val += 127 + exp;	/* 127 is the bias */
168*7f93f875SJason King 		val = val << 23;	/* for the mantissa */
169*7f93f875SJason King 		val += (int32_t)((f - 1) * 8388608);	/* 2 ^ 23 */
1704b05e997SJason King 		return (XDR_PUTINT32(xdrs, &val));
1714b05e997SJason King 
172*7f93f875SJason King 	case XDR_DECODE:
173*7f93f875SJason King 		/*
174*7f93f875SJason King 		 * It assumes that the decoding machine's float can represent
175*7f93f875SJason King 		 * any value in the range of
176*7f93f875SJason King 		 *	ieee largest  float  = (2 ^ 128)  * 0x1.fffff
177*7f93f875SJason King 		 *	to
178*7f93f875SJason King 		 *	ieee smallest float  = (2 ^ -127) * 0x1.00000
179*7f93f875SJason King 		 * In addtion, some rounding errors may occur do to the
180*7f93f875SJason King 		 * calculations involved.
181*7f93f875SJason King 		 */
182*7f93f875SJason King 
183*7f93f875SJason King 		if (!XDR_GETINT32(xdrs, (int32_t *)&val))
184*7f93f875SJason King 			return (FALSE);
185*7f93f875SJason King 		neg = val & 0x80000000;
186*7f93f875SJason King 		exp = (val & 0x7f800000) >> 23;
187*7f93f875SJason King 		exp -= 127;		/* subtract exponent base */
188*7f93f875SJason King 		f = (val & 0x007fffff) * 0.00000011920928955078125;
189*7f93f875SJason King 		/* 2 ^ -23 */
190*7f93f875SJason King 		f++;
191*7f93f875SJason King 
192*7f93f875SJason King 		while (exp != 0) {
193*7f93f875SJason King 			if (exp < 0) {
194*7f93f875SJason King 				f = f/2.0;
195*7f93f875SJason King 				++exp;
196*7f93f875SJason King 			} else {
197*7f93f875SJason King 				f = f * 2.0;
198*7f93f875SJason King 				--exp;
199*7f93f875SJason King 			}
2004b05e997SJason King 		}
2014b05e997SJason King 
202*7f93f875SJason King 		if (neg)
203*7f93f875SJason King 			f = 0 - f;
2044b05e997SJason King 
205*7f93f875SJason King 		*fp = f;
206*7f93f875SJason King 		return (TRUE);
207*7f93f875SJason King 
208*7f93f875SJason King 	case XDR_FREE:
209*7f93f875SJason King 		return (TRUE);
210*7f93f875SJason King 	}
211*7f93f875SJason King 
212*7f93f875SJason King 	return (FALSE);
2134b05e997SJason King }
2144b05e997SJason King 
215*7f93f875SJason King bool_t
xdr_double(XDR * xdrs,double * dp)216*7f93f875SJason King xdr_double(XDR *xdrs, double *dp)
2174b05e997SJason King {
2184b05e997SJason King 	/*
2194b05e997SJason King 	 * Every machine can do this, its just not very efficient.
2204b05e997SJason King 	 * In addtion, some rounding errors may occur do to the
2214b05e997SJason King 	 * calculations involved.
2224b05e997SJason King 	 */
2234b05e997SJason King 
2244b05e997SJason King 	int *lp;
2254b05e997SJason King 	double d;
2264b05e997SJason King 	int neg = 0;
2274b05e997SJason King 	int exp = 0;
2284b05e997SJason King 	int32_t val[2];
2294b05e997SJason King 
230*7f93f875SJason King 	switch (xdrs->x_op) {
231*7f93f875SJason King 	case XDR_ENCODE:
232*7f93f875SJason King 		d = *dp;
233*7f93f875SJason King 		if (d == 0) {
234*7f93f875SJason King 			val[0] = 0;
235*7f93f875SJason King 			val[1] = 0;
236*7f93f875SJason King 			lp = val;
237*7f93f875SJason King 			return (XDR_PUTINT32(xdrs, lp++) &&
238*7f93f875SJason King 			    XDR_PUTINT32(xdrs, lp));
239*7f93f875SJason King 		}
240*7f93f875SJason King 		if (d < 0) {
241*7f93f875SJason King 			d = 0 - d;
242*7f93f875SJason King 			neg = 1;
243*7f93f875SJason King 		}
244*7f93f875SJason King 		while (d < 1) {
245*7f93f875SJason King 			d = d * 2;
246*7f93f875SJason King 			--exp;
247*7f93f875SJason King 		}
248*7f93f875SJason King 		while (d >= 2) {
249*7f93f875SJason King 			d = d/2;
250*7f93f875SJason King 			++exp;
251*7f93f875SJason King 		}
252*7f93f875SJason King 		if ((exp > 1024) || (exp < -1023)) {
253*7f93f875SJason King 			/* over or under flowing ieee exponent */
254*7f93f875SJason King 			return (FALSE);
255*7f93f875SJason King 		}
256*7f93f875SJason King 		val[0] = (neg << 11);	/* for the exponent */
257*7f93f875SJason King 		val[0] += 1023 + exp;	/* 1023 is the bias */
258*7f93f875SJason King 		val[0] = val[0] << 20;	/* for the mantissa */
259*7f93f875SJason King 		val[0] += (int32_t)((d - 1) * 1048576);	/* 2 ^ 20 */
260*7f93f875SJason King 		val[1] += (uint32_t)((((d - 1) * 1048576) - val[0]) *
261*7f93f875SJason King 		    4294967296); /* 2 ^ 32 */
2624b05e997SJason King 		lp = val;
263*7f93f875SJason King 
2644b05e997SJason King 		return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
2654b05e997SJason King 
266*7f93f875SJason King 	case XDR_DECODE:
267*7f93f875SJason King 		/*
268*7f93f875SJason King 		 * It assumes that the decoding machine's
269*7f93f875SJason King 		 * double can represent any value in the range of
270*7f93f875SJason King 		 *	ieee largest  double  = (2 ^ 1024)  * 0x1.fffffffffffff
271*7f93f875SJason King 		 *	to
272*7f93f875SJason King 		 *	ieee smallest double  = (2 ^ -1023) * 0x1.0000000000000
273*7f93f875SJason King 		 * In addtion, some rounding errors may occur do to the
274*7f93f875SJason King 		 * calculations involved.
275*7f93f875SJason King 		 */
2764b05e997SJason King 
277*7f93f875SJason King 		lp = val;
278*7f93f875SJason King 		if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
279*7f93f875SJason King 			return (FALSE);
280*7f93f875SJason King 		neg = val[0] & 0x80000000;
281*7f93f875SJason King 		exp = (val[0] & 0x7ff00000) >> 20;
282*7f93f875SJason King 		exp -= 1023;		/* subtract exponent base */
283*7f93f875SJason King 		d = (val[0] & 0x000fffff) * 0.00000095367431640625;
284*7f93f875SJason King 		/* 2 ^ -20 */
285*7f93f875SJason King 		d += (val[1] * 0.0000000000000002220446049250313);
286*7f93f875SJason King 		/* 2 ^ -52 */
287*7f93f875SJason King 		d++;
288*7f93f875SJason King 		while (exp != 0) {
289*7f93f875SJason King 			if (exp < 0) {
290*7f93f875SJason King 				d = d/2.0;
291*7f93f875SJason King 				++exp;
292*7f93f875SJason King 			} else {
293*7f93f875SJason King 				d = d * 2.0;
294*7f93f875SJason King 				--exp;
295*7f93f875SJason King 			}
2964b05e997SJason King 		}
297*7f93f875SJason King 		if (neg)
298*7f93f875SJason King 			d = 0 - d;
299*7f93f875SJason King 
300*7f93f875SJason King 		*dp = d;
301*7f93f875SJason King 		return (TRUE);
302*7f93f875SJason King 
303*7f93f875SJason King 	case XDR_FREE:
304*7f93f875SJason King 		return (TRUE);
3054b05e997SJason King 	}
3064b05e997SJason King 
307*7f93f875SJason King 	return (FALSE);
308*7f93f875SJason King }
309*7f93f875SJason King 
310*7f93f875SJason King bool_t
xdr_quadruple(XDR * xdrs,long double * fp)311*7f93f875SJason King xdr_quadruple(XDR *xdrs, long double *fp)
312*7f93f875SJason King {
313*7f93f875SJason King 	return (FALSE);
3144b05e997SJason King }
3154b05e997SJason King 
316*7f93f875SJason King #endif /* _IEEE_754 */
317