📄 v1hpg.c
字号:
/* * Copyright 1996, University Corporation for Atmospheric Research * See netcdf/COPYRIGHT file for copying and redistribution conditions. *//* $Id: v1hpg.c 2501 2007-11-20 02:33:29Z benkirk $ */#include "nc.h"#include <stdlib.h>#include <stdio.h>#include <string.h>#include <assert.h>#include "rnd.h"#include "ncx.h"/* * This module defines the external representation * of the "header" of a netcdf version one file and * the version two variant that uses 64-bit file * offsets instead of the 32-bit file offsets in version * one files. * For each of the components of the NC structure, * There are (static) ncx_len_XXX(), v1h_put_XXX() * and v1h_get_XXX() functions. These define the * external representation of the components. * The exported entry points for the whole NC structure * are built up from these. *//* * "magic number" at beginning of file: 0x43444601 (big endian) * assert(sizeof(ncmagic) % X_ALIGN == 0); */static const schar ncmagic[] = {'C', 'D', 'F', 0x02};static const schar ncmagic1[] = {'C', 'D', 'F', 0x01};/* * v1hs == "Version 1 Header Stream" * * The netcdf file version 1 header is * of unknown and potentially unlimited size. * So, we don't know how much to get() on * the initial read. We build a stream, 'v1hs' * on top of ncio to do the header get. */typedef struct v1hs { ncio *nciop; off_t offset; /* argument to nciop->get() */ size_t extent; /* argument to nciop->get() */ int flags; /* set to RGN_WRITE for write */ int version; /* format variant: NC_FORMAT_CLASSIC or NC_FORMAT_64BIT */ void *base; /* beginning of current buffer */ void *pos; /* current position in buffer */ void *end; /* end of current buffer = base + extent */} v1hs;/* * Release the stream, invalidate buffer */static intrel_v1hs(v1hs *gsp){ int status; if(gsp->offset == OFF_NONE || gsp->base == NULL) return ENOERR; status = gsp->nciop->rel(gsp->nciop, gsp->offset, gsp->flags == RGN_WRITE ? RGN_MODIFIED : 0); gsp->end = NULL; gsp->pos = NULL; gsp->base = NULL; return status;}/* * Release the current chunk and get the next one. * Also used for initialization when gsp->base == NULL. */static intfault_v1hs(v1hs *gsp, size_t extent){ int status; if(gsp->base != NULL) { const ptrdiff_t incr = (char *)gsp->pos - (char *)gsp->base; status = rel_v1hs(gsp); if(status) return status; gsp->offset += incr; } if(extent > gsp->extent) gsp->extent = extent; status = gsp->nciop->get(gsp->nciop, gsp->offset, gsp->extent, gsp->flags, &gsp->base); if(status) return status; gsp->pos = gsp->base; gsp->end = (char *)gsp->base + gsp->extent; return ENOERR;}/* * Ensure that 'nextread' bytes are available. */static intcheck_v1hs(v1hs *gsp, size_t nextread){#if 0 /* DEBUG */fprintf(stderr, "nextread %lu, remaining %lu\n", (unsigned long)nextread, (unsigned long)((char *)gsp->end - (char *)gsp->pos));#endif if((char *)gsp->pos + nextread <= (char *)gsp->end) return ENOERR; return fault_v1hs(gsp, nextread);}/* End v1hs *//* Write a size_t to the header */static intv1h_put_size_t(v1hs *psp, const size_t *sp){ int status = check_v1hs(psp, X_SIZEOF_SIZE_T); if(status != ENOERR) return status; return ncx_put_size_t(&psp->pos, sp);}/* Read a size_t from the header */static intv1h_get_size_t(v1hs *gsp, size_t *sp){ int status = check_v1hs(gsp, X_SIZEOF_SIZE_T); if(status != ENOERR) return status; return ncx_get_size_t((const void **)(&gsp->pos), sp);}/* Begin nc_type */#define X_SIZEOF_NC_TYPE X_SIZEOF_INT/* Write a nc_type to the header */static intv1h_put_nc_type(v1hs *psp, const nc_type *typep){ const int itype = (int) *typep; int status = check_v1hs(psp, X_SIZEOF_INT); if(status != ENOERR) return status; status = ncx_put_int_int(psp->pos, &itype); psp->pos = (void *)((char *)psp->pos + X_SIZEOF_INT); return status;}/* Read a nc_type from the header */static intv1h_get_nc_type(v1hs *gsp, nc_type *typep){ int type = 0; int status = check_v1hs(gsp, X_SIZEOF_INT); if(status != ENOERR) return status; status = ncx_get_int_int(gsp->pos, &type); gsp->pos = (void *)((char *)gsp->pos + X_SIZEOF_INT); if(status != ENOERR) return status; assert(type == NC_BYTE || type == NC_CHAR || type == NC_SHORT || type == NC_INT || type == NC_FLOAT || type == NC_DOUBLE); /* else */ *typep = (nc_type) type; return ENOERR;}/* End nc_type *//* Begin NCtype (internal tags) */#define X_SIZEOF_NCTYPE X_SIZEOF_INT/* Write a NCtype to the header */static intv1h_put_NCtype(v1hs *psp, NCtype type){ const int itype = (int) type; int status = check_v1hs(psp, X_SIZEOF_INT); if(status != ENOERR) return status; status = ncx_put_int_int(psp->pos, &itype); psp->pos = (void *)((char *)psp->pos + X_SIZEOF_INT); return status;}/* Read a NCtype from the header */static intv1h_get_NCtype(v1hs *gsp, NCtype *typep){ int type = 0; int status = check_v1hs(gsp, X_SIZEOF_INT); if(status != ENOERR) return status; status = ncx_get_int_int(gsp->pos, &type); gsp->pos = (void *)((char *)gsp->pos + X_SIZEOF_INT); if(status != ENOERR) return status; /* else */ *typep = (NCtype) type; return ENOERR;}/* End NCtype *//* Begin NC_string *//* * How much space will the xdr'd string take. * FormerlyNC_xlen_string(cdfstr) */static size_tncx_len_NC_string(const NC_string *ncstrp){ size_t sz = X_SIZEOF_SIZE_T; /* nchars */ assert(ncstrp != NULL); if(ncstrp->nchars != 0) {#if 0 assert(ncstrp->nchars % X_ALIGN == 0); sz += ncstrp->nchars;#else sz += _RNDUP(ncstrp->nchars, X_ALIGN);#endif } return sz;}/* Write a NC_string to the header */static intv1h_put_NC_string(v1hs *psp, const NC_string *ncstrp){ int status;#if 0 assert(ncstrp->nchars % X_ALIGN == 0);#endif status = v1h_put_size_t(psp, &ncstrp->nchars); if(status != ENOERR) return status; status = check_v1hs(psp, _RNDUP(ncstrp->nchars, X_ALIGN)); if(status != ENOERR) return status; status = ncx_pad_putn_text(&psp->pos, ncstrp->nchars, ncstrp->cp); if(status != ENOERR) return status; return ENOERR;}/* Read a NC_string from the header */static intv1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp){ int status; size_t nchars = 0; NC_string *ncstrp; status = v1h_get_size_t(gsp, &nchars); if(status != ENOERR) return status; ncstrp = new_NC_string(nchars, NULL); if(ncstrp == NULL) { return NC_ENOMEM; }#if 0/* assert(ncstrp->nchars == nchars || ncstrp->nchars - nchars < X_ALIGN); */ assert(ncstrp->nchars % X_ALIGN == 0); status = check_v1hs(gsp, ncstrp->nchars);#else status = check_v1hs(gsp, _RNDUP(ncstrp->nchars, X_ALIGN));#endif if(status != ENOERR) goto unwind_alloc; status = ncx_pad_getn_text((const void **)(&gsp->pos), nchars, ncstrp->cp); if(status != ENOERR) goto unwind_alloc; *ncstrpp = ncstrp; return ENOERR;unwind_alloc: free_NC_string(ncstrp); return status; }/* End NC_string *//* Begin NC_dim *//* * How much space will the xdr'd dim take. * FormerlyNC_xlen_dim(dpp) */static size_tncx_len_NC_dim(const NC_dim *dimp){ size_t sz; assert(dimp != NULL); sz = ncx_len_NC_string(dimp->name); sz += X_SIZEOF_SIZE_T; return(sz);}/* Write a NC_dim to the header */static intv1h_put_NC_dim(v1hs *psp, const NC_dim *dimp){ int status; status = v1h_put_NC_string(psp, dimp->name); if(status != ENOERR) return status; status = v1h_put_size_t(psp, &dimp->size); if(status != ENOERR) return status; return ENOERR;}/* Read a NC_dim from the header */static intv1h_get_NC_dim(v1hs *gsp, NC_dim **dimpp){ int status; NC_string *ncstrp; NC_dim *dimp; status = v1h_get_NC_string(gsp, &ncstrp); if(status != ENOERR) return status; dimp = new_x_NC_dim(ncstrp); if(dimp == NULL) { status = NC_ENOMEM; goto unwind_name; } status = v1h_get_size_t(gsp, &dimp->size); if(status != ENOERR) { free_NC_dim(dimp); /* frees name */ return status; } *dimpp = dimp; return ENOERR;unwind_name: free_NC_string(ncstrp); return status;}/* How much space in the header is required for this NC_dimarray? */static size_tncx_len_NC_dimarray(const NC_dimarray *ncap){ size_t xlen = X_SIZEOF_NCTYPE; /* type */ xlen += X_SIZEOF_SIZE_T; /* count */ if(ncap == NULL) return xlen; /* else */ { const NC_dim **dpp = (const NC_dim **)ncap->value; const NC_dim *const *const end = &dpp[ncap->nelems]; for( /*NADA*/; dpp < end; dpp++) { xlen += ncx_len_NC_dim(*dpp); } } return xlen;}/* Write a NC_dimarray to the header */static intv1h_put_NC_dimarray(v1hs *psp, const NC_dimarray *ncap){ int status; assert(psp != NULL); if(ncap == NULL#if 1 /* Backward: * This clause is for 'byte for byte' * backward compatibility. * Strickly speaking, it is 'bug for bug'. */ || ncap->nelems == 0#endif ) { /* * Handle empty netcdf */ const size_t nosz = 0; status = v1h_put_NCtype(psp, NC_UNSPECIFIED); if(status != ENOERR) return status; status = v1h_put_size_t(psp, &nosz); if(status != ENOERR) return status; return ENOERR; } /* else */ status = v1h_put_NCtype(psp, NC_DIMENSION); if(status != ENOERR) return status; status = v1h_put_size_t(psp, &ncap->nelems); if(status != ENOERR) return status; { const NC_dim **dpp = (const NC_dim **)ncap->value; const NC_dim *const *const end = &dpp[ncap->nelems]; for( /*NADA*/; dpp < end; dpp++) { status = v1h_put_NC_dim(psp, *dpp); if(status) return status; } } return ENOERR;}/* Read a NC_dimarray from the header */static intv1h_get_NC_dimarray(v1hs *gsp, NC_dimarray *ncap){ int status; NCtype type = NC_UNSPECIFIED; assert(gsp != NULL && gsp->pos != NULL); assert(ncap != NULL); assert(ncap->value == NULL); status = v1h_get_NCtype(gsp, &type); if(status != ENOERR) return status; status = v1h_get_size_t(gsp, &ncap->nelems); if(status != ENOERR) return status; if(ncap->nelems == 0) return ENOERR; /* else */ if(type != NC_DIMENSION) return EINVAL; ncap->value = (NC_dim **) malloc(ncap->nelems * sizeof(NC_dim *)); if(ncap->value == NULL) return NC_ENOMEM; ncap->nalloc = ncap->nelems; { NC_dim **dpp = ncap->value; NC_dim *const *const end = &dpp[ncap->nelems]; for( /*NADA*/; dpp < end; dpp++) { status = v1h_get_NC_dim(gsp, dpp); if(status) { ncap->nelems = (size_t)(dpp - ncap->value); free_NC_dimarrayV(ncap); return status; } } } return ENOERR;}/* End NC_dim *//* Begin NC_attr *//* * How much space will 'attrp' take in external representation? * FormerlyNC_xlen_attr(app) */static size_tncx_len_NC_attr(const NC_attr *attrp){ size_t sz; assert(attrp != NULL); sz = ncx_len_NC_string(attrp->name); sz += X_SIZEOF_NC_TYPE; /* type */ sz += X_SIZEOF_SIZE_T; /* nelems */ sz += attrp->xsz; return(sz);}#undef MIN#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))/* * Put the values of an attribute * The loop is necessary since attrp->nelems * could potentially be quite large. */static intv1h_put_NC_attrV(v1hs *psp, const NC_attr *attrp){ int status; const size_t perchunk = psp->extent; size_t remaining = attrp->xsz; void *value = attrp->xvalue; size_t nbytes; assert(psp->extent % X_ALIGN == 0); do { nbytes = MIN(perchunk, remaining); status = check_v1hs(psp, nbytes); if(status != ENOERR) return status; (void) memcpy(psp->pos, value, nbytes); psp->pos = (void *)((char *)psp->pos + nbytes); value = (void *)((char *)value + nbytes); remaining -= nbytes; } while(remaining != 0); return ENOERR;}/* Write a NC_attr to the header */static intv1h_put_NC_attr(v1hs *psp, const NC_attr *attrp){ int status; status = v1h_put_NC_string(psp, attrp->name); if(status != ENOERR) return status; status = v1h_put_nc_type(psp, &attrp->type); if(status != ENOERR) return status; status = v1h_put_size_t(psp, &attrp->nelems); if(status != ENOERR) return status; status = v1h_put_NC_attrV(psp, attrp); if(status != ENOERR) return status; return ENOERR;}/* * Get the values of an attribute * The loop is necessary since attrp->nelems * could potentially be quite large. */static intv1h_get_NC_attrV(v1hs *gsp, NC_attr *attrp){ int status; const size_t perchunk = gsp->extent; size_t remaining = attrp->xsz; void *value = attrp->xvalue; size_t nget; do { nget = MIN(perchunk, remaining); status = check_v1hs(gsp, nget); if(status != ENOERR) return status; (void) memcpy(value, gsp->pos, nget); gsp->pos = (void *)((char *)gsp->pos + nget); value = (void *)((char *)value + nget); remaining -= nget; } while(remaining != 0); return ENOERR;}/* Read a NC_attr from the header */static intv1h_get_NC_attr(v1hs *gsp, NC_attr **attrpp){ NC_string *strp; int status; nc_type type; size_t nelems; NC_attr *attrp; status = v1h_get_NC_string(gsp, &strp); if(status != ENOERR) return status; status = v1h_get_nc_type(gsp, &type); if(status != ENOERR) goto unwind_name; status = v1h_get_size_t(gsp, &nelems); if(status != ENOERR) goto unwind_name; attrp = new_x_NC_attr(strp, type, nelems); if(attrp == NULL) { status = NC_ENOMEM; goto unwind_name; } status = v1h_get_NC_attrV(gsp, attrp); if(status != ENOERR) { free_NC_attr(attrp); /* frees strp */ return status; } *attrpp = attrp; return ENOERR;unwind_name: free_NC_string(strp); return status;}/* How much space in the header is required for this NC_attrarray? */static size_tncx_len_NC_attrarray(const NC_attrarray *ncap){ size_t xlen = X_SIZEOF_NCTYPE; /* type */ xlen += X_SIZEOF_SIZE_T; /* count */ if(ncap == NULL) return xlen; /* else */ { const NC_attr **app = (const NC_attr **)ncap->value; const NC_attr *const *const end = &app[ncap->nelems]; for( /*NADA*/; app < end; app++) { xlen += ncx_len_NC_attr(*app);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -