/src/gdal/port/cpl_vax.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /******************************************************************************  | 
2  |  |  *  | 
3  |  |  * Project:  CPL  | 
4  |  |  * Purpose:  Convert between VAX and IEEE floating point formats  | 
5  |  |  * Author:   Frank Warmerdam, warmerdam@pobox.com  | 
6  |  |  *  | 
7  |  |  ******************************************************************************  | 
8  |  |  * Copyright (c) 2000, Avenza Systems Inc, http://www.avenza.com/  | 
9  |  |  *  | 
10  |  |  * SPDX-License-Identifier: MIT  | 
11  |  |  ****************************************************************************/  | 
12  |  |  | 
13  |  | #include "cpl_port.h"  | 
14  |  | #include "cpl_vax.h"  | 
15  |  |  | 
16  |  | namespace  | 
17  |  | { | 
18  |  | typedef struct dbl  | 
19  |  | { | 
20  |  |     // cppcheck-suppress unusedStructMember  | 
21  |  |     GUInt32 hi;  | 
22  |  |     // cppcheck-suppress unusedStructMember  | 
23  |  |     GUInt32 lo;  | 
24  |  | } double64_t;  | 
25  |  | }  // namespace  | 
26  |  |  | 
27  |  | /************************************************************************/  | 
28  |  | /*                          CPLVaxToIEEEDouble()                        */  | 
29  |  | /************************************************************************/  | 
30  |  |  | 
31  |  | void CPLVaxToIEEEDouble(void *dbl)  | 
32  |  |  | 
33  | 0  | { | 
34  | 0  |     double64_t dt;  | 
35  | 0  |     GUInt32 sign;  | 
36  | 0  |     int exponent;  | 
37  | 0  |     GUInt32 rndbits;  | 
38  |  |  | 
39  |  |     /* -------------------------------------------------------------------- */  | 
40  |  |     /*      Arrange the VAX double so that it may be accessed by a          */  | 
41  |  |     /*      double64_t structure, (two GUInt32s).                           */  | 
42  |  |     /* -------------------------------------------------------------------- */  | 
43  | 0  |     { | 
44  | 0  |         const unsigned char *src = static_cast<const unsigned char *>(dbl);  | 
45  | 0  |         unsigned char dest[8];  | 
46  | 0  | #ifdef CPL_LSB  | 
47  | 0  |         dest[2] = src[0];  | 
48  | 0  |         dest[3] = src[1];  | 
49  | 0  |         dest[0] = src[2];  | 
50  | 0  |         dest[1] = src[3];  | 
51  | 0  |         dest[6] = src[4];  | 
52  | 0  |         dest[7] = src[5];  | 
53  | 0  |         dest[4] = src[6];  | 
54  | 0  |         dest[5] = src[7];  | 
55  |  | #else  | 
56  |  |         dest[1] = src[0];  | 
57  |  |         dest[0] = src[1];  | 
58  |  |         dest[3] = src[2];  | 
59  |  |         dest[2] = src[3];  | 
60  |  |         dest[5] = src[4];  | 
61  |  |         dest[4] = src[5];  | 
62  |  |         dest[7] = src[6];  | 
63  |  |         dest[6] = src[7];  | 
64  |  | #endif  | 
65  | 0  |         memcpy(&dt, dest, 8);  | 
66  | 0  |     }  | 
67  |  |  | 
68  |  |     /* -------------------------------------------------------------------- */  | 
69  |  |     /*      Save the sign of the double                                     */  | 
70  |  |     /* -------------------------------------------------------------------- */  | 
71  | 0  |     sign = dt.hi & 0x80000000;  | 
72  |  |  | 
73  |  |     /* -------------------------------------------------------------------- */  | 
74  |  |     /*      Adjust the exponent so that we may work with it                 */  | 
75  |  |     /* -------------------------------------------------------------------- */  | 
76  | 0  |     exponent = (dt.hi >> 23) & 0x000000ff;  | 
77  |  | 
  | 
78  | 0  |     if (exponent)  | 
79  | 0  |         exponent = exponent - 129 + 1023;  | 
80  |  |  | 
81  |  |     /* -------------------------------------------------------------------- */  | 
82  |  |     /*      Save the bits that we are discarding so we can round properly   */  | 
83  |  |     /* -------------------------------------------------------------------- */  | 
84  | 0  |     rndbits = dt.lo & 0x00000007;  | 
85  |  | 
  | 
86  | 0  |     dt.lo = dt.lo >> 3;  | 
87  | 0  |     dt.lo = (dt.lo & 0x1fffffff) | (dt.hi << 29);  | 
88  |  | 
  | 
89  | 0  |     if (rndbits)  | 
90  | 0  |         dt.lo = dt.lo | 0x00000001;  | 
91  |  |  | 
92  |  |     /* -------------------------------------------------------------------- */  | 
93  |  |     /*      Shift the hi-order int over 3 and insert the exponent and sign  */  | 
94  |  |     /* -------------------------------------------------------------------- */  | 
95  | 0  |     dt.hi = dt.hi >> 3;  | 
96  | 0  |     dt.hi = dt.hi & 0x000fffff;  | 
97  | 0  |     dt.hi = dt.hi | (static_cast<GUInt32>(exponent) << 20) | sign;  | 
98  |  | 
  | 
99  | 0  | #ifdef CPL_LSB  | 
100  |  |     /* -------------------------------------------------------------------- */  | 
101  |  |     /*      Change the number to a byte swapped format                      */  | 
102  |  |     /* -------------------------------------------------------------------- */  | 
103  | 0  |     const unsigned char *src = reinterpret_cast<const unsigned char *>(&dt);  | 
104  | 0  |     unsigned char *dest = static_cast<unsigned char *>(dbl);  | 
105  |  | 
  | 
106  | 0  |     memcpy(dest + 0, src + 4, 4);  | 
107  | 0  |     memcpy(dest + 4, src + 0, 4);  | 
108  |  | #else  | 
109  |  |     memcpy(dbl, &dt, 8);  | 
110  |  | #endif  | 
111  | 0  | }  | 
112  |  |  | 
113  |  | /************************************************************************/  | 
114  |  | /*                         CPLIEEEToVaxDouble()                         */  | 
115  |  | /************************************************************************/  | 
116  |  |  | 
117  |  | void CPLIEEEToVaxDouble(void *dbl)  | 
118  |  |  | 
119  | 0  | { | 
120  | 0  |     double64_t dt;  | 
121  |  | 
  | 
122  | 0  | #ifdef CPL_LSB  | 
123  | 0  |     { | 
124  | 0  |         const GByte *src = static_cast<const GByte *>(dbl);  | 
125  | 0  |         GByte dest[8];  | 
126  |  | 
  | 
127  | 0  |         dest[0] = src[4];  | 
128  | 0  |         dest[1] = src[5];  | 
129  | 0  |         dest[2] = src[6];  | 
130  | 0  |         dest[3] = src[7];  | 
131  | 0  |         dest[4] = src[0];  | 
132  | 0  |         dest[5] = src[1];  | 
133  | 0  |         dest[6] = src[2];  | 
134  | 0  |         dest[7] = src[3];  | 
135  | 0  |         memcpy(&dt, dest, 8);  | 
136  | 0  |     }  | 
137  |  | #else  | 
138  |  |     memcpy(&dt, dbl, 8);  | 
139  |  | #endif  | 
140  |  | 
  | 
141  | 0  |     GInt32 sign = dt.hi & 0x80000000;  | 
142  | 0  |     GInt32 exponent = dt.hi >> 20;  | 
143  | 0  |     exponent = exponent & 0x000007ff;  | 
144  |  |  | 
145  |  |     /* -------------------------------------------------------------------- */  | 
146  |  |     /*      An exponent of zero means a zero value.                         */  | 
147  |  |     /* -------------------------------------------------------------------- */  | 
148  | 0  |     if (exponent)  | 
149  | 0  |         exponent = exponent - 1023 + 129;  | 
150  |  |  | 
151  |  |     /* -------------------------------------------------------------------- */  | 
152  |  |     /*      In the case of overflow, return the largest number we can       */  | 
153  |  |     /* -------------------------------------------------------------------- */  | 
154  | 0  |     if (exponent > 255)  | 
155  | 0  |     { | 
156  | 0  |         GByte dest[8];  | 
157  |  | 
  | 
158  | 0  |         if (sign)  | 
159  | 0  |             dest[1] = 0xff;  | 
160  | 0  |         else  | 
161  | 0  |             dest[1] = 0x7f;  | 
162  |  | 
  | 
163  | 0  |         dest[0] = 0xff;  | 
164  | 0  |         dest[2] = 0xff;  | 
165  | 0  |         dest[3] = 0xff;  | 
166  | 0  |         dest[4] = 0xff;  | 
167  | 0  |         dest[5] = 0xff;  | 
168  | 0  |         dest[6] = 0xff;  | 
169  | 0  |         dest[7] = 0xff;  | 
170  | 0  |         memcpy(dbl, dest, 8);  | 
171  |  | 
  | 
172  | 0  |         return;  | 
173  | 0  |     }  | 
174  |  |  | 
175  |  |     /* -------------------------------------------------------------------- */  | 
176  |  |     /*      In the case of of underflow return zero                         */  | 
177  |  |     /* -------------------------------------------------------------------- */  | 
178  | 0  |     else if ((exponent < 0) || (exponent == 0 && sign == 0))  | 
179  | 0  |     { | 
180  | 0  |         memset(dbl, 0, 8);  | 
181  |  | 
  | 
182  | 0  |         return;  | 
183  | 0  |     }  | 
184  | 0  |     else  | 
185  | 0  |     { | 
186  |  |         /* --------------------------------------------------------------------  | 
187  |  |          */  | 
188  |  |         /*          Shift the fraction 3 bits left and set the exponent and  | 
189  |  |          * sign*/  | 
190  |  |         /* --------------------------------------------------------------------  | 
191  |  |          */  | 
192  | 0  |         dt.hi = dt.hi << 3;  | 
193  | 0  |         dt.hi = dt.hi | (dt.lo >> 29);  | 
194  | 0  |         dt.hi = dt.hi & 0x007fffff;  | 
195  | 0  |         dt.hi = dt.hi | (exponent << 23) | sign;  | 
196  |  | 
  | 
197  | 0  |         dt.lo = dt.lo << 3;  | 
198  | 0  |     }  | 
199  |  |  | 
200  |  |     /* -------------------------------------------------------------------- */  | 
201  |  |     /*      Convert the double back to VAX format                           */  | 
202  |  |     /* -------------------------------------------------------------------- */  | 
203  | 0  |     const GByte *src = reinterpret_cast<GByte *>(&dt);  | 
204  |  | 
  | 
205  | 0  | #ifdef CPL_LSB  | 
206  | 0  |     GByte *dest = static_cast<GByte *>(dbl);  | 
207  | 0  |     memcpy(dest + 2, src + 0, 2);  | 
208  | 0  |     memcpy(dest + 0, src + 2, 2);  | 
209  | 0  |     memcpy(dest + 6, src + 4, 2);  | 
210  | 0  |     memcpy(dest + 4, src + 6, 2);  | 
211  |  | #else  | 
212  |  |     GByte dest[8];  | 
213  |  |     dest[1] = src[0];  | 
214  |  |     dest[0] = src[1];  | 
215  |  |     dest[3] = src[2];  | 
216  |  |     dest[2] = src[3];  | 
217  |  |     dest[5] = src[4];  | 
218  |  |     dest[4] = src[5];  | 
219  |  |     dest[7] = src[6];  | 
220  |  |     dest[6] = src[7];  | 
221  |  |     memcpy(dbl, dest, 8);  | 
222  |  | #endif  | 
223  | 0  | }  | 
224  |  |  | 
225  |  | //////////////////////////////////////////////////////////////////////////  | 
226  |  | /// Below code is adapted from Public Domain VICAR project  | 
227  |  | /// https://github.com/nasa/VICAR/blob/master/vos/rtl/source/conv_vax_ieee_r.c  | 
228  |  | //////////////////////////////////////////////////////////////////////////  | 
229  |  |  | 
230  |  | static void real_byte_swap(const unsigned char from[4], unsigned char to[4])  | 
231  | 0  | { | 
232  | 0  |     to[0] = from[1];  | 
233  | 0  |     to[1] = from[0];  | 
234  | 0  |     to[2] = from[3];  | 
235  | 0  |     to[3] = from[2];  | 
236  | 0  | }  | 
237  |  |  | 
238  |  | /* Shift x[1]..x[3] right one bit by bytes, don't bother with x[0] */  | 
239  |  | #define SHIFT_RIGHT(x)                                                         \  | 
240  | 0  |     {                                                                          \ | 
241  | 0  |         x[3] = ((x[3] >> 1) & 0x7F) | ((x[2] << 7) & 0x80);                    \  | 
242  | 0  |         x[2] = ((x[2] >> 1) & 0x7F) | ((x[1] << 7) & 0x80);                    \  | 
243  | 0  |         x[1] = (x[1] >> 1) & 0x7F;                                             \  | 
244  | 0  |     }  | 
245  |  |  | 
246  |  | /* Shift x[1]..x[3] left one bit by bytes, don't bother with x[0] */  | 
247  |  | #define SHIFT_LEFT(x)                                                          \  | 
248  | 0  |     {                                                                          \ | 
249  | 0  |         x[1] = ((x[1] << 1) & 0xFE) | ((x[2] >> 7) & 0x01);                    \  | 
250  | 0  |         x[2] = ((x[2] << 1) & 0xFE) | ((x[3] >> 7) & 0x01);                    \  | 
251  | 0  |         x[3] = (x[3] << 1) & 0xFE;                                             \  | 
252  | 0  |     }  | 
253  |  |  | 
254  |  | /************************************************************************/  | 
255  |  | /* Convert between IEEE and Vax single-precision floating point.        */  | 
256  |  | /* Both formats are represented as:                                     */  | 
257  |  | /* (-1)^s * f * 2^(e-bias)                                              */  | 
258  |  | /* where s is the sign bit, f is the mantissa (see below), e is the     */  | 
259  |  | /* exponent, and bias is the exponent bias (see below).                 */  | 
260  |  | /* There is an assumed leading 1 on the mantissa (except for IEEE       */  | 
261  |  | /* denormalized numbers), but the placement of the binary point varies. */  | 
262  |  | /*                                                                      */  | 
263  |  | /* IEEE format:    seeeeeee efffffff 8*f 8*f                            */  | 
264  |  | /*        where e is exponent with bias of 127 and f is of the          */  | 
265  |  | /*        form 1.fffff...                                               */  | 
266  |  | /* Special cases:                                                       */  | 
267  |  | /*    e=255, f!=0:        NaN (Not a Number)                            */  | 
268  |  | /*    e=255, f=0:        Infinity (+/- depending on s)                  */  | 
269  |  | /*    e=0, f!=0:        Denormalized numbers, of the form               */  | 
270  |  | /*                (-1)^s * (0.ffff) * 2^(-126)                          */  | 
271  |  | /*    e=0, f=0:        Zero (can be +/-)                                */  | 
272  |  | /*                                                                      */  | 
273  |  | /* VAX format:    seeeeeee efffffff 8*f 8*f                             */  | 
274  |  | /*        where e is exponent with bias of 128 and f is of the          */  | 
275  |  | /*        form .1fffff...                                               */  | 
276  |  | /* Byte swapping: Note that the above format is the logical format,     */  | 
277  |  | /*        which can be represented as bytes SE1 E2F1 F2 F3.             */  | 
278  |  | /*        The actual order in memory is E2F1 SE1 F3 F2 (which is        */  | 
279  |  | /*        two half-word swaps, NOT a full-word swap).                   */  | 
280  |  | /* Special cases:                                                       */  | 
281  |  | /*    e=0, s=0:        Zero (no +/-)                                    */  | 
282  |  | /*    e=0, s=1:        Invalid, causes Reserved Operand error           */  | 
283  |  | /*                                                                      */  | 
284  |  | /* The same code works on all byte-order machines because only byte     */  | 
285  |  | /* operations are performed.  It could perhaps be done more efficiently */  | 
286  |  | /* on a longword basis, but then the code would be byte-order dependent.*/  | 
287  |  | /* MAKE SURE any mods will work on either byte order!!!                 */  | 
288  |  | /************************************************************************/  | 
289  |  |  | 
290  |  | /************************************************************************/  | 
291  |  | /* This routine will convert VAX F floating point values to IEEE        */  | 
292  |  | /* single precision floating point.                                     */  | 
293  |  | /************************************************************************/  | 
294  |  |  | 
295  |  | static void vax_ieee_r(const unsigned char *from, unsigned char *ieee)  | 
296  | 0  | { | 
297  | 0  |     unsigned char vaxf[4];  | 
298  | 0  |     unsigned char exp;  | 
299  |  | 
  | 
300  | 0  |     real_byte_swap(from, vaxf); /* Put bytes in rational order */  | 
301  | 0  |     memcpy(ieee, vaxf, 4);      /* Since most bits are the same */  | 
302  |  | 
  | 
303  | 0  |     exp = ((vaxf[0] << 1) & 0xFE) | ((vaxf[1] >> 7) & 0x01);  | 
304  |  | 
  | 
305  | 0  |     if (exp == 0)  | 
306  | 0  |     { /* Zero or invalid pattern */ | 
307  | 0  |         if (vaxf[0] & 0x80)  | 
308  | 0  |         {                   /* Sign bit set, which is illegal for VAX */ | 
309  | 0  |             ieee[0] = 0x7F; /* IEEE NaN */  | 
310  | 0  |             ieee[1] = 0xFF;  | 
311  | 0  |             ieee[2] = 0xFF;  | 
312  | 0  |             ieee[3] = 0xFF;  | 
313  | 0  |         }  | 
314  | 0  |         else  | 
315  | 0  |         { /* Zero */ | 
316  | 0  |             ieee[0] = ieee[1] = ieee[2] = ieee[3] = 0;  | 
317  | 0  |         }  | 
318  | 0  |     }  | 
319  |  |  | 
320  | 0  |     else if (exp >= 3)  | 
321  | 0  |     { /* Normal case */ | 
322  | 0  |         exp -= 2;  | 
323  | 0  |         ieee[0] =  | 
324  | 0  |             (vaxf[0] & 0x80) | ((exp >> 1) & 0x7F); /* remake sign + exponent */  | 
325  | 0  |     } /* Low bit of exp can't change, so don't bother w/it */  | 
326  |  |  | 
327  | 0  |     else if (exp == 2)  | 
328  | 0  |     {                                      /* Denormalize the number */ | 
329  | 0  |         SHIFT_RIGHT(ieee);                 /* Which means shift right 1, */  | 
330  | 0  |         ieee[1] = (ieee[1] & 0x3F) | 0x40; /* Add suppressed most signif bit, */  | 
331  | 0  |         ieee[0] = vaxf[0] & 0x80; /* and set exponent to 0 (preserving sign) */  | 
332  | 0  |     }  | 
333  |  |  | 
334  | 0  |     else  | 
335  | 0  |     {                      /* Exp==1, denormalize again */ | 
336  | 0  |         SHIFT_RIGHT(ieee); /* Like above but shift by 2 */  | 
337  | 0  |         SHIFT_RIGHT(ieee);  | 
338  | 0  |         ieee[1] = (ieee[1] & 0x1F) | 0x20;  | 
339  | 0  |         ieee[0] = vaxf[0] & 0x80;  | 
340  | 0  |     }  | 
341  |  | 
  | 
342  | 0  | #ifdef CPL_LSB  | 
343  | 0  |     CPL_SWAP32PTR(ieee);  | 
344  | 0  | #endif  | 
345  | 0  | }  | 
346  |  |  | 
347  |  | /************************************************************************/  | 
348  |  | /* This routine will convert IEEE single precision floating point       */  | 
349  |  | /* values to VAX F floating point.                                      */  | 
350  |  | /************************************************************************/  | 
351  |  |  | 
352  |  | static void ieee_vax_r(unsigned char *ieee, unsigned char *to)  | 
353  | 0  | { | 
354  | 0  |     unsigned char vaxf[4];  | 
355  | 0  |     unsigned char exp;  | 
356  |  | 
  | 
357  | 0  | #ifdef CPL_LSB  | 
358  | 0  |     CPL_SWAP32PTR(ieee);  | 
359  | 0  | #endif  | 
360  |  | 
  | 
361  | 0  |     memcpy(vaxf, ieee, 4); /* Since most bits are the same */  | 
362  |  | 
  | 
363  | 0  |     exp = ((ieee[0] << 1) & 0xFE) | ((ieee[1] >> 7) & 0x01);  | 
364  |  |  | 
365  |  |     /* Exponent 255 means NaN or Infinity, exponent 254 is too large for */  | 
366  |  |     /* VAX notation.  In either case, set to sign * highest possible number */  | 
367  |  | 
  | 
368  | 0  |     if (exp == 255 || exp == 254)  | 
369  | 0  |     { /* Infinity or NaN or too big */ | 
370  | 0  |         vaxf[0] = 0x7F | (ieee[0] & 0x80);  | 
371  | 0  |         vaxf[1] = 0xFF;  | 
372  | 0  |         vaxf[2] = 0xFF;  | 
373  | 0  |         vaxf[3] = 0xFF;  | 
374  | 0  |     }  | 
375  |  |  | 
376  | 0  |     else if (exp != 0)  | 
377  | 0  |     { /* Normal case */ | 
378  | 0  |         exp += 2;  | 
379  | 0  |         vaxf[0] =  | 
380  | 0  |             (ieee[0] & 0x80) | ((exp >> 1) & 0x7F); /* remake sign + exponent */  | 
381  | 0  |     } /* Low bit of exp can't change, so don't bother w/it */  | 
382  |  |  | 
383  | 0  |     else  | 
384  | 0  |     { /* exp == 0, zero or denormalized number */ | 
385  | 0  |         if (ieee[1] == 0 && ieee[2] == 0 && ieee[3] == 0)  | 
386  | 0  |         { /* +/- 0 */ | 
387  | 0  |             vaxf[0] = vaxf[1] = vaxf[2] = vaxf[3] = 0;  | 
388  | 0  |         }  | 
389  | 0  |         else  | 
390  | 0  |         { /* denormalized number */ | 
391  | 0  |             if (ieee[1] & 0x40)  | 
392  | 0  |             {                                      /* hi bit set (0.1ffff) */ | 
393  | 0  |                 SHIFT_LEFT(vaxf);                  /* Renormalize */  | 
394  | 0  |                 vaxf[1] = vaxf[1] & 0x7F;          /* Set vax exponent to 2 */  | 
395  | 0  |                 vaxf[0] = (ieee[0] & 0x80) | 0x01; /* sign, exponent==2 */  | 
396  | 0  |             }  | 
397  | 0  |             else if (ieee[1] & 0x20)  | 
398  | 0  |             {                     /* next bit set (0.01ffff) */ | 
399  | 0  |                 SHIFT_LEFT(vaxf); /* Renormalize */  | 
400  | 0  |                 SHIFT_LEFT(vaxf);  | 
401  | 0  |                 vaxf[1] = vaxf[1] | 0x80; /* Set vax exponent to 1 */  | 
402  | 0  |                 vaxf[0] = ieee[0] & 0x80; /* sign, exponent==1 */  | 
403  | 0  |             }  | 
404  | 0  |             else  | 
405  | 0  |             { /* Number too small for VAX */ | 
406  | 0  |                 vaxf[0] = vaxf[1] = vaxf[2] = vaxf[3] = 0; /* so set to 0 */  | 
407  | 0  |             }  | 
408  | 0  |         }  | 
409  | 0  |     }  | 
410  |  | 
  | 
411  | 0  |     real_byte_swap(vaxf, to); /* Put bytes in weird VAX order */  | 
412  | 0  | }  | 
413  |  |  | 
414  |  | void CPLVaxToIEEEFloat(void *f)  | 
415  | 0  | { | 
416  | 0  |     unsigned char res[4];  | 
417  | 0  |     vax_ieee_r(static_cast<const unsigned char *>(f), res);  | 
418  | 0  |     memcpy(f, res, 4);  | 
419  | 0  | }  | 
420  |  |  | 
421  |  | void CPLIEEEToVaxFloat(void *f)  | 
422  | 0  | { | 
423  | 0  |     unsigned char res[4];  | 
424  | 0  |     ieee_vax_r(static_cast<unsigned char *>(f), res);  | 
425  | 0  |     memcpy(f, res, 4);  | 
426  | 0  | }  |