LCOV - code coverage report
Current view: top level - port - cpl_vax.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 94 137 68.6 %
Date: 2024-11-21 22:18:42 Functions: 7 7 100.0 %

          Line data    Source code
       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       12688 : void CPLVaxToIEEEDouble(void *dbl)
      32             : 
      33             : {
      34             :     double64_t dt;
      35             :     GUInt32 sign;
      36             :     int exponent;
      37             :     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             :     {
      44       12688 :         const unsigned char *src = static_cast<const unsigned char *>(dbl);
      45             :         unsigned char dest[8];
      46             : #ifdef CPL_LSB
      47       12688 :         dest[2] = src[0];
      48       12688 :         dest[3] = src[1];
      49       12688 :         dest[0] = src[2];
      50       12688 :         dest[1] = src[3];
      51       12688 :         dest[6] = src[4];
      52       12688 :         dest[7] = src[5];
      53       12688 :         dest[4] = src[6];
      54       12688 :         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       12688 :         memcpy(&dt, dest, 8);
      66             :     }
      67             : 
      68             :     /* -------------------------------------------------------------------- */
      69             :     /*      Save the sign of the double                                     */
      70             :     /* -------------------------------------------------------------------- */
      71       12688 :     sign = dt.hi & 0x80000000;
      72             : 
      73             :     /* -------------------------------------------------------------------- */
      74             :     /*      Adjust the exponent so that we may work with it                 */
      75             :     /* -------------------------------------------------------------------- */
      76       12688 :     exponent = (dt.hi >> 23) & 0x000000ff;
      77             : 
      78       12688 :     if (exponent)
      79        4082 :         exponent = exponent - 129 + 1023;
      80             : 
      81             :     /* -------------------------------------------------------------------- */
      82             :     /*      Save the bits that we are discarding so we can round properly   */
      83             :     /* -------------------------------------------------------------------- */
      84       12688 :     rndbits = dt.lo & 0x00000007;
      85             : 
      86       12688 :     dt.lo = dt.lo >> 3;
      87       12688 :     dt.lo = (dt.lo & 0x1fffffff) | (dt.hi << 29);
      88             : 
      89       12688 :     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       12688 :     dt.hi = dt.hi >> 3;
      96       12688 :     dt.hi = dt.hi & 0x000fffff;
      97       12688 :     dt.hi = dt.hi | (static_cast<GUInt32>(exponent) << 20) | sign;
      98             : 
      99             : #ifdef CPL_LSB
     100             :     /* -------------------------------------------------------------------- */
     101             :     /*      Change the number to a byte swapped format                      */
     102             :     /* -------------------------------------------------------------------- */
     103       12688 :     const unsigned char *src = reinterpret_cast<const unsigned char *>(&dt);
     104       12688 :     unsigned char *dest = static_cast<unsigned char *>(dbl);
     105             : 
     106       12688 :     memcpy(dest + 0, src + 4, 4);
     107       12688 :     memcpy(dest + 4, src + 0, 4);
     108             : #else
     109             :     memcpy(dbl, &dt, 8);
     110             : #endif
     111       12688 : }
     112             : 
     113             : /************************************************************************/
     114             : /*                         CPLIEEEToVaxDouble()                         */
     115             : /************************************************************************/
     116             : 
     117         114 : void CPLIEEEToVaxDouble(void *dbl)
     118             : 
     119             : {
     120             :     double64_t dt;
     121             : 
     122             : #ifdef CPL_LSB
     123             :     {
     124         114 :         const GByte *src = static_cast<const GByte *>(dbl);
     125             :         GByte dest[8];
     126             : 
     127         114 :         dest[0] = src[4];
     128         114 :         dest[1] = src[5];
     129         114 :         dest[2] = src[6];
     130         114 :         dest[3] = src[7];
     131         114 :         dest[4] = src[0];
     132         114 :         dest[5] = src[1];
     133         114 :         dest[6] = src[2];
     134         114 :         dest[7] = src[3];
     135         114 :         memcpy(&dt, dest, 8);
     136             :     }
     137             : #else
     138             :     memcpy(&dt, dbl, 8);
     139             : #endif
     140             : 
     141         114 :     GInt32 sign = dt.hi & 0x80000000;
     142         114 :     GInt32 exponent = dt.hi >> 20;
     143         114 :     exponent = exponent & 0x000007ff;
     144             : 
     145             :     /* -------------------------------------------------------------------- */
     146             :     /*      An exponent of zero means a zero value.                         */
     147             :     /* -------------------------------------------------------------------- */
     148         114 :     if (exponent)
     149         113 :         exponent = exponent - 1023 + 129;
     150             : 
     151             :     /* -------------------------------------------------------------------- */
     152             :     /*      In the case of overflow, return the largest number we can       */
     153             :     /* -------------------------------------------------------------------- */
     154         114 :     if (exponent > 255)
     155             :     {
     156             :         GByte dest[8];
     157             : 
     158           0 :         if (sign)
     159           0 :             dest[1] = 0xff;
     160             :         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             :     }
     174             : 
     175             :     /* -------------------------------------------------------------------- */
     176             :     /*      In the case of of underflow return zero                         */
     177             :     /* -------------------------------------------------------------------- */
     178         114 :     else if ((exponent < 0) || (exponent == 0 && sign == 0))
     179             :     {
     180           1 :         memset(dbl, 0, 8);
     181             : 
     182           1 :         return;
     183             :     }
     184             :     else
     185             :     {
     186             :         /* --------------------------------------------------------------------
     187             :          */
     188             :         /*          Shift the fraction 3 bits left and set the exponent and
     189             :          * sign*/
     190             :         /* --------------------------------------------------------------------
     191             :          */
     192         113 :         dt.hi = dt.hi << 3;
     193         113 :         dt.hi = dt.hi | (dt.lo >> 29);
     194         113 :         dt.hi = dt.hi & 0x007fffff;
     195         113 :         dt.hi = dt.hi | (exponent << 23) | sign;
     196             : 
     197         113 :         dt.lo = dt.lo << 3;
     198             :     }
     199             : 
     200             :     /* -------------------------------------------------------------------- */
     201             :     /*      Convert the double back to VAX format                           */
     202             :     /* -------------------------------------------------------------------- */
     203         113 :     const GByte *src = reinterpret_cast<GByte *>(&dt);
     204             : 
     205             : #ifdef CPL_LSB
     206         113 :     GByte *dest = static_cast<GByte *>(dbl);
     207         113 :     memcpy(dest + 2, src + 0, 2);
     208         113 :     memcpy(dest + 0, src + 2, 2);
     209         113 :     memcpy(dest + 6, src + 4, 2);
     210         113 :     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             : }
     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         192 : static void real_byte_swap(const unsigned char from[4], unsigned char to[4])
     231             : {
     232         192 :     to[0] = from[1];
     233         192 :     to[1] = from[0];
     234         192 :     to[2] = from[3];
     235         192 :     to[3] = from[2];
     236         192 : }
     237             : 
     238             : /* Shift x[1]..x[3] right one bit by bytes, don't bother with x[0] */
     239             : #define SHIFT_RIGHT(x)                                                         \
     240             :     {                                                                          \
     241             :         x[3] = ((x[3] >> 1) & 0x7F) | ((x[2] << 7) & 0x80);                    \
     242             :         x[2] = ((x[2] >> 1) & 0x7F) | ((x[1] << 7) & 0x80);                    \
     243             :         x[1] = (x[1] >> 1) & 0x7F;                                             \
     244             :     }
     245             : 
     246             : /* Shift x[1]..x[3] left one bit by bytes, don't bother with x[0] */
     247             : #define SHIFT_LEFT(x)                                                          \
     248             :     {                                                                          \
     249             :         x[1] = ((x[1] << 1) & 0xFE) | ((x[2] >> 7) & 0x01);                    \
     250             :         x[2] = ((x[2] << 1) & 0xFE) | ((x[3] >> 7) & 0x01);                    \
     251             :         x[3] = (x[3] << 1) & 0xFE;                                             \
     252             :     }
     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         156 : static void vax_ieee_r(const unsigned char *from, unsigned char *ieee)
     296             : {
     297             :     unsigned char vaxf[4];
     298             :     unsigned char exp;
     299             : 
     300         156 :     real_byte_swap(from, vaxf); /* Put bytes in rational order */
     301         156 :     memcpy(ieee, vaxf, 4);      /* Since most bits are the same */
     302             : 
     303         156 :     exp = ((vaxf[0] << 1) & 0xFE) | ((vaxf[1] >> 7) & 0x01);
     304             : 
     305         156 :     if (exp == 0)
     306             :     { /* Zero or invalid pattern */
     307           0 :         if (vaxf[0] & 0x80)
     308             :         {                   /* 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             :         }
     314             :         else
     315             :         { /* Zero */
     316           0 :             ieee[0] = ieee[1] = ieee[2] = ieee[3] = 0;
     317             :         }
     318             :     }
     319             : 
     320         156 :     else if (exp >= 3)
     321             :     { /* Normal case */
     322         156 :         exp -= 2;
     323         156 :         ieee[0] =
     324         156 :             (vaxf[0] & 0x80) | ((exp >> 1) & 0x7F); /* remake sign + exponent */
     325             :     } /* Low bit of exp can't change, so don't bother w/it */
     326             : 
     327           0 :     else if (exp == 2)
     328             :     {                                      /* 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             :     }
     333             : 
     334             :     else
     335             :     {                      /* 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             :     }
     341             : 
     342             : #ifdef CPL_LSB
     343         156 :     CPL_SWAP32PTR(ieee);
     344             : #endif
     345         156 : }
     346             : 
     347             : /************************************************************************/
     348             : /* This routine will convert IEEE single precision floating point       */
     349             : /* values to VAX F floating point.                                      */
     350             : /************************************************************************/
     351             : 
     352          36 : static void ieee_vax_r(unsigned char *ieee, unsigned char *to)
     353             : {
     354             :     unsigned char vaxf[4];
     355             :     unsigned char exp;
     356             : 
     357             : #ifdef CPL_LSB
     358          36 :     CPL_SWAP32PTR(ieee);
     359             : #endif
     360             : 
     361          36 :     memcpy(vaxf, ieee, 4); /* Since most bits are the same */
     362             : 
     363          36 :     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          36 :     if (exp == 255 || exp == 254)
     369             :     { /* 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             :     }
     375             : 
     376          36 :     else if (exp != 0)
     377             :     { /* Normal case */
     378          36 :         exp += 2;
     379          36 :         vaxf[0] =
     380          36 :             (ieee[0] & 0x80) | ((exp >> 1) & 0x7F); /* remake sign + exponent */
     381             :     } /* Low bit of exp can't change, so don't bother w/it */
     382             : 
     383             :     else
     384             :     { /* exp == 0, zero or denormalized number */
     385           0 :         if (ieee[1] == 0 && ieee[2] == 0 && ieee[3] == 0)
     386             :         { /* +/- 0 */
     387           0 :             vaxf[0] = vaxf[1] = vaxf[2] = vaxf[3] = 0;
     388             :         }
     389             :         else
     390             :         { /* denormalized number */
     391           0 :             if (ieee[1] & 0x40)
     392             :             {                                      /* 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             :             }
     397           0 :             else if (ieee[1] & 0x20)
     398             :             {                     /* 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             :             }
     404             :             else
     405             :             { /* Number too small for VAX */
     406           0 :                 vaxf[0] = vaxf[1] = vaxf[2] = vaxf[3] = 0; /* so set to 0 */
     407             :             }
     408             :         }
     409             :     }
     410             : 
     411          36 :     real_byte_swap(vaxf, to); /* Put bytes in weird VAX order */
     412          36 : }
     413             : 
     414         156 : void CPLVaxToIEEEFloat(void *f)
     415             : {
     416             :     unsigned char res[4];
     417         156 :     vax_ieee_r(static_cast<const unsigned char *>(f), res);
     418         156 :     memcpy(f, res, 4);
     419         156 : }
     420             : 
     421          36 : void CPLIEEEToVaxFloat(void *f)
     422             : {
     423             :     unsigned char res[4];
     424          36 :     ieee_vax_r(static_cast<unsigned char *>(f), res);
     425          36 :     memcpy(f, res, 4);
     426          36 : }

Generated by: LCOV version 1.14