xref: /freebsd/lib/libc/xdr/xdr_float.c (revision 4543ef516683042d46f3bd3bb8a4f3f746e00499)
1 /*	$NetBSD: xdr_float.c,v 1.23 2000/07/17 04:59:51 matt Exp $	*/
2 
3 /*-
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Copyright (c) 2010, Oracle America, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  *     * Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *     * Redistributions in binary form must reproduce the above
15  *       copyright notice, this list of conditions and the following
16  *       disclaimer in the documentation and/or other materials
17  *       provided with the distribution.
18  *     * Neither the name of the "Oracle America, Inc." nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /*
37  * xdr_float.c, Generic XDR routines implementation.
38  *
39  * These are the "floating point" xdr routines used to (de)serialize
40  * most common data items.  See xdr.h for more info on the interface to
41  * xdr.
42  */
43 
44 #include "namespace.h"
45 #include <sys/param.h>
46 
47 #include <stdio.h>
48 
49 #include <rpc/types.h>
50 #include <rpc/xdr.h>
51 #include "un-namespace.h"
52 
53 /*
54  * NB: Not portable.
55  * This routine works on machines with IEEE754 FP and Vaxen.
56  */
57 
58 #include <machine/endian.h>
59 #define IEEEFP
60 
61 #if defined(__vax__)
62 
63 /* What IEEE single precision floating point looks like on a Vax */
64 struct	ieee_single {
65 	unsigned int	mantissa: 23;
66 	unsigned int	exp     : 8;
67 	unsigned int	sign    : 1;
68 };
69 
70 /* Vax single precision floating point */
71 struct	vax_single {
72 	unsigned int	mantissa1 : 7;
73 	unsigned int	exp       : 8;
74 	unsigned int	sign      : 1;
75 	unsigned int	mantissa2 : 16;
76 };
77 
78 #define VAX_SNG_BIAS	0x81
79 #define IEEE_SNG_BIAS	0x7f
80 
81 static struct sgl_limits {
82 	struct vax_single s;
83 	struct ieee_single ieee;
84 } sgl_limits[2] = {
85 	{{ 0x7f, 0xff, 0x0, 0xffff },	/* Max Vax */
86 	{ 0x0, 0xff, 0x0 }},		/* Max IEEE */
87 	{{ 0x0, 0x0, 0x0, 0x0 },	/* Min Vax */
88 	{ 0x0, 0x0, 0x0 }}		/* Min IEEE */
89 };
90 #endif /* vax */
91 
92 bool_t
93 xdr_float(XDR *xdrs, float *fp)
94 {
95 #ifndef IEEEFP
96 	struct ieee_single is;
97 	struct vax_single vs, *vsp;
98 	struct sgl_limits *lim;
99 	u_int i;
100 #endif
101 	switch (xdrs->x_op) {
102 
103 	case XDR_ENCODE:
104 #ifdef IEEEFP
105 		return (XDR_PUTINT32(xdrs, (int32_t *)fp));
106 #else
107 		vs = *((struct vax_single *)fp);
108 		for (i = 0, lim = sgl_limits; i < nitems(sgl_limits);
109 		    i++, lim++) {
110 			if ((vs.mantissa2 == lim->s.mantissa2) &&
111 				(vs.exp == lim->s.exp) &&
112 				(vs.mantissa1 == lim->s.mantissa1)) {
113 				is = lim->ieee;
114 				goto shipit;
115 			}
116 		}
117 		is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
118 		is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
119 	shipit:
120 		is.sign = vs.sign;
121 		return (XDR_PUTINT32(xdrs, (int32_t *)&is));
122 #endif
123 
124 	case XDR_DECODE:
125 #ifdef IEEEFP
126 		return (XDR_GETINT32(xdrs, (int32_t *)fp));
127 #else
128 		vsp = (struct vax_single *)fp;
129 		if (!XDR_GETINT32(xdrs, (int32_t *)&is))
130 			return (FALSE);
131 		for (i = 0, lim = sgl_limits; i < nitems(sgl_limits);
132 		    i++, lim++) {
133 			if ((is.exp == lim->ieee.exp) &&
134 				(is.mantissa == lim->ieee.mantissa)) {
135 				*vsp = lim->s;
136 				goto doneit;
137 			}
138 		}
139 		vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
140 		vsp->mantissa2 = is.mantissa;
141 		vsp->mantissa1 = (is.mantissa >> 16);
142 	doneit:
143 		vsp->sign = is.sign;
144 		return (TRUE);
145 #endif
146 
147 	case XDR_FREE:
148 		return (TRUE);
149 	}
150 	/* NOTREACHED */
151 	return (FALSE);
152 }
153 
154 #if defined(__vax__)
155 /* What IEEE double precision floating point looks like on a Vax */
156 struct	ieee_double {
157 	unsigned int	mantissa1 : 20;
158 	unsigned int	exp       : 11;
159 	unsigned int	sign      : 1;
160 	unsigned int	mantissa2 : 32;
161 };
162 
163 /* Vax double precision floating point */
164 struct  vax_double {
165 	unsigned int	mantissa1 : 7;
166 	unsigned int	exp       : 8;
167 	unsigned int	sign      : 1;
168 	unsigned int	mantissa2 : 16;
169 	unsigned int	mantissa3 : 16;
170 	unsigned int	mantissa4 : 16;
171 };
172 
173 #define VAX_DBL_BIAS	0x81
174 #define IEEE_DBL_BIAS	0x3ff
175 #define MASK(nbits)	((1 << nbits) - 1)
176 
177 static struct dbl_limits {
178 	struct	vax_double d;
179 	struct	ieee_double ieee;
180 } dbl_limits[2] = {
181 	{{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff },	/* Max Vax */
182 	{ 0x0, 0x7ff, 0x0, 0x0 }},			/* Max IEEE */
183 	{{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},		/* Min Vax */
184 	{ 0x0, 0x0, 0x0, 0x0 }}				/* Min IEEE */
185 };
186 
187 #endif /* vax */
188 
189 
190 bool_t
191 xdr_double(XDR *xdrs, double *dp)
192 {
193 #ifdef IEEEFP
194 	int32_t *i32p;
195 	bool_t rv;
196 #else
197 	int32_t *lp;
198 	struct	ieee_double id;
199 	struct	vax_double vd;
200 	struct dbl_limits *lim;
201 	u_int i;
202 #endif
203 
204 	switch (xdrs->x_op) {
205 
206 	case XDR_ENCODE:
207 #ifdef IEEEFP
208 		i32p = (int32_t *)(void *)dp;
209 #if BYTE_ORDER == BIG_ENDIAN
210 		rv = XDR_PUTINT32(xdrs, i32p);
211 		if (!rv)
212 			return (rv);
213 		rv = XDR_PUTINT32(xdrs, i32p+1);
214 #else
215 		rv = XDR_PUTINT32(xdrs, i32p+1);
216 		if (!rv)
217 			return (rv);
218 		rv = XDR_PUTINT32(xdrs, i32p);
219 #endif
220 		return (rv);
221 #else
222 		vd = *((struct vax_double *)dp);
223 		for (i = 0, lim = dbl_limits; i < nitems(dbl_limits);
224 		    i++, lim++) {
225 			if ((vd.mantissa4 == lim->d.mantissa4) &&
226 				(vd.mantissa3 == lim->d.mantissa3) &&
227 				(vd.mantissa2 == lim->d.mantissa2) &&
228 				(vd.mantissa1 == lim->d.mantissa1) &&
229 				(vd.exp == lim->d.exp)) {
230 				id = lim->ieee;
231 				goto shipit;
232 			}
233 		}
234 		id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
235 		id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3);
236 		id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) |
237 				(vd.mantissa3 << 13) |
238 				((vd.mantissa4 >> 3) & MASK(13));
239 	shipit:
240 		id.sign = vd.sign;
241 		lp = (int32_t *)&id;
242 		return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
243 #endif
244 
245 	case XDR_DECODE:
246 #ifdef IEEEFP
247 		i32p = (int32_t *)(void *)dp;
248 #if BYTE_ORDER == BIG_ENDIAN
249 		rv = XDR_GETINT32(xdrs, i32p);
250 		if (!rv)
251 			return (rv);
252 		rv = XDR_GETINT32(xdrs, i32p+1);
253 #else
254 		rv = XDR_GETINT32(xdrs, i32p+1);
255 		if (!rv)
256 			return (rv);
257 		rv = XDR_GETINT32(xdrs, i32p);
258 #endif
259 		return (rv);
260 #else
261 		lp = (int32_t *)&id;
262 		if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
263 			return (FALSE);
264 		for (i = 0, lim = dbl_limits; i < nitems(dbl_limits);
265 		    i++, lim++) {
266 			if ((id.mantissa2 == lim->ieee.mantissa2) &&
267 				(id.mantissa1 == lim->ieee.mantissa1) &&
268 				(id.exp == lim->ieee.exp)) {
269 				vd = lim->d;
270 				goto doneit;
271 			}
272 		}
273 		vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
274 		vd.mantissa1 = (id.mantissa1 >> 13);
275 		vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) |
276 				(id.mantissa2 >> 29);
277 		vd.mantissa3 = (id.mantissa2 >> 13);
278 		vd.mantissa4 = (id.mantissa2 << 3);
279 	doneit:
280 		vd.sign = id.sign;
281 		*dp = *((double *)&vd);
282 		return (TRUE);
283 #endif
284 
285 	case XDR_FREE:
286 		return (TRUE);
287 	}
288 	/* NOTREACHED */
289 	return (FALSE);
290 }
291