v1hpg.c 27 KB

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