123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740 |
- /*
- * Copyright 1996, University Corporation for Atmospheric Research
- * See netcdf/COPYRIGHT file for copying and redistribution conditions.
- */
- /* $Id: var.c,v 1.144 2010/05/30 00:50:35 russ Exp $ */
- #include "nc.h"
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <limits.h>
- #include "ncx.h"
- #include "rnd.h"
- #include "utf8proc.h"
- #ifndef OFF_T_MAX
- #define OFF_T_MAX (~ (off_t) 0 - (~ (off_t) 0 << (CHAR_BIT * sizeof (off_t) - 1)))
- #endif
- /*
- * Free var
- * Formerly
- NC_free_var(var)
- */
- void
- free_NC_var(NC_var *varp)
- {
- if(varp == NULL)
- return;
- free_NC_attrarrayV(&varp->attrs);
- free_NC_string(varp->name);
- #ifndef MALLOCHACK
- if(varp->dimids != NULL) free(varp->dimids);
- if(varp->shape != NULL) free(varp->shape);
- if(varp->dsizes != NULL) free(varp->dsizes);
- #endif /*!MALLOCHACK*/
- free(varp);
- }
- /*
- * Common code for new_NC_var()
- * and ncx_get_NC_var()
- */
- NC_var *
- new_x_NC_var(
- NC_string *strp,
- size_t ndims)
- {
- NC_var *varp;
- const size_t o1 = M_RNDUP(ndims * sizeof(int));
- const size_t o2 = M_RNDUP(ndims * sizeof(size_t));
- #ifdef MALLOCHACK
- const size_t sz = M_RNDUP(sizeof(NC_var)) +
- o1 + o2 + ndims * sizeof(off_t);
- #else /*!MALLOCHACK*/
- const size_t o3 = ndims * sizeof(off_t);
- const size_t sz = sizeof(NC_var);
- #endif /*!MALLOCHACK*/
- varp = (NC_var *) malloc(sz);
- if(varp == NULL )
- return NULL;
- (void) memset(varp, 0, sz);
- varp->name = strp;
- varp->ndims = ndims;
- varp->hash = hash_fast(strp->cp, strlen(strp->cp));
- if(ndims != 0)
- {
- #ifdef MALLOCHACK
- /*
- * NOTE: lint may complain about the next 3 lines:
- * "pointer cast may result in improper alignment".
- * We use the M_RNDUP() macro to get the proper alignment.
- */
- varp->dimids = (int *)((char *)varp + M_RNDUP(sizeof(NC_var)));
- varp->shape = (size_t *)((char *)varp->dimids + o1);
- varp->dsizes = (off_t *)((char *)varp->shape + o2);
- #else /*!MALLOCHACK*/
- varp->dimids = (int*)malloc(o1);
- varp->shape = (size_t*)malloc(o2);
- varp->dsizes = (off_t*)malloc(o3);
- #endif /*!MALLOCHACK*/
- }
- varp->xsz = 0;
- varp->len = 0;
- varp->begin = 0;
- return varp;
- }
- /*
- * Formerly
- NC_new_var()
- */
- static NC_var *
- new_NC_var(const char *uname, nc_type type,
- size_t ndims, const int *dimids)
- {
- NC_string *strp;
- NC_var *varp;
- char *name = (char *)utf8proc_NFC((const unsigned char *)uname);
- if(name == NULL)
- return NULL;
- strp = new_NC_string(strlen(name), name);
- free(name);
- if(strp == NULL)
- return NULL;
- varp = new_x_NC_var(strp, ndims);
- if(varp == NULL )
- {
- free_NC_string(strp);
- return NULL;
- }
-
- varp->type = type;
- if( ndims != 0 && dimids != NULL)
- (void) memcpy(varp->dimids, dimids, ndims * sizeof(int));
- return(varp);
- }
- static NC_var *
- dup_NC_var(const NC_var *rvarp)
- {
- NC_var *varp = new_NC_var(rvarp->name->cp, rvarp->type,
- rvarp->ndims, rvarp->dimids);
- if(varp == NULL)
- return NULL;
-
- if(dup_NC_attrarrayV(&varp->attrs, &rvarp->attrs) != NC_NOERR)
- {
- free_NC_var(varp);
- return NULL;
- }
- (void) memcpy(varp->shape, rvarp->shape,
- rvarp->ndims * sizeof(size_t));
- (void) memcpy(varp->dsizes, rvarp->dsizes,
- rvarp->ndims * sizeof(size_t));
- varp->xsz = rvarp->xsz;
- varp->len = rvarp->len;
- varp->begin = rvarp->begin;
- return varp;
- }
- /* vararray */
- /*
- * Free the stuff "in" (referred to by) an NC_vararray.
- * Leaves the array itself allocated.
- */
- void
- free_NC_vararrayV0(NC_vararray *ncap)
- {
- assert(ncap != NULL);
- if(ncap->nelems == 0)
- return;
- assert(ncap->value != NULL);
- {
- NC_var **vpp = ncap->value;
- NC_var *const *const end = &vpp[ncap->nelems];
- for( /*NADA*/; vpp < end; vpp++)
- {
- free_NC_var(*vpp);
- *vpp = NULL;
- }
- }
- ncap->nelems = 0;
- }
- /*
- * Free NC_vararray values.
- * formerly
- NC_free_array()
- */
- void
- free_NC_vararrayV(NC_vararray *ncap)
- {
- assert(ncap != NULL);
-
- if(ncap->nalloc == 0)
- return;
- assert(ncap->value != NULL);
- free_NC_vararrayV0(ncap);
- free(ncap->value);
- ncap->value = NULL;
- ncap->nalloc = 0;
- }
- int
- dup_NC_vararrayV(NC_vararray *ncap, const NC_vararray *ref)
- {
- int status = NC_NOERR;
- assert(ref != NULL);
- assert(ncap != NULL);
- if(ref->nelems != 0)
- {
- const size_t sz = ref->nelems * sizeof(NC_var *);
- ncap->value = (NC_var **) malloc(sz);
- if(ncap->value == NULL)
- return NC_ENOMEM;
- (void) memset(ncap->value, 0, sz);
- ncap->nalloc = ref->nelems;
- }
- ncap->nelems = 0;
- {
- NC_var **vpp = ncap->value;
- const NC_var **drpp = (const NC_var **)ref->value;
- NC_var *const *const end = &vpp[ref->nelems];
- for( /*NADA*/; vpp < end; drpp++, vpp++, ncap->nelems++)
- {
- *vpp = dup_NC_var(*drpp);
- if(*vpp == NULL)
- {
- status = NC_ENOMEM;
- break;
- }
- }
- }
- if(status != NC_NOERR)
- {
- free_NC_vararrayV(ncap);
- return status;
- }
- assert(ncap->nelems == ref->nelems);
- return NC_NOERR;
- }
- /*
- * Add a new handle on the end of an array of handles
- * Formerly
- NC_incr_array(array, tail)
- */
- static int
- incr_NC_vararray(NC_vararray *ncap, NC_var *newelemp)
- {
- NC_var **vp;
- assert(ncap != NULL);
- if(ncap->nalloc == 0)
- {
- assert(ncap->nelems == 0);
- vp = (NC_var **) malloc(NC_ARRAY_GROWBY * sizeof(NC_var *));
- if(vp == NULL)
- return NC_ENOMEM;
- ncap->value = vp;
- ncap->nalloc = NC_ARRAY_GROWBY;
- }
- else if(ncap->nelems +1 > ncap->nalloc)
- {
- vp = (NC_var **) realloc(ncap->value,
- (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_var *));
- if(vp == NULL)
- return NC_ENOMEM;
- ncap->value = vp;
- ncap->nalloc += NC_ARRAY_GROWBY;
- }
- if(newelemp != NULL)
- {
- ncap->value[ncap->nelems] = newelemp;
- ncap->nelems++;
- }
- return NC_NOERR;
- }
- static NC_var *
- elem_NC_vararray(const NC_vararray *ncap, size_t elem)
- {
- assert(ncap != NULL);
- /* cast needed for braindead systems with signed size_t */
- if(ncap->nelems == 0 || (unsigned long)elem >= ncap->nelems)
- return NULL;
- assert(ncap->value != NULL);
- return ncap->value[elem];
- }
- /* End vararray per se */
- /*
- * Step thru NC_VARIABLE array, seeking match on name.
- * Return varid or -1 on not found.
- * *varpp is set to the appropriate NC_var.
- * Formerly (sort of)
- NC_hvarid
- */
- int
- NC_findvar(const NC_vararray *ncap, const char *uname, NC_var **varpp)
- {
- NC_var **loc;
- uint32_t shash;
- int varid;
- char *name;
- assert(ncap != NULL);
- if(ncap->nelems == 0)
- return -1;
- loc = (NC_var **) ncap->value;
- /* normalized version of uname */
- name = (char *)utf8proc_NFC((const unsigned char *)uname);
- if(name == NULL)
- return NC_ENOMEM;
- shash = hash_fast(name, strlen(name));
- for(varid = 0; (size_t) varid < ncap->nelems; varid++, loc++)
- {
- if((*loc)->hash == shash &&
- strncmp((*loc)->name->cp, name, strlen(name)) == 0)
- {
- if(varpp != NULL)
- *varpp = *loc;
- free(name);
- return(varid); /* Normal return */
- }
- }
- free(name);
- return(-1); /* not found */
- }
- /*
- * For a netcdf type
- * return the size of one element in the external representation.
- * Note that arrays get rounded up to X_ALIGN boundaries.
- * Formerly
- NC_xtypelen
- * See also ncx_len()
- */
- size_t
- ncx_szof(nc_type type)
- {
- switch(type){
- case NC_BYTE:
- case NC_CHAR:
- return(1);
- case NC_SHORT :
- return(2);
- case NC_INT:
- return X_SIZEOF_INT;
- case NC_FLOAT:
- return X_SIZEOF_FLOAT;
- case NC_DOUBLE :
- return X_SIZEOF_DOUBLE;
- default:
- assert("ncx_szof invalid type" == 0);
- return 0;
- }
- }
- /*
- * 'compile' the shape and len of a variable
- * Formerly
- NC_var_shape(var, dims)
- */
- int
- NC_var_shape(NC_var *varp, const NC_dimarray *dims)
- {
- size_t *shp, *op;
- off_t *dsp;
- int *ip;
- const NC_dim *dimp;
- off_t product = 1;
-
- varp->xsz = ncx_szof(varp->type);
- if(varp->ndims == 0)
- {
- goto out;
- }
- /*
- * use the user supplied dimension indices
- * to determine the shape
- */
- for(ip = varp->dimids, op = varp->shape
- ; ip < &varp->dimids[varp->ndims]; ip++, op++)
- {
- if(*ip < 0 || (size_t) (*ip) >= ((dims != NULL) ? dims->nelems : 1) )
- return NC_EBADDIM;
-
- dimp = elem_NC_dimarray(dims, (size_t)*ip);
- *op = dimp->size;
- if(*op == NC_UNLIMITED && ip != varp->dimids)
- return NC_EUNLIMPOS;
- }
- /*
- * Compute the dsizes
- */
- /* ndims is > 0 here */
- for(shp = varp->shape + varp->ndims -1,
- dsp = varp->dsizes + varp->ndims -1;
- shp >= varp->shape;
- shp--, dsp--)
- {
- if(!(shp == varp->shape && IS_RECVAR(varp)))
- {
- if( (off_t)(*shp) <= OFF_T_MAX / product )
- {
- product *= *shp;
- } else
- {
- product = OFF_T_MAX ;
- }
- }
- *dsp = product;
- }
- out :
- if( varp->xsz <= (X_UINT_MAX - 1) / product ) /* if integer multiply will not overflow */
- {
- varp->len = product * varp->xsz;
- switch(varp->type) {
- case NC_BYTE :
- case NC_CHAR :
- case NC_SHORT :
- if( varp->len%4 != 0 )
- {
- varp->len += 4 - varp->len%4; /* round up */
- /* *dsp += 4 - *dsp%4; */
- }
- break;
- default:
- /* already aligned */
- break;
- }
- } else
- { /* OK for last var to be "too big", indicated by this special len */
- varp->len = X_UINT_MAX;
- }
- #if 0
- arrayp("\tshape", varp->ndims, varp->shape);
- arrayp("\tdsizes", varp->ndims, varp->dsizes);
- #endif
- return NC_NOERR;
- }
- /*
- * Check whether variable size is less than or equal to vlen_max,
- * without overflowing in arithmetic calculations. If OK, return 1,
- * else, return 0. For CDF1 format or for CDF2 format on non-LFS
- * platforms, vlen_max should be 2^31 - 4, but for CDF2 format on
- * systems with LFS it should be 2^32 - 4.
- */
- int
- NC_check_vlen(NC_var *varp, size_t vlen_max) {
- size_t prod=varp->xsz; /* product of xsz and dimensions so far */
- int ii;
- assert(varp != NULL);
- for(ii = IS_RECVAR(varp) ? 1 : 0; ii < varp->ndims; ii++) {
- if (varp->shape[ii] > vlen_max / prod) {
- return 0; /* size in bytes won't fit in a 32-bit int */
- }
- prod *= varp->shape[ii];
- }
- return 1; /* OK */
- }
- /*
- * Given valid ncp and varid, return var
- * else NULL on error
- * Formerly
- NC_hlookupvar()
- */
- NC_var *
- NC_lookupvar(NC *ncp, int varid)
- {
- NC_var *varp;
- if(varid == NC_GLOBAL)
- {
- /* Global is error in this context */
- return(NULL);
- }
- varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
- if(varp == NULL)
- {
- return NULL;
- }
- assert(varp != NULL);
- return(varp);
- }
- /* Public */
- int
- NC3_def_var( int ncid, const char *name, nc_type type,
- int ndims, const int *dimids, int *varidp)
- {
- int status;
- NC *ncp;
- int varid;
- NC_var *varp;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- if(!NC_indef(ncp))
- {
- return NC_ENOTINDEFINE;
- }
- status = NC_check_name(name);
- if(status != NC_NOERR)
- return status;
- status = nc_cktype(type);
- if(status != NC_NOERR)
- return status;
- /* cast needed for braindead systems with signed size_t */
- if((unsigned long) ndims > X_INT_MAX) /* Backward compat */
- {
- return NC_EINVAL;
- }
- if(ncp->vars.nelems >= NC_MAX_VARS)
- {
- return NC_EMAXVARS;
- }
- varid = NC_findvar(&ncp->vars, name, &varp);
- if(varid != -1)
- {
- return NC_ENAMEINUSE;
- }
-
- varp = new_NC_var(name, type, ndims, dimids);
- if(varp == NULL)
- return NC_ENOMEM;
- status = NC_var_shape(varp, &ncp->dims);
- if(status != NC_NOERR)
- {
- free_NC_var(varp);
- return status;
- }
- status = incr_NC_vararray(&ncp->vars, varp);
- if(status != NC_NOERR)
- {
- free_NC_var(varp);
- return status;
- }
- if(varidp != NULL)
- *varidp = (int)ncp->vars.nelems -1; /* varid */
- return NC_NOERR;
- }
- int
- NC3_inq_varid(int ncid, const char *name, int *varid_ptr)
- {
- int status;
- NC *ncp;
- NC_var *varp;
- int varid;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- varid = NC_findvar(&ncp->vars, name, &varp);
- if(varid == -1)
- {
- return NC_ENOTVAR;
- }
- *varid_ptr = varid;
- return NC_NOERR;
- }
- int
- NC3_inq_var(int ncid,
- int varid,
- char *name,
- nc_type *typep,
- int *ndimsp,
- int *dimids,
- int *nattsp)
- {
- int status;
- NC *ncp;
- NC_var *varp;
- size_t ii;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
- if(varp == NULL)
- return NC_ENOTVAR;
- if(name != NULL)
- {
- (void) strncpy(name, varp->name->cp, varp->name->nchars);
- name[varp->name->nchars] = 0;
- }
- if(typep != 0)
- *typep = varp->type;
- if(ndimsp != 0)
- {
- *ndimsp = (int) varp->ndims;
- }
- if(dimids != 0)
- {
- for(ii = 0; ii < varp->ndims; ii++)
- {
- dimids[ii] = varp->dimids[ii];
- }
- }
- if(nattsp != 0)
- {
- *nattsp = (int) varp->attrs.nelems;
- }
- return NC_NOERR;
- }
- int
- NC3_rename_var(int ncid, int varid, const char *unewname)
- {
- int status;
- NC *ncp;
- NC_var *varp;
- NC_string *old, *newStr;
- int other;
- char *newname; /* normalized */
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- if(NC_readonly(ncp))
- {
- return NC_EPERM;
- }
- status = NC_check_name(unewname);
- if(status != NC_NOERR)
- return status;
- /* check for name in use */
- other = NC_findvar(&ncp->vars, unewname, &varp);
- if(other != -1)
- {
- return NC_ENAMEINUSE;
- }
-
- varp = NC_lookupvar(ncp, varid);
- if(varp == NULL)
- {
- /* invalid varid */
- return NC_ENOTVAR; /* TODO: is this the right error code? */
- }
- old = varp->name;
- newname = (char *)utf8proc_NFC((const unsigned char *)unewname);
- if(newname == NULL)
- return NC_ENOMEM;
- if(NC_indef(ncp))
- {
- newStr = new_NC_string(strlen(newname),newname);
- free(newname);
- if(newStr == NULL)
- return(-1);
- varp->name = newStr;
- varp->hash = hash_fast(newStr->cp, strlen(newStr->cp));
- free_NC_string(old);
- return NC_NOERR;
- }
- /* else, not in define mode */
- status = set_NC_string(varp->name, newname);
- varp->hash = hash_fast(newname, strlen(newname));
- free(newname);
- if(status != NC_NOERR)
- return status;
- set_NC_hdirty(ncp);
- if(NC_doHsync(ncp))
- {
- status = NC_sync(ncp);
- if(status != NC_NOERR)
- return status;
- }
- return NC_NOERR;
- }
|