PageRenderTime 50ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/other/netcdf_write_matrix/src/libsrc/v1hpg.c

http://github.com/jbeezley/wrf-fire
C | 1395 lines | 977 code | 254 blank | 164 comment | 322 complexity | c3240c383f6055dde6cefedbd1b5e5a3 MD5 | raw file
Possible License(s): AGPL-1.0
  1. /*
  2. * Copyright 1996, University Corporation for Atmospheric Research
  3. * See netcdf/COPYRIGHT file for copying and redistribution conditions.
  4. */
  5. /* $Id: v1hpg.c,v 1.63 2006/01/03 04:59:28 russ Exp $ */
  6. #include "nc.h"
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <assert.h>
  11. #include "rnd.h"
  12. #include "ncx.h"
  13. /*
  14. * This module defines the external representation
  15. * of the "header" of a netcdf version one file and
  16. * the version two variant that uses 64-bit file
  17. * offsets instead of the 32-bit file offsets in version
  18. * one files.
  19. * For each of the components of the NC structure,
  20. * There are (static) ncx_len_XXX(), v1h_put_XXX()
  21. * and v1h_get_XXX() functions. These define the
  22. * external representation of the components.
  23. * The exported entry points for the whole NC structure
  24. * are built up from these.
  25. */
  26. /*
  27. * "magic number" at beginning of file: 0x43444601 (big endian)
  28. * assert(sizeof(ncmagic) % X_ALIGN == 0);
  29. */
  30. static const schar ncmagic[] = {'C', 'D', 'F', 0x02};
  31. static const schar ncmagic1[] = {'C', 'D', 'F', 0x01};
  32. /*
  33. * v1hs == "Version 1 Header Stream"
  34. *
  35. * The netcdf file version 1 header is
  36. * of unknown and potentially unlimited size.
  37. * So, we don't know how much to get() on
  38. * the initial read. We build a stream, 'v1hs'
  39. * on top of ncio to do the header get.
  40. */
  41. typedef struct v1hs {
  42. ncio *nciop;
  43. off_t offset; /* argument to nciop->get() */
  44. size_t extent; /* argument to nciop->get() */
  45. int flags; /* set to RGN_WRITE for write */
  46. int version; /* format variant: NC_FORMAT_CLASSIC or NC_FORMAT_64BIT */
  47. void *base; /* beginning of current buffer */
  48. void *pos; /* current position in buffer */
  49. void *end; /* end of current buffer = base + extent */
  50. } v1hs;
  51. /*
  52. * Release the stream, invalidate buffer
  53. */
  54. static int
  55. rel_v1hs(v1hs *gsp)
  56. {
  57. int status;
  58. if(gsp->offset == OFF_NONE || gsp->base == NULL)
  59. return ENOERR;
  60. status = gsp->nciop->rel(gsp->nciop, gsp->offset,
  61. gsp->flags == RGN_WRITE ? RGN_MODIFIED : 0);
  62. gsp->end = NULL;
  63. gsp->pos = NULL;
  64. gsp->base = NULL;
  65. return status;
  66. }
  67. /*
  68. * Release the current chunk and get the next one.
  69. * Also used for initialization when gsp->base == NULL.
  70. */
  71. static int
  72. fault_v1hs(v1hs *gsp, size_t extent)
  73. {
  74. int status;
  75. if(gsp->base != NULL)
  76. {
  77. const ptrdiff_t incr = (char *)gsp->pos - (char *)gsp->base;
  78. status = rel_v1hs(gsp);
  79. if(status)
  80. return status;
  81. gsp->offset += incr;
  82. }
  83. if(extent > gsp->extent)
  84. gsp->extent = extent;
  85. status = gsp->nciop->get(gsp->nciop,
  86. gsp->offset, gsp->extent,
  87. gsp->flags, &gsp->base);
  88. if(status)
  89. return status;
  90. gsp->pos = gsp->base;
  91. gsp->end = (char *)gsp->base + gsp->extent;
  92. return ENOERR;
  93. }
  94. /*
  95. * Ensure that 'nextread' bytes are available.
  96. */
  97. static int
  98. check_v1hs(v1hs *gsp, size_t nextread)
  99. {
  100. #if 0 /* DEBUG */
  101. fprintf(stderr, "nextread %lu, remaining %lu\n",
  102. (unsigned long)nextread,
  103. (unsigned long)((char *)gsp->end - (char *)gsp->pos));
  104. #endif
  105. if((char *)gsp->pos + nextread <= (char *)gsp->end)
  106. return ENOERR;
  107. return fault_v1hs(gsp, nextread);
  108. }
  109. /* End v1hs */
  110. static int
  111. v1h_put_size_t(v1hs *psp, const size_t *sp)
  112. {
  113. int status = check_v1hs(psp, X_SIZEOF_SIZE_T);
  114. if(status != ENOERR)
  115. return status;
  116. return ncx_put_size_t(&psp->pos, sp);
  117. }
  118. static int
  119. v1h_get_size_t(v1hs *gsp, size_t *sp)
  120. {
  121. int status = check_v1hs(gsp, X_SIZEOF_SIZE_T);
  122. if(status != ENOERR)
  123. return status;
  124. return ncx_get_size_t((const void **)(&gsp->pos), sp);
  125. }
  126. /* Begin nc_type */
  127. #define X_SIZEOF_NC_TYPE X_SIZEOF_INT
  128. static int
  129. v1h_put_nc_type(v1hs *psp, const nc_type *typep)
  130. {
  131. const int itype = (int) *typep;
  132. int status = check_v1hs(psp, X_SIZEOF_INT);
  133. if(status != ENOERR)
  134. return status;
  135. status = ncx_put_int_int(psp->pos, &itype);
  136. psp->pos = (void *)((char *)psp->pos + X_SIZEOF_INT);
  137. return status;
  138. }
  139. static int
  140. v1h_get_nc_type(v1hs *gsp, nc_type *typep)
  141. {
  142. int type = 0;
  143. int status = check_v1hs(gsp, X_SIZEOF_INT);
  144. if(status != ENOERR)
  145. return status;
  146. status = ncx_get_int_int(gsp->pos, &type);
  147. gsp->pos = (void *)((char *)gsp->pos + X_SIZEOF_INT);
  148. if(status != ENOERR)
  149. return status;
  150. assert(type == NC_BYTE
  151. || type == NC_CHAR
  152. || type == NC_SHORT
  153. || type == NC_INT
  154. || type == NC_FLOAT
  155. || type == NC_DOUBLE);
  156. /* else */
  157. *typep = (nc_type) type;
  158. return ENOERR;
  159. }
  160. /* End nc_type */
  161. /* Begin NCtype (internal tags) */
  162. #define X_SIZEOF_NCTYPE X_SIZEOF_INT
  163. static int
  164. v1h_put_NCtype(v1hs *psp, NCtype type)
  165. {
  166. const int itype = (int) type;
  167. int status = check_v1hs(psp, X_SIZEOF_INT);
  168. if(status != ENOERR)
  169. return status;
  170. status = ncx_put_int_int(psp->pos, &itype);
  171. psp->pos = (void *)((char *)psp->pos + X_SIZEOF_INT);
  172. return status;
  173. }
  174. static int
  175. v1h_get_NCtype(v1hs *gsp, NCtype *typep)
  176. {
  177. int type = 0;
  178. int status = check_v1hs(gsp, X_SIZEOF_INT);
  179. if(status != ENOERR)
  180. return status;
  181. status = ncx_get_int_int(gsp->pos, &type);
  182. gsp->pos = (void *)((char *)gsp->pos + X_SIZEOF_INT);
  183. if(status != ENOERR)
  184. return status;
  185. /* else */
  186. *typep = (NCtype) type;
  187. return ENOERR;
  188. }
  189. /* End NCtype */
  190. /* Begin NC_string */
  191. /*
  192. * How much space will the xdr'd string take.
  193. * Formerly
  194. NC_xlen_string(cdfstr)
  195. */
  196. static size_t
  197. ncx_len_NC_string(const NC_string *ncstrp)
  198. {
  199. size_t sz = X_SIZEOF_SIZE_T; /* nchars */
  200. assert(ncstrp != NULL);
  201. if(ncstrp->nchars != 0)
  202. {
  203. #if 0
  204. assert(ncstrp->nchars % X_ALIGN == 0);
  205. sz += ncstrp->nchars;
  206. #else
  207. sz += _RNDUP(ncstrp->nchars, X_ALIGN);
  208. #endif
  209. }
  210. return sz;
  211. }
  212. static int
  213. v1h_put_NC_string(v1hs *psp, const NC_string *ncstrp)
  214. {
  215. int status;
  216. #if 0
  217. assert(ncstrp->nchars % X_ALIGN == 0);
  218. #endif
  219. status = v1h_put_size_t(psp, &ncstrp->nchars);
  220. if(status != ENOERR)
  221. return status;
  222. status = check_v1hs(psp, _RNDUP(ncstrp->nchars, X_ALIGN));
  223. if(status != ENOERR)
  224. return status;
  225. status = ncx_pad_putn_text(&psp->pos, ncstrp->nchars, ncstrp->cp);
  226. if(status != ENOERR)
  227. return status;
  228. return ENOERR;
  229. }
  230. static int
  231. v1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp)
  232. {
  233. int status;
  234. size_t nchars = 0;
  235. NC_string *ncstrp;
  236. status = v1h_get_size_t(gsp, &nchars);
  237. if(status != ENOERR)
  238. return status;
  239. ncstrp = new_NC_string(nchars, NULL);
  240. if(ncstrp == NULL)
  241. {
  242. return NC_ENOMEM;
  243. }
  244. #if 0
  245. /* assert(ncstrp->nchars == nchars || ncstrp->nchars - nchars < X_ALIGN); */
  246. assert(ncstrp->nchars % X_ALIGN == 0);
  247. status = check_v1hs(gsp, ncstrp->nchars);
  248. #else
  249. status = check_v1hs(gsp, _RNDUP(ncstrp->nchars, X_ALIGN));
  250. #endif
  251. if(status != ENOERR)
  252. goto unwind_alloc;
  253. status = ncx_pad_getn_text((const void **)(&gsp->pos),
  254. nchars, ncstrp->cp);
  255. if(status != ENOERR)
  256. goto unwind_alloc;
  257. *ncstrpp = ncstrp;
  258. return ENOERR;
  259. unwind_alloc:
  260. free_NC_string(ncstrp);
  261. return status;
  262. }
  263. /* End NC_string */
  264. /* Begin NC_dim */
  265. /*
  266. * How much space will the xdr'd dim take.
  267. * Formerly
  268. NC_xlen_dim(dpp)
  269. */
  270. static size_t
  271. ncx_len_NC_dim(const NC_dim *dimp)
  272. {
  273. size_t sz;
  274. assert(dimp != NULL);
  275. sz = ncx_len_NC_string(dimp->name);
  276. sz += X_SIZEOF_SIZE_T;
  277. return(sz);
  278. }
  279. static int
  280. v1h_put_NC_dim(v1hs *psp, const NC_dim *dimp)
  281. {
  282. int status;
  283. status = v1h_put_NC_string(psp, dimp->name);
  284. if(status != ENOERR)
  285. return status;
  286. status = v1h_put_size_t(psp, &dimp->size);
  287. if(status != ENOERR)
  288. return status;
  289. return ENOERR;
  290. }
  291. static int
  292. v1h_get_NC_dim(v1hs *gsp, NC_dim **dimpp)
  293. {
  294. int status;
  295. NC_string *ncstrp;
  296. NC_dim *dimp;
  297. status = v1h_get_NC_string(gsp, &ncstrp);
  298. if(status != ENOERR)
  299. return status;
  300. dimp = new_x_NC_dim(ncstrp);
  301. if(dimp == NULL)
  302. {
  303. status = NC_ENOMEM;
  304. goto unwind_name;
  305. }
  306. status = v1h_get_size_t(gsp, &dimp->size);
  307. if(status != ENOERR)
  308. {
  309. free_NC_dim(dimp); /* frees name */
  310. return status;
  311. }
  312. *dimpp = dimp;
  313. return ENOERR;
  314. unwind_name:
  315. free_NC_string(ncstrp);
  316. return status;
  317. }
  318. static size_t
  319. ncx_len_NC_dimarray(const NC_dimarray *ncap)
  320. {
  321. size_t xlen = X_SIZEOF_NCTYPE; /* type */
  322. xlen += X_SIZEOF_SIZE_T; /* count */
  323. if(ncap == NULL)
  324. return xlen;
  325. /* else */
  326. {
  327. const NC_dim **dpp = (const NC_dim **)ncap->value;
  328. const NC_dim *const *const end = &dpp[ncap->nelems];
  329. for( /*NADA*/; dpp < end; dpp++)
  330. {
  331. xlen += ncx_len_NC_dim(*dpp);
  332. }
  333. }
  334. return xlen;
  335. }
  336. static int
  337. v1h_put_NC_dimarray(v1hs *psp, const NC_dimarray *ncap)
  338. {
  339. int status;
  340. assert(psp != NULL);
  341. if(ncap == NULL
  342. #if 1
  343. /* Backward:
  344. * This clause is for 'byte for byte'
  345. * backward compatibility.
  346. * Strickly speaking, it is 'bug for bug'.
  347. */
  348. || ncap->nelems == 0
  349. #endif
  350. )
  351. {
  352. /*
  353. * Handle empty netcdf
  354. */
  355. const size_t nosz = 0;
  356. status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
  357. if(status != ENOERR)
  358. return status;
  359. status = v1h_put_size_t(psp, &nosz);
  360. if(status != ENOERR)
  361. return status;
  362. return ENOERR;
  363. }
  364. /* else */
  365. status = v1h_put_NCtype(psp, NC_DIMENSION);
  366. if(status != ENOERR)
  367. return status;
  368. status = v1h_put_size_t(psp, &ncap->nelems);
  369. if(status != ENOERR)
  370. return status;
  371. {
  372. const NC_dim **dpp = (const NC_dim **)ncap->value;
  373. const NC_dim *const *const end = &dpp[ncap->nelems];
  374. for( /*NADA*/; dpp < end; dpp++)
  375. {
  376. status = v1h_put_NC_dim(psp, *dpp);
  377. if(status)
  378. return status;
  379. }
  380. }
  381. return ENOERR;
  382. }
  383. static int
  384. v1h_get_NC_dimarray(v1hs *gsp, NC_dimarray *ncap)
  385. {
  386. int status;
  387. NCtype type = NC_UNSPECIFIED;
  388. assert(gsp != NULL && gsp->pos != NULL);
  389. assert(ncap != NULL);
  390. assert(ncap->value == NULL);
  391. status = v1h_get_NCtype(gsp, &type);
  392. if(status != ENOERR)
  393. return status;
  394. status = v1h_get_size_t(gsp, &ncap->nelems);
  395. if(status != ENOERR)
  396. return status;
  397. if(ncap->nelems == 0)
  398. return ENOERR;
  399. /* else */
  400. if(type != NC_DIMENSION)
  401. return EINVAL;
  402. ncap->value = (NC_dim **) malloc(ncap->nelems * sizeof(NC_dim *));
  403. if(ncap->value == NULL)
  404. return NC_ENOMEM;
  405. ncap->nalloc = ncap->nelems;
  406. {
  407. NC_dim **dpp = ncap->value;
  408. NC_dim *const *const end = &dpp[ncap->nelems];
  409. for( /*NADA*/; dpp < end; dpp++)
  410. {
  411. status = v1h_get_NC_dim(gsp, dpp);
  412. if(status)
  413. {
  414. ncap->nelems = (size_t)(dpp - ncap->value);
  415. free_NC_dimarrayV(ncap);
  416. return status;
  417. }
  418. }
  419. }
  420. return ENOERR;
  421. }
  422. /* End NC_dim */
  423. /* Begin NC_attr */
  424. /*
  425. * How much space will 'attrp' take in external representation?
  426. * Formerly
  427. NC_xlen_attr(app)
  428. */
  429. static size_t
  430. ncx_len_NC_attr(const NC_attr *attrp)
  431. {
  432. size_t sz;
  433. assert(attrp != NULL);
  434. sz = ncx_len_NC_string(attrp->name);
  435. sz += X_SIZEOF_NC_TYPE; /* type */
  436. sz += X_SIZEOF_SIZE_T; /* nelems */
  437. sz += attrp->xsz;
  438. return(sz);
  439. }
  440. #undef MIN
  441. #define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))
  442. /*
  443. * Put the values of an attribute
  444. * The loop is necessary since attrp->nelems
  445. * could potentially be quite large.
  446. */
  447. static int
  448. v1h_put_NC_attrV(v1hs *psp, const NC_attr *attrp)
  449. {
  450. int status;
  451. const size_t perchunk = psp->extent;
  452. size_t remaining = attrp->xsz;
  453. void *value = attrp->xvalue;
  454. size_t nbytes;
  455. assert(psp->extent % X_ALIGN == 0);
  456. do {
  457. nbytes = MIN(perchunk, remaining);
  458. status = check_v1hs(psp, nbytes);
  459. if(status != ENOERR)
  460. return status;
  461. (void) memcpy(psp->pos, value, nbytes);
  462. psp->pos = (void *)((char *)psp->pos + nbytes);
  463. value = (void *)((char *)value + nbytes);
  464. remaining -= nbytes;
  465. } while(remaining != 0);
  466. return ENOERR;
  467. }
  468. static int
  469. v1h_put_NC_attr(v1hs *psp, const NC_attr *attrp)
  470. {
  471. int status;
  472. status = v1h_put_NC_string(psp, attrp->name);
  473. if(status != ENOERR)
  474. return status;
  475. status = v1h_put_nc_type(psp, &attrp->type);
  476. if(status != ENOERR)
  477. return status;
  478. status = v1h_put_size_t(psp, &attrp->nelems);
  479. if(status != ENOERR)
  480. return status;
  481. status = v1h_put_NC_attrV(psp, attrp);
  482. if(status != ENOERR)
  483. return status;
  484. return ENOERR;
  485. }
  486. /*
  487. * Get the values of an attribute
  488. * The loop is necessary since attrp->nelems
  489. * could potentially be quite large.
  490. */
  491. static int
  492. v1h_get_NC_attrV(v1hs *gsp, NC_attr *attrp)
  493. {
  494. int status;
  495. const size_t perchunk = gsp->extent;
  496. size_t remaining = attrp->xsz;
  497. void *value = attrp->xvalue;
  498. size_t nget;
  499. assert(gsp->extent % X_ALIGN == 0);
  500. do {
  501. nget = MIN(perchunk, remaining);
  502. status = check_v1hs(gsp, nget);
  503. if(status != ENOERR)
  504. return status;
  505. (void) memcpy(value, gsp->pos, nget);
  506. gsp->pos = (void *)((char *)gsp->pos + nget);
  507. value = (void *)((char *)value + nget);
  508. remaining -= nget;
  509. } while(remaining != 0);
  510. return ENOERR;
  511. }
  512. static int
  513. v1h_get_NC_attr(v1hs *gsp, NC_attr **attrpp)
  514. {
  515. NC_string *strp;
  516. int status;
  517. nc_type type;
  518. size_t nelems;
  519. NC_attr *attrp;
  520. status = v1h_get_NC_string(gsp, &strp);
  521. if(status != ENOERR)
  522. return status;
  523. status = v1h_get_nc_type(gsp, &type);
  524. if(status != ENOERR)
  525. goto unwind_name;
  526. status = v1h_get_size_t(gsp, &nelems);
  527. if(status != ENOERR)
  528. goto unwind_name;
  529. attrp = new_x_NC_attr(strp, type, nelems);
  530. if(attrp == NULL)
  531. {
  532. status = NC_ENOMEM;
  533. goto unwind_name;
  534. }
  535. status = v1h_get_NC_attrV(gsp, attrp);
  536. if(status != ENOERR)
  537. {
  538. free_NC_attr(attrp); /* frees strp */
  539. return status;
  540. }
  541. *attrpp = attrp;
  542. return ENOERR;
  543. unwind_name:
  544. free_NC_string(strp);
  545. return status;
  546. }
  547. static size_t
  548. ncx_len_NC_attrarray(const NC_attrarray *ncap)
  549. {
  550. size_t xlen = X_SIZEOF_NCTYPE; /* type */
  551. xlen += X_SIZEOF_SIZE_T; /* count */
  552. if(ncap == NULL)
  553. return xlen;
  554. /* else */
  555. {
  556. const NC_attr **app = (const NC_attr **)ncap->value;
  557. const NC_attr *const *const end = &app[ncap->nelems];
  558. for( /*NADA*/; app < end; app++)
  559. {
  560. xlen += ncx_len_NC_attr(*app);
  561. }
  562. }
  563. return xlen;
  564. }
  565. static int
  566. v1h_put_NC_attrarray(v1hs *psp, const NC_attrarray *ncap)
  567. {
  568. int status;
  569. assert(psp != NULL);
  570. if(ncap == NULL
  571. #if 1
  572. /* Backward:
  573. * This clause is for 'byte for byte'
  574. * backward compatibility.
  575. * Strickly speaking, it is 'bug for bug'.
  576. */
  577. || ncap->nelems == 0
  578. #endif
  579. )
  580. {
  581. /*
  582. * Handle empty netcdf
  583. */
  584. const size_t nosz = 0;
  585. status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
  586. if(status != ENOERR)
  587. return status;
  588. status = v1h_put_size_t(psp, &nosz);
  589. if(status != ENOERR)
  590. return status;
  591. return ENOERR;
  592. }
  593. /* else */
  594. status = v1h_put_NCtype(psp, NC_ATTRIBUTE);
  595. if(status != ENOERR)
  596. return status;
  597. status = v1h_put_size_t(psp, &ncap->nelems);
  598. if(status != ENOERR)
  599. return status;
  600. {
  601. const NC_attr **app = (const NC_attr **)ncap->value;
  602. const NC_attr *const *const end = &app[ncap->nelems];
  603. for( /*NADA*/; app < end; app++)
  604. {
  605. status = v1h_put_NC_attr(psp, *app);
  606. if(status)
  607. return status;
  608. }
  609. }
  610. return ENOERR;
  611. }
  612. static int
  613. v1h_get_NC_attrarray(v1hs *gsp, NC_attrarray *ncap)
  614. {
  615. int status;
  616. NCtype type = NC_UNSPECIFIED;
  617. assert(gsp != NULL && gsp->pos != NULL);
  618. assert(ncap != NULL);
  619. assert(ncap->value == NULL);
  620. status = v1h_get_NCtype(gsp, &type);
  621. if(status != ENOERR)
  622. return status;
  623. status = v1h_get_size_t(gsp, &ncap->nelems);
  624. if(status != ENOERR)
  625. return status;
  626. if(ncap->nelems == 0)
  627. return ENOERR;
  628. /* else */
  629. if(type != NC_ATTRIBUTE)
  630. return EINVAL;
  631. ncap->value = (NC_attr **) malloc(ncap->nelems * sizeof(NC_attr *));
  632. if(ncap->value == NULL)
  633. return NC_ENOMEM;
  634. ncap->nalloc = ncap->nelems;
  635. {
  636. NC_attr **app = ncap->value;
  637. NC_attr *const *const end = &app[ncap->nelems];
  638. for( /*NADA*/; app < end; app++)
  639. {
  640. status = v1h_get_NC_attr(gsp, app);
  641. if(status)
  642. {
  643. ncap->nelems = (size_t)(app - ncap->value);
  644. free_NC_attrarrayV(ncap);
  645. return status;
  646. }
  647. }
  648. }
  649. return ENOERR;
  650. }
  651. /* End NC_attr */
  652. /* Begin NC_var */
  653. /*
  654. * How much space will the xdr'd var take.
  655. * Formerly
  656. NC_xlen_var(vpp)
  657. */
  658. static size_t
  659. ncx_len_NC_var(const NC_var *varp, size_t sizeof_off_t)
  660. {
  661. size_t sz;
  662. assert(varp != NULL);
  663. assert(sizeof_off_t != 0);
  664. sz = ncx_len_NC_string(varp->name);
  665. sz += X_SIZEOF_SIZE_T; /* ndims */
  666. sz += ncx_len_int(varp->ndims); /* dimids */
  667. sz += ncx_len_NC_attrarray(&varp->attrs);
  668. sz += X_SIZEOF_NC_TYPE; /* type */
  669. sz += X_SIZEOF_SIZE_T; /* len */
  670. sz += sizeof_off_t; /* begin */
  671. return(sz);
  672. }
  673. static int
  674. v1h_put_NC_var(v1hs *psp, const NC_var *varp)
  675. {
  676. int status;
  677. status = v1h_put_NC_string(psp, varp->name);
  678. if(status != ENOERR)
  679. return status;
  680. status = v1h_put_size_t(psp, &varp->ndims);
  681. if(status != ENOERR)
  682. return status;
  683. status = check_v1hs(psp, ncx_len_int(varp->ndims));
  684. if(status != ENOERR)
  685. return status;
  686. status = ncx_putn_int_int(&psp->pos,
  687. varp->ndims, varp->dimids);
  688. if(status != ENOERR)
  689. return status;
  690. status = v1h_put_NC_attrarray(psp, &varp->attrs);
  691. if(status != ENOERR)
  692. return status;
  693. status = v1h_put_nc_type(psp, &varp->type);
  694. if(status != ENOERR)
  695. return status;
  696. status = v1h_put_size_t(psp, &varp->len);
  697. if(status != ENOERR)
  698. return status;
  699. status = check_v1hs(psp, psp->version == 1 ? 4 : 8);
  700. if(status != ENOERR)
  701. return status;
  702. status = ncx_put_off_t(&psp->pos, &varp->begin, psp->version == 1 ? 4 : 8);
  703. if(status != ENOERR)
  704. return status;
  705. return ENOERR;
  706. }
  707. static int
  708. v1h_get_NC_var(v1hs *gsp, NC_var **varpp)
  709. {
  710. NC_string *strp;
  711. int status;
  712. size_t ndims;
  713. NC_var *varp;
  714. status = v1h_get_NC_string(gsp, &strp);
  715. if(status != ENOERR)
  716. return status;
  717. status = v1h_get_size_t(gsp, &ndims);
  718. if(status != ENOERR)
  719. goto unwind_name;
  720. varp = new_x_NC_var(strp, ndims);
  721. if(varp == NULL)
  722. {
  723. status = NC_ENOMEM;
  724. goto unwind_name;
  725. }
  726. status = check_v1hs(gsp, ncx_len_int(ndims));
  727. if(status != ENOERR)
  728. goto unwind_alloc;
  729. status = ncx_getn_int_int((const void **)(&gsp->pos),
  730. ndims, varp->dimids);
  731. if(status != ENOERR)
  732. goto unwind_alloc;
  733. status = v1h_get_NC_attrarray(gsp, &varp->attrs);
  734. if(status != ENOERR)
  735. goto unwind_alloc;
  736. status = v1h_get_nc_type(gsp, &varp->type);
  737. if(status != ENOERR)
  738. goto unwind_alloc;
  739. status = v1h_get_size_t(gsp, &varp->len);
  740. if(status != ENOERR)
  741. goto unwind_alloc;
  742. status = check_v1hs(gsp, gsp->version == 1 ? 4 : 8);
  743. if(status != ENOERR)
  744. goto unwind_alloc;
  745. status = ncx_get_off_t((const void **)&gsp->pos,
  746. &varp->begin, gsp->version == 1 ? 4 : 8);
  747. if(status != ENOERR)
  748. goto unwind_alloc;
  749. *varpp = varp;
  750. return ENOERR;
  751. unwind_alloc:
  752. free_NC_var(varp); /* frees name */
  753. return status;
  754. unwind_name:
  755. free_NC_string(strp);
  756. return status;
  757. }
  758. static size_t
  759. ncx_len_NC_vararray(const NC_vararray *ncap, size_t sizeof_off_t)
  760. {
  761. size_t xlen = X_SIZEOF_NCTYPE; /* type */
  762. xlen += X_SIZEOF_SIZE_T; /* count */
  763. if(ncap == NULL)
  764. return xlen;
  765. /* else */
  766. {
  767. const NC_var **vpp = (const NC_var **)ncap->value;
  768. const NC_var *const *const end = &vpp[ncap->nelems];
  769. for( /*NADA*/; vpp < end; vpp++)
  770. {
  771. xlen += ncx_len_NC_var(*vpp, sizeof_off_t);
  772. }
  773. }
  774. return xlen;
  775. }
  776. static int
  777. v1h_put_NC_vararray(v1hs *psp, const NC_vararray *ncap)
  778. {
  779. int status;
  780. assert(psp != NULL);
  781. if(ncap == NULL
  782. #if 1
  783. /* Backward:
  784. * This clause is for 'byte for byte'
  785. * backward compatibility.
  786. * Strickly speaking, it is 'bug for bug'.
  787. */
  788. || ncap->nelems == 0
  789. #endif
  790. )
  791. {
  792. /*
  793. * Handle empty netcdf
  794. */
  795. const size_t nosz = 0;
  796. status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
  797. if(status != ENOERR)
  798. return status;
  799. status = v1h_put_size_t(psp, &nosz);
  800. if(status != ENOERR)
  801. return status;
  802. return ENOERR;
  803. }
  804. /* else */
  805. status = v1h_put_NCtype(psp, NC_VARIABLE);
  806. if(status != ENOERR)
  807. return status;
  808. status = v1h_put_size_t(psp, &ncap->nelems);
  809. if(status != ENOERR)
  810. return status;
  811. {
  812. const NC_var **vpp = (const NC_var **)ncap->value;
  813. const NC_var *const *const end = &vpp[ncap->nelems];
  814. for( /*NADA*/; vpp < end; vpp++)
  815. {
  816. status = v1h_put_NC_var(psp, *vpp);
  817. if(status)
  818. return status;
  819. }
  820. }
  821. return ENOERR;
  822. }
  823. static int
  824. v1h_get_NC_vararray(v1hs *gsp, NC_vararray *ncap)
  825. {
  826. int status;
  827. NCtype type = NC_UNSPECIFIED;
  828. assert(gsp != NULL && gsp->pos != NULL);
  829. assert(ncap != NULL);
  830. assert(ncap->value == NULL);
  831. status = v1h_get_NCtype(gsp, &type);
  832. if(status != ENOERR)
  833. return status;
  834. status = v1h_get_size_t(gsp, &ncap->nelems);
  835. if(status != ENOERR)
  836. return status;
  837. if(ncap->nelems == 0)
  838. return ENOERR;
  839. /* else */
  840. if(type != NC_VARIABLE)
  841. return EINVAL;
  842. ncap->value = (NC_var **) malloc(ncap->nelems * sizeof(NC_var *));
  843. if(ncap->value == NULL)
  844. return NC_ENOMEM;
  845. ncap->nalloc = ncap->nelems;
  846. {
  847. NC_var **vpp = ncap->value;
  848. NC_var *const *const end = &vpp[ncap->nelems];
  849. for( /*NADA*/; vpp < end; vpp++)
  850. {
  851. status = v1h_get_NC_var(gsp, vpp);
  852. if(status)
  853. {
  854. ncap->nelems = (size_t)(vpp - ncap->value);
  855. free_NC_vararrayV(ncap);
  856. return status;
  857. }
  858. }
  859. }
  860. return ENOERR;
  861. }
  862. /* End NC_var */
  863. /* Begin NC */
  864. /*
  865. * Recompute the shapes of all variables
  866. * Sets ncp->begin_var to start of first variable.
  867. * Sets ncp->begin_rec to start of first record variable.
  868. * Returns -1 on error. The only possible error is a reference
  869. * to a non existent dimension, which could occur for a corrupted
  870. * netcdf file.
  871. */
  872. static int
  873. NC_computeshapes(NC *ncp)
  874. {
  875. NC_var **vpp = (NC_var **)ncp->vars.value;
  876. NC_var *const *const end = &vpp[ncp->vars.nelems];
  877. NC_var *first_var = NULL; /* first "non-record" var */
  878. NC_var *first_rec = NULL; /* first "record" var */
  879. int status;
  880. ncp->begin_var = (off_t) ncp->xsz;
  881. ncp->begin_rec = (off_t) ncp->xsz;
  882. ncp->recsize = 0;
  883. if(ncp->vars.nelems == 0)
  884. return(0);
  885. for( /*NADA*/; vpp < end; vpp++)
  886. {
  887. status = NC_var_shape(*vpp, &ncp->dims);
  888. if(status != ENOERR)
  889. return(status);
  890. if(IS_RECVAR(*vpp))
  891. {
  892. if(first_rec == NULL)
  893. first_rec = *vpp;
  894. ncp->recsize += (*vpp)->len;
  895. }
  896. else
  897. {
  898. if(first_var == NULL)
  899. first_var = *vpp;
  900. /*
  901. * Overwritten each time thru.
  902. * Usually overwritten in first_rec != NULL clause below.
  903. */
  904. ncp->begin_rec = (*vpp)->begin + (off_t)(*vpp)->len;
  905. }
  906. }
  907. if(first_rec != NULL)
  908. {
  909. assert(ncp->begin_rec <= first_rec->begin);
  910. ncp->begin_rec = first_rec->begin;
  911. /*
  912. * for special case of exactly one record variable, pack value
  913. */
  914. if(ncp->recsize == first_rec->len)
  915. ncp->recsize = *first_rec->dsizes * first_rec->xsz;
  916. }
  917. if(first_var != NULL)
  918. {
  919. ncp->begin_var = first_var->begin;
  920. }
  921. else
  922. {
  923. ncp->begin_var = ncp->begin_rec;
  924. }
  925. assert(ncp->begin_var > 0);
  926. assert(ncp->xsz <= (size_t)ncp->begin_var);
  927. assert(ncp->begin_rec > 0);
  928. assert(ncp->begin_var <= ncp->begin_rec);
  929. return(ENOERR);
  930. }
  931. /*
  932. * Return actual unpadded length (in bytes) of a variable, which
  933. * doesn't include any extra padding used for alignment. For a record
  934. * variable, this is the length in bytes of one record's worth of that
  935. * variable's data.
  936. */
  937. static off_t
  938. NC_var_unpadded_len(const NC_var *varp, const NC_dimarray *dims)
  939. {
  940. size_t *shp;
  941. off_t product = 1;
  942. if(varp->ndims != 0) {
  943. for(shp = varp->shape + varp->ndims -1; shp >= varp->shape; shp--) {
  944. if(!(shp == varp->shape && IS_RECVAR(varp)))
  945. product *= *shp;
  946. }
  947. }
  948. product = product * varp->xsz;
  949. return product;
  950. }
  951. size_t
  952. ncx_len_NC(const NC *ncp, size_t sizeof_off_t)
  953. {
  954. size_t xlen = sizeof(ncmagic);
  955. assert(ncp != NULL);
  956. xlen += X_SIZEOF_SIZE_T; /* numrecs */
  957. xlen += ncx_len_NC_dimarray(&ncp->dims);
  958. xlen += ncx_len_NC_attrarray(&ncp->attrs);
  959. xlen += ncx_len_NC_vararray(&ncp->vars, sizeof_off_t);
  960. return xlen;
  961. }
  962. int
  963. ncx_put_NC(const NC *ncp, void **xpp, off_t offset, size_t extent)
  964. {
  965. int status = ENOERR;
  966. v1hs ps; /* the get stream */
  967. assert(ncp != NULL);
  968. /* Initialize stream ps */
  969. ps.nciop = ncp->nciop;
  970. ps.flags = RGN_WRITE;
  971. if (ncp->flags & NC_64BIT_OFFSET)
  972. ps.version = 2;
  973. else
  974. ps.version = 1;
  975. if(xpp == NULL)
  976. {
  977. /*
  978. * Come up with a reasonable stream read size.
  979. */
  980. extent = ncp->xsz;
  981. if(extent <= MIN_NC_XSZ)
  982. {
  983. /* first time read */
  984. extent = ncp->chunk;
  985. /* Protection for when ncp->chunk is huge;
  986. * no need to read hugely. */
  987. if(extent > 4096)
  988. extent = 4096;
  989. }
  990. else if(extent > ncp->chunk)
  991. {
  992. extent = ncp->chunk;
  993. }
  994. ps.offset = 0;
  995. ps.extent = extent;
  996. ps.base = NULL;
  997. ps.pos = ps.base;
  998. status = fault_v1hs(&ps, extent);
  999. if(status)
  1000. return status;
  1001. }
  1002. else
  1003. {
  1004. ps.offset = offset;
  1005. ps.extent = extent;
  1006. ps.base = *xpp;
  1007. ps.pos = ps.base;
  1008. ps.end = (char *)ps.base + ps.extent;
  1009. }
  1010. if (ps.version == 2)
  1011. status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic), ncmagic);
  1012. else
  1013. status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic1), ncmagic1);
  1014. if(status != ENOERR)
  1015. goto release;
  1016. {
  1017. const size_t nrecs = NC_get_numrecs(ncp);
  1018. status = ncx_put_size_t(&ps.pos, &nrecs);
  1019. if(status != ENOERR)
  1020. goto release;
  1021. }
  1022. assert((char *)ps.pos < (char *)ps.end);
  1023. status = v1h_put_NC_dimarray(&ps, &ncp->dims);
  1024. if(status != ENOERR)
  1025. goto release;
  1026. status = v1h_put_NC_attrarray(&ps, &ncp->attrs);
  1027. if(status != ENOERR)
  1028. goto release;
  1029. status = v1h_put_NC_vararray(&ps, &ncp->vars);
  1030. if(status != ENOERR)
  1031. goto release;
  1032. release:
  1033. (void) rel_v1hs(&ps);
  1034. return status;
  1035. }
  1036. int
  1037. nc_get_NC(NC *ncp)
  1038. {
  1039. int status;
  1040. v1hs gs; /* the get stream */
  1041. assert(ncp != NULL);
  1042. /* Initialize stream gs */
  1043. gs.nciop = ncp->nciop;
  1044. gs.offset = 0; /* beginning of file */
  1045. gs.extent = 0;
  1046. gs.flags = 0;
  1047. gs.version = 0;
  1048. gs.base = NULL;
  1049. gs.pos = gs.base;
  1050. {
  1051. /*
  1052. * Come up with a reasonable stream read size.
  1053. */
  1054. off_t filesize;
  1055. size_t extent = MIN_NC_XSZ;
  1056. extent = ncp->xsz;
  1057. if(extent <= MIN_NC_XSZ)
  1058. {
  1059. status = ncio_filesize(ncp->nciop, &filesize);
  1060. if(status)
  1061. return status;
  1062. /* first time read */
  1063. extent = ncp->chunk;
  1064. /* Protection for when ncp->chunk is huge;
  1065. * no need to read hugely. */
  1066. if(extent > 4096)
  1067. extent = 4096;
  1068. if(extent > filesize)
  1069. extent = filesize;
  1070. }
  1071. else if(extent > ncp->chunk)
  1072. {
  1073. extent = ncp->chunk;
  1074. }
  1075. /*
  1076. * Invalidate the I/O buffers to force a read of the header
  1077. * region.
  1078. */
  1079. status = gs.nciop->sync(gs.nciop);
  1080. if(status)
  1081. return status;
  1082. status = fault_v1hs(&gs, extent);
  1083. if(status)
  1084. return status;
  1085. }
  1086. /* get the header from the stream gs */
  1087. {
  1088. /* Get & check magic number */
  1089. schar magic[sizeof(ncmagic)];
  1090. (void) memset(magic, 0, sizeof(magic));
  1091. status = ncx_getn_schar_schar(
  1092. (const void **)(&gs.pos), sizeof(magic), magic);
  1093. if(status != ENOERR)
  1094. goto unwind_get;
  1095. if(memcmp(magic, ncmagic, sizeof(ncmagic)-1) != 0)
  1096. {
  1097. status = NC_ENOTNC;
  1098. goto unwind_get;
  1099. }
  1100. /* Check version number in last byte of magic */
  1101. if (magic[sizeof(ncmagic)-1] == 0x1) {
  1102. gs.version = 1;
  1103. } else if (magic[sizeof(ncmagic)-1] == 0x2) {
  1104. gs.version = 2;
  1105. fSet(ncp->flags, NC_64BIT_OFFSET);
  1106. /* Now we support version 2 file access on non-LFS systems -- rkr */
  1107. #if 0
  1108. if (sizeof(off_t) != 8) {
  1109. fprintf(stderr, "NETCDF WARNING: Version 2 file on 32-bit system.\n");
  1110. }
  1111. #endif
  1112. } else {
  1113. status = NC_ENOTNC;
  1114. goto unwind_get;
  1115. }
  1116. }
  1117. {
  1118. size_t nrecs = 0;
  1119. status = ncx_get_size_t((const void **)(&gs.pos), &nrecs);
  1120. if(status != ENOERR)
  1121. goto unwind_get;
  1122. NC_set_numrecs(ncp, nrecs);
  1123. }
  1124. assert((char *)gs.pos < (char *)gs.end);
  1125. status = v1h_get_NC_dimarray(&gs, &ncp->dims);
  1126. if(status != ENOERR)
  1127. goto unwind_get;
  1128. status = v1h_get_NC_attrarray(&gs, &ncp->attrs);
  1129. if(status != ENOERR)
  1130. goto unwind_get;
  1131. status = v1h_get_NC_vararray(&gs, &ncp->vars);
  1132. if(status != ENOERR)
  1133. goto unwind_get;
  1134. ncp->xsz = ncx_len_NC(ncp, (gs.version == 1) ? 4 : 8);
  1135. status = NC_computeshapes(ncp);
  1136. if(status != ENOERR)
  1137. goto unwind_get;
  1138. unwind_get:
  1139. (void) rel_v1hs(&gs);
  1140. return status;
  1141. }