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

Generated by: LCOV version 1.14