source: XIOS/dev/dev_olga/extern/src_netcdf4/v1hpg.c @ 1620

Last change on this file since 1620 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

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