/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "local_nc.h"
#ifdef HDF
#include "hfile.h"

/* constants/macros pulled out of the CDF library source */
#define V2_CDR_OFFSET     8
#define VDRzVDR_RFUe_LEN  128
#define CDF_VAR_NAME_LEN  64
#define CDF_ATTR_NAME_LEN 64
#define CDF_FORMAT_BIT                                                                                       \
    1 /* format: set = single file,                                                                          \
               clear = multi file */

#define rVAR_RECVARY_BIT                                                                                     \
    0 /* record variance:                                                                                    \
           set = VARY,                                                                                       \
           clear = NOVARY */
#define rVAR_PADVALUE_BIT                                                                                    \
    1 /* pad value:                                                                                          \
           set = specified,                                                                                  \
           clear = not specified (use                                                                        \
                   default) */
#define zVAR_RECVARY_BIT                                                                                     \
    0 /* record variance:                                                                                    \
           set = VARY,                                                                                       \
           clear = NOVARY */
#define zVAR_PADVALUE_BIT                                                                                    \
    1 /* pad value:                                                                                          \
           set = specified,                                                                                  \
           clear = not specified (use                                                                        \
                   default) */

#define bitset(a, bit) (a & (1 << bit))
#define CDF_INT1       (long)1
#define CDF_INT2       (long)2
#define CDF_INT4       (long)4

#define CDF_UINT1 (long)11
#define CDF_UINT2 (long)12
#define CDF_UINT4 (long)14

#define CDF_REAL4 (long)21
#define CDF_REAL8 (long)22

#define CDF_EPOCH (long)31 /* NSSDC standard */

#define CDF_BYTE   (long)41 /* same as CDF_INT1 (signed) */
#define CDF_FLOAT  (long)44 /* same as CDF_REAL4 */
#define CDF_DOUBLE (long)45 /* same as CDF_REAL8 */

#define CDF_CHAR  (long)51 /* a "string" data type */
#define CDF_UCHAR (long)52 /* a "string" data type */

#define NETWORK_ENCODING    1L
#define SUN_ENCODING        2L
#define VAX_ENCODING        3L
#define DECSTATION_ENCODING 4L
#define SGi_ENCODING        5L
#define IBMPC_ENCODING      6L
#define IBMRS_ENCODING      7L
#define HOST_ENCODING       8L
#define HP_ENCODING         11L
#define NeXT_ENCODING       12L
#define ALPHAOSF1_ENCODING  13L
#define ALPHAVMSd_ENCODING  14L
#define ALPHAVMSg_ENCODING  15L

/* ---------------------------- cdf_unmap_type ---------------------------- */
/*
  UnMap a data type.  I.e. go from a CDF type to an NC_<type>
*/
nc_type
cdf_unmap_type(int type)
{

    switch (type & 0xff) {
        case CDF_CHAR:
        case CDF_UCHAR:
            return NC_CHAR;
        case CDF_BYTE:
        case CDF_INT1:
        case CDF_UINT1:
            return NC_BYTE;
        case CDF_INT2:
        case CDF_UINT2:
            return NC_SHORT;
        case CDF_INT4:
        case CDF_UINT4:
            return NC_LONG;
        case CDF_REAL4:
        case CDF_FLOAT:
            return NC_FLOAT;
        case CDF_REAL8:
        case CDF_DOUBLE:
        case CDF_EPOCH:
            return NC_DOUBLE;
        default:
            return (nc_type)FAIL; /* need to return a better (legal) value */
    }

} /* cdf_unmap_type */

/* ---------------------------- nssdc_read_cdf ---------------------------- */
/*
  Read a NC structure out of a CDF file
*/
bool_t
nssdc_read_cdf(XDR *xdrs, NC **handlep)
{

    NC        *handle;
    uint8      buffer[1000];
    uint8     *b;
    int32      dummy;
    hdf_file_t fp;
    intn       i, j;
    int32      rank, current_var, current_dim, hdftype;
    nc_type    nctype;
    intn       dims[H4_MAX_VAR_DIMS];
    int32      dim_sz[H4_MAX_VAR_DIMS];
    NC_dim    *dim_rec[H4_MAX_VAR_DIMS];
    NC_var    *vars[H4_MAX_NC_VARS];
    NC_var    *var = NULL; /* shorthand for vars[current_var] */
    vix_t     *end;

    (void)xdrs;

    /* interesting stuff in CDR record */
    int32 gdrOffset, vers, release, encoding, flags, inc;

    /* interesting stuff in GDR record */
    int32 varNext, zVarNext, adrNext, numRVars, numAttrs, maxRec;
    int32 numDims, numZVars;

    /* interesting stuff in VDR record */
    int32 nt, vMaxRec, vxrNext, VXRtail, vFlags, numElem, num;
    char  name[CDF_VAR_NAME_LEN + 1];

    /* interesting stuff in ADR record */
    int32 scope, aedrNext, aedzNext;

    /* interesting stuff in AEDR record */
    int32 count;

#if DEBUG
    fprintf(stderr, "nssdc_read_cdf i've been called\n");
#endif

    handle      = (*handlep);
    fp          = handle->cdf_fp;
    current_var = 0;

    /*
     * pull in the CDR and see what we want out of it
     */
    if (HI_SEEK(fp, V2_CDR_OFFSET) == FAIL)
        HRETURN_ERROR(DFE_SEEKERROR, FALSE);

    if (HI_READ(fp, buffer, 12 * sizeof(int32)) == FAIL)
        HRETURN_ERROR(DFE_READERROR, FALSE);

    b = buffer;
    INT32DECODE(b, dummy);     /* record size */
    INT32DECODE(b, dummy);     /* record type */
    INT32DECODE(b, gdrOffset); /* offset of GDR record */
    INT32DECODE(b, vers);      /* version number */
    INT32DECODE(b, release);   /* release number */
    INT32DECODE(b, encoding);  /* type of encoding */
    INT32DECODE(b, flags);     /* special flags (uint32????) */
    INT32DECODE(b, dummy);     /* rfuA */
    INT32DECODE(b, dummy);     /* rfuB */
    INT32DECODE(b, inc);       /* increment - do we care?? */
    INT32DECODE(b, dummy);     /* rfuD */
    INT32DECODE(b, dummy);     /* rfuE */

    /*
     * Only handle single file implementations for now
     */
    if (!bitset(flags, CDF_FORMAT_BIT)) {
#ifdef DEBUG
        fprintf(stderr, "We are only able to handle single-file CDFs.  Sorry.\n");
#endif
        return (FALSE);
    }

    /* Check the encoding */
    if ((encoding != NETWORK_ENCODING) && (encoding != SUN_ENCODING) && (encoding != SGi_ENCODING) &&
        (encoding != IBMRS_ENCODING) && (encoding != HP_ENCODING)) {
#ifdef DEBUG
        fprintf(stderr, "We are only able to handle IEEE encoded files.  Sorry.\n");
#endif
        return (FALSE);
    }

    /*
     * pull in the GDR and see what we want out of it
     */
    if (HI_SEEK(fp, gdrOffset) == FAIL)
        HRETURN_ERROR(DFE_SEEKERROR, FALSE);

    if (HI_READ(fp, buffer, 15 * sizeof(int32)) == FAIL)
        HRETURN_ERROR(DFE_READERROR, FALSE);

    b = buffer;
    INT32DECODE(b, dummy);    /* record size */
    INT32DECODE(b, dummy);    /* record type */
    INT32DECODE(b, varNext);  /* start of next R variable */
    INT32DECODE(b, zVarNext); /* start of Zvariables */
    INT32DECODE(b, adrNext);  /* start of attributes */
    INT32DECODE(b, dummy);    /* eof */
    INT32DECODE(b, numRVars); /* number of R variables */
    INT32DECODE(b, numAttrs); /* number of attributes */
    INT32DECODE(b, maxRec);   /* dunno */
    INT32DECODE(b, numDims);  /* number of dimensions */
    INT32DECODE(b, numZVars); /* number of Z variables */
    INT32DECODE(b, dummy);    /* rfuB */
    INT32DECODE(b, dummy);    /* rfuC */
    INT32DECODE(b, dummy);    /* rfuD */
    INT32DECODE(b, dummy);    /* rfuE */

    /*
     * dimension sizes are here
     */
    if (numDims > H4_MAX_VAR_DIMS)
        return FALSE;

    if (HI_READ(fp, buffer, numDims * sizeof(int32)) == FAIL)
        HRETURN_ERROR(DFE_READERROR, FALSE);

#ifdef DEBUG
    fprintf(stderr, "File version %d.%d\n", (int)vers, (int)release);
    fprintf(stderr, " rVars %d, Attrs %d, zVars %d\n", (int)numRVars, (int)numAttrs, (int)numZVars);
    fprintf(stderr, " Dims %d, maxRec %d\n", (int)numDims, (int)maxRec);
#endif

    /*
     * For each rVariable dimension size create a new dimension object
     */
    b           = buffer;
    current_dim = 0;
    for (i = 0; i < numDims; i++) {
        char tmpname[80];
        INT32DECODE(b, dim_sz[i]);
        sprintf(tmpname, "CDFdim%d_%d", i, (int)dim_sz[i]);
        dim_rec[current_dim++] = NC_new_dim(tmpname, dim_sz[i]);

#ifdef DEBUG
        fprintf(stderr, "Created dimension %s\n", tmpname);
#endif
    }

    /*
     * Loop over Rvariables and read them in
     */
    while (varNext != 0) {

#ifdef DEBUG
        fprintf(stderr, "Variable %d seeking to %d\n", (int)current_var, (int)varNext);
#endif

        if (HI_SEEK(fp, varNext) == FAIL)
            HRETURN_ERROR(DFE_SEEKERROR, FALSE);

        if (HI_READ(fp, buffer, 4) == FAIL)
            HRETURN_ERROR(DFE_READERROR, FALSE);

        b = buffer;
        INT32DECODE(b, dummy); /* record size */
        dummy -= 4;

        if (HI_READ(fp, buffer, dummy) == FAIL)
            HRETURN_ERROR(DFE_READERROR, FALSE);

        b = buffer;
        INT32DECODE(b, dummy);   /* record type */
        INT32DECODE(b, varNext); /* start of next R variable */
        INT32DECODE(b, nt);      /* number type */
        INT32DECODE(b, vMaxRec); /* number of records for this variable */
        INT32DECODE(b, vxrNext); /* start of VXR records */
        INT32DECODE(b, VXRtail); /* ??? */
        INT32DECODE(b, vFlags);  /* variable flags <---- record variance in here */
        INT32DECODE(b, dummy);   /* rfuA */
        INT32DECODE(b, dummy);   /* rfuB */
        INT32DECODE(b, dummy);   /* rfuC */
        INT32DECODE(b, dummy);   /* rfuF */
        b += VDRzVDR_RFUe_LEN;   /* reserved field */
        INT32DECODE(b, numElem); /* == 1 unless string variable */
        INT32DECODE(b, num);     /* */
        INT32DECODE(b, dummy);   /* rfuD */
        INT32DECODE(b, dummy);   /* nextEndRecs */

        memcpy(name, b, CDF_VAR_NAME_LEN);
        name[CDF_VAR_NAME_LEN] = '\0';
        b += CDF_VAR_NAME_LEN;

        j = 0;
        while ((name[j] != ' ') && (name[j] != '\0'))
            j++;
        name[j] = '\0';

#ifdef DEBUG
        fprintf(stderr, "\tName %s nt %d vMaxRec %d\n", name, (int)nt, (int)vMaxRec);
        fprintf(stderr, "\tNext var at %d\n", (int)varNext);
#endif

        /*
         *  Figure out which dimensions are meaningful
         *  If we vary in the record dimension it is reflected in the variable's
         *    flags
         *  Variance in the other dimensions is specified singly as int32
         *    quantities in the file
         *  Only define the variable in terms of dimensions in which it varies
         */
        rank = 0;

        if (bitset(vFlags, rVAR_RECVARY_BIT)) {
            char dimname[1000];
            sprintf(dimname, "%s_REC", name);
            if (numElem > 1)
                dim_rec[current_dim] = NC_new_dim(dimname, numElem);
            else if (maxRec > 0)
                dim_rec[current_dim] = NC_new_dim(dimname, maxRec);
            else
                dim_rec[current_dim] = NC_new_dim(dimname, NC_UNLIMITED);

            dims[rank++] = current_dim++;
        }

        for (j = 0; j < numDims; j++) {
            INT32DECODE(b, dummy);
            if (dummy)
                dims[rank++] = j;
        }

        /* map the CDF type into a netCDF type */
        nctype = cdf_unmap_type(nt);

        /* define the variable */
        var = vars[current_var] = NC_new_var((char *)name, nctype, (int)rank, dims);
        if (var == NULL)
            HRETURN_ERROR(DFE_NOSPACE, FALSE);

#ifdef DEBUG
        fprintf(stderr, "Was able to call NC_new_var()\n");
#endif

        /* if it is unsigned at least set the HDFtype to reflect it */
        switch (nt) {
            case CDF_UINT1:
                var->HDFtype = DFNT_UINT8;
                break;
            case CDF_UINT2:
                var->HDFtype = DFNT_UINT16;
                break;
            case CDF_UINT4:
                var->HDFtype = DFNT_UINT32;
                break;
            default:
                break;
        }

        /*
         *  Read the pad value if applicable
         */
        if (bitset(vFlags, rVAR_PADVALUE_BIT)) {
            /* need to pull the pad value out of the file at current location */
            /* make into _Fillvalue attribute */
        }

        /*
         *  Mess with setting up VXR records
         */

        var->vixHead = end = NULL;
        while (vxrNext != 0) {
            vix_t *vix;

            vix = malloc(sizeof(vix_t));
            if (vix == NULL)
                HRETURN_ERROR(DFE_NOSPACE, FALSE);

            /* stick vix at the end of our list and update end pointer */
            if (end == NULL)
                var->vixHead = end = vix;
            else
                end = end->next = vix;

            vix->next = NULL;

#ifdef DEBUG
            fprintf(stderr, "Reading a VXR record at %d\n", (int)vxrNext);
#endif
            /*
             * Read the next record out of the file
             */
            if (HI_SEEK(fp, vxrNext) == FAIL)
                HRETURN_ERROR(DFE_SEEKERROR, FALSE);

            if (HI_READ(fp, buffer, 4) == FAIL)
                HRETURN_ERROR(DFE_READERROR, FALSE);

            b = buffer;
            INT32DECODE(b, dummy); /* record size */
            dummy -= 4;

            if (HI_READ(fp, buffer, dummy) == FAIL)
                HRETURN_ERROR(DFE_READERROR, FALSE);

            b = buffer;
            INT32DECODE(b, dummy);         /* record type */
            INT32DECODE(b, vxrNext);       /* next VXR record */
            INT32DECODE(b, vix->nEntries); /* number of entries */
            INT32DECODE(b, vix->nUsed);    /* number of used entries */

            for (i = 0; i < vix->nEntries; i++)
                INT32DECODE(b, vix->firstRec[i]);
            for (i = 0; i < vix->nEntries; i++)
                INT32DECODE(b, vix->lastRec[i]);
            for (i = 0; i < vix->nEntries; i++)
                INT32DECODE(b, vix->offset[i]);

#ifdef DEBUG
            for (i = 0; i < vix->nEntries; i++)
                fprintf(stderr, "\t%d %d %d\n", (int)vix->firstRec[i], (int)vix->lastRec[i],
                        (int)vix->offset[i]);
            fprintf(stderr, "Next record at %d\n", (int)vxrNext);
#endif
        }

        current_var++;
    }

    /*
     * Loop over Zvariables and read them in
     */
    while (zVarNext != 0) {

#ifdef DEBUG
        fprintf(stderr, "zVariable %d seeking to %d\n", i, (int)zVarNext);
#endif

        if (HI_SEEK(fp, zVarNext) == FAIL)
            HRETURN_ERROR(DFE_SEEKERROR, FALSE);

        if (HI_READ(fp, buffer, 4) == FAIL)
            HRETURN_ERROR(DFE_READERROR, FALSE);

        b = buffer;
        INT32DECODE(b, dummy); /* record size */
        dummy -= 4;

        if (HI_READ(fp, buffer, dummy) == FAIL)
            HRETURN_ERROR(DFE_READERROR, FALSE);

        b = buffer;
        INT32DECODE(b, dummy);    /* record type */
        INT32DECODE(b, zVarNext); /* start of next R variable */
        INT32DECODE(b, nt);       /* number type */
        INT32DECODE(b, vMaxRec);  /* dunno */
        INT32DECODE(b, vxrNext);  /* start of VXR records */
        INT32DECODE(b, VXRtail);  /* ??? */
        INT32DECODE(b, vFlags);   /* variable flags <---- record variance in here */
        INT32DECODE(b, dummy);    /* rfuA */
        INT32DECODE(b, dummy);    /* rfuB */
        INT32DECODE(b, dummy);    /* rfuC */
        INT32DECODE(b, dummy);    /* rfuF */
        b += VDRzVDR_RFUe_LEN;    /* reserved field */
        INT32DECODE(b, numElem);  /* */
        INT32DECODE(b, num);      /* */
        INT32DECODE(b, dummy);    /* rfuD */
        INT32DECODE(b, dummy);    /* nextEndRecs */

        memcpy(name, b, CDF_VAR_NAME_LEN);
        name[CDF_VAR_NAME_LEN] = '\0';
        b += CDF_VAR_NAME_LEN;

        j = 0;
        while ((name[j] != ' ') && (name[j] != '\0'))
            j++;
        name[j] = '\0';

        /* MORE STUFF */
#ifdef DEBUG
        fprintf(stderr, "\tName %s nt %d vMaxRec %d\n", name, (int)nt, (int)vMaxRec);
#endif

        /*
         * Get the number of dimensions defined with this dataset
         * This is not necessarily the rank since we may not vary in
         *   some of them.  In that case, do not create dimension
         *   objects for them.
         */
        INT32DECODE(b, numDims); /* number of dimensions */

        /*
         * read dimension sizes
         * figure out which ones are actually used
         * create dimension objects for the dimensions that are used
         */
        for (j = 0; j < numDims; j++)
            INT32DECODE(b, dim_sz[j]);

        rank = 0;
        for (j = 0; j < numDims; j++) {
            INT32DECODE(b, dummy);
            if (dummy) {
                char dimname[1000];
                sprintf(dimname, "%s%d_%d", name, (int)rank, (int)dim_sz[j]);
                dim_rec[current_dim] = NC_new_dim(dimname, dim_sz[j]);
                dims[rank++]         = current_dim++;
            }
        }

#ifdef DEBUG
        fprintf(stderr, "\trank %d numDims %d\n", (int)rank, (int)numDims);
#endif

        /* map the CDF type into a netCDF type */
        nctype = cdf_unmap_type(nt);

        /* define the variable */
        var = vars[current_var] = NC_new_var((char *)name, nctype, (int)rank, dims);
        if (var == NULL)
            return (FALSE);

        /* if it is unsigned at least set the HDFtype to reflect it */
        switch (nt) {
            case CDF_UINT1:
                var->HDFtype = DFNT_UINT8;
                break;
            case CDF_UINT2:
                var->HDFtype = DFNT_UINT16;
                break;
            case CDF_UINT4:
                var->HDFtype = DFNT_UINT32;
                break;
            default:
                break;
        }

        /* what's up with PadValues ??? */

        /*
         *  Mess with setting up VXR records
         */
        var->vixHead = end = NULL;
        while (vxrNext != 0) {
            vix_t *vix;

            vix = malloc(sizeof(vix_t));
            if (vix == NULL)
                HRETURN_ERROR(DFE_NOSPACE, FALSE);

            /* stick vix at the end of our list and update end pointer */
            if (end == NULL)
                var->vixHead = end = vix;
            else
                end = end->next = vix;

            vix->next = NULL;

#ifdef DEBUG
            fprintf(stderr, "Reading a VXR record at %d\n", (int)vxrNext);
#endif
            /*
             * Read the next record out of the file
             */
            if (HI_SEEK(fp, vxrNext) == FAIL)
                HRETURN_ERROR(DFE_SEEKERROR, FALSE);

            if (HI_READ(fp, buffer, 4) == FAIL)
                HRETURN_ERROR(DFE_READERROR, FALSE);

            b = buffer;
            INT32DECODE(b, dummy); /* record size */
            dummy -= 4;

            if (HI_READ(fp, buffer, dummy) == FAIL)
                HRETURN_ERROR(DFE_READERROR, FALSE);

            b = buffer;
            INT32DECODE(b, dummy);         /* record type */
            INT32DECODE(b, vxrNext);       /* next VXR record */
            INT32DECODE(b, vix->nEntries); /* number of entries */
            INT32DECODE(b, vix->nUsed);    /* number of used entries */

            for (i = 0; i < vix->nEntries; i++)
                INT32DECODE(b, vix->firstRec[i]);
            for (i = 0; i < vix->nEntries; i++)
                INT32DECODE(b, vix->lastRec[i]);
            for (i = 0; i < vix->nEntries; i++)
                INT32DECODE(b, vix->offset[i]);

#ifdef DEBUG
            for (i = 0; i < vix->nEntries; i++)
                fprintf(stderr, "\t%d %d %d\n", (int)vix->firstRec[i], (int)vix->lastRec[i],
                        (int)vix->offset[i]);
            fprintf(stderr, "Next record at %d\n", (int)vxrNext);
#endif
        }

        current_var++;

    } /* loop over zVariabes */

    /*
     * Loop over Attributes and read them in
     */
    for (i = 0; i < numAttrs; i++) {

#ifdef DEBUG
        fprintf(stderr, "Attribute %d seeking to %d\n", i, (int)adrNext);
#endif

        if (HI_SEEK(fp, adrNext) == FAIL)
            HRETURN_ERROR(DFE_SEEKERROR, FALSE);

        if (HI_READ(fp, buffer, 4) == FAIL)
            HRETURN_ERROR(DFE_READERROR, FALSE);

        b = buffer;
        INT32DECODE(b, dummy); /* record size */
        dummy -= 4;

        if (HI_READ(fp, buffer, dummy) == FAIL)
            HRETURN_ERROR(DFE_READERROR, FALSE);

        b = buffer;
        INT32DECODE(b, dummy);    /* record type */
        INT32DECODE(b, adrNext);  /* start of next ADR record */
        INT32DECODE(b, aedrNext); /* start of next AEDR object */
        INT32DECODE(b, scope);    /* scope 1==global 2==local */
        INT32DECODE(b, dummy);    /* num */
        INT32DECODE(b, dummy);    /* numR */
        INT32DECODE(b, dummy);    /* maxR */
        INT32DECODE(b, dummy);    /* rfuA */
        INT32DECODE(b, aedzNext); /* AzEDRhread */
        INT32DECODE(b, dummy);    /* NumZ */
        INT32DECODE(b, dummy);    /* MaxZ */
        INT32DECODE(b, dummy);    /* rfuE */

        memcpy(name, b, CDF_ATTR_NAME_LEN);
        name[CDF_ATTR_NAME_LEN] = '\0';

#ifdef DEBUG
        fprintf(stderr, "\tname %s (%s) data at %d\n", name, (scope == 1 ? "global" : "local"),
                (int)aedrNext);
        fprintf(stderr, "\taedrNext %d    aedzNext %d\n", (int)aedrNext, (int)aedzNext);

#endif

        /*
         * Read in the AEDR records now and add them to the appropriate object
         */
        while (aedrNext != 0) {
            NC_array **ap;
            NC_attr   *attr[1];
            char      *tBuf;
            int32      bsize;

            if (HI_SEEK(fp, aedrNext) == FAIL)
                HRETURN_ERROR(DFE_SEEKERROR, FALSE);

            if (HI_READ(fp, buffer, 4) == FAIL)
                HRETURN_ERROR(DFE_READERROR, FALSE);

            b = buffer;
            INT32DECODE(b, dummy); /* record size */
            dummy -= 4;

            if (HI_READ(fp, buffer, dummy) == FAIL)
                HRETURN_ERROR(DFE_READERROR, FALSE);

            b = buffer;
            INT32DECODE(b, dummy);    /* record type */
            INT32DECODE(b, aedrNext); /* start of next AEDR record */
            INT32DECODE(b, num);      /* attr (?) number */
            INT32DECODE(b, nt);       /* number type */
            INT32DECODE(b, num);      /* var (?) number */
            INT32DECODE(b, count);    /* number of elements */
            INT32DECODE(b, dummy);    /* rfuA */
            INT32DECODE(b, dummy);    /* rfuB */
            INT32DECODE(b, dummy);    /* rfuC */
            INT32DECODE(b, dummy);    /* rfuD */
            INT32DECODE(b, dummy);    /* rfuE */

            /* map the CDF type into a netCDF type */
            nctype  = cdf_unmap_type(nt);
            hdftype = hdf_map_type(nctype);

            bsize = nctypelen(nctype) * count;
            tBuf  = malloc((uint32)bsize);

            /* convert attribute values and create attr object */
            DFKconvert((void *)b, (void *)tBuf, hdftype, count, DFACC_READ, 0, 0);
            attr[0] = NC_new_attr(name, nctype, count, tBuf);
            free(tBuf);

            /* make sure we got a valid attribute */
            if (attr[0] == NULL)
                return (FALSE);

            /* find the appropriate attribute list */
            if (scope == 1) {
                /* global attribute */
                ap = &(handle->attrs);
            }
            else {
                /* local --- find the appropriate variable */
                ap = &(vars[num]->attrs);
#ifdef DEBUG
                fprintf(stderr, "\tAdding %s (%s) to var %d \n", name, (scope == 1 ? "global" : "local"),
                        (int)num);
#endif
            }

            /* add the attribute to the list */
            if (*ap == NULL) {
                /* first time */
                (*ap) = NC_new_array(NC_ATTRIBUTE, (unsigned)1, (Void *)attr);
                if ((*ap) == NULL)
                    return (FALSE);
            }
            else {
                if (NC_incr_array((*ap), (Void *)attr) == NULL)
                    return (FALSE);
            }
        } /* AEDR loop */

        /*
         * Read in the AEDZ records now and add them to the appropriate object
         * It is not clear to me how these are different from aedr records
         *   except for that they are for Zvariables rather than Rvariables.
         *   Any other reasons?????
         */
        while (aedzNext != 0) {
            NC_array **ap;
            NC_attr   *attr[1];
            char      *tBuf;
            int32      bsize;

#ifdef DEBUG
            fprintf(stderr, "\tReading aedz from %d\n", (int)aedzNext);
#endif

            if (HI_SEEK(fp, aedzNext) == FAIL)
                HRETURN_ERROR(DFE_SEEKERROR, FALSE);

            if (HI_READ(fp, buffer, 4) == FAIL)
                HRETURN_ERROR(DFE_READERROR, FALSE);

            b = buffer;
            INT32DECODE(b, dummy); /* record size */
            dummy -= 4;

            if (HI_READ(fp, buffer, dummy) == FAIL)
                HRETURN_ERROR(DFE_READERROR, FALSE);

            b = buffer;
            INT32DECODE(b, dummy);    /* record type */
            INT32DECODE(b, aedzNext); /* start of next AEDR record */
            INT32DECODE(b, num);      /* attr (?) number */
            INT32DECODE(b, nt);       /* number type */
            INT32DECODE(b, num);      /* var (?) number */
            INT32DECODE(b, count);    /* number of elements */
            INT32DECODE(b, dummy);    /* rfuA */
            INT32DECODE(b, dummy);    /* rfuB */
            INT32DECODE(b, dummy);    /* rfuC */
            INT32DECODE(b, dummy);    /* rfuD */
            INT32DECODE(b, dummy);    /* rfuE */

            /* map the CDF type into a netCDF type */
            nctype  = cdf_unmap_type(nt);
            hdftype = hdf_map_type(nctype);

            bsize = nctypelen(nctype) * count;
            tBuf  = malloc((uint32)bsize);

            /* convert attribute values and create attr object */
            DFKconvert((void *)b, (void *)tBuf, hdftype, count, DFACC_READ, 0, 0);
            attr[0] = NC_new_attr(name, nctype, count, tBuf);
            free(tBuf);

            /* make sure we got a valid attribute */
            if (attr[0] == NULL)
                return (FALSE);

            /* find the appropriate attribute list */
            if (scope == 1) {
                /* global attribute */
                ap = &(handle->attrs);
            }
            else {
                /* local --- find the appropriate variable */
                ap = &(vars[num]->attrs);
#ifdef DEBUG
                fprintf(stderr, "\tAdding %s (%s) to Zvar %d \n", name, (scope == 1 ? "global" : "local"),
                        (int)num);
#endif
            }

            /* add the attribute to the list */
            if (*ap == NULL) {
                /* first time */
                (*ap) = NC_new_array(NC_ATTRIBUTE, (unsigned)1, (Void *)attr);
                if ((*ap) == NULL)
                    return (FALSE);
            }
            else {
                if (NC_incr_array((*ap), (Void *)attr) == NULL)
                    return (FALSE);
            }
        } /* AEDZ loop */

    } /* ADR loop */

    /*
     * Set up the dimension list
     */
    if (current_dim)
        handle->dims = NC_new_array(NC_DIMENSION, current_dim, (Void *)dim_rec);
    else
        handle->dims = NULL;

    /*
     * Set up the variable list define the variables
     */
    if (current_var)
        handle->vars = NC_new_array(NC_VARIABLE, current_var, (Void *)vars);
    else
        handle->vars = NULL;

    return (TRUE);

} /* nssdc_read_cdf */

/* ---------------------------- nssdc_write_cdf ---------------------------- */
/*
  Write a NC structure out to a CDF file
*/
bool_t
nssdc_write_cdf(XDR *xdrs, NC **handlep)
{
    (void)xdrs;
    (void)handlep;

#if DEBUG
    fprintf(stderr, "nssdc_write_cdf i've been called\n");
#endif

#ifdef DEBUG
    fprintf(stderr, "We are sorry, we currently do not support writing to\n");
    fprintf(stderr, "CDF files.  If you would like to see this capabilities\n");
    fprintf(stderr, "please contact the HDF group at NCSA.\n");
#endif

    return (FALSE);

} /* nssdc_write_cdf */

/* ---------------------------- nssdc_xdr_cdf ----------------------------- */
/*
  Handle basic I/O of the NC structure.
  CDF analogue of hdf_xdr_cdf and NC_xdr_cdf
*/
bool_t
nssdc_xdr_cdf(XDR *xdrs, NC **handlep)
{

    int status;

#if DEBUG
    fprintf(stderr, "nssdc_xdr_cdf i've been called op = %d \n", xdrs->x_op);
#endif

    switch (xdrs->x_op) {
        case XDR_ENCODE:
            status = nssdc_write_cdf(xdrs, handlep);
            break;
        case XDR_DECODE:
            status = nssdc_read_cdf(xdrs, handlep);
            break;
        case XDR_FREE:
            NC_free_cdf((*handlep));
            status = TRUE;
            break;
        default:
            status = TRUE;
    }

    return (status);

} /* nssdc_xdr_cdf */

#endif /* HDF */
