#include "netcdf.h" int netcdf_unstuff_header(unsigned char **stream, NETCDFHdr **hdr) int netcdf_print_header(NETCDFHdr *hdr, FILE *file)
NetCDF file forms are used in the atmospheric sciences community for representing geophysical data. These files are also used for representing basic geographic data, such as vector river and political boundary data that is distributed as part of the GMT package (see http://gmt.soest.hawaii.edu). NetCDF files are basically composed of two parts: a header that contains a dictionary for describing the data and the binary data. This utility allows for efficient extraction and unstuffing of the NetCDF header into an internal structure that can then be used to get at the binary data. Note that this utility will only work with version 01 of NetCDF.
netcdf_unstuff_header will unstuff a NetCDF file header into an internal C-structure. stream is the byte stream that represents the NetCDF file and can be conveniently obtained with the mapfile(3) subroutine. The header is returned in hdr which will be either malloc'ed, if the input value is NULL, or reused, if the input value is not NULL. A -1 return value indicates an error. The header can be printed out with a call to netcdf_print_header. The NETCDFHdr structure is defined in netcdf.h as follows:
/* netcdf structure definitions */ typedef struct netcdf_values_ { /* an array of netcdf values */ int type; /* type (e.g. NETCDF_CODE_INT, etc.) */ int n; /* number of values */ void *values; /* array of values */ }NETCDFValues; typedef struct netcdf_dim_ { /* "dimension" entry */ char *name; /* dimension name */ int value; /* dimension value */ } NETCDFDim; typedef struct netcdf_attr_ { /* "attribute" entry */ char *name; /* attribute name */ NETCDFValues values; /* attribute values */ } NETCDFAttr; typedef struct netcdf_var_ { /* "variable" entry */ char *name; /* variable name */ int ndims; /* number of dimensions */ NETCDFDim **dims; /* pointers to the dimension definitions */ int nattrs; /* number in attributes array */ NETCDFAttr *attrs; /* variable "attributes" array */ int type; /* variable type (e.g. NETCDF_CODE_INT, etc.) */ int vsize; /* variable size */ int begin; /* variable start location (file byte offset) */ int fixed; /* If set, then this is a fixed size, or non-record variable */ } NETCDFVar; typedef struct netcdf_hdr_ { /* header */ unsigned char *stream; /* File stream pointer */ int numrecs; /* number of data "records" */ NETCDFDim *dims; /* "dimensions" array */ int dims_n; /* number in dimensions array */ NETCDFAttr *attrs; /* Global "attributes" array */ int attrs_n; /* number in attributes array */ NETCDFVar *vars; /* "variables" array */ int vars_n; /* number in variables array */ Arr *vars_array; /* Associative array that indexes into vars structures */ } NETCDFHdr; typedef struct netcdf_ { /* maps to a single cdf file */ NETCDFHdr hdr; /* header */ } NETCDF;
NetCDF binary data is always in SUN network byte order. Different data types are specified through the type variables in the various structures. These types are defined below:
% cat testcdf.c #include <stdlib.h> #include "brttutil.h" #include "stock.h" #include "netcdf.h" int main (int argc, char **argv) { int size; char *strm = NULL; unsigned char *stream = NULL; NETCDFHdr *hdr = NULL; if (argc != 2) { fprintf (stderr, "usage: testcdf cdffile\n"); exit (1); } /* map netcdf file */ size = mapfile (argv[1], NULL, &strm); if (size < 0) { die (0, "mapfile(%s) error.\n", argv[1] ); } stream = (unsigned char *) strm; /* unstuff the cdf header */ if (netcdf_unstuff_header (&stream, &hdr) < 0) { die (0, "netcdf_unstuff_header(%s) error.\n", argv[1] ); } /* print out header */ netcdf_print_header (hdr, stdout); exit (0); } % cat Makefile BIN = testcdf MAN1 = PF = ldlibs= -lmappts -lbrttutil -lstock -ldeviants include $(ANTELOPEMAKE) DIRS= OBJS= \ testcdf.o testcdf : $(OBJS) $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS) % .\testcdf /opt/antelope/4.8/data/maps/mappts/binned_border_c.cdf numrecs = 0 dims_n = 4 dims[00].name = Dimension_of_scalar dims[00].value = 1 dims[01].name = Dimension_of_bin_arrays dims[01].value = 162 dims[02].name = Dimension_of_segment_arrays dims[02].value = 1374 dims[03].name = Dimension_of_point_arrays dims[03].value = 4945 attrs_n = 2 attrs[00].name = title attrs[00].values.type = char attrs[00].values.n = 49 attrs[00].values.values[..] = Political boundaries derived from CIA WDB-II data attrs[01].name = source attrs[01].values.type = char attrs[01].values.n = 64 attrs[01].values.values[..] = Processed by Paul Wessel and Walter H. F. Smith, 1994-1999, v1.2 vars_n = 13 vars[00].name = Bin_size_in_minutes vars[00].type = int vars[00].vsize = 4 vars[00].begin = 1252 vars[00].fixed = 1 vars[00].dims_n = 1 vars[00].dims[00].name = Dimension_of_scalar (1) vars[00].attrs_n= 0 ...