The R Project SVN R

Rev

Rev 44218 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

/*******************************************************************************
 *  BDX: Binary Data eXchange format library
 *  Copyright (C) 1999-2006 Thomas Baier
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 * 
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 * 
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, a copy is available at
 *  http://www.r-project.org/Licenses/
 *
 *  Conversion functions from SEXP to BDX and vice versa.
 *
 ******************************************************************************/

#ifndef  _BDX_SEXP_H_
#include "bdx_SEXP.h"
#endif

#include "bdx.h"
#include "bdx_util.h"
#include "Rinternals.h"
/*#include "rproxy_impl.h" */
#include "com_util.h"
#include <stdio.h>
#include <assert.h>

/*
 * prototypes for internal helper functions
 */
static int EXTPTRSXP2LPSTREAM(RCOM_OBJHANDLE pHandle,
                  LPSTREAM* pStream);
#define getSpecialValueFromLogical(x) getSpecialValueFromInteger((x))
static unsigned long getSpecialValueFromInteger(int pSEXPVal);
static unsigned long getSpecialValueFromDouble(double pSEXPVal);
static double getDoubleFromSpecialValue(unsigned long pSpecialValue);

#define BDX_DM_DEFAULT    0UL
#define BDX_DM_UNDEFINED  ((unsigned long) -1)
#define BDX_DM_NO_SPECIAL 1UL

static unsigned long s_data_mode = BDX_DM_UNDEFINED;

/* ==========================================================================
   Implementation
   ========================================================================== */
/* 05-05-19 | baier | handle BDX_GENERIC */
int BDX2SEXP(BDX_Data const* pBDXData,SEXP* pSEXPData)
{
  SEXP lData = NULL;
  SEXP lDimensions = NULL;
  int lTotalSize = 1;
  int lProtectCount = 0;
  int i;

  assert(pSEXPData != NULL);

  switch(pBDXData->type & BDX_CMASK) {
  case BDX_SCALAR:
    /* no DIM attribute */
    break;
  case BDX_ARRAY:
    /* create DIM attribute */
    PROTECT(lDimensions = allocVector(INTSXP,pBDXData->dim_count));
    lProtectCount++;
    for (i = 0;i < pBDXData->dim_count;i++) {
      INTEGER (lDimensions)[i] = pBDXData->dimensions[i];
      lTotalSize *= pBDXData->dimensions[i];
    }
    break;
  default:
    /* unknown/unsupported type */
    UNPROTECT(lProtectCount);
    return -1;
  }

  /* now allocate the SEXP and copy the data */
  switch(pBDXData->type & BDX_SMASK) {
  case BDX_BOOL:
    lData = PROTECT(allocVector(LGLSXP,lTotalSize));
    lProtectCount++;
    for(i = 0;i < lTotalSize;i++) {
      LOGICAL(lData)[i] = pBDXData->data.raw_data[i].bool_value;
    }
    break;
  case BDX_INT:
    lData = PROTECT(allocVector(INTSXP,lTotalSize));
    lProtectCount++;
    for(i = 0;i < lTotalSize;i++) {
      INTEGER(lData)[i] = pBDXData->data.raw_data[i].int_value;
    }
    break;
  case BDX_DOUBLE:
    lData = PROTECT(allocVector(REALSXP,lTotalSize));
    lProtectCount++;
    for(i = 0;i < lTotalSize;i++) {
      REAL(lData)[i] = pBDXData->data.raw_data[i].double_value;
    }
    break;
  case BDX_STRING:
    lData = PROTECT(allocVector(STRSXP,lTotalSize));
    lProtectCount++;
    for(i = 0;i < lTotalSize;i++)
      SET_STRING_ELT(lData, i, mkChar(pBDXData->data.raw_data[i].string_value));
    break;
  case BDX_POINTER:
    /* BDX_POINTER not supported now, trace the contents */
    BDX_ERR(printf("BDX_POINTER found, value is %p\n",
           pBDXData->data.raw_data[0].ptr));
    *pSEXPData = NULL;
    UNPROTECT(lProtectCount);
    return -1;
  case BDX_HANDLE:
    /* only single COM object supported (no arrays) */
    if((pBDXData->type & BDX_CMASK) != BDX_SCALAR) {
      BDX_ERR(printf("array of BDX_HANDLE found. Not supported\n"));
      *pSEXPData = NULL;
      UNPROTECT(lProtectCount);
      return -1;
    }

    /* marshalled COM object as an LPSTREAM:
     *
     * 1. unmarshal the object from the stream (IDispatch) using
     *    CoGetInterfaceAndReleaseStream()
     * 2. COM object must be Release()d afterwards
     * 3. Stream still valid. Must be released afterwards
     */
    {
      LPSTREAM lStream = pBDXData->data.raw_data[0].ptr;
      LPDISPATCH lDispatch;
      RCOM_OBJHANDLE lHandle;
#if 1
      HRESULT lRc = CoUnmarshalInterface(lStream,&IID_IDispatch,
                     (void*) &lDispatch);
#else
      HRESULT lRc = CoGetInterfaceAndReleaseStream(lStream,&IID_IDispatch,
                           (void*) &lDispatch);
#endif
      if(FAILED(lRc)) {
    BDX_ERR(printf("unmarshalling stream ptr %p failed with hr=%08x\n",
              lStream,lRc));
    *pSEXPData = NULL;
    UNPROTECT(lProtectCount);
    return -1;
      }

      /* create SEXP for COM object */
      lHandle = com_addObject (lDispatch);
      lData = com_createSEXP(lHandle);
    }
    break;
  case BDX_SPECIAL:
    lData = PROTECT (allocVector (REALSXP,lTotalSize));
    lProtectCount++;
    for(i = 0;i < lTotalSize;i++) {
      REAL(lData)[i] =
    getDoubleFromSpecialValue(pBDXData->data.raw_data[i].special_value);
    }
    break;
  case BDX_GENERIC:
    /* generic array */
    lData = PROTECT(allocVector(VECSXP,lTotalSize));
    lProtectCount++;
    for(i = 0;i < lTotalSize;i++) {
      SEXP lSEXP = NULL;
      /* handle contents */
      switch(pBDXData->data.raw_data_with_type[i].type & BDX_SMASK) {
      case BDX_BOOL:
    lSEXP = allocVector(LGLSXP,1);
    LOGICAL(lSEXP)[0] =
      pBDXData->data.raw_data_with_type[i].raw_data.bool_value;
    break;
      case BDX_INT:
    lSEXP = allocVector(INTSXP,1);
    INTEGER(lSEXP)[0] =
      pBDXData->data.raw_data_with_type[i].raw_data.int_value;
    break;
      case BDX_DOUBLE:
    lSEXP = allocVector(REALSXP,1);
    REAL(lSEXP)[0] =
      pBDXData->data.raw_data_with_type[i].raw_data.double_value;
    break;
      case BDX_STRING:
        lSEXP = mkString(pBDXData->data.raw_data_with_type[i].raw_data.string_value);
    break;
      case BDX_SPECIAL:
    lSEXP = allocVector(REALSXP,1);
    REAL(lSEXP)[0] =
      getDoubleFromSpecialValue(pBDXData->data.raw_data_with_type[i].raw_data.special_value);
    break;
      default:
    lSEXP = allocVector(REALSXP,1);
    REAL(lSEXP)[0] = 
      getDoubleFromSpecialValue(BDX_SV_NULL);
    BDX_ERR(printf("unknown BDX type %d in generic vector element %d, using NA\n",
               pBDXData->data.raw_data_with_type[i].type & BDX_SMASK,
               i));
      }
      SET_VECTOR_ELT(lData,i,lSEXP);
    }
    break;
  default:
    /* unknown/unsupported BDX type */
    *pSEXPData = NULL;
    BDX_ERR(printf("unknown BDX type %08x, (SMASK %08x)\n",
              pBDXData->type,pBDXData->type & BDX_SMASK));
    UNPROTECT(lProtectCount);
    return -1;
  }

  if(lDimensions) {
    setAttrib (lData,R_DimSymbol,lDimensions);
  }

  *pSEXPData = lData;
  UNPROTECT(lProtectCount);

  return 0;
}

/* 05-05-24 | baier | VECSXP */
/* 05-06-05 | baier | support for special values (R_NaN,...), generic vectors */
/* 05-06-08 | baier | BDX_SPECIAL for scalars (REALSXP conversions) */
/* 06-02-15 | baier | fixes for COM objects/EXTPTRSXP */
/* 06-06-18 | baier | special values also for LOGICAL and INTEGER */
int SEXP2BDX(struct SEXPREC const* pSexp,BDX_Data** ppBDXData)
{
  BDX_Data* lData;
  SEXP lDimension;
  int lTotalSize = 1;
  int i;
  int lGeneric = 0;
  SEXP sexp = (SEXP) pSexp; /* to get rid of const/non-const warning */
  double lDoubleValue;
  int lLogicalValue;
  int lIntegerValue;

  assert(ppBDXData != NULL);

  *ppBDXData = 0;
  lData = bdx_alloc();

  /*
   * we support the following types at the moment
   *
   *  integer (scalar, vectors and arrays)
   *  real (scalars, vectors and arrays)
   *  logical (scalars, vectors and arrays)
   *  string (scalars, vectors and arrays)
   *  COM objects (IDispatch)
   *  null
   *
   * we should support soon
   *
   *  complex vectors
   *  generic vectors
   * bug: no dimensions stored
   */

  /*
   * zero-length SEXP: this is an error!
   */
  if (LENGTH(sexp) == 0) {
    /* empty/undefined symbol */
    BDX_ERR(printf("SEXP2BDX: SEXP has length 0\n"));
    bdx_free(lData);
    return -6;
  }

  /*
   * find out if the data type is supported
   */
  switch(TYPEOF(sexp)) {
  case NILSXP:
    lData->type |= BDX_SPECIAL;
    break;
  case LGLSXP:
    lData->type |= BDX_BOOL;
    break;
  case INTSXP:
    lData->type |= BDX_INT;
    break;
  case REALSXP:
    lData->type |= BDX_DOUBLE;
    break;
  case EXTPTRSXP:
    lData->type |= BDX_HANDLE;
    break;
  case STRSXP:
    lData->type |= BDX_STRING;
    break;
  case VECSXP:
    /* generic vectors */
    lData->type |= BDX_GENERIC;
    lGeneric = 1;
    break;
  default:
    bdx_free(lData);
    BDX_TRACE(printf("SEXP2BDX: unsupported SEXP type %d\n",
              TYPEOF(sexp)));
    return -6;
  }

  /*
   * vector/matrix/scalar
   */
  lDimension = getAttrib (sexp,R_DimSymbol);
  PROTECT (lDimension);

  /* get dimension infos, allocate BDX_Dimension[] array */
  if(TYPEOF(lDimension) == INTSXP) {
    /* DIM atribute -> matrix */
    lData->type |= BDX_ARRAY;
    lData->dim_count = LENGTH(lDimension);
    lData->dimensions = (BDX_Dimension*) calloc(lData->dim_count,
                        sizeof(BDX_Dimension));
    for (i = 0;i < lData->dim_count;i++) {
      lData->dimensions[i] = INTEGER(lDimension)[i];
      lTotalSize *= lData->dimensions[i];
    }
    /* lData->data.raw_data = (BDX_RawData*) malloc(sizeof(BDX_RawData)); */
  } else if((LENGTH(sexp) == 1) 
        || (TYPEOF(sexp) == EXTPTRSXP)){
    /* scalar */
    lData->type |= BDX_SCALAR;
    lData->dim_count = 1;
    lData->dimensions = (BDX_Dimension*) malloc(sizeof(BDX_Dimension));
    lData->dimensions[0] = 1;
  } else if(TYPEOF(lDimension) == NILSXP) {
    /* no DIM atribute -> vector (== one-dimensional array) */
    lData->type |= BDX_ARRAY;
    lData->dim_count = 1;
    lData->dimensions = (BDX_Dimension*) malloc(sizeof(BDX_Dimension));
    lData->dimensions[0] = LENGTH(sexp);
    lTotalSize = lData->dimensions[0];
  }

  UNPROTECT(1); /* unlock lDimension */

  if(!lGeneric) {
    /* allocate memory for the data: BDX_RawData or BDX_RawDataWithType */
    lData->data.raw_data = (BDX_RawData*) calloc(lTotalSize,
                         sizeof(BDX_RawData));

    for(i = 0;(i < lTotalSize) && !lGeneric;i++) {
      switch(TYPEOF(sexp)) {
      case NILSXP:
    lData->data.raw_data[i].special_value = BDX_SV_NULL;
    break;
      case LGLSXP:
    /* check special values: R_NaInt */
    lLogicalValue = LOGICAL(sexp)[i];
    if(getSpecialValueFromLogical(lLogicalValue) != BDX_SV_UNK) {
      lGeneric = 1;
    } else {
      lData->data.raw_data[i].bool_value = lLogicalValue;
    }
    break;
      case INTSXP:
    /* check special values: R_NaInt */
    lIntegerValue = INTEGER(sexp)[i];
    if(getSpecialValueFromInteger(lIntegerValue) != BDX_SV_UNK) {
      lGeneric = 1;
    } else {
      lData->data.raw_data[i].int_value = lIntegerValue;
    }
    break;
      case REALSXP:
    /* check special values: R_NaReal, R_PosInf, R_NaN, R_NegInf */
    lDoubleValue = REAL(sexp)[i];
    if(getSpecialValueFromDouble(lDoubleValue) != BDX_SV_UNK) {
      lGeneric = 1;
    } else {
      lData->data.raw_data[i].double_value = lDoubleValue;
    }
    break;
      case EXTPTRSXP:
    /*
     * according to BDR (mail on r-devel, 05-10-24) an EXTPTRSXP is not
     * a vector, therefore LENGTH() does not work
     */
    lTotalSize = 1; 
#if 0
    /* no EXTPTRSXP for arrays */
    if(lTotalSize != 1) {
      bdx_free(lData);
      BDX_TRACE(printf("SEXP2BDX[1]: EXTPTRSXP in array with %d elements\n",
                  lTotalSize));
      return -7;
    }
#endif
    {
      /* is it a COM object? */
      RCOM_OBJHANDLE lHandle = com_getHandle(sexp);
      LPSTREAM lStream = NULL;
      int lRc = EXTPTRSXP2LPSTREAM(lHandle,&lStream); /* 0 for success */
      
      /* COM object is marshalled into stream
       *
       * 1. stream object holds reference to IDispatch
       * 2. reference count is increased in the meanwhile
       * 3. must use CoGetInterfaceAndReleaseStream() to unmarshal
       * 4. Release() must be called on object afterwards
       */
      if (lRc == 0) {
        /* we don't support generic pointers */
        lData->data.raw_data[0].ptr = lStream;
        lData->type |= BDX_HANDLE;
#if 0
        if(lStream) {
          /* marshalled COM object */
        } else {
          /* pointer */
          lData->type |= BDX_POINTER;
          lData->data.raw_data[0].ptr =
        (unsigned long) R_ExternalPtrAddr(sexp);
        }
#endif
      } else {
        lData->type |= BDX_POINTER;
        lData->data.raw_data[0].ptr = NULL; /* NULL pointer */
        BDX_TRACE(printf("SEXP2BDX: error %d marshalling COM object at index %d\n",
                lRc,i));
        
      }
      BDX_TRACE(printf("SEXP2BDX: base=%08x, type=%08x, ptr=%08x\n",
               lData,lData->type,lData->data.raw_data[0].ptr));
    }
    break;
      case STRSXP:
    lData->data.raw_data[i].string_value = strdup(CHAR(STRING_ELT(sexp,i)));
    if(lData->data.raw_data[i].string_value == NULL) {
      lData->data.raw_data[i].string_value = strdup("");
    }
    
    break;
      }
    }
  }

  /* VECSXP or REALSXP with special values */
  if(lGeneric) {
    if(lData->data.raw_data) {
      /* memory has been allocated */
      free(lData->data.raw_data);
    }
    if((lData->type & BDX_CMASK) == BDX_SCALAR) {
      /* scalar BDX_SPECIAL */
      lData->type = (lData->type & ~BDX_SMASK) | BDX_SPECIAL;
      lData->data.raw_data[0].special_value =
    getSpecialValueFromDouble(REAL(sexp)[0]);
    } else {
      /* BDX_GENERIC */
      lData->type = (lData->type & ~BDX_SMASK) | BDX_GENERIC;
      lData->data.raw_data_with_type =
    (BDX_RawDataWithType*) calloc(lTotalSize,
                      sizeof(BDX_RawDataWithType));
      switch(TYPEOF(sexp)) {
      case LGLSXP:
    for(i = 0;i < lTotalSize;i++) {
      lData->data.raw_data_with_type[i].type = BDX_SPECIAL;
      lData->data.raw_data_with_type[i].raw_data.special_value =
        getSpecialValueFromLogical(LOGICAL(sexp)[i]);
      if(lData->data.raw_data_with_type[i].raw_data.special_value ==
         BDX_SV_UNK) {
        lData->data.raw_data_with_type[i].type = BDX_BOOL;
        lData->data.raw_data_with_type[i].raw_data.double_value =
          LOGICAL(sexp)[i];
      }
    }
    break;
      case INTSXP:
    for(i = 0;i < lTotalSize;i++) {
      lData->data.raw_data_with_type[i].type = BDX_SPECIAL;
      lData->data.raw_data_with_type[i].raw_data.special_value =
        getSpecialValueFromInteger(INTEGER(sexp)[i]);
      if(lData->data.raw_data_with_type[i].raw_data.special_value ==
         BDX_SV_UNK) {
        lData->data.raw_data_with_type[i].type = BDX_INT;
        lData->data.raw_data_with_type[i].raw_data.double_value =
          LOGICAL(sexp)[i];
      }
    }
    break;
      case REALSXP:
    for(i = 0;i < lTotalSize;i++) {
      lData->data.raw_data_with_type[i].type = BDX_SPECIAL;
      lData->data.raw_data_with_type[i].raw_data.special_value =
        getSpecialValueFromDouble(REAL(sexp)[i]);
      if(lData->data.raw_data_with_type[i].raw_data.special_value ==
         BDX_SV_UNK) {
        lData->data.raw_data_with_type[i].type = BDX_DOUBLE;
        lData->data.raw_data_with_type[i].raw_data.double_value =
          REAL(sexp)[i];
      }
    }
    break;
      default:
    for(i = 0;i < lTotalSize;i++) {
      SEXP lElementSexp = VECTOR_ELT(sexp,i);
      switch(TYPEOF(lElementSexp)) {
      case NILSXP:
        lData->data.raw_data_with_type[i].type = BDX_SPECIAL;
        lData->data.raw_data_with_type[i].raw_data.special_value = BDX_SV_NULL;
        break;
      case LGLSXP:
        lData->data.raw_data_with_type[i].type = BDX_SPECIAL;
        lData->data.raw_data_with_type[i].raw_data.special_value =
          getSpecialValueFromLogical(LOGICAL(lElementSexp)[0]);
        if(lData->data.raw_data_with_type[i].raw_data.special_value == BDX_SV_UNK) {
          lData->data.raw_data_with_type[i].type = BDX_BOOL;
          lData->data.raw_data_with_type[i].raw_data.bool_value =
        LOGICAL(lElementSexp)[0];
        }
        break;
      case INTSXP:
        lData->data.raw_data_with_type[i].type = BDX_SPECIAL;
        lData->data.raw_data_with_type[i].raw_data.special_value =
          getSpecialValueFromInteger(INTEGER(lElementSexp)[0]);
        if(lData->data.raw_data_with_type[i].raw_data.special_value == BDX_SV_UNK) {
          lData->data.raw_data_with_type[i].type = BDX_INT;
          lData->data.raw_data_with_type[i].raw_data.int_value =
        INTEGER(lElementSexp)[0];
        }
        break;
      case REALSXP:
        lData->data.raw_data_with_type[i].type = BDX_SPECIAL;
        lData->data.raw_data_with_type[i].raw_data.special_value =
          getSpecialValueFromDouble(REAL(lElementSexp)[0]);
        if(lData->data.raw_data_with_type[i].raw_data.special_value == BDX_SV_UNK) {
          lData->data.raw_data_with_type[i].type = BDX_DOUBLE;
          lData->data.raw_data_with_type[i].raw_data.double_value =
        REAL(lElementSexp)[0];
        }
        break;
      case EXTPTRSXP:
        lData->data.raw_data_with_type[i].type = BDX_HANDLE;
        /*
         * according to BDR (mail on r-devel, 05-10-24) an EXTPTRSXP is not
         * a vector, therefore LENGTH() does not work
         */
        lTotalSize = 1; 
        /* no EXTPTRSXP for arrays */
        {
          /* is it a COM object? */
          RCOM_OBJHANDLE lHandle = com_getHandle(lElementSexp);
          LPSTREAM lStream = NULL;
          int lRc = EXTPTRSXP2LPSTREAM(lHandle,&lStream); /* 0 for success */
          /* COM object is marshalled into stream
           *
           * 1. stream object holds reference to IDispatch
           * 2. reference count is increased in the meanwhile
           * 3. must use CoGetInterfaceAndReleaseStream() to unmarshal
           * 4. Release() must be called on object afterwards
           */
          if (lRc == 0) {
        /* we don't support generic pointers */
        lData->data.raw_data_with_type[i].raw_data.ptr = lStream;
        lData->type |= BDX_HANDLE;
          } else {
        lData->type |= BDX_POINTER;
        lData->data.raw_data_with_type[i].raw_data.ptr =
          NULL; /* NULL pointer */
        BDX_TRACE(printf("SEXP2BDX: error %d marshalling COM object at index %d\n",
                 lRc,i));
          }
        }
        break;
      case STRSXP:
        lData->data.raw_data_with_type[i].type = BDX_STRING;
        lData->data.raw_data_with_type[i].raw_data.string_value =
          strdup(CHAR(STRING_ELT(lElementSexp,0)));
        break;
      default:
        bdx_free(lData);
        BDX_TRACE(printf("SEXP2BDX: unsupported SEXP type %d in VECSXP element %d\n",
                 TYPEOF(lElementSexp),i));
        return -6;
      }
    }
      }
    }
  }
  *ppBDXData = lData;

  return 0;
}

unsigned long bdx_get_datamode(void)
{
  return s_data_mode;
}
void bdx_set_datamode(unsigned long pDM)
{
  BDX_TRACE(printf("BDX: data mode set to %08x\n",pDM));
  s_data_mode = pDM;
}

static int EXTPTRSXP2LPSTREAM(RCOM_OBJHANDLE pHandle,
                  LPSTREAM* pStream)
{
  IUnknown* lUnk = NULL;
  LPSTREAM lStream = NULL;
  HRESULT hr = E_FAIL;

  if (pHandle == RCOM_NULLHANDLE) {
    return -1;
  }

  /* valid COM object */
  lUnk = (LPUNKNOWN) com_getObject(pHandle);

  /*
   * Marshal interface into stream (can be unmarshalled in any thread of
   * the same process. This may slow down things a bit, but we're on the
   * safe side if the BDX_Data is processed in a thread different from
   * the current one.
   */
  hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown,
                         lUnk,
                         &lStream);
  if(FAILED(hr)) {
    BDX_TRACE(printf("SEXP2BDX: error %08x marshalling interface into stream\n",
             hr));
    return -5;
  } else {
    *pStream = lStream;
  }
  return 0;
}

/* 06-06-24 | baier | NaN also transforms to IEEE double NaN for dm=1 */
static unsigned long getSpecialValueFromDouble(double pSEXPVal)
{
  if(ISNA(pSEXPVal)) {
    return BDX_SV_NA;
  } else if(pSEXPVal == R_PosInf) {
    if(bdx_get_datamode() == BDX_DM_NO_SPECIAL) {
      return BDX_SV_UNK;
    }
    return BDX_SV_INF;
  } else if(ISNAN(pSEXPVal)) {
    if(bdx_get_datamode() == BDX_DM_NO_SPECIAL) {
      return BDX_SV_UNK;
    }
    return BDX_SV_NAN;
  } else if(pSEXPVal == R_NegInf) {
    if(bdx_get_datamode() == BDX_DM_NO_SPECIAL) {
      return BDX_SV_UNK;
    }
    return BDX_SV_NINF;
  }
  return BDX_SV_UNK;
}
static unsigned long getSpecialValueFromInteger(int pSEXPVal)
{
  if(pSEXPVal == R_NaInt) {
    return BDX_SV_NA;
  }
  return BDX_SV_UNK;
}
static double getDoubleFromSpecialValue(unsigned long pSpecialValue)
{
  switch(pSpecialValue) {
  case BDX_SV_NULL:
  case BDX_SV_NA:
    /* NULL and NA both transform to NA */
    return R_NaReal;
  case BDX_SV_DIV0:
  case BDX_SV_INF:
    /* DIV/0 and +Inf transform to +Inf */
    return R_PosInf;
  case BDX_SV_NAN:
    /* NAN is just NaN */
    return R_NaN;
  case BDX_SV_NINF:
    /* -Inf is -Inf */
    return R_NegInf;
  case BDX_SV_UNK:
  default:
    return R_NaReal;
  }
}