/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright 1993, University Corporation for Atmospheric Research           *
 * See netcdf/COPYRIGHT file for copying and redistribution conditions.      *
 *                                                                           *
 * Copyright by The HDF Group.                                               *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF.  The full HDF copyright notice, including       *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/.  *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*    $Id$ */

#include    <string.h>
#include    "local_nc.h"
#include    "alloc.h"

#ifdef NOT_USED
static int ncvarcpy(int, int, int);
#endif /* NOT_USED */

NC_var *
NC_new_var(name,type,ndims,dims)
const char *name ;
nc_type type ;
int ndims ;
const int *dims ;
{
    NC_var *ret ;

    ret = (NC_var *)HDcalloc(1,sizeof(NC_var)) ;
    if( ret == NULL )
        goto alloc_err ;

    ret->name = NC_new_string((unsigned)strlen(name),name) ;
    if( ret->name == NULL)
        goto alloc_err ;

    ret->assoc = NC_new_iarray((unsigned)ndims, dims) ;
    if( ret->assoc == NULL)
        goto alloc_err ;

    ret->shape = NULL ;
    ret->dsizes = NULL ;
    ret->attrs = NULL ;
    ret->type = type ;
    ret->len = 0 ;
    ret->szof = NC_typelen(type) ;
    ret->begin = 0 ;

#ifdef HDF
        ret->vgid = 0;
        ret->data_ref = 0;
        ret->data_tag = DATA_TAG;  /* Assume normal data unless set   */
        ret->data_offset = 0;      /* Assume data starts at beginning */
        ret->block_size = -1;      /* start off with no block size set */
        ret->numrecs = 0;       /* Only used in unlimited dimension case */
        ret->aid = FAIL;
        ret->ndg_ref = 0;
        ret->var_type = UNKNOWN;   /* Unknown whether this var is an SDS or a coord var */
        ret->HDFtype = hdf_map_type(type);
        ret->HDFsize = DFKNTsize(ret->HDFtype);
        ret->is_ragged = FALSE;
        ret->created = FALSE;      /* This is set in SDcreate() if it's a new SDS */
        ret->set_length = FALSE;   /* This is set in SDwritedata() if the data needs its length set */
#endif

    return(ret) ;
alloc_err :
    nc_serror("NC_new_var") ;
    return(NULL) ;
}


/*
 * Free var
 *
 * NOTE: Changed return value to return 'int'
 *       If successful returns SUCCEED else FAIL -GV 9/19/97
 */
intn
NC_free_var(var)
NC_var *var ;
{
    intn ret_value = SUCCEED;

    if(var != NULL)
      {
          if (NC_free_string(var->name) == FAIL)
            {
                ret_value = FAIL;
                goto done;
            }
          if (NC_free_iarray(var->assoc) == FAIL)
            {
                ret_value = FAIL;
                goto done;
            }
          if(var->shape != NULL)
              Free(var->shape) ;
          if(var->dsizes != NULL)
              Free(var->dsizes) ;

          if (NC_free_array(var->attrs) == FAIL)
            {
                ret_value = FAIL;
                goto done;
            }
          Free(var) ;
      }

done:
    if (ret_value == FAIL)
      { /* Failure cleanup */

      }
     /* Normal cleanup */

    return ret_value;
}


/*
 * 'compile' the shape and len of a variable
 *  return -1 on error
 */
#ifndef HDF
static
#endif
int NC_var_shape(var, dims)
NC_var *var ;
NC_array *dims;
{
    unsigned long *shape, *dsizes ;
    int ii ;
    unsigned long *shp, *dsp, *op ;
    int *ip ;
    NC_dim **dp ;
    size_t xszof ;

#ifdef HDF
    xszof = var->HDFsize ;
#else
    xszof = NC_xtypelen(var->type) ;
#endif

    /* Fixed memory leaks reported in bug# 418. BMR - Apr 8, 01 */

    /*
    * Allocate the shape array
    */
    ii = var->assoc->count ;
    if(ii == 0)
    {
        /* scalar var, len == szof */
        var->len = xszof ;
        goto out ;
    }
    shape = (unsigned long *)HDmalloc(ii * sizeof(unsigned long)) ;
    if(shape == NULL)
    {
        nc_serror("NC_var_shape") ;
        return(-1) ;
    }

    /*
    * use the user supplied dimension indices
    * to determine the shape
    */
    for(ip = var->assoc->values, op = shape
        ; ii > 0 ; ii--)
    {
        if(*ip < 0 || *ip >= ((dims != NULL) ? dims->count : 1) )
        {
            NCadvise(NC_EBADDIM, "Bad dimension id %d", *ip) ;
            Free(shape) ;
            return(-1) ;
        }
        dp = (NC_dim **)dims->values + *ip ;
        *op = (*dp)->size ;
        if(*op == NC_UNLIMITED && ii != var->assoc->count )
        {
            NCadvise(NC_EUNLIMPOS, "NC_UNLIMITED size applied to index other than 0 %d",
                var->assoc->count - ii) ;
            Free(shape) ;
            return(-1) ;
        }
        op++ ; ip++ ;
    }

    /* Free memory if this var already has shape previously allocated */
    if(var->shape != NULL)
            Free(var->shape);
    var->shape = shape ;

    /*
    * Allocate the dsizes array
    */
    ii = var->assoc->count ;
    dsizes = (unsigned long *)HDmalloc(ii * sizeof(unsigned long)) ;
    if(dsizes == NULL)
    {
            Free(shape) ;
            var->shape = NULL;
        nc_serror("NC_var_shape") ;
        return(-1) ;
    }

    /* Free memory if this var already has dsizes previously allocated */
    if(var->dsizes != NULL)
            Free(var->dsizes);
    var->dsizes = dsizes ;

    /*
    * Compute var->len and the dsizes
    */
    shp = shape + var->assoc->count - 1 ; /* count is > 0 here */
    dsp = dsizes + var->assoc->count - 1 ;
    var->len = (*shp) ? (*shp) : 1 ; /* boundary condition for rec */
    var->len = var->len * xszof ;
    if(dsp != NULL) *dsp = xszof ;

    for( shp--, dsp-- ; shp >= shape ; shp--,dsp--)
    {
        *dsp = var->len ;
        if(shp != shape || *shp ) /* include last mult for non-rec vars */
            var->len *= *shp ;
    }

out :
/* don't round-up for HDF-encoded files */
#ifdef HDF
    if (var->cdf->file_type != HDF_FILE)
#endif

    switch(var->type) {
    case NC_BYTE :
    case NC_CHAR :
    case NC_SHORT :
        if( var->len%4 != 0 )
        {
            var->len += 4 - var->len%4 ; /* round up */
    /*        *dsp += 4 - *dsp%4 ; */
        }
    default:
        break;
    }

#if 0
    NCadvise(NC_NOERR, "%s var->len %d, var->szof %d",
        var->name->values, var->len, var->szof) ;
    arrayp("\tshape", var->assoc->count, var->shape) ;
    arrayp("\tdsizes", var->assoc->count, var->dsizes) ;
#endif
    return(var->assoc->count) ;
}


int ncvardef(cdfid, name, type, ndims, dims)
int cdfid ;
const char *name ;
nc_type type ;
int ndims ;
const int dims[] ;
{
    NC *handle ;
    NC_var *var[1] ;
    NC_var **dp ;
    int ii ;
    int len ;

    cdf_routine_name = "ncvardef" ;

    if( !NC_indefine(cdfid,TRUE) )
        return(-1) ;

    handle = NC_check_id(cdfid) ;
    if(handle == NULL)
        return(-1) ;

    if(!NCcktype(type))
        return(-1) ;

    if(ndims < 0) /* 0 => scalar */
      {
          NCadvise(NC_EINVAL, "Number of dimensions %d < 0", ndims) ;
          return(-1) ;
      }

    if(ndims > 0 )
      {
          if(handle->dims == NULL || ndims > handle->dims->count )
            {
                NCadvise(NC_EINVAL, "Invalid number of dimensions %d > %d",
                         ndims, (handle->dims != NULL) ? handle->dims->count : 0) ;
                return(-1) ;
            }
      }

    if(handle->vars == NULL) /* first time */
      {
          var[0] = NC_new_var(name,type,ndims,dims) ;
          if(var[0] == NULL)
              return(-1) ;
          handle->vars = NC_new_array(NC_VARIABLE,(unsigned)1,
                                      (Void *)var) ;
          if(handle->vars == NULL)
              return(-1) ;
      } else if(handle->vars->count >= H4_MAX_NC_VARS)
        {
            NCadvise(NC_EMAXVARS, "maximum number of variables %d exceeded",
                     handle->vars->count ) ;
            return(-1) ;
        } else {
            /* check for name in use */
            len = strlen(name) ;
            dp = (NC_var**)handle->vars->values ;
            for(ii = 0 ; ii < handle->vars->count ; ii++, dp++)
              {
                  if( len == (*dp)->name->len &&
                      strncmp(name, (*dp)->name->values, len) == 0)
                    {
                        NCadvise(NC_ENAMEINUSE, "variable \"%s\" in use with index %d",
                                 (*dp)->name->values, ii) ;
                        return(-1) ;
                    }
              }
            var[0] = NC_new_var(name,type,ndims,dims) ;
            if(var[0] == NULL)
                return(-1) ;
            if( NC_incr_array(handle->vars, (Void *)var) == NULL)
                return(-1) ;
        }
#ifdef HDF
    (*var)->cdf = handle; /* for NC_var_shape */
#endif
    if( NC_var_shape(*var, handle->dims) != -1)
      {
#ifdef HDF
#ifdef NOT_YET
          (*var)->ndg_ref = Htagnewref(handle->hdf_file,DFTAG_NDG);
#else /* NOT_YET */
          (*var)->ndg_ref = Hnewref(handle->hdf_file);
#endif /* NOT_YET */
#endif
          return(handle->vars->count -1) ;
      }
    /* unwind */
    handle->vars->count-- ;
    NC_free_var(var[0]) ;
    return(-1) ;
}


/*
 * Recompute the shapes of all variables
 * Sets handle->begin_rec to start of first record variable
 * returns -1 on error
 */
int NC_computeshapes( handle )
NC *handle ;
{
    NC_var **vbase, **vpp ;
    NC_var *first = NULL ;

    handle->begin_rec = 0 ;
    handle->recsize = 0 ;

    if(handle->vars == NULL)
        return(0) ;
    vbase = (NC_var **)handle->vars->values ;
    for( vpp =  vbase ;
         vpp < &vbase[handle->vars->count] ;
         vpp ++)
      {
#ifdef HDF
          (*vpp)->cdf= handle;
#endif

          if( NC_var_shape(*vpp, handle->dims) == -1)
              return(-1) ;
          if(IS_RECVAR(*vpp))
            {
                if(first == NULL)
                    first = *vpp ;
                handle->recsize += (*vpp)->len ;
            }
      }
    if(first != NULL)
      {
          handle->begin_rec = first->begin ;
          /*
           * for special case of exactly one record variable, pack values
           */
          if(handle->recsize == first->len)
              handle->recsize = *first->dsizes ;
      }
    return(handle->vars->count) ;
}


int ncvarid( cdfid, name)
int cdfid ;
const char *name ;
{
    NC *handle ;
    NC_var **dp ;
    int ii ;
    int len ;

    cdf_routine_name = "ncvarid" ;

    handle = NC_check_id(cdfid) ;
    if(handle == NULL)
        return(-1) ;
    if(handle->vars == NULL)
        return(-1) ;
    len = strlen(name) ;
    dp = (NC_var**)handle->vars->values ;
    for(ii = 0 ; ii < handle->vars->count ; ii++, dp++)
    {
        if( len == (*dp)->name->len &&
            strncmp(name, (*dp)->name->values, len) == 0)
        {
            return(ii) ;
        }
    }
    NCadvise(NC_ENOTVAR, "variable \"%s\" not found", name) ;
    return(-1) ;
}


/*
 * Given valid handle and varid, return var
 *  else NULL on error
 */
NC_var *
NC_hlookupvar( handle, varid )
NC *handle ;
int varid ;
{
    NC_array **ap ;

    if(varid == NC_GLOBAL) /* Global is error in this context */
    {
        return(NULL) ;
    }else if(handle->vars != NULL && varid >= 0 && varid < handle->vars->count)
    {
        ap = (NC_array **)handle->vars->values ;
        ap += varid ;
    } else {
        NCadvise(NC_ENOTVAR, "%d is not a valid variable id", varid) ;
        return( NULL ) ;
    }
    return((NC_var *)*ap) ;
}


/*
 * Given cdfid and varid, return var
 *  else NULL on error
 */
static NC_var *
NC_lookupvar( cdfid, varid )
int cdfid ;
int varid ;
{
    NC *handle ;

    handle = NC_check_id(cdfid) ;
    if(handle == NULL)
        return(NULL) ;

    return(NC_hlookupvar(handle,varid)) ;
}


int ncvarinq( cdfid, varid, name, typep, ndimsp, dims, nattrsp)
int cdfid ;
int varid ;
char *name ;
nc_type *typep ;
int *ndimsp ;
int dims[] ;
int *nattrsp ;
{
    NC_var *vp ;
    int ii ;

    cdf_routine_name = "ncvarinq" ;

    vp = NC_lookupvar( cdfid, varid ) ;
    if(vp == NULL)
        return(-1) ;

    if(name != NULL)
    {
#ifdef HDF
        (void)memcpy( name, vp->name->values, vp->name->len) ;
#else
        (void)strncpy( name, vp->name->values, vp->name->len) ;
#endif
        name[vp->name->len] = 0 ;
    }

    if(typep != NULL)
        *typep = vp->type ;
    if(ndimsp != NULL)
    {
        *ndimsp = vp->assoc->count ;
    }
    if(dims != NULL)
    {
        for(ii = 0 ; ii < vp->assoc->count ; ii++)
        {
            dims[ii] = vp->assoc->values[ii] ;
        }
    }
    if(nattrsp != NULL)
    {
        if( vp->attrs != NULL)
        {
            *nattrsp = vp->attrs->count ;
        } else {
            *nattrsp = 0 ;
        }
    }

    return(varid) ;
}


int ncvarrename(cdfid, varid, newname)
int cdfid ;
int varid ;
const char *newname ;
{

    NC *handle ;
    NC_var **vpp ;
    int ii ;
    int len ;
    NC_string *old, *new ;

    cdf_routine_name = "ncvarrename" ;

    handle = NC_check_id(cdfid) ;
    if(handle == NULL)
        return(-1) ;
    if(!(handle->flags & NC_RDWR))
        return(-1) ;

    /* check for name in use */
    len = strlen(newname) ;
    vpp = (NC_var**)handle->vars->values ;
    for(ii = 0 ; ii < handle->vars->count ; ii++, vpp++)
    {
        if( len == (*vpp)->name->len &&
            strncmp(newname, (*vpp)->name->values, len) == 0)
        {
            NCadvise(NC_ENAMEINUSE, "variable name \"%s\" in use with index %d",
                (*vpp)->name->values, ii) ;
            return(-1) ;
        }
    }

    if(varid == NC_GLOBAL) /* Global is error in this context */
    {
        NCadvise(NC_EGLOBAL, "action prohibited on NC_GLOBAL varid") ;
        return(-1) ;
    }else if(handle->vars != NULL && varid >= 0 && varid < handle->vars->count)
    {
        vpp = (NC_var **)handle->vars->values ;
        vpp += varid ;
    } else {
        NCadvise(NC_ENOTVAR, "%d is not a valid variable id", varid) ;
        return( -1 ) ;
    }

    old = (*vpp)->name ;
    if( NC_indefine(cdfid,TRUE) )
    {
        new = NC_new_string((unsigned)strlen(newname),newname) ;
        if( new == NULL)
            return(-1) ;
        (*vpp)->name = new ;
        NC_free_string(old) ;
        return(varid) ;
    } /* else */
    new = NC_re_string(old, (unsigned)strlen(newname),newname) ;
    if( new == NULL)
        return(-1) ;
    if(handle->flags & NC_HSYNC)
    {
        handle->xdrs->x_op = XDR_ENCODE ;
        if(!xdr_cdf(handle->xdrs, &handle) )
            return(-1) ;
        handle->flags &= ~(NC_NDIRTY | NC_HDIRTY) ;
    } else
        handle->flags |= NC_HDIRTY ;
    return(varid) ;
}


#ifdef NOT_USED
/*
 * Given valid handle, name string, and length of the name, get a var.
 *  else NULL on error
 */
static NC_var *
NC_hvarid(handle, name, namelen)
NC *handle ;
const char *name ;
int namelen ;
{
    NC_var **dp ;
    int ii ;
    if(handle->vars == NULL)
        return NULL ;
    dp = (NC_var**)handle->vars->values ;
    for(ii = 0 ; ii < handle->vars->count ; ii++, dp++)
    {
        if( namelen == (*dp)->name->len &&
                strncmp(name, (*dp)->name->values, namelen) == 0)
        {
            return(*dp) ; /* normal exit */
        }
    }
    return NULL ; /* not found */
}


/*
 * Copy the values of a variable from an input netCDF to an output netCDF.
 * Input and output var assummed to have the same shape.
 * return -1 on error.
 *
 * This function added to support the netcdf operators. The interface
 * is not documented. We plan to supercede it with something more
 * general in a future release.
 */
static int
ncvarcpy(incdf, varid, outcdf)
int             incdf;
int             varid;
int             outcdf;
{
    NC *inhandle, *outhandle ;
    NC_var *invp, *outvp ;
    int ndims ;
    int ii ;

    cdf_routine_name = "ncvarcpy" ;

    inhandle = NC_check_id(incdf) ;
    if(inhandle == NULL)
        return(-1) ;

    if(inhandle->flags & NC_INDEF)
    {
        NCadvise(NC_EINDEFINE, "%s in define mode.", inhandle->path) ;
        return(-1) ;
    }

    outhandle = NC_check_id(outcdf) ;
    if(outhandle == NULL)
        return(-1) ;

    if(!(outhandle->flags & NC_RDWR))
    {
        /* output file isn't writable */
        NCadvise(NC_EPERM, "%s is not writable", outhandle->path) ;
        return -1 ;
    }

    if(outhandle->flags & NC_INDEF)
    {
        NCadvise(NC_EINDEFINE, "%s in define mode.", outhandle->path) ;
        return(-1) ;
    }

    /* find the variable in the input cdf */
    if(inhandle->vars == NULL
            || (invp = NC_hlookupvar(inhandle, varid )) == NULL)
    {
        NCadvise(NC_ENOTVAR, "%s: varid %d not found",
            inhandle->path, varid) ;
        return(-1) ;
    }

    /* find the variable in the output cdf */
    outvp = NC_hvarid(outhandle, invp->name->values, invp->name->len) ;
    if(outvp == NULL)
    {
        NCadvise(NC_ENOTVAR, "%s: variable %s not found",
            outhandle->path, invp->name->values) ;
        return(-1) ;
    }

    /* can we even attempt to copy without conversion? */
    if(outvp->type != invp->type)
    {
        NCadvise(NC_EINVAL,
            "Input and output variables must be same type") ;
        return -1 ;
    }

    ndims = invp->assoc->count ;

    if (ndims == 0)
    {
    /* special case scalar vars */
        if(outvp->assoc->count != 0)
        {
            NCadvise(NC_EINVAL,
                "Input and output variables must be same shape") ;
            return -1 ;
        }

    }
    else
    {
        long end[H4_MAX_VAR_DIMS] ;
        memcpy(end, invp->shape, ndims * sizeof(unsigned long)) ;
        if(IS_RECVAR(invp))
        {
            /* assert(*end == 0) ; */
            *end = inhandle->numrecs ;
        }

        for(ii = 0 ; ii < ndims ; ii++)
            end[ii] -- ;
        /* at this point, end is the largest valid coord of invp */
        if( !NCcoordck(outhandle, outvp, end) )
        {
            NCadvise(NC_EINVAL,
                "Input and output variables not conformable") ;
            return -1 ;
        }
        /* Fill is side effect of NCcoordck */
    }

    /* four cases, really not neccessary here, left for future generalization */
    if(IS_RECVAR(invp))
    {
        if(IS_RECVAR(outvp))
        {
            long outoff, inoff ;
            /* both input and output are rec vars */
            /* check that input fits in output. (per record) */
            if(invp->len > outvp->len)
            {
                NCadvise(NC_EINVALCOORDS,
                    "Output var smaller than input") ;
                return -1 ;
            }
            /* copy the data */
            outoff = outhandle->begin_rec + outvp->begin ;
            inoff = inhandle->begin_rec + invp->begin ;
            outhandle->flags |= NC_NDIRTY ;
            for(ii=0 ; ii < inhandle->numrecs ; ii++)
            {
                if(!xdr_setpos(outhandle->xdrs, outoff))
                {
                    NCadvise(NC_EXDR, "%s: xdr_setpos",
                        outhandle->path) ;
                    return -1 ;
                }
                if(!xdr_setpos(inhandle->xdrs, inoff))
                {
                    NCadvise(NC_EXDR, "%s: xdr_setpos",
                        inhandle->path) ;
                    return -1 ;
                }
                /* copy data */
                if(!NC_dcpy(outhandle->xdrs, inhandle->xdrs, invp->len))
                    return(-1) ;
                outoff += outhandle->recsize ;
                inoff += inhandle->recsize ;
            }
        }
        else
        {
            NCadvise(NC_EINVAL,
                "Input and output variables must be same shape") ;
            return -1 ;
        }
    }
    else
    {
        if(IS_RECVAR(outvp))
        {
            /* input not rec var, output is rec var */
            NCadvise(NC_EINVAL,
                "Input and output variables must be same shape") ;
            return -1 ;
        }
        else
        {
            /* both input and output are not rec vars */
            /* check that input fits in output. */
            if(invp->len > outvp->len)
            {
                NCadvise(NC_EINVALCOORDS,
                    "Output var smaller than input") ;
                return -1 ;
            }
            if(!xdr_setpos(outhandle->xdrs, outvp->begin))
            {
                NCadvise(NC_EXDR, "%s: xdr_setpos",
                    outhandle->path) ;
                return -1 ;
            }
            if(!xdr_setpos(inhandle->xdrs, invp->begin))
            {
                NCadvise(NC_EXDR, "%s: xdr_setpos",
                    inhandle->path) ;
                return -1 ;
            }
            /* copy data */
            outhandle->flags |= NC_NDIRTY ;
            if(!NC_dcpy(outhandle->xdrs, inhandle->xdrs, invp->len))
                return(-1) ;
        }
    }
    return 0 ;
}
#endif /* NOT_USED */


bool_t
xdr_NC_var(xdrs, vpp)
    XDR *xdrs;
    NC_var **vpp;
{
    u_long begin = 0;

    if( xdrs->x_op == XDR_FREE)
    {
        NC_free_var((*vpp)) ;
        return(TRUE) ;
    }

    if( xdrs->x_op == XDR_DECODE )
    {
        *vpp = (NC_var *)HDcalloc(1,sizeof(NC_var)) ;
        if( *vpp == NULL )
        {
            nc_serror("xdr_NC_var") ;
            return(FALSE) ;
        }
    }

    if( !xdr_NC_string(xdrs, &((*vpp)->name)))
        return(FALSE) ;
    if( !xdr_NC_iarray(xdrs, &((*vpp)->assoc)))
        return(FALSE) ;
    if( !xdr_NC_array(xdrs, &((*vpp)->attrs)))
        return(FALSE) ;

    /* This USE_ENUM may not be necessary after xdr and code cleanup.
    See HDFFR-1318, HDFFR-1327, and other Mac/XDR issues for details.
    I had tried and xdr_enum worked consistently even though there were
    failures in other places. -BMR, 6/14/2016 */
#ifdef USE_ENUM
    if (! xdr_enum(xdrs, (enum_t *)&((*vpp)->type)) ) {
        return (FALSE);
    }
#else
    /* Using static variable seemed to help prevent bad memory accesses */
    {
        int temp_type = 0;
        if (! xdr_int(xdrs, &temp_type)) {
            return (FALSE);
        }
        (*vpp)->type = (nc_type)temp_type;
    }

#endif
    {
        u_long temp_len = 0;
        if (! xdr_u_long(xdrs, &temp_len)) {
            return (FALSE);
        }
        (*vpp)->len = temp_len;
    }

    if( xdrs->x_op == XDR_DECODE )
        (*vpp)->szof = NC_typelen((*vpp)->type) ;

    if( xdrs->x_op == XDR_ENCODE )
        begin = (*vpp)->begin ;
    if (! xdr_u_long(xdrs, &begin))
        return (FALSE);
    if( xdrs->x_op == XDR_DECODE )
        (*vpp)->begin = begin ;

#ifdef HDF

        if( xdrs->x_op == XDR_DECODE ) {

            (*vpp)->HDFtype = hdf_map_type((*vpp)->type);
            (*vpp)->HDFsize = DFKNTsize((*vpp)->HDFtype);
            (*vpp)->aid = FAIL;
            (*vpp)->is_ragged = FALSE;

        }

#endif

    return( TRUE ) ;
}


/*
 * How much space will the xdr'd var take.
 *
 */
int NC_xlen_var(vpp)
NC_var **vpp ;
{
    int len ;

    if(*vpp == NULL)
        return(4) ;

    len = NC_xlen_string((*vpp)->name) ;
    len += NC_xlen_iarray((*vpp)->assoc) ;
    len += NC_xlen_array((*vpp)->attrs) ;
    len += 12 ;

    return(len) ;
}
