xref: /illumos-gate/usr/src/lib/libnsl/rpc/xdr_float.c (revision 598f4ceed9327d2d6c2325dd67cae3aa06f7fea6)
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 <values.h>
50 #include <rpc/types.h>
51 #include <rpc/xdr.h>
52 #include <sys/byteorder.h>
53 
54 #ifdef _IEEE_754
55 
56 /*
57  * The OTW format is IEEE 754 with big endian ordering.
58  */
59 bool_t
60 xdr_float(XDR *xdrs, float *fp)
61 {
62 	switch (xdrs->x_op) {
63 
64 	case XDR_ENCODE:
65 		return (XDR_PUTINT32(xdrs, (int *)fp));
66 
67 	case XDR_DECODE:
68 		return (XDR_GETINT32(xdrs, (int *)fp));
69 
70 	case XDR_FREE:
71 		return (TRUE);
72 	}
73 	return (FALSE);
74 }
75 
76 bool_t
77 xdr_double(XDR *xdrs, double *dp)
78 {
79 	int64_t *i64p = (int64_t *)dp;
80 	int64_t val;
81 	bool_t ret;
82 
83 	switch (xdrs->x_op) {
84 
85 	case XDR_ENCODE:
86 		val = BE_64(*i64p);
87 		return (XDR_PUTBYTES(xdrs, (char *)&val, sizeof (val)));
88 
89 	case XDR_DECODE:
90 		ret = XDR_GETBYTES(xdrs, (char *)dp, sizeof (double));
91 		if (ret)
92 			*i64p = BE_64(*i64p);
93 		return (ret);
94 
95 	case XDR_FREE:
96 		return (TRUE);
97 	}
98 
99 	return (FALSE);
100 }
101 
102 /* ARGSUSED */
103 bool_t
104 xdr_quadruple(XDR *xdrs, long double *fp)
105 {
106 /*
107  * The Sparc uses IEEE FP encoding, so just do a byte copy
108  */
109 
110 #if !defined(sparc)
111 	return (FALSE);
112 #else
113 	switch (xdrs->x_op) {
114 	case XDR_ENCODE:
115 		return (XDR_PUTBYTES(xdrs, (char *)fp, sizeof (long double)));
116 	case XDR_DECODE:
117 		return (XDR_GETBYTES(xdrs, (char *)fp, sizeof (long double)));
118 	case XDR_FREE:
119 		return (TRUE);
120 	}
121 	return (FALSE);
122 #endif
123 }
124 
125 #else
126 
127 #warn No platform specific implementation defined for floats
128 
129 bool_t
130 xdr_float(XDR *xdrs, float *fp)
131 {
132 	/*
133 	 * Every machine can do this, its just not very efficient.
134 	 * In addtion, some rounding errors may occur do to the
135 	 * calculations involved.
136 	 */
137 	float f;
138 	int neg = 0;
139 	int exp = 0;
140 	int32_t val;
141 
142 	switch (xdrs->x_op) {
143 	case XDR_ENCODE:
144 		f = *fp;
145 		if (f == 0) {
146 			val = 0;
147 			return (XDR_PUTINT32(xdrs, &val));
148 		}
149 		if (f < 0) {
150 			f = 0 - f;
151 			neg = 1;
152 		}
153 		while (f < 1) {
154 			f = f * 2;
155 			--exp;
156 		}
157 		while (f >= 2) {
158 			f = f/2;
159 			++exp;
160 		}
161 		if ((exp > 128) || (exp < -127)) {
162 			/* over or under flowing ieee exponent */
163 			return (FALSE);
164 		}
165 		val = neg;
166 		val = val << 8;		/* for the exponent */
167 		val += 127 + exp;	/* 127 is the bias */
168 		val = val << 23;	/* for the mantissa */
169 		val += (int32_t)((f - 1) * 8388608);	/* 2 ^ 23 */
170 		return (XDR_PUTINT32(xdrs, &val));
171 
172 	case XDR_DECODE:
173 		/*
174 		 * It assumes that the decoding machine's float can represent
175 		 * any value in the range of
176 		 *	ieee largest  float  = (2 ^ 128)  * 0x1.fffff
177 		 *	to
178 		 *	ieee smallest float  = (2 ^ -127) * 0x1.00000
179 		 * In addtion, some rounding errors may occur do to the
180 		 * calculations involved.
181 		 */
182 
183 		if (!XDR_GETINT32(xdrs, (int32_t *)&val))
184 			return (FALSE);
185 		neg = val & 0x80000000;
186 		exp = (val & 0x7f800000) >> 23;
187 		exp -= 127;		/* subtract exponent base */
188 		f = (val & 0x007fffff) * 0.00000011920928955078125;
189 		/* 2 ^ -23 */
190 		f++;
191 
192 		while (exp != 0) {
193 			if (exp < 0) {
194 				f = f/2.0;
195 				++exp;
196 			} else {
197 				f = f * 2.0;
198 				--exp;
199 			}
200 		}
201 
202 		if (neg)
203 			f = 0 - f;
204 
205 		*fp = f;
206 		return (TRUE);
207 
208 	case XDR_FREE:
209 		return (TRUE);
210 	}
211 
212 	return (FALSE);
213 }
214 
215 bool_t
216 xdr_double(XDR *xdrs, double *dp)
217 {
218 	/*
219 	 * Every machine can do this, its just not very efficient.
220 	 * In addtion, some rounding errors may occur do to the
221 	 * calculations involved.
222 	 */
223 
224 	int *lp;
225 	double d;
226 	int neg = 0;
227 	int exp = 0;
228 	int32_t val[2];
229 
230 	switch (xdrs->x_op) {
231 	case XDR_ENCODE:
232 		d = *dp;
233 		if (d == 0) {
234 			val[0] = 0;
235 			val[1] = 0;
236 			lp = val;
237 			return (XDR_PUTINT32(xdrs, lp++) &&
238 			    XDR_PUTINT32(xdrs, lp));
239 		}
240 		if (d < 0) {
241 			d = 0 - d;
242 			neg = 1;
243 		}
244 		while (d < 1) {
245 			d = d * 2;
246 			--exp;
247 		}
248 		while (d >= 2) {
249 			d = d/2;
250 			++exp;
251 		}
252 		if ((exp > 1024) || (exp < -1023)) {
253 			/* over or under flowing ieee exponent */
254 			return (FALSE);
255 		}
256 		val[0] = (neg << 11);	/* for the exponent */
257 		val[0] += 1023 + exp;	/* 1023 is the bias */
258 		val[0] = val[0] << 20;	/* for the mantissa */
259 		val[0] += (int32_t)((d - 1) * 1048576);	/* 2 ^ 20 */
260 		val[1] += (uint32_t)((((d - 1) * 1048576) - val[0]) *
261 		    4294967296); /* 2 ^ 32 */
262 		lp = val;
263 
264 		return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
265 
266 	case XDR_DECODE:
267 		/*
268 		 * It assumes that the decoding machine's
269 		 * double can represent any value in the range of
270 		 *	ieee largest  double  = (2 ^ 1024)  * 0x1.fffffffffffff
271 		 *	to
272 		 *	ieee smallest double  = (2 ^ -1023) * 0x1.0000000000000
273 		 * In addtion, some rounding errors may occur do to the
274 		 * calculations involved.
275 		 */
276 
277 		lp = val;
278 		if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
279 			return (FALSE);
280 		neg = val[0] & 0x80000000;
281 		exp = (val[0] & 0x7ff00000) >> 20;
282 		exp -= 1023;		/* subtract exponent base */
283 		d = (val[0] & 0x000fffff) * 0.00000095367431640625;
284 		/* 2 ^ -20 */
285 		d += (val[1] * 0.0000000000000002220446049250313);
286 		/* 2 ^ -52 */
287 		d++;
288 		while (exp != 0) {
289 			if (exp < 0) {
290 				d = d/2.0;
291 				++exp;
292 			} else {
293 				d = d * 2.0;
294 				--exp;
295 			}
296 		}
297 		if (neg)
298 			d = 0 - d;
299 
300 		*dp = d;
301 		return (TRUE);
302 
303 	case XDR_FREE:
304 		return (TRUE);
305 	}
306 
307 	return (FALSE);
308 }
309 
310 bool_t
311 xdr_quadruple(XDR *xdrs, long double *fp)
312 {
313 	return (FALSE);
314 }
315 
316 #endif /* _IEEE_754 */
317