1 /*
2 * Copyright 1996, University Corporation for Atmospheric Research
3 * See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 */
5
6 #if HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9
10 #include "nc3internal.h"
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <assert.h>
15 #include "rnd.h"
16 #include "ncx.h"
17
18 /*
19 * This module defines the external representation
20 * of the "header" of a netcdf version one file and
21 * the version two variant that uses 64-bit file
22 * offsets instead of the 32-bit file offsets in version
23 * one files.
24 * For each of the components of the NC structure,
25 * There are (static) ncx_len_XXX(), v1h_put_XXX()
26 * and v1h_get_XXX() functions. These define the
27 * external representation of the components.
28 * The exported entry points for the whole NC structure
29 * are built up from these.
30 */
31
32
33 /*
34 * "magic number" at beginning of file: 0x43444601 (big endian)
35 * assert(sizeof(ncmagic) % X_ALIGN == 0);
36 */
37 static const schar ncmagic[] = {'C', 'D', 'F', 0x02};
38 static const schar ncmagic1[] = {'C', 'D', 'F', 0x01};
39 static const schar ncmagic5[] = {'C', 'D', 'F', 0x05};
40
41 /*
42 * v1hs == "Version 1 Header Stream"
43 *
44 * The netcdf file version 1 header is
45 * of unknown and potentially unlimited size.
46 * So, we don't know how much to get() on
47 * the initial read. We build a stream, 'v1hs'
48 * on top of ncio to do the header get.
49 */
50 typedef struct v1hs {
51 ncio *nciop;
52 off_t offset; /* argument to nciop->get() */
53 size_t extent; /* argument to nciop->get() */
54 int flags; /* set to RGN_WRITE for write */
55 int version; /* format variant: NC_FORMAT_CLASSIC, NC_FORMAT_64BIT_OFFSET or NC_FORMAT_CDF5 */
56 void *base; /* beginning of current buffer */
57 void *pos; /* current position in buffer */
58 void *end; /* end of current buffer = base + extent */
59 } v1hs;
60
61
62 /*
63 * Release the stream, invalidate buffer
64 */
65 static int
rel_v1hs(v1hs * gsp)66 rel_v1hs(v1hs *gsp)
67 {
68 int status;
69 if(gsp->offset == OFF_NONE || gsp->base == NULL)
70 return NC_NOERR;
71 status = ncio_rel(gsp->nciop, gsp->offset,
72 gsp->flags == RGN_WRITE ? RGN_MODIFIED : 0);
73 gsp->end = NULL;
74 gsp->pos = NULL;
75 gsp->base = NULL;
76 return status;
77 }
78
79
80 /*
81 * Release the current chunk and get the next one.
82 * Also used for initialization when gsp->base == NULL.
83 */
84 static int
fault_v1hs(v1hs * gsp,size_t extent)85 fault_v1hs(v1hs *gsp, size_t extent)
86 {
87 int status;
88
89 if(gsp->base != NULL)
90 {
91 const ptrdiff_t incr = (char *)gsp->pos - (char *)gsp->base;
92 status = rel_v1hs(gsp);
93 if(status)
94 return status;
95 gsp->offset += incr;
96 }
97
98 if(extent > gsp->extent)
99 gsp->extent = extent;
100
101 status = ncio_get(gsp->nciop,
102 gsp->offset, gsp->extent,
103 gsp->flags, &gsp->base);
104 if(status)
105 return status;
106
107 gsp->pos = gsp->base;
108
109 gsp->end = (char *)gsp->base + gsp->extent;
110 return NC_NOERR;
111 }
112
113
114 /*
115 * Ensure that 'nextread' bytes are available.
116 */
117 static int
check_v1hs(v1hs * gsp,size_t nextread)118 check_v1hs(v1hs *gsp, size_t nextread)
119 {
120
121 #if 0 /* DEBUG */
122 fprintf(stderr, "nextread %lu, remaining %lu\n",
123 (unsigned long)nextread,
124 (unsigned long)((char *)gsp->end - (char *)gsp->pos));
125 #endif
126 if((char *)gsp->pos + nextread <= (char *)gsp->end)
127 return NC_NOERR;
128
129 return fault_v1hs(gsp, nextread);
130 }
131
132 /* End v1hs */
133
134 /* Write a size_t to the header */
135 static int
v1h_put_size_t(v1hs * psp,const size_t * sp)136 v1h_put_size_t(v1hs *psp, const size_t *sp)
137 {
138 int status;
139 if (psp->version == 5) /* all integers in CDF-5 are 64 bits */
140 status = check_v1hs(psp, X_SIZEOF_INT64);
141 else
142 status = check_v1hs(psp, X_SIZEOF_SIZE_T);
143 if(status != NC_NOERR)
144 return status;
145 if (psp->version == 5) {
146 unsigned long long tmp = (unsigned long long) (*sp);
147 return ncx_put_uint64(&psp->pos, tmp);
148 }
149 else
150 return ncx_put_size_t(&psp->pos, sp);
151 }
152
153 /* Read a size_t from the header */
154 static int
v1h_get_size_t(v1hs * gsp,size_t * sp)155 v1h_get_size_t(v1hs *gsp, size_t *sp)
156 {
157 int status;
158 if (gsp->version == 5) /* all integers in CDF-5 are 64 bits */
159 status = check_v1hs(gsp, X_SIZEOF_INT64);
160 else
161 status = check_v1hs(gsp, X_SIZEOF_SIZE_T);
162 if(status != NC_NOERR)
163 return status;
164 if (gsp->version == 5) {
165 unsigned long long tmp=0;
166 status = ncx_get_uint64((const void **)(&gsp->pos), &tmp);
167 *sp = (size_t)tmp;
168 return status;
169 }
170 else
171 return ncx_get_size_t((const void **)(&gsp->pos), sp);
172 }
173
174 /* Begin nc_type */
175
176 #define X_SIZEOF_NC_TYPE X_SIZEOF_INT
177
178 /* Write a nc_type to the header */
179 static int
v1h_put_nc_type(v1hs * psp,const nc_type * typep)180 v1h_put_nc_type(v1hs *psp, const nc_type *typep)
181 {
182 const unsigned int itype = (unsigned int) *typep;
183 int status = check_v1hs(psp, X_SIZEOF_INT);
184 if(status != NC_NOERR) return status;
185 status = ncx_put_uint32(&psp->pos, itype);
186 return status;
187 }
188
189
190 /* Read a nc_type from the header */
191 static int
v1h_get_nc_type(v1hs * gsp,nc_type * typep)192 v1h_get_nc_type(v1hs *gsp, nc_type *typep)
193 {
194 unsigned int type = 0;
195 int status = check_v1hs(gsp, X_SIZEOF_INT);
196 if(status != NC_NOERR) return status;
197 status = ncx_get_uint32((const void**)(&gsp->pos), &type);
198 if(status != NC_NOERR)
199 return status;
200
201 assert(type == NC_BYTE
202 || type == NC_CHAR
203 || type == NC_SHORT
204 || type == NC_INT
205 || type == NC_FLOAT
206 || type == NC_DOUBLE
207 || type == NC_UBYTE
208 || type == NC_USHORT
209 || type == NC_UINT
210 || type == NC_INT64
211 || type == NC_UINT64
212 || type == NC_STRING);
213
214 /* else */
215 *typep = (nc_type) type;
216
217 return NC_NOERR;
218 }
219
220 /* End nc_type */
221 /* Begin NCtype (internal tags) */
222
223 #define X_SIZEOF_NCTYPE X_SIZEOF_INT
224
225 /* Write a NCtype to the header */
226 static int
v1h_put_NCtype(v1hs * psp,NCtype type)227 v1h_put_NCtype(v1hs *psp, NCtype type)
228 {
229 const unsigned int itype = (unsigned int) type;
230 int status = check_v1hs(psp, X_SIZEOF_INT);
231 if(status != NC_NOERR) return status;
232 status = ncx_put_uint32(&psp->pos, itype);
233 return status;
234 }
235
236 /* Read a NCtype from the header */
237 static int
v1h_get_NCtype(v1hs * gsp,NCtype * typep)238 v1h_get_NCtype(v1hs *gsp, NCtype *typep)
239 {
240 unsigned int type = 0;
241 int status = check_v1hs(gsp, X_SIZEOF_INT);
242 if(status != NC_NOERR) return status;
243 status = ncx_get_uint32((const void**)(&gsp->pos), &type);
244 if(status != NC_NOERR) return status;
245 /* else */
246 *typep = (NCtype) type;
247 return NC_NOERR;
248 }
249
250 /* End NCtype */
251 /* Begin NC_string */
252
253 /*
254 * How much space will the xdr'd string take.
255 * Formerly
256 NC_xlen_string(cdfstr)
257 */
258 static size_t
ncx_len_NC_string(const NC_string * ncstrp,int version)259 ncx_len_NC_string(const NC_string *ncstrp, int version)
260 {
261 size_t sz = (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_INT; /* nchars */
262
263 assert(ncstrp != NULL);
264
265 if(ncstrp->nchars != 0)
266 {
267 #if 0
268 assert(ncstrp->nchars % X_ALIGN == 0);
269 sz += ncstrp->nchars;
270 #else
271 sz += _RNDUP(ncstrp->nchars, X_ALIGN);
272 #endif
273 }
274 return sz;
275 }
276
277
278 /* Write a NC_string to the header */
279 static int
v1h_put_NC_string(v1hs * psp,const NC_string * ncstrp)280 v1h_put_NC_string(v1hs *psp, const NC_string *ncstrp)
281 {
282 int status;
283
284 #if 0
285 assert(ncstrp->nchars % X_ALIGN == 0);
286 #endif
287
288 status = v1h_put_size_t(psp, &ncstrp->nchars);
289 if(status != NC_NOERR)
290 return status;
291 status = check_v1hs(psp, _RNDUP(ncstrp->nchars, X_ALIGN));
292 if(status != NC_NOERR)
293 return status;
294 status = ncx_pad_putn_text(&psp->pos, ncstrp->nchars, ncstrp->cp);
295 if(status != NC_NOERR)
296 return status;
297
298 return NC_NOERR;
299 }
300
301
302 /* Read a NC_string from the header */
303 static int
v1h_get_NC_string(v1hs * gsp,NC_string ** ncstrpp)304 v1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp)
305 {
306 int status;
307 size_t padding, nchars = 0;
308 NC_string *ncstrp;
309
310 status = v1h_get_size_t(gsp, &nchars);
311 if(status != NC_NOERR)
312 return status;
313
314 ncstrp = new_NC_string(nchars, NULL);
315 if(ncstrp == NULL)
316 {
317 return NC_ENOMEM;
318 }
319
320 #if 0
321 /* assert(ncstrp->nchars == nchars || ncstrp->nchars - nchars < X_ALIGN); */
322 assert(ncstrp->nchars % X_ALIGN == 0);
323 status = check_v1hs(gsp, ncstrp->nchars);
324 #else
325
326 status = check_v1hs(gsp, _RNDUP(ncstrp->nchars, X_ALIGN));
327 #endif
328 if(status != NC_NOERR)
329 goto unwind_alloc;
330
331 status = ncx_pad_getn_text((const void **)(&gsp->pos),
332 nchars, ncstrp->cp);
333 if(status != NC_NOERR)
334 goto unwind_alloc;
335
336 padding = _RNDUP(X_SIZEOF_CHAR * ncstrp->nchars, X_ALIGN)
337 - X_SIZEOF_CHAR * ncstrp->nchars;
338 if (padding > 0) {
339 /* CDF specification: Header padding uses null (\x00) bytes. */
340 char pad[X_ALIGN-1];
341 memset(pad, 0, X_ALIGN-1);
342 if (memcmp((char*)gsp->pos-padding, pad, padding) != 0) {
343 free_NC_string(ncstrp);
344 return NC_EINVAL;
345 }
346 }
347
348 *ncstrpp = ncstrp;
349
350 return NC_NOERR;
351
352 unwind_alloc:
353 free_NC_string(ncstrp);
354 return status;
355 }
356
357 /* End NC_string */
358 /* Begin NC_dim */
359
360 /*
361 * How much space will the xdr'd dim take.
362 * Formerly
363 NC_xlen_dim(dpp)
364 */
365 static size_t
ncx_len_NC_dim(const NC_dim * dimp,int version)366 ncx_len_NC_dim(const NC_dim *dimp, int version)
367 {
368 size_t sz;
369
370 assert(dimp != NULL);
371
372 sz = ncx_len_NC_string(dimp->name, version);
373 sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T;
374
375 return(sz);
376 }
377
378
379 /* Write a NC_dim to the header */
380 static int
v1h_put_NC_dim(v1hs * psp,const NC_dim * dimp)381 v1h_put_NC_dim(v1hs *psp, const NC_dim *dimp)
382 {
383 int status;
384
385 status = v1h_put_NC_string(psp, dimp->name);
386 if(status != NC_NOERR)
387 return status;
388
389 status = v1h_put_size_t(psp, &dimp->size);
390 if(status != NC_NOERR)
391 return status;
392
393 return NC_NOERR;
394 }
395
396 /* Read a NC_dim from the header */
397 static int
v1h_get_NC_dim(v1hs * gsp,NC_dim ** dimpp)398 v1h_get_NC_dim(v1hs *gsp, NC_dim **dimpp)
399 {
400 int status;
401 NC_string *ncstrp;
402 NC_dim *dimp;
403
404 status = v1h_get_NC_string(gsp, &ncstrp);
405 if(status != NC_NOERR)
406 return status;
407
408 dimp = new_x_NC_dim(ncstrp);
409 if(dimp == NULL)
410 {
411 status = NC_ENOMEM;
412 goto unwind_name;
413 }
414
415 status = v1h_get_size_t(gsp, &dimp->size);
416 if(status != NC_NOERR)
417 {
418 free_NC_dim(dimp); /* frees name */
419 return status;
420 }
421
422 *dimpp = dimp;
423
424 return NC_NOERR;
425
426 unwind_name:
427 free_NC_string(ncstrp);
428 return status;
429 }
430
431
432 /* How much space in the header is required for this NC_dimarray? */
433 static size_t
ncx_len_NC_dimarray(const NC_dimarray * ncap,int version)434 ncx_len_NC_dimarray(const NC_dimarray *ncap, int version)
435 {
436 size_t xlen = X_SIZEOF_NCTYPE; /* type */
437 xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */
438 if(ncap == NULL)
439 return xlen;
440 /* else */
441 {
442 const NC_dim **dpp = (const NC_dim **)ncap->value;
443 const NC_dim *const *const end = &dpp[ncap->nelems];
444 for( /*NADA*/; dpp < end; dpp++)
445 {
446 xlen += ncx_len_NC_dim(*dpp,version);
447 }
448 }
449 return xlen;
450 }
451
452
453 /* Write a NC_dimarray to the header */
454 static int
v1h_put_NC_dimarray(v1hs * psp,const NC_dimarray * ncap)455 v1h_put_NC_dimarray(v1hs *psp, const NC_dimarray *ncap)
456 {
457 int status;
458
459 assert(psp != NULL);
460
461 if(ncap == NULL
462 #if 1
463 /* Backward:
464 * This clause is for 'byte for byte'
465 * backward compatibility.
466 * Strickly speaking, it is 'bug for bug'.
467 */
468 || ncap->nelems == 0
469 #endif
470 )
471 {
472 /*
473 * Handle empty netcdf
474 */
475 const size_t nosz = 0;
476
477 status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
478 if(status != NC_NOERR)
479 return status;
480 status = v1h_put_size_t(psp, &nosz);
481 if(status != NC_NOERR)
482 return status;
483 return NC_NOERR;
484 }
485 /* else */
486
487 status = v1h_put_NCtype(psp, NC_DIMENSION);
488 if(status != NC_NOERR)
489 return status;
490 status = v1h_put_size_t(psp, &ncap->nelems);
491 if(status != NC_NOERR)
492 return status;
493
494 {
495 const NC_dim **dpp = (const NC_dim **)ncap->value;
496 const NC_dim *const *const end = &dpp[ncap->nelems];
497 for( /*NADA*/; dpp < end; dpp++)
498 {
499 status = v1h_put_NC_dim(psp, *dpp);
500 if(status)
501 return status;
502 }
503 }
504 return NC_NOERR;
505 }
506
507
508 /* Read a NC_dimarray from the header */
509 static int
v1h_get_NC_dimarray(v1hs * gsp,NC_dimarray * ncap)510 v1h_get_NC_dimarray(v1hs *gsp, NC_dimarray *ncap)
511 {
512 int status;
513 NCtype type = NC_UNSPECIFIED;
514
515 assert(gsp != NULL && gsp->pos != NULL);
516 assert(ncap != NULL);
517 assert(ncap->value == NULL);
518
519 status = v1h_get_NCtype(gsp, &type);
520 if(status != NC_NOERR)
521 return status;
522
523 status = v1h_get_size_t(gsp, &ncap->nelems);
524 if(status != NC_NOERR)
525 return status;
526
527 if(ncap->nelems == 0)
528 return NC_NOERR;
529 /* else */
530 if(type != NC_DIMENSION)
531 return EINVAL;
532
533 ncap->value = (NC_dim **) malloc(ncap->nelems * sizeof(NC_dim *));
534 if(ncap->value == NULL)
535 return NC_ENOMEM;
536 ncap->nalloc = ncap->nelems;
537
538 ncap->hashmap = NC_hashmapCreate(ncap->nelems);
539
540 {
541 NC_dim **dpp = ncap->value;
542 NC_dim *const *const end = &dpp[ncap->nelems];
543 for( /*NADA*/; dpp < end; dpp++)
544 {
545 status = v1h_get_NC_dim(gsp, dpp);
546 if(status)
547 {
548 ncap->nelems = (size_t)(dpp - ncap->value);
549 free_NC_dimarrayV(ncap);
550 return status;
551 }
552 {
553 int dimid = (size_t)(dpp - ncap->value);
554 NC_hashmapAddDim(ncap, dimid, (*dpp)->name->cp);
555 }
556 }
557 }
558
559 return NC_NOERR;
560 }
561
562
563 /* End NC_dim */
564 /* Begin NC_attr */
565
566
567 /*
568 * How much space will 'attrp' take in external representation?
569 * Formerly
570 NC_xlen_attr(app)
571 */
572 static size_t
ncx_len_NC_attr(const NC_attr * attrp,int version)573 ncx_len_NC_attr(const NC_attr *attrp, int version)
574 {
575 size_t sz;
576
577 assert(attrp != NULL);
578
579 sz = ncx_len_NC_string(attrp->name, version);
580 sz += X_SIZEOF_NC_TYPE; /* type */
581 sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* nelems */
582 sz += attrp->xsz;
583
584 return(sz);
585 }
586
587
588 #undef MIN
589 #define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))
590
591 /*----< ncmpix_len_nctype() >------------------------------------------------*/
592 /* return the length of external data type */
593 static int
ncmpix_len_nctype(nc_type type)594 ncmpix_len_nctype(nc_type type) {
595 switch(type) {
596 case NC_BYTE:
597 case NC_CHAR:
598 case NC_UBYTE: return X_SIZEOF_CHAR;
599 case NC_SHORT: return X_SIZEOF_SHORT;
600 case NC_USHORT: return X_SIZEOF_USHORT;
601 case NC_INT: return X_SIZEOF_INT;
602 case NC_UINT: return X_SIZEOF_UINT;
603 case NC_FLOAT: return X_SIZEOF_FLOAT;
604 case NC_DOUBLE: return X_SIZEOF_DOUBLE;
605 case NC_INT64: return X_SIZEOF_INT64;
606 case NC_UINT64: return X_SIZEOF_UINT64;
607 default: fprintf(stderr,"ncmpix_len_nctype bad type %d\n",type);
608 assert(0);
609 }
610 return 0;
611 }
612
613 /*
614 * Put the values of an attribute
615 * The loop is necessary since attrp->nelems
616 * could potentially be quite large.
617 */
618 static int
v1h_put_NC_attrV(v1hs * psp,const NC_attr * attrp)619 v1h_put_NC_attrV(v1hs *psp, const NC_attr *attrp)
620 {
621 int status;
622 const size_t perchunk = psp->extent;
623 size_t remaining = attrp->xsz;
624 void *value = attrp->xvalue;
625 size_t nbytes, padding;
626
627 assert(psp->extent % X_ALIGN == 0);
628
629 do {
630 nbytes = MIN(perchunk, remaining);
631
632 status = check_v1hs(psp, nbytes);
633 if(status != NC_NOERR)
634 return status;
635
636 (void) memcpy(psp->pos, value, nbytes);
637
638 psp->pos = (void *)((char *)psp->pos + nbytes);
639 value = (void *)((char *)value + nbytes);
640 remaining -= nbytes;
641
642 } while(remaining != 0);
643
644 padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems;
645 if (padding > 0) {
646 /* CDF specification: Header padding uses null (\x00) bytes. */
647 memset((char*)psp->pos-padding, 0, padding);
648 }
649
650 return NC_NOERR;
651 }
652
653 /* Write a NC_attr to the header */
654 static int
v1h_put_NC_attr(v1hs * psp,const NC_attr * attrp)655 v1h_put_NC_attr(v1hs *psp, const NC_attr *attrp)
656 {
657 int status;
658
659 status = v1h_put_NC_string(psp, attrp->name);
660 if(status != NC_NOERR)
661 return status;
662
663 status = v1h_put_nc_type(psp, &attrp->type);
664 if(status != NC_NOERR)
665 return status;
666
667 status = v1h_put_size_t(psp, &attrp->nelems);
668 if(status != NC_NOERR)
669 return status;
670
671 status = v1h_put_NC_attrV(psp, attrp);
672 if(status != NC_NOERR)
673 return status;
674
675 return NC_NOERR;
676 }
677
678
679 /*
680 * Get the values of an attribute
681 * The loop is necessary since attrp->nelems
682 * could potentially be quite large.
683 */
684 static int
v1h_get_NC_attrV(v1hs * gsp,NC_attr * attrp)685 v1h_get_NC_attrV(v1hs *gsp, NC_attr *attrp)
686 {
687 int status;
688 const size_t perchunk = gsp->extent;
689 size_t remaining = attrp->xsz;
690 void *value = attrp->xvalue;
691 size_t nget, padding;
692
693 do {
694 nget = MIN(perchunk, remaining);
695
696 status = check_v1hs(gsp, nget);
697 if(status != NC_NOERR)
698 return status;
699
700 (void) memcpy(value, gsp->pos, nget);
701 gsp->pos = (void*)((unsigned char *)gsp->pos + nget);
702
703 value = (void *)((signed char *)value + nget);
704
705 remaining -= nget;
706
707 } while(remaining != 0);
708
709 padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems;
710 if (padding > 0) {
711 /* CDF specification: Header padding uses null (\x00) bytes. */
712 char pad[X_ALIGN-1];
713 memset(pad, 0, X_ALIGN-1);
714 if (memcmp((char*)gsp->pos-padding, pad, (size_t)padding) != 0)
715 return NC_EINVAL;
716 }
717
718 return NC_NOERR;
719 }
720
721
722 /* Read a NC_attr from the header */
723 static int
v1h_get_NC_attr(v1hs * gsp,NC_attr ** attrpp)724 v1h_get_NC_attr(v1hs *gsp, NC_attr **attrpp)
725 {
726 NC_string *strp;
727 int status;
728 nc_type type;
729 size_t nelems;
730 NC_attr *attrp;
731
732 status = v1h_get_NC_string(gsp, &strp);
733 if(status != NC_NOERR)
734 return status;
735
736 status = v1h_get_nc_type(gsp, &type);
737 if(status != NC_NOERR)
738 goto unwind_name;
739
740 status = v1h_get_size_t(gsp, &nelems);
741 if(status != NC_NOERR)
742 goto unwind_name;
743
744 attrp = new_x_NC_attr(strp, type, nelems);
745 if(attrp == NULL)
746 {
747 status = NC_ENOMEM;
748 goto unwind_name;
749 }
750
751 status = v1h_get_NC_attrV(gsp, attrp);
752 if(status != NC_NOERR)
753 {
754 free_NC_attr(attrp); /* frees strp */
755 return status;
756 }
757
758 *attrpp = attrp;
759
760 return NC_NOERR;
761
762 unwind_name:
763 free_NC_string(strp);
764 return status;
765 }
766
767
768 /* How much space in the header is required for this NC_attrarray? */
769 static size_t
ncx_len_NC_attrarray(const NC_attrarray * ncap,int version)770 ncx_len_NC_attrarray(const NC_attrarray *ncap, int version)
771 {
772 size_t xlen = X_SIZEOF_NCTYPE; /* type */
773 xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */
774 if(ncap == NULL)
775 return xlen;
776 /* else */
777 {
778 const NC_attr **app = (const NC_attr **)ncap->value;
779 const NC_attr *const *const end = &app[ncap->nelems];
780 for( /*NADA*/; app < end; app++)
781 {
782 xlen += ncx_len_NC_attr(*app,version);
783 }
784 }
785 return xlen;
786 }
787
788
789 /* Write a NC_attrarray to the header */
790 static int
v1h_put_NC_attrarray(v1hs * psp,const NC_attrarray * ncap)791 v1h_put_NC_attrarray(v1hs *psp, const NC_attrarray *ncap)
792 {
793 int status;
794
795 assert(psp != NULL);
796
797 if(ncap == NULL
798 #if 1
799 /* Backward:
800 * This clause is for 'byte for byte'
801 * backward compatibility.
802 * Strickly speaking, it is 'bug for bug'.
803 */
804 || ncap->nelems == 0
805 #endif
806 )
807 {
808 /*
809 * Handle empty netcdf
810 */
811 const size_t nosz = 0;
812
813 status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
814 if(status != NC_NOERR)
815 return status;
816 status = v1h_put_size_t(psp, &nosz);
817 if(status != NC_NOERR)
818 return status;
819 return NC_NOERR;
820 }
821 /* else */
822
823 status = v1h_put_NCtype(psp, NC_ATTRIBUTE);
824 if(status != NC_NOERR)
825 return status;
826 status = v1h_put_size_t(psp, &ncap->nelems);
827 if(status != NC_NOERR)
828 return status;
829
830 {
831 const NC_attr **app = (const NC_attr **)ncap->value;
832 const NC_attr *const *const end = &app[ncap->nelems];
833 for( /*NADA*/; app < end; app++)
834 {
835 status = v1h_put_NC_attr(psp, *app);
836 if(status)
837 return status;
838 }
839 }
840 return NC_NOERR;
841 }
842
843
844 /* Read a NC_attrarray from the header */
845 static int
v1h_get_NC_attrarray(v1hs * gsp,NC_attrarray * ncap)846 v1h_get_NC_attrarray(v1hs *gsp, NC_attrarray *ncap)
847 {
848 int status;
849 NCtype type = NC_UNSPECIFIED;
850
851 assert(gsp != NULL && gsp->pos != NULL);
852 assert(ncap != NULL);
853 assert(ncap->value == NULL);
854
855 status = v1h_get_NCtype(gsp, &type);
856 if(status != NC_NOERR)
857 return status;
858 status = v1h_get_size_t(gsp, &ncap->nelems);
859 if(status != NC_NOERR)
860 return status;
861
862 if(ncap->nelems == 0)
863 return NC_NOERR;
864 /* else */
865 if(type != NC_ATTRIBUTE)
866 return EINVAL;
867
868 ncap->value = (NC_attr **) malloc(ncap->nelems * sizeof(NC_attr *));
869 if(ncap->value == NULL)
870 return NC_ENOMEM;
871 ncap->nalloc = ncap->nelems;
872
873 {
874 NC_attr **app = ncap->value;
875 NC_attr *const *const end = &app[ncap->nelems];
876 for( /*NADA*/; app < end; app++)
877 {
878 status = v1h_get_NC_attr(gsp, app);
879 if(status)
880 {
881 ncap->nelems = (size_t)(app - ncap->value);
882 free_NC_attrarrayV(ncap);
883 return status;
884 }
885 }
886 }
887
888 return NC_NOERR;
889 }
890
891 /* End NC_attr */
892 /* Begin NC_var */
893
894 /*
895 * How much space will the xdr'd var take.
896 * Formerly
897 NC_xlen_var(vpp)
898 */
899 static size_t
ncx_len_NC_var(const NC_var * varp,size_t sizeof_off_t,int version)900 ncx_len_NC_var(const NC_var *varp, size_t sizeof_off_t, int version)
901 {
902 size_t sz;
903
904 assert(varp != NULL);
905 assert(sizeof_off_t != 0);
906
907 sz = ncx_len_NC_string(varp->name, version);
908 if (version == 5) {
909 sz += X_SIZEOF_INT64; /* ndims */
910 sz += ncx_len_int64(varp->ndims); /* dimids */
911 }
912 else {
913 sz += X_SIZEOF_SIZE_T; /* ndims */
914 sz += ncx_len_int(varp->ndims); /* dimids */
915 }
916 sz += ncx_len_NC_attrarray(&varp->attrs, version);
917 sz += X_SIZEOF_NC_TYPE; /* nc_type */
918 sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* vsize */
919 sz += sizeof_off_t; /* begin */
920
921 return(sz);
922 }
923
924
925 /* Write a NC_var to the header */
926 static int
v1h_put_NC_var(v1hs * psp,const NC_var * varp)927 v1h_put_NC_var(v1hs *psp, const NC_var *varp)
928 {
929 int status;
930
931 status = v1h_put_NC_string(psp, varp->name);
932 if(status != NC_NOERR)
933 return status;
934
935 status = v1h_put_size_t(psp, &varp->ndims);
936 if(status != NC_NOERR)
937 return status;
938
939 if (psp->version == 5) {
940 status = check_v1hs(psp, ncx_len_int64(varp->ndims));
941 if(status != NC_NOERR)
942 return status;
943 status = ncx_putn_longlong_int(&psp->pos,
944 varp->ndims, varp->dimids, NULL);
945 if(status != NC_NOERR)
946 return status;
947 }
948 else {
949 status = check_v1hs(psp, ncx_len_int(varp->ndims));
950 if(status != NC_NOERR)
951 return status;
952 status = ncx_putn_int_int(&psp->pos,
953 varp->ndims, varp->dimids, NULL);
954 if(status != NC_NOERR)
955 return status;
956 }
957
958 status = v1h_put_NC_attrarray(psp, &varp->attrs);
959 if(status != NC_NOERR)
960 return status;
961
962 status = v1h_put_nc_type(psp, &varp->type);
963 if(status != NC_NOERR)
964 return status;
965
966 status = v1h_put_size_t(psp, &varp->len);
967 if(status != NC_NOERR)
968 return status;
969
970 status = check_v1hs(psp, psp->version == 1 ? 4 : 8); /*begin*/
971 if(status != NC_NOERR)
972 return status;
973 status = ncx_put_off_t(&psp->pos, &varp->begin, psp->version == 1 ? 4 : 8);
974 if(status != NC_NOERR)
975 return status;
976
977 return NC_NOERR;
978 }
979
980
981 /* Read a NC_var from the header */
982 static int
v1h_get_NC_var(v1hs * gsp,NC_var ** varpp)983 v1h_get_NC_var(v1hs *gsp, NC_var **varpp)
984 {
985 NC_string *strp;
986 int status;
987 size_t ndims;
988 NC_var *varp;
989
990 status = v1h_get_NC_string(gsp, &strp);
991 if(status != NC_NOERR)
992 return status;
993
994 status = v1h_get_size_t(gsp, &ndims);
995 if(status != NC_NOERR)
996 goto unwind_name;
997
998 varp = new_x_NC_var(strp, ndims);
999 if(varp == NULL)
1000 {
1001 status = NC_ENOMEM;
1002 goto unwind_name;
1003 }
1004
1005 if (gsp->version == 5) {
1006 status = check_v1hs(gsp, ncx_len_int64(ndims));
1007 if(status != NC_NOERR)
1008 goto unwind_alloc;
1009 status = ncx_getn_longlong_int((const void **)(&gsp->pos),
1010 ndims, varp->dimids);
1011 if(status != NC_NOERR)
1012 goto unwind_alloc;
1013 }
1014 else {
1015 status = check_v1hs(gsp, ncx_len_int(ndims));
1016 if(status != NC_NOERR)
1017 goto unwind_alloc;
1018 status = ncx_getn_int_int((const void **)(&gsp->pos),
1019 ndims, varp->dimids);
1020 if(status != NC_NOERR)
1021 goto unwind_alloc;
1022 }
1023 status = v1h_get_NC_attrarray(gsp, &varp->attrs);
1024 if(status != NC_NOERR)
1025 goto unwind_alloc;
1026 status = v1h_get_nc_type(gsp, &varp->type);
1027 if(status != NC_NOERR)
1028 goto unwind_alloc;
1029
1030 status = v1h_get_size_t(gsp, &varp->len);
1031 if(status != NC_NOERR)
1032 goto unwind_alloc;
1033
1034 status = check_v1hs(gsp, gsp->version == 1 ? 4 : 8);
1035 if(status != NC_NOERR)
1036 goto unwind_alloc;
1037 status = ncx_get_off_t((const void **)&gsp->pos,
1038 &varp->begin, gsp->version == 1 ? 4 : 8);
1039 if(status != NC_NOERR)
1040 goto unwind_alloc;
1041
1042 *varpp = varp;
1043 return NC_NOERR;
1044
1045 unwind_alloc:
1046 free_NC_var(varp); /* frees name */
1047 return status;
1048
1049 unwind_name:
1050 free_NC_string(strp);
1051 return status;
1052 }
1053
1054
1055 /* How much space in the header is required for this NC_vararray? */
1056 static size_t
ncx_len_NC_vararray(const NC_vararray * ncap,size_t sizeof_off_t,int version)1057 ncx_len_NC_vararray(const NC_vararray *ncap, size_t sizeof_off_t, int version)
1058 {
1059 size_t xlen = X_SIZEOF_NCTYPE; /* type */
1060 xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */
1061 if(ncap == NULL)
1062 return xlen;
1063 /* else */
1064 {
1065 const NC_var **vpp = (const NC_var **)ncap->value;
1066 const NC_var *const *const end = &vpp[ncap->nelems];
1067 for( /*NADA*/; vpp < end; vpp++)
1068 {
1069 xlen += ncx_len_NC_var(*vpp, sizeof_off_t, version);
1070 }
1071 }
1072 return xlen;
1073 }
1074
1075
1076 /* Write a NC_vararray to the header */
1077 static int
v1h_put_NC_vararray(v1hs * psp,const NC_vararray * ncap)1078 v1h_put_NC_vararray(v1hs *psp, const NC_vararray *ncap)
1079 {
1080 int status;
1081
1082 assert(psp != NULL);
1083
1084 if(ncap == NULL
1085 #if 1
1086 /* Backward:
1087 * This clause is for 'byte for byte'
1088 * backward compatibility.
1089 * Strickly speaking, it is 'bug for bug'.
1090 */
1091 || ncap->nelems == 0
1092 #endif
1093 )
1094 {
1095 /*
1096 * Handle empty netcdf
1097 */
1098 const size_t nosz = 0;
1099
1100 status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
1101 if(status != NC_NOERR)
1102 return status;
1103 status = v1h_put_size_t(psp, &nosz);
1104 if(status != NC_NOERR)
1105 return status;
1106 return NC_NOERR;
1107 }
1108 /* else */
1109
1110 status = v1h_put_NCtype(psp, NC_VARIABLE);
1111 if(status != NC_NOERR)
1112 return status;
1113 status = v1h_put_size_t(psp, &ncap->nelems);
1114 if(status != NC_NOERR)
1115 return status;
1116
1117 {
1118 const NC_var **vpp = (const NC_var **)ncap->value;
1119 const NC_var *const *const end = &vpp[ncap->nelems];
1120 for( /*NADA*/; vpp < end; vpp++)
1121 {
1122 status = v1h_put_NC_var(psp, *vpp);
1123 if(status)
1124 return status;
1125 }
1126 }
1127 return NC_NOERR;
1128 }
1129
1130
1131 /* Read a NC_vararray from the header */
1132 static int
v1h_get_NC_vararray(v1hs * gsp,NC_vararray * ncap)1133 v1h_get_NC_vararray(v1hs *gsp, NC_vararray *ncap)
1134 {
1135 int status;
1136 NCtype type = NC_UNSPECIFIED;
1137
1138 assert(gsp != NULL && gsp->pos != NULL);
1139 assert(ncap != NULL);
1140 assert(ncap->value == NULL);
1141
1142 status = v1h_get_NCtype(gsp, &type);
1143 if(status != NC_NOERR)
1144 return status;
1145
1146 status = v1h_get_size_t(gsp, &ncap->nelems);
1147 if(status != NC_NOERR)
1148 return status;
1149
1150 if(ncap->nelems == 0)
1151 return NC_NOERR;
1152 /* else */
1153 if(type != NC_VARIABLE)
1154 return EINVAL;
1155
1156 ncap->value = (NC_var **) malloc(ncap->nelems * sizeof(NC_var *));
1157 if(ncap->value == NULL)
1158 return NC_ENOMEM;
1159 ncap->nalloc = ncap->nelems;
1160
1161 ncap->hashmap = NC_hashmapCreate(ncap->nelems);
1162 {
1163 NC_var **vpp = ncap->value;
1164 NC_var *const *const end = &vpp[ncap->nelems];
1165 for( /*NADA*/; vpp < end; vpp++)
1166 {
1167 status = v1h_get_NC_var(gsp, vpp);
1168 if(status)
1169 {
1170 ncap->nelems = (size_t)(vpp - ncap->value);
1171 free_NC_vararrayV(ncap);
1172 return status;
1173 }
1174 {
1175 int varid = (size_t)(vpp - ncap->value);
1176 NC_hashmapAddVar(ncap, varid, (*vpp)->name->cp);
1177 }
1178 }
1179 }
1180
1181 return NC_NOERR;
1182 }
1183
1184
1185 /* End NC_var */
1186 /* Begin NC */
1187
1188 /*
1189 * Recompute the shapes of all variables
1190 * Sets ncp->begin_var to start of first variable.
1191 * Sets ncp->begin_rec to start of first record variable.
1192 * Returns -1 on error. The only possible error is a reference
1193 * to a non existent dimension, which could occur for a corrupted
1194 * netcdf file.
1195 */
1196 static int
NC_computeshapes(NC3_INFO * ncp)1197 NC_computeshapes(NC3_INFO* ncp)
1198 {
1199 NC_var **vpp = (NC_var **)ncp->vars.value;
1200 NC_var *const *const end = &vpp[ncp->vars.nelems];
1201 NC_var *first_var = NULL; /* first "non-record" var */
1202 NC_var *first_rec = NULL; /* first "record" var */
1203 int status;
1204
1205 ncp->begin_var = (off_t) ncp->xsz;
1206 ncp->begin_rec = (off_t) ncp->xsz;
1207 ncp->recsize = 0;
1208
1209 if(ncp->vars.nelems == 0)
1210 return(0);
1211
1212 for( /*NADA*/; vpp < end; vpp++)
1213 {
1214 status = NC_var_shape(*vpp, &ncp->dims);
1215 if(status != NC_NOERR)
1216 return(status);
1217
1218 if(IS_RECVAR(*vpp))
1219 {
1220 if(first_rec == NULL)
1221 first_rec = *vpp;
1222 if((*vpp)->len == UINT32_MAX &&
1223 (fIsSet(ncp->flags, NC_64BIT_OFFSET) ||
1224 fIsSet(ncp->flags, NC_64BIT_DATA))) /* Flag for large last record */
1225 ncp->recsize += (*vpp)->dsizes[0] * (*vpp)->xsz;
1226 else
1227 ncp->recsize += (*vpp)->len;
1228 }
1229 else
1230 {
1231 if(first_var == NULL)
1232 first_var = *vpp;
1233 /*
1234 * Overwritten each time thru.
1235 * Usually overwritten in first_rec != NULL clause below.
1236 */
1237 ncp->begin_rec = (*vpp)->begin + (off_t)(*vpp)->len;
1238 }
1239 }
1240
1241 if(first_rec != NULL)
1242 {
1243 if(ncp->begin_rec > first_rec->begin)
1244 return(NC_ENOTNC); /* not a netCDF file or corrupted */
1245 ncp->begin_rec = first_rec->begin;
1246 /*
1247 * for special case of exactly one record variable, pack value
1248 */
1249 if(ncp->recsize == first_rec->len)
1250 ncp->recsize = *first_rec->dsizes * first_rec->xsz;
1251 }
1252
1253 if(first_var != NULL)
1254 {
1255 ncp->begin_var = first_var->begin;
1256 }
1257 else
1258 {
1259 ncp->begin_var = ncp->begin_rec;
1260 }
1261
1262 if(ncp->begin_var <= 0 ||
1263 ncp->xsz > (size_t)ncp->begin_var ||
1264 ncp->begin_rec <= 0 ||
1265 ncp->begin_var > ncp->begin_rec)
1266 return(NC_ENOTNC); /* not a netCDF file or corrupted */
1267
1268 return(NC_NOERR);
1269 }
1270
1271 /* How much space in the header is required for the NC data structure? */
1272 size_t
ncx_len_NC(const NC3_INFO * ncp,size_t sizeof_off_t)1273 ncx_len_NC(const NC3_INFO* ncp, size_t sizeof_off_t)
1274 {
1275 int version=1;
1276 size_t xlen = sizeof(ncmagic);
1277
1278 assert(ncp != NULL);
1279 if (fIsSet(ncp->flags, NC_64BIT_DATA)) /* CDF-5 */
1280 version = 5;
1281 else if (fIsSet(ncp->flags, NC_64BIT_OFFSET)) /* CDF-2 */
1282 version = 2;
1283
1284 xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* numrecs */
1285 xlen += ncx_len_NC_dimarray(&ncp->dims, version);
1286 xlen += ncx_len_NC_attrarray(&ncp->attrs, version);
1287 xlen += ncx_len_NC_vararray(&ncp->vars, sizeof_off_t, version);
1288
1289 return xlen;
1290 }
1291
1292
1293 /* Write the file header */
1294 int
ncx_put_NC(const NC3_INFO * ncp,void ** xpp,off_t offset,size_t extent)1295 ncx_put_NC(const NC3_INFO* ncp, void **xpp, off_t offset, size_t extent)
1296 {
1297 int status = NC_NOERR;
1298 v1hs ps; /* the get stream */
1299
1300 assert(ncp != NULL);
1301
1302 /* Initialize stream ps */
1303
1304 ps.nciop = ncp->nciop;
1305 ps.flags = RGN_WRITE;
1306
1307 if (ncp->flags & NC_64BIT_DATA)
1308 ps.version = 5;
1309 else if (ncp->flags & NC_64BIT_OFFSET)
1310 ps.version = 2;
1311 else
1312 ps.version = 1;
1313
1314 if(xpp == NULL)
1315 {
1316 /*
1317 * Come up with a reasonable stream read size.
1318 */
1319 extent = ncp->xsz;
1320 if(extent <= ((ps.version==5)?MIN_NC5_XSZ:MIN_NC3_XSZ))
1321 {
1322 /* first time read */
1323 extent = ncp->chunk;
1324 /* Protection for when ncp->chunk is huge;
1325 * no need to read hugely. */
1326 if(extent > 4096)
1327 extent = 4096;
1328 }
1329 else if(extent > ncp->chunk)
1330 extent = ncp->chunk;
1331
1332 ps.offset = 0;
1333 ps.extent = extent;
1334 ps.base = NULL;
1335 ps.pos = ps.base;
1336
1337 status = fault_v1hs(&ps, extent);
1338 if(status)
1339 return status;
1340 }
1341 else
1342 {
1343 ps.offset = offset;
1344 ps.extent = extent;
1345 ps.base = *xpp;
1346 ps.pos = ps.base;
1347 ps.end = (char *)ps.base + ps.extent;
1348 }
1349
1350 if (ps.version == 5)
1351 status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic5), ncmagic5, NULL);
1352 else if (ps.version == 2)
1353 status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic), ncmagic, NULL);
1354 else
1355 status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic1), ncmagic1, NULL);
1356 if(status != NC_NOERR)
1357 goto release;
1358
1359 {
1360 const size_t nrecs = NC_get_numrecs(ncp);
1361 if (ps.version == 5) {
1362 unsigned long long tmp = (unsigned long long) nrecs;
1363 status = ncx_put_uint64(&ps.pos, tmp);
1364 }
1365 else
1366 status = ncx_put_size_t(&ps.pos, &nrecs);
1367 if(status != NC_NOERR)
1368 goto release;
1369 }
1370
1371 assert((char *)ps.pos < (char *)ps.end);
1372
1373 status = v1h_put_NC_dimarray(&ps, &ncp->dims);
1374 if(status != NC_NOERR)
1375 goto release;
1376
1377 status = v1h_put_NC_attrarray(&ps, &ncp->attrs);
1378 if(status != NC_NOERR)
1379 goto release;
1380
1381 status = v1h_put_NC_vararray(&ps, &ncp->vars);
1382 if(status != NC_NOERR)
1383 goto release;
1384
1385 release:
1386 (void) rel_v1hs(&ps);
1387
1388 return status;
1389 }
1390
1391
1392 /* Make the in-memory NC structure from reading the file header */
1393 int
nc_get_NC(NC3_INFO * ncp)1394 nc_get_NC(NC3_INFO* ncp)
1395 {
1396 int status;
1397 v1hs gs; /* the get stream */
1398
1399 assert(ncp != NULL);
1400
1401 /* Initialize stream gs */
1402
1403 gs.nciop = ncp->nciop;
1404 gs.offset = 0; /* beginning of file */
1405 gs.extent = 0;
1406 gs.flags = 0;
1407 gs.version = 0;
1408 gs.base = NULL;
1409 gs.pos = gs.base;
1410
1411 {
1412 /*
1413 * Come up with a reasonable stream read size.
1414 */
1415 off_t filesize;
1416 size_t extent = ncp->xsz;
1417
1418 if(extent <= ((fIsSet(ncp->flags, NC_64BIT_DATA))?MIN_NC5_XSZ:MIN_NC3_XSZ))
1419 {
1420 status = ncio_filesize(ncp->nciop, &filesize);
1421 if(status)
1422 return status;
1423 if(filesize < sizeof(ncmagic)) { /* too small, not netcdf */
1424
1425 status = NC_ENOTNC;
1426 return status;
1427 }
1428 /* first time read */
1429 extent = ncp->chunk;
1430 /* Protection for when ncp->chunk is huge;
1431 * no need to read hugely. */
1432 if(extent > 4096)
1433 extent = 4096;
1434 if(extent > filesize)
1435 extent = (size_t)filesize;
1436 }
1437 else if(extent > ncp->chunk)
1438 extent = ncp->chunk;
1439
1440 /*
1441 * Invalidate the I/O buffers to force a read of the header
1442 * region.
1443 */
1444 status = ncio_sync(gs.nciop);
1445 if(status)
1446 return status;
1447
1448 status = fault_v1hs(&gs, extent);
1449 if(status)
1450 return status;
1451 }
1452
1453 /* get the header from the stream gs */
1454
1455 {
1456 /* Get & check magic number */
1457 schar magic[sizeof(ncmagic)];
1458 (void) memset(magic, 0, sizeof(magic));
1459
1460 status = ncx_getn_schar_schar(
1461 (const void **)(&gs.pos), sizeof(magic), magic);
1462 if(status != NC_NOERR)
1463 goto unwind_get;
1464
1465 if(memcmp(magic, ncmagic, sizeof(ncmagic)-1) != 0)
1466 {
1467 status = NC_ENOTNC;
1468 goto unwind_get;
1469 }
1470 /* Check version number in last byte of magic */
1471 if (magic[sizeof(ncmagic)-1] == 0x1) {
1472 gs.version = 1;
1473 } else if (magic[sizeof(ncmagic)-1] == 0x2) {
1474 gs.version = 2;
1475 fSet(ncp->flags, NC_64BIT_OFFSET);
1476 /* Now we support version 2 file access on non-LFS systems -- rkr */
1477 #if 0
1478 if (sizeof(off_t) != 8) {
1479 fprintf(stderr, "NETCDF WARNING: Version 2 file on 32-bit system.\n");
1480 }
1481 #endif
1482 } else if (magic[sizeof(ncmagic)-1] == 0x5) {
1483 gs.version = 5;
1484 fSet(ncp->flags, NC_64BIT_DATA);
1485 } else {
1486 status = NC_ENOTNC;
1487 goto unwind_get;
1488 }
1489 }
1490
1491 {
1492 size_t nrecs = 0;
1493 if (gs.version == 5) {
1494 unsigned long long tmp = 0;
1495 status = ncx_get_uint64((const void **)(&gs.pos), &tmp);
1496 nrecs = (size_t)tmp;
1497 }
1498 else
1499 status = ncx_get_size_t((const void **)(&gs.pos), &nrecs);
1500 if(status != NC_NOERR)
1501 goto unwind_get;
1502 NC_set_numrecs(ncp, nrecs);
1503 }
1504
1505 assert((char *)gs.pos < (char *)gs.end);
1506
1507 status = v1h_get_NC_dimarray(&gs, &ncp->dims);
1508 if(status != NC_NOERR)
1509 goto unwind_get;
1510
1511 status = v1h_get_NC_attrarray(&gs, &ncp->attrs);
1512 if(status != NC_NOERR)
1513 goto unwind_get;
1514
1515 status = v1h_get_NC_vararray(&gs, &ncp->vars);
1516 if(status != NC_NOERR)
1517 goto unwind_get;
1518
1519 ncp->xsz = ncx_len_NC(ncp, (gs.version == 1) ? 4 : 8);
1520
1521 status = NC_computeshapes(ncp);
1522 if(status != NC_NOERR)
1523 goto unwind_get;
1524
1525 status = NC_check_vlens(ncp);
1526 if(status != NC_NOERR)
1527 goto unwind_get;
1528
1529 unwind_get:
1530 (void) rel_v1hs(&gs);
1531 return status;
1532 }
1533