var.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  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. #include "nc.h"
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <assert.h>
  10. #include <limits.h>
  11. #include "ncx.h"
  12. #include "rnd.h"
  13. #include "utf8proc.h"
  14. #ifndef OFF_T_MAX
  15. #define OFF_T_MAX (~ (off_t) 0 - (~ (off_t) 0 << (CHAR_BIT * sizeof (off_t) - 1)))
  16. #endif
  17. /*
  18. * Free var
  19. * Formerly
  20. NC_free_var(var)
  21. */
  22. void
  23. free_NC_var(NC_var *varp)
  24. {
  25. if(varp == NULL)
  26. return;
  27. free_NC_attrarrayV(&varp->attrs);
  28. free_NC_string(varp->name);
  29. #ifndef MALLOCHACK
  30. if(varp->dimids != NULL) free(varp->dimids);
  31. if(varp->shape != NULL) free(varp->shape);
  32. if(varp->dsizes != NULL) free(varp->dsizes);
  33. #endif /*!MALLOCHACK*/
  34. free(varp);
  35. }
  36. /*
  37. * Common code for new_NC_var()
  38. * and ncx_get_NC_var()
  39. */
  40. NC_var *
  41. new_x_NC_var(
  42. NC_string *strp,
  43. size_t ndims)
  44. {
  45. NC_var *varp;
  46. const size_t o1 = M_RNDUP(ndims * sizeof(int));
  47. const size_t o2 = M_RNDUP(ndims * sizeof(size_t));
  48. #ifdef MALLOCHACK
  49. const size_t sz = M_RNDUP(sizeof(NC_var)) +
  50. o1 + o2 + ndims * sizeof(off_t);
  51. #else /*!MALLOCHACK*/
  52. const size_t o3 = ndims * sizeof(off_t);
  53. const size_t sz = sizeof(NC_var);
  54. #endif /*!MALLOCHACK*/
  55. varp = (NC_var *) malloc(sz);
  56. if(varp == NULL )
  57. return NULL;
  58. (void) memset(varp, 0, sz);
  59. varp->name = strp;
  60. varp->ndims = ndims;
  61. varp->hash = hash_fast(strp->cp, strlen(strp->cp));
  62. if(ndims != 0)
  63. {
  64. #ifdef MALLOCHACK
  65. /*
  66. * NOTE: lint may complain about the next 3 lines:
  67. * "pointer cast may result in improper alignment".
  68. * We use the M_RNDUP() macro to get the proper alignment.
  69. */
  70. varp->dimids = (int *)((char *)varp + M_RNDUP(sizeof(NC_var)));
  71. varp->shape = (size_t *)((char *)varp->dimids + o1);
  72. varp->dsizes = (off_t *)((char *)varp->shape + o2);
  73. #else /*!MALLOCHACK*/
  74. varp->dimids = (int*)malloc(o1);
  75. varp->shape = (size_t*)malloc(o2);
  76. varp->dsizes = (off_t*)malloc(o3);
  77. #endif /*!MALLOCHACK*/
  78. }
  79. varp->xsz = 0;
  80. varp->len = 0;
  81. varp->begin = 0;
  82. return varp;
  83. }
  84. /*
  85. * Formerly
  86. NC_new_var()
  87. */
  88. static NC_var *
  89. new_NC_var(const char *uname, nc_type type,
  90. size_t ndims, const int *dimids)
  91. {
  92. NC_string *strp;
  93. NC_var *varp;
  94. char *name = (char *)utf8proc_NFC((const unsigned char *)uname);
  95. if(name == NULL)
  96. return NULL;
  97. strp = new_NC_string(strlen(name), name);
  98. free(name);
  99. if(strp == NULL)
  100. return NULL;
  101. varp = new_x_NC_var(strp, ndims);
  102. if(varp == NULL )
  103. {
  104. free_NC_string(strp);
  105. return NULL;
  106. }
  107. varp->type = type;
  108. if( ndims != 0 && dimids != NULL)
  109. (void) memcpy(varp->dimids, dimids, ndims * sizeof(int));
  110. return(varp);
  111. }
  112. static NC_var *
  113. dup_NC_var(const NC_var *rvarp)
  114. {
  115. NC_var *varp = new_NC_var(rvarp->name->cp, rvarp->type,
  116. rvarp->ndims, rvarp->dimids);
  117. if(varp == NULL)
  118. return NULL;
  119. if(dup_NC_attrarrayV(&varp->attrs, &rvarp->attrs) != NC_NOERR)
  120. {
  121. free_NC_var(varp);
  122. return NULL;
  123. }
  124. (void) memcpy(varp->shape, rvarp->shape,
  125. rvarp->ndims * sizeof(size_t));
  126. (void) memcpy(varp->dsizes, rvarp->dsizes,
  127. rvarp->ndims * sizeof(size_t));
  128. varp->xsz = rvarp->xsz;
  129. varp->len = rvarp->len;
  130. varp->begin = rvarp->begin;
  131. return varp;
  132. }
  133. /* vararray */
  134. /*
  135. * Free the stuff "in" (referred to by) an NC_vararray.
  136. * Leaves the array itself allocated.
  137. */
  138. void
  139. free_NC_vararrayV0(NC_vararray *ncap)
  140. {
  141. assert(ncap != NULL);
  142. if(ncap->nelems == 0)
  143. return;
  144. assert(ncap->value != NULL);
  145. {
  146. NC_var **vpp = ncap->value;
  147. NC_var *const *const end = &vpp[ncap->nelems];
  148. for( /*NADA*/; vpp < end; vpp++)
  149. {
  150. free_NC_var(*vpp);
  151. *vpp = NULL;
  152. }
  153. }
  154. ncap->nelems = 0;
  155. }
  156. /*
  157. * Free NC_vararray values.
  158. * formerly
  159. NC_free_array()
  160. */
  161. void
  162. free_NC_vararrayV(NC_vararray *ncap)
  163. {
  164. assert(ncap != NULL);
  165. if(ncap->nalloc == 0)
  166. return;
  167. assert(ncap->value != NULL);
  168. free_NC_vararrayV0(ncap);
  169. free(ncap->value);
  170. ncap->value = NULL;
  171. ncap->nalloc = 0;
  172. }
  173. int
  174. dup_NC_vararrayV(NC_vararray *ncap, const NC_vararray *ref)
  175. {
  176. int status = NC_NOERR;
  177. assert(ref != NULL);
  178. assert(ncap != NULL);
  179. if(ref->nelems != 0)
  180. {
  181. const size_t sz = ref->nelems * sizeof(NC_var *);
  182. ncap->value = (NC_var **) malloc(sz);
  183. if(ncap->value == NULL)
  184. return NC_ENOMEM;
  185. (void) memset(ncap->value, 0, sz);
  186. ncap->nalloc = ref->nelems;
  187. }
  188. ncap->nelems = 0;
  189. {
  190. NC_var **vpp = ncap->value;
  191. const NC_var **drpp = (const NC_var **)ref->value;
  192. NC_var *const *const end = &vpp[ref->nelems];
  193. for( /*NADA*/; vpp < end; drpp++, vpp++, ncap->nelems++)
  194. {
  195. *vpp = dup_NC_var(*drpp);
  196. if(*vpp == NULL)
  197. {
  198. status = NC_ENOMEM;
  199. break;
  200. }
  201. }
  202. }
  203. if(status != NC_NOERR)
  204. {
  205. free_NC_vararrayV(ncap);
  206. return status;
  207. }
  208. assert(ncap->nelems == ref->nelems);
  209. return NC_NOERR;
  210. }
  211. /*
  212. * Add a new handle on the end of an array of handles
  213. * Formerly
  214. NC_incr_array(array, tail)
  215. */
  216. static int
  217. incr_NC_vararray(NC_vararray *ncap, NC_var *newelemp)
  218. {
  219. NC_var **vp;
  220. assert(ncap != NULL);
  221. if(ncap->nalloc == 0)
  222. {
  223. assert(ncap->nelems == 0);
  224. vp = (NC_var **) malloc(NC_ARRAY_GROWBY * sizeof(NC_var *));
  225. if(vp == NULL)
  226. return NC_ENOMEM;
  227. ncap->value = vp;
  228. ncap->nalloc = NC_ARRAY_GROWBY;
  229. }
  230. else if(ncap->nelems +1 > ncap->nalloc)
  231. {
  232. vp = (NC_var **) realloc(ncap->value,
  233. (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_var *));
  234. if(vp == NULL)
  235. return NC_ENOMEM;
  236. ncap->value = vp;
  237. ncap->nalloc += NC_ARRAY_GROWBY;
  238. }
  239. if(newelemp != NULL)
  240. {
  241. ncap->value[ncap->nelems] = newelemp;
  242. ncap->nelems++;
  243. }
  244. return NC_NOERR;
  245. }
  246. static NC_var *
  247. elem_NC_vararray(const NC_vararray *ncap, size_t elem)
  248. {
  249. assert(ncap != NULL);
  250. /* cast needed for braindead systems with signed size_t */
  251. if(ncap->nelems == 0 || (unsigned long)elem >= ncap->nelems)
  252. return NULL;
  253. assert(ncap->value != NULL);
  254. return ncap->value[elem];
  255. }
  256. /* End vararray per se */
  257. /*
  258. * Step thru NC_VARIABLE array, seeking match on name.
  259. * Return varid or -1 on not found.
  260. * *varpp is set to the appropriate NC_var.
  261. * Formerly (sort of)
  262. NC_hvarid
  263. */
  264. int
  265. NC_findvar(const NC_vararray *ncap, const char *uname, NC_var **varpp)
  266. {
  267. NC_var **loc;
  268. uint32_t shash;
  269. int varid;
  270. char *name;
  271. assert(ncap != NULL);
  272. if(ncap->nelems == 0)
  273. return -1;
  274. loc = (NC_var **) ncap->value;
  275. /* normalized version of uname */
  276. name = (char *)utf8proc_NFC((const unsigned char *)uname);
  277. if(name == NULL)
  278. return NC_ENOMEM;
  279. shash = hash_fast(name, strlen(name));
  280. for(varid = 0; (size_t) varid < ncap->nelems; varid++, loc++)
  281. {
  282. if((*loc)->hash == shash &&
  283. strncmp((*loc)->name->cp, name, strlen(name)) == 0)
  284. {
  285. if(varpp != NULL)
  286. *varpp = *loc;
  287. free(name);
  288. return(varid); /* Normal return */
  289. }
  290. }
  291. free(name);
  292. return(-1); /* not found */
  293. }
  294. /*
  295. * For a netcdf type
  296. * return the size of one element in the external representation.
  297. * Note that arrays get rounded up to X_ALIGN boundaries.
  298. * Formerly
  299. NC_xtypelen
  300. * See also ncx_len()
  301. */
  302. size_t
  303. ncx_szof(nc_type type)
  304. {
  305. switch(type){
  306. case NC_BYTE:
  307. case NC_CHAR:
  308. return(1);
  309. case NC_SHORT :
  310. return(2);
  311. case NC_INT:
  312. return X_SIZEOF_INT;
  313. case NC_FLOAT:
  314. return X_SIZEOF_FLOAT;
  315. case NC_DOUBLE :
  316. return X_SIZEOF_DOUBLE;
  317. default:
  318. assert("ncx_szof invalid type" == 0);
  319. return 0;
  320. }
  321. }
  322. /*
  323. * 'compile' the shape and len of a variable
  324. * Formerly
  325. NC_var_shape(var, dims)
  326. */
  327. int
  328. NC_var_shape(NC_var *varp, const NC_dimarray *dims)
  329. {
  330. size_t *shp, *op;
  331. off_t *dsp;
  332. int *ip;
  333. const NC_dim *dimp;
  334. off_t product = 1;
  335. varp->xsz = ncx_szof(varp->type);
  336. if(varp->ndims == 0)
  337. {
  338. goto out;
  339. }
  340. /*
  341. * use the user supplied dimension indices
  342. * to determine the shape
  343. */
  344. for(ip = varp->dimids, op = varp->shape
  345. ; ip < &varp->dimids[varp->ndims]; ip++, op++)
  346. {
  347. if(*ip < 0 || (size_t) (*ip) >= ((dims != NULL) ? dims->nelems : 1) )
  348. return NC_EBADDIM;
  349. dimp = elem_NC_dimarray(dims, (size_t)*ip);
  350. *op = dimp->size;
  351. if(*op == NC_UNLIMITED && ip != varp->dimids)
  352. return NC_EUNLIMPOS;
  353. }
  354. /*
  355. * Compute the dsizes
  356. */
  357. /* ndims is > 0 here */
  358. for(shp = varp->shape + varp->ndims -1,
  359. dsp = varp->dsizes + varp->ndims -1;
  360. shp >= varp->shape;
  361. shp--, dsp--)
  362. {
  363. if(!(shp == varp->shape && IS_RECVAR(varp)))
  364. {
  365. if( (off_t)(*shp) <= OFF_T_MAX / product )
  366. {
  367. product *= *shp;
  368. } else
  369. {
  370. product = OFF_T_MAX ;
  371. }
  372. }
  373. *dsp = product;
  374. }
  375. out :
  376. if( varp->xsz <= (X_UINT_MAX - 1) / product ) /* if integer multiply will not overflow */
  377. {
  378. varp->len = product * varp->xsz;
  379. switch(varp->type) {
  380. case NC_BYTE :
  381. case NC_CHAR :
  382. case NC_SHORT :
  383. if( varp->len%4 != 0 )
  384. {
  385. varp->len += 4 - varp->len%4; /* round up */
  386. /* *dsp += 4 - *dsp%4; */
  387. }
  388. break;
  389. default:
  390. /* already aligned */
  391. break;
  392. }
  393. } else
  394. { /* OK for last var to be "too big", indicated by this special len */
  395. varp->len = X_UINT_MAX;
  396. }
  397. #if 0
  398. arrayp("\tshape", varp->ndims, varp->shape);
  399. arrayp("\tdsizes", varp->ndims, varp->dsizes);
  400. #endif
  401. return NC_NOERR;
  402. }
  403. /*
  404. * Check whether variable size is less than or equal to vlen_max,
  405. * without overflowing in arithmetic calculations. If OK, return 1,
  406. * else, return 0. For CDF1 format or for CDF2 format on non-LFS
  407. * platforms, vlen_max should be 2^31 - 4, but for CDF2 format on
  408. * systems with LFS it should be 2^32 - 4.
  409. */
  410. int
  411. NC_check_vlen(NC_var *varp, size_t vlen_max) {
  412. size_t prod=varp->xsz; /* product of xsz and dimensions so far */
  413. int ii;
  414. assert(varp != NULL);
  415. for(ii = IS_RECVAR(varp) ? 1 : 0; ii < varp->ndims; ii++) {
  416. if (varp->shape[ii] > vlen_max / prod) {
  417. return 0; /* size in bytes won't fit in a 32-bit int */
  418. }
  419. prod *= varp->shape[ii];
  420. }
  421. return 1; /* OK */
  422. }
  423. /*
  424. * Given valid ncp and varid, return var
  425. * else NULL on error
  426. * Formerly
  427. NC_hlookupvar()
  428. */
  429. NC_var *
  430. NC_lookupvar(NC *ncp, int varid)
  431. {
  432. NC_var *varp;
  433. if(varid == NC_GLOBAL)
  434. {
  435. /* Global is error in this context */
  436. return(NULL);
  437. }
  438. varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
  439. if(varp == NULL)
  440. {
  441. return NULL;
  442. }
  443. assert(varp != NULL);
  444. return(varp);
  445. }
  446. /* Public */
  447. int
  448. NC3_def_var( int ncid, const char *name, nc_type type,
  449. int ndims, const int *dimids, int *varidp)
  450. {
  451. int status;
  452. NC *ncp;
  453. int varid;
  454. NC_var *varp;
  455. status = NC_check_id(ncid, &ncp);
  456. if(status != NC_NOERR)
  457. return status;
  458. if(!NC_indef(ncp))
  459. {
  460. return NC_ENOTINDEFINE;
  461. }
  462. status = NC_check_name(name);
  463. if(status != NC_NOERR)
  464. return status;
  465. status = nc_cktype(type);
  466. if(status != NC_NOERR)
  467. return status;
  468. /* cast needed for braindead systems with signed size_t */
  469. if((unsigned long) ndims > X_INT_MAX) /* Backward compat */
  470. {
  471. return NC_EINVAL;
  472. }
  473. if(ncp->vars.nelems >= NC_MAX_VARS)
  474. {
  475. return NC_EMAXVARS;
  476. }
  477. varid = NC_findvar(&ncp->vars, name, &varp);
  478. if(varid != -1)
  479. {
  480. return NC_ENAMEINUSE;
  481. }
  482. varp = new_NC_var(name, type, ndims, dimids);
  483. if(varp == NULL)
  484. return NC_ENOMEM;
  485. status = NC_var_shape(varp, &ncp->dims);
  486. if(status != NC_NOERR)
  487. {
  488. free_NC_var(varp);
  489. return status;
  490. }
  491. status = incr_NC_vararray(&ncp->vars, varp);
  492. if(status != NC_NOERR)
  493. {
  494. free_NC_var(varp);
  495. return status;
  496. }
  497. if(varidp != NULL)
  498. *varidp = (int)ncp->vars.nelems -1; /* varid */
  499. return NC_NOERR;
  500. }
  501. int
  502. NC3_inq_varid(int ncid, const char *name, int *varid_ptr)
  503. {
  504. int status;
  505. NC *ncp;
  506. NC_var *varp;
  507. int varid;
  508. status = NC_check_id(ncid, &ncp);
  509. if(status != NC_NOERR)
  510. return status;
  511. varid = NC_findvar(&ncp->vars, name, &varp);
  512. if(varid == -1)
  513. {
  514. return NC_ENOTVAR;
  515. }
  516. *varid_ptr = varid;
  517. return NC_NOERR;
  518. }
  519. int
  520. NC3_inq_var(int ncid,
  521. int varid,
  522. char *name,
  523. nc_type *typep,
  524. int *ndimsp,
  525. int *dimids,
  526. int *nattsp)
  527. {
  528. int status;
  529. NC *ncp;
  530. NC_var *varp;
  531. size_t ii;
  532. status = NC_check_id(ncid, &ncp);
  533. if(status != NC_NOERR)
  534. return status;
  535. varp = elem_NC_vararray(&ncp->vars, (size_t)varid);
  536. if(varp == NULL)
  537. return NC_ENOTVAR;
  538. if(name != NULL)
  539. {
  540. (void) strncpy(name, varp->name->cp, varp->name->nchars);
  541. name[varp->name->nchars] = 0;
  542. }
  543. if(typep != 0)
  544. *typep = varp->type;
  545. if(ndimsp != 0)
  546. {
  547. *ndimsp = (int) varp->ndims;
  548. }
  549. if(dimids != 0)
  550. {
  551. for(ii = 0; ii < varp->ndims; ii++)
  552. {
  553. dimids[ii] = varp->dimids[ii];
  554. }
  555. }
  556. if(nattsp != 0)
  557. {
  558. *nattsp = (int) varp->attrs.nelems;
  559. }
  560. return NC_NOERR;
  561. }
  562. int
  563. NC3_rename_var(int ncid, int varid, const char *unewname)
  564. {
  565. int status;
  566. NC *ncp;
  567. NC_var *varp;
  568. NC_string *old, *newStr;
  569. int other;
  570. char *newname; /* normalized */
  571. status = NC_check_id(ncid, &ncp);
  572. if(status != NC_NOERR)
  573. return status;
  574. if(NC_readonly(ncp))
  575. {
  576. return NC_EPERM;
  577. }
  578. status = NC_check_name(unewname);
  579. if(status != NC_NOERR)
  580. return status;
  581. /* check for name in use */
  582. other = NC_findvar(&ncp->vars, unewname, &varp);
  583. if(other != -1)
  584. {
  585. return NC_ENAMEINUSE;
  586. }
  587. varp = NC_lookupvar(ncp, varid);
  588. if(varp == NULL)
  589. {
  590. /* invalid varid */
  591. return NC_ENOTVAR; /* TODO: is this the right error code? */
  592. }
  593. old = varp->name;
  594. newname = (char *)utf8proc_NFC((const unsigned char *)unewname);
  595. if(newname == NULL)
  596. return NC_ENOMEM;
  597. if(NC_indef(ncp))
  598. {
  599. newStr = new_NC_string(strlen(newname),newname);
  600. free(newname);
  601. if(newStr == NULL)
  602. return(-1);
  603. varp->name = newStr;
  604. varp->hash = hash_fast(newStr->cp, strlen(newStr->cp));
  605. free_NC_string(old);
  606. return NC_NOERR;
  607. }
  608. /* else, not in define mode */
  609. status = set_NC_string(varp->name, newname);
  610. varp->hash = hash_fast(newname, strlen(newname));
  611. free(newname);
  612. if(status != NC_NOERR)
  613. return status;
  614. set_NC_hdirty(ncp);
  615. if(NC_doHsync(ncp))
  616. {
  617. status = NC_sync(ncp);
  618. if(status != NC_NOERR)
  619. return status;
  620. }
  621. return NC_NOERR;
  622. }