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