1/*
2 * Copyright 1996, University Corporation for Atmospheric Research
3 *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 */
5/* $Id: var.c,v 1.144 2010/05/30 00:50:35 russ Exp $ */
6
7#include "config.h"
8#include "nc3internal.h"
9#include <stdlib.h>
10#include <string.h>
11#include <assert.h>
12#include <limits.h>
13#include "ncx.h"
14#include "rnd.h"
15#include "utf8proc.h"
16
17#ifndef OFF_T_MAX
18//#define OFF_T_MAX (~ (off_t) 0 - (~ (off_t) 0 << (CHAR_BIT * sizeof (off_t) - 1)))
19
20/* The behavior above is undefined, re: bitshifting a negative value, according
21   to warnings thrown by clang/gcc.  An alternative OFF_T_MAX was written
22   based on info found at:
23   * http://stackoverflow.com/questions/4514572/c-question-off-t-and-other-signed-integer-types-minimum-and-maximum-values
24   */
25#define MAX_INT_VAL_STEP(t) \
26    ((t) 1 << (CHAR_BIT * sizeof(t) - 1 - ((t) -1 < 1)))
27
28#define MAX_INT_VAL(t) \
29    ((MAX_INT_VAL_STEP(t) - 1) + MAX_INT_VAL_STEP(t))
30
31#define MIN_INT_VAL(t) \
32    ((t) -MAX_INT_VAL(t) - 1)
33
34#define OFF_T_MAX MAX_INT_VAL(off_t)
35
36#endif
37
38/*
39 * Free var
40 * Formerly NC_free_var(var)
41 */
42void
43free_NC_var(NC_var *varp)
44{
45 if(varp == NULL)
46 return;
47 free_NC_attrarrayV(&varp->attrs);
48 free_NC_string(varp->name);
49#ifndef MALLOCHACK
50 if(varp->dimids != NULL) free(varp->dimids);
51 if(varp->shape != NULL) free(varp->shape);
52 if(varp->dsizes != NULL) free(varp->dsizes);
53#endif /*!MALLOCHACK*/
54 free(varp);
55}
56
57
58/*
59 * Common code for new_NC_var()
60 * and ncx_get_NC_var()
61 */
62NC_var *
63new_x_NC_var(
64 NC_string *strp,
65 size_t ndims)
66{
67 NC_var *varp;
68 const size_t o1 = M_RNDUP(ndims * sizeof(int));
69 const size_t o2 = M_RNDUP(ndims * sizeof(size_t));
70
71#ifdef MALLOCHACK
72 const size_t sz =  M_RNDUP(sizeof(NC_var)) +
73  o1 + o2 + ndims * sizeof(off_t);
74#else /*!MALLOCHACK*/
75 const size_t o3 = ndims * sizeof(off_t);
76 const size_t sz = sizeof(NC_var);
77#endif /*!MALLOCHACK*/
78
79 varp = (NC_var *) malloc(sz);
80 if(varp == NULL )
81 return NULL;
82 (void) memset(varp, 0, sz);
83 varp->name = strp;
84 varp->ndims = ndims;
85
86 if(ndims != 0)
87 {
88#ifdef MALLOCHACK
89   /*
90    * NOTE: lint may complain about the next 3 lines:
91    * "pointer cast may result in improper alignment".
92    * We use the M_RNDUP() macro to get the proper alignment.
93    */
94   varp->dimids = (int *)((char *)varp + M_RNDUP(sizeof(NC_var)));
95   varp->shape = (size_t *)((char *)varp->dimids + o1);
96   varp->dsizes = (off_t *)((char *)varp->shape + o2);
97#else /*!MALLOCHACK*/
98   varp->dimids = (int*)malloc(o1);
99   varp->shape = (size_t*)malloc(o2);
100   varp->dsizes = (off_t*)malloc(o3);
101#endif /*!MALLOCHACK*/
102 } else {
103   varp->dimids = NULL;
104   varp->shape = NULL;
105   varp->dsizes=NULL;
106 }
107
108
109 varp->xsz = 0;
110 varp->len = 0;
111 varp->begin = 0;
112
113 return varp;
114}
115
116
117/*
118 * Formerly
119NC_new_var()
120 */
121static NC_var *
122new_NC_var(const char *unamenc_type type,
123 size_t ndims, const int *dimids)
124{
125 NC_string *strp = NULL;
126 NC_var *varp = NULL;
127
128 char *name = (char *)utf8proc_NFC((const unsigned char *)uname);
129 if(name == NULL)
130     return NULL;
131 strp = new_NC_string(strlen(name), name);
132 free(name);
133 if(strp == NULL)
134   return NULL;
135
136 varp = new_x_NC_var(strpndims);
137 if(varp == NULL )
138 {
139 free_NC_string(strp);
140 return NULL;
141 }
142
143 varp->type = type;
144
145 if( ndims != 0 && dimids != NULL)
146   (void) memcpy(varp->dimidsdimidsndims * sizeof(int));
147    else
148      varp->dimids=NULL;
149
150
151 return(varp);
152}
153
154
155static NC_var *
156dup_NC_var(const NC_var *rvarp)
157{
158 NC_var *varp = new_NC_var(rvarp->name->cprvarp->type,
159  rvarp->ndimsrvarp->dimids);
160 if(varp == NULL)
161 return NULL;
162
163
164 if(dup_NC_attrarrayV(&varp->attrs, &rvarp->attrs) != NC_NOERR)
165 {
166 free_NC_var(varp);
167 return NULL;
168 }
169
170 (void) memcpy(varp->shapervarp->shape,
171  rvarp->ndims * sizeof(size_t));
172 (void) memcpy(varp->dsizesrvarp->dsizes,
173  rvarp->ndims * sizeof(size_t));
174 varp->xsz = rvarp->xsz;
175 varp->len = rvarp->len;
176 varp->begin = rvarp->begin;
177
178 return varp;
179}
180
181
182/* vararray */
183
184
185/*
186 * Free the stuff "in" (referred to by) an NC_vararray.
187 * Leaves the array itself allocated.
188 */
189void
190free_NC_vararrayV0(NC_vararray *ncap)
191{
192 assert(ncap != NULL);
193
194 if(ncap->nelems == 0)
195 return;
196
197 assert(ncap->value != NULL);
198
199 {
200 NC_var **vpp = ncap->value;
201 NC_var *const *const end = &vpp[ncap->nelems];
202 for( /*NADA*/; vpp < endvpp++)
203 {
204 free_NC_var(*vpp);
205 *vpp = NULL;
206 }
207 }
208 ncap->nelems = 0;
209}
210
211
212/*
213 * Free NC_vararray values.
214 * formerly
215NC_free_array()
216 */
217void
218free_NC_vararrayV(NC_vararray *ncap)
219{
220 assert(ncap != NULL);
221
222 if(ncap->nalloc == 0)
223 return;
224
225 NC_hashmapDelete(ncap->hashmap);
226 ncap->hashmap = NULL;
227
228 assert(ncap->value != NULL);
229
230 free_NC_vararrayV0(ncap);
231
232 free(ncap->value);
233 ncap->value = NULL;
234 ncap->nalloc = 0;
235}
236
237
238int
239dup_NC_vararrayV(NC_vararray *ncap, const NC_vararray *ref)
240{
241 int status = NC_NOERR;
242
243 assert(ref != NULL);
244 assert(ncap != NULL);
245
246 if(ref->nelems != 0)
247 {
248 const size_t sz = ref->nelems * sizeof(NC_var *);
249 ncap->value = (NC_var **) malloc(sz);
250 if(ncap->value == NULL)
251 return NC_ENOMEM;
252 (void) memset(ncap->value, 0, sz);
253 ncap->nalloc = ref->nelems;
254 }
255
256 ncap->nelems = 0;
257 {
258 NC_var **vpp = ncap->value;
259 const NC_var **drpp = (const NC_var **)ref->value;
260 NC_var *const *const end = &vpp[ref->nelems];
261 for( /*NADA*/; vpp < enddrpp++, vpp++, ncap->nelems++)
262 {
263 *vpp = dup_NC_var(*drpp);
264 if(*vpp == NULL)
265 {
266 status = NC_ENOMEM;
267 break;
268 }
269 }
270 }
271
272 if(status != NC_NOERR)
273 {
274 free_NC_vararrayV(ncap);
275 return status;
276 }
277
278 assert(ncap->nelems == ref->nelems);
279
280 return NC_NOERR;
281}
282
283
284/*
285 * Add a new handle on the end of an array of handles
286 * Formerly
287NC_incr_array(array, tail)
288 */
289static int
290incr_NC_vararray(NC_vararray *ncapNC_var *newelemp)
291{
292 NC_var **vp;
293
294 assert(ncap != NULL);
295
296 if(ncap->nalloc == 0)
297 {
298 assert(ncap->nelems == 0);
299 vp = (NC_var **) malloc(NC_ARRAY_GROWBY * sizeof(NC_var *));
300 if(vp == NULL)
301 return NC_ENOMEM;
302 ncap->value = vp;
303 ncap->nalloc = NC_ARRAY_GROWBY;
304
305 ncap->hashmap = NC_hashmapCreate(0);
306 }
307 else if(ncap->nelems +1 > ncap->nalloc)
308 {
309 vp = (NC_var **) realloc(ncap->value,
310 (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_var *));
311 if(vp == NULL)
312 return NC_ENOMEM;
313 ncap->value = vp;
314 ncap->nalloc += NC_ARRAY_GROWBY;
315 }
316
317 if(newelemp != NULL)
318 {
319 NC_hashmapAddVar(ncap, (long)ncap->nelemsnewelemp->name->cp);
320 ncap->value[ncap->nelems] = newelemp;
321 ncap->nelems++;
322 }
323 return NC_NOERR;
324}
325
326
327static NC_var *
328elem_NC_vararray(const NC_vararray *ncap, size_t elem)
329{
330 assert(ncap != NULL);
331 /* cast needed for braindead systems with signed size_t */
332 if(ncap->nelems == 0 || (unsigned long)elem >= ncap->nelems)
333 return NULL;
334
335 assert(ncap->value != NULL);
336
337 return ncap->value[elem];
338}
339
340
341/* End vararray per se */
342
343
344/*
345 * Step thru NC_VARIABLE array, seeking match on name.
346 * Return varid or -1 on not found.
347 * *varpp is set to the appropriate NC_var.
348 * Formerly (sort of)
349NC_hvarid
350 */
351int
352NC_findvar(const NC_vararray *ncap, const char *unameNC_var **varpp)
353{
354 int hash_var_id;
355 char *name;
356
357 assert(ncap != NULL);
358
359 if(ncap->nelems == 0)
360 return -1;
361
362
363 /* normalized version of uname */
364 name = (char *)utf8proc_NFC((const unsigned char *)uname);
365 if(name == NULL)
366     return NC_ENOMEM;
367
368 hash_var_id = (int)NC_hashmapGetVar(ncapname);
369 free(name);
370 if (hash_var_id >= 0) {
371   if (varpp != NULL)
372     *varpp = ncap->value[hash_var_id];
373   return(hash_var_id); /* Normal return */
374 }
375 return(-1); /* not found */
376}
377
378/*
379 * For a netcdf type
380 *  return the size of one element in the external representation.
381 * Note that arrays get rounded up to X_ALIGN boundaries.
382 * Formerly
383NC_xtypelen
384 * See also ncx_len()
385 */
386size_t
387ncx_szof(nc_type type)
388{
389 switch(type){
390 case NC_BYTE:
391 case NC_CHAR:
392 case NC_UBYTE:
393 return(1);
394 case NC_SHORT :
395 return(2);
396 case NC_INT:
397 return X_SIZEOF_INT;
398 case NC_FLOAT:
399 return X_SIZEOF_FLOAT;
400 case NC_DOUBLE :
401 return X_SIZEOF_DOUBLE;
402 case NC_USHORT :
403 return X_SIZEOF_USHORT;
404 case NC_UINT :
405 return X_SIZEOF_UINT;
406 case NC_INT64 :
407 return X_SIZEOF_INT64;
408 case NC_UINT64 :
409 return X_SIZEOF_UINT64;
410 default:
411         assert("ncx_szof invalid type" == 0);
412         return 0;
413 }
414}
415
416
417/*
418 * 'compile' the shape and len of a variable
419 *  Formerly
420NC_var_shape(var, dims)
421 */
422int
423NC_var_shape(NC_var *varp, const NC_dimarray *dims)
424{
425 size_t *shp, *op;
426 off_t *dsp;
427 int *ip = NULL;
428 const NC_dim *dimp;
429 off_t product = 1;
430
431 varp->xsz = ncx_szof(varp->type);
432
433 if(varp->ndims == 0 || varp->dimids == NULL)
434 {
435 goto out;
436 }
437
438 /*
439  * use the user supplied dimension indices
440  * to determine the shape
441  */
442 for(ip = varp->dimidsop = varp->shape
443          ; ip < &varp->dimids[varp->ndims]; ip++, op++)
444 {
445 if(*ip < 0 || (size_t) (*ip) >= ((dims != NULL) ? dims->nelems : 1) )
446 return NC_EBADDIM;
447
448 dimp = elem_NC_dimarray(dims, (size_t)*ip);
449 *op = dimp->size;
450 if(*op == NC_UNLIMITED && ip != varp->dimids)
451 return NC_EUNLIMPOS;
452 }
453
454 /*
455  * Compute the dsizes
456  */
457 /* ndims is > 0 here */
458 for(shp = varp->shape + varp->ndims -1,
459 dsp = varp->dsizes + varp->ndims -1;
460  shp >= varp->shape;
461 shp--, dsp--)
462 {
463      /*if(!(shp == varp->shape && IS_RECVAR(varp)))*/
464      if( shp != NULL && (shp != varp->shape || !IS_RECVAR(varp)))
465 {
466          if( ((off_t)(*shp)) <= OFF_T_MAX / product )
467 {
468              product *= (*shp > 0 ? *shp : 1);
469 } else
470 {
471              product = OFF_T_MAX ;
472 }
473 }
474      *dsp = product;
475 }
476
477
478out :
479    if( varp->xsz <= (X_UINT_MAX - 1) / product ) /* if integer multiply will not overflow */
480 {
481         varp->len = product * varp->xsz;
482 switch(varp->type) {
483 case NC_BYTE :
484 case NC_CHAR :
485 case NC_UBYTE :
486 case NC_SHORT :
487         if( varp->len%4 != 0 )
488 {
489         varp->len += 4 - varp->len%4; /* round up */
490 /* *dsp += 4 - *dsp%4; */
491     }
492     break;
493 default:
494 /* already aligned */
495 break;
496 }
497        } else
498 { /* OK for last var to be "too big", indicated by this special len */
499         varp->len = X_UINT_MAX;
500        }
501#if 0
502 arrayp("\tshape", varp->ndimsvarp->shape);
503 arrayp("\tdsizes", varp->ndimsvarp->dsizes);
504#endif
505 return NC_NOERR;
506}
507
508/*
509 * Check whether variable size is less than or equal to vlen_max,
510 * without overflowing in arithmetic calculations.  If OK, return 1,
511 * else, return 0.  For CDF1 format or for CDF2 format on non-LFS
512 * platforms, vlen_max should be 2^31 - 4, but for CDF2 format on
513 * systems with LFS it should be 2^32 - 4.
514 */
515int
516NC_check_vlen(NC_var *varp, size_t vlen_max) {
517    size_t prod=varp->xsz; /* product of xsz and dimensions so far */
518
519    int ii;
520
521    assert(varp != NULL);
522    for(ii = IS_RECVAR(varp) ? 1 : 0; ii < varp->ndimsii++) {
523      if(!varp->shape)
524        return 0; /* Shape is undefined/NULL. */
525      if (varp->shape[ii] > vlen_max / prod) {
526        return 0; /* size in bytes won't fit in a 32-bit int */
527      }
528      prod *= varp->shape[ii];
529    }
530    return 1; /* OK */
531}
532
533
534/*! Look up a variable by varid.
535 *
536 * Given a valid ncp structure and varid, return the var.
537 *
538 * Formerly NC_hlookupvar()
539 *
540 * @param[in] ncp NC3_INFO data structure.
541 * @param[in] varid The varid key for the var we are looking up.
542 * @param[out] varp Data structure to contain the varp pointer.
543 * @return Error code, if one exists, 0 otherwise.
544 */
545
546int NC_lookupvar(NC3_INFOncp, int varidNC_var **varp)
547{
548  if(varid == NC_GLOBAL)
549 {
550      /* Global is error in this context */
551      return NC_EGLOBAL;
552 }
553
554  if(varp)
555    *varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
556  else
557    return NC_ENOTVAR;
558
559  if(*varp == NULL)
560    return NC_ENOTVAR;
561
562  return NC_NOERR;
563
564}
565
566
567/* Public */
568
569int
570NC3_def_var( int ncid, const char *namenc_type type,
571  int ndims, const int *dimids, int *varidp)
572{
573 int status;
574 NC *nc;
575 NC3_INFOncp;
576 int varid;
577 NC_var *varp = NULL;
578
579 status = NC_check_id(ncid, &nc);
580 if(status != NC_NOERR)
581 return status;
582 ncp = NC3_DATA(nc);
583
584 if(!NC_indef(ncp))
585 {
586 return NC_ENOTINDEFINE;
587 }
588
589 status = NC_check_name(name);
590 if(status != NC_NOERR)
591 return status;
592
593 status = nc3_cktype(nc->modetype);
594 if(status != NC_NOERR)
595 return status;
596
597 /* cast needed for braindead systems with signed size_t */
598 if((unsigned long) ndims > X_INT_MAX) /* Backward compat */
599 {
600 return NC_EINVAL;
601 }
602
603 if(ncp->vars.nelems >= NC_MAX_VARS)
604 {
605 return NC_EMAXVARS;
606 }
607
608 varid = NC_findvar(&ncp->varsname, &varp);
609 if(varid != -1)
610 {
611 return NC_ENAMEINUSE;
612 }
613
614 varp = new_NC_var(nametypendimsdimids);
615 if(varp == NULL)
616 return NC_ENOMEM;
617
618 status = NC_var_shape(varp, &ncp->dims);
619 if(status != NC_NOERR)
620 {
621 free_NC_var(varp);
622 return status;
623 }
624
625 status = incr_NC_vararray(&ncp->varsvarp);
626 if(status != NC_NOERR)
627 {
628 free_NC_var(varp);
629 return status;
630 }
631
632 if(varidp != NULL)
633 *varidp = (int)ncp->vars.nelems -1; /* varid */
634 return NC_NOERR;
635}
636
637
638int
639NC3_inq_varid(int ncid, const char *name, int *varid_ptr)
640{
641 int status;
642 NC *nc;
643 NC3_INFOncp;
644 NC_var *varp;
645 int varid;
646
647 status = NC_check_id(ncid, &nc);
648 if(status != NC_NOERR)
649 return status;
650 ncp = NC3_DATA(nc);
651
652 varid = NC_findvar(&ncp->varsname, &varp);
653 if(varid == -1)
654 {
655 return NC_ENOTVAR;
656 }
657
658 *varid_ptr = varid;
659 return NC_NOERR;
660}
661
662
663int
664NC3_inq_var(int ncid,
665 int varid,
666 char *name,
667 nc_type *typep,
668 int *ndimsp,
669 int *dimids,
670 int *nattsp)
671{
672 int status;
673 NC *nc;
674 NC3_INFOncp;
675 NC_var *varp;
676 size_t ii;
677
678 status = NC_check_id(ncid, &nc);
679 if(status != NC_NOERR)
680 return status;
681 ncp = NC3_DATA(nc);
682
683 varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
684 if(varp == NULL)
685 return NC_ENOTVAR;
686
687 if(name != NULL)
688 {
689 (void) strncpy(namevarp->name->cpvarp->name->nchars);
690 name[varp->name->nchars] = 0;
691 }
692
693 if(typep != 0)
694 *typep = varp->type;
695 if(ndimsp != 0)
696 {
697 *ndimsp = (int) varp->ndims;
698 }
699 if(dimids != 0)
700 {
701 for(ii = 0; ii < varp->ndimsii++)
702 {
703 dimids[ii] = varp->dimids[ii];
704 }
705 }
706 if(nattsp != 0)
707 {
708 *nattsp = (int) varp->attrs.nelems;
709 }
710
711 return NC_NOERR;
712}
713
714int
715NC3_rename_var(int ncid, int varid, const char *unewname)
716{
717 int status;
718 NC *nc;
719 NC3_INFOncp;
720 NC_var *varp;
721 NC_string *old, *newStr;
722 int other;
723 char *newname; /* normalized */
724
725 status = NC_check_id(ncid, &nc);
726 if(status != NC_NOERR)
727 return status;
728 ncp = NC3_DATA(nc);
729
730 if(NC_readonly(ncp))
731 {
732 return NC_EPERM;
733 }
734
735 status = NC_check_name(unewname);
736 if(status != NC_NOERR)
737 return status;
738
739 /* check for name in use */
740 other = NC_findvar(&ncp->varsunewname, &varp);
741 if(other != -1)
742 {
743 return NC_ENAMEINUSE;
744 }
745
746 status = NC_lookupvar(ncpvarid, &varp);
747 if(status != NC_NOERR)
748 {
749 /* invalid varid */
750 return status;
751 }
752
753
754 old = varp->name;
755 newname = (char *)utf8proc_NFC((const unsigned char *)unewname);
756 if(newname == NULL)
757     return NC_ENOMEM;
758 if(NC_indef(ncp))
759 {
760 /* Remove old name from hashmap; add new... */
761 NC_hashmapRemoveVar(&ncp->varsold->cp);
762
763 newStr = new_NC_string(strlen(newname),newname);
764 free(newname);
765 if(newStr == NULL)
766 return(-1);
767 varp->name = newStr;
768 NC_hashmapAddVar(&ncp->varsvaridnewStr->cp);
769 free_NC_string(old);
770
771 return NC_NOERR;
772 }
773
774 /* else, not in define mode */
775 /* Remove old name from hashmap; add new... */
776 NC_hashmapRemoveVar(&ncp->varsold->cp);
777
778 status = set_NC_string(varp->namenewname);
779 free(newname);
780 if(status != NC_NOERR)
781 return status;
782
783 NC_hashmapAddVar(&ncp->varsvaridvarp->name->cp);
784
785 set_NC_hdirty(ncp);
786
787 if(NC_doHsync(ncp))
788 {
789 status = NC_sync(ncp);
790 if(status != NC_NOERR)
791 return status;
792 }
793
794 return NC_NOERR;
795}


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed