netcdf-c/libdap4/d4varx.c
Dennis Heimbigner 97ce621091 Improve operation of the DAP4 code and fix bugs
re: esupport 31942

* Add a new set of remote tests based on using the opendap hyrax server
* Re-enable --enable-dap-remote-tests as default on
* Make it possible to query the DMR separate from the DAP
  so that it is possible to delay reading data until it is actually
  requested. This make things like ncdump -h much more efficient.
* Fix handling of <Map>s in DMRs.
* Fix some memory leaks
2021-01-14 21:39:08 -07:00

192 lines
5.5 KiB
C

/*********************************************************************
* Copyright 2018, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
#include "config.h"
#include "ncdispatch.h"
#include "ncd4dispatch.h"
#include "nc4internal.h"
#include "d4includes.h"
#include "d4odom.h"
/* Forward */
static int getvarx(int ncid, int varid, NCD4INFO**, NCD4node** varp, nc_type* xtypep, size_t*, nc_type* nc4typep, size_t*);
int
NCD4_get_vara(int ncid, int varid,
const size_t *start, const size_t *edges,
void *value,
nc_type memtype)
{
int ret;
/* TODO: optimize since we know stride is 1 */
ret = NCD4_get_vars(ncid,varid,start,edges,NC_stride_one,value,memtype);
return ret;
}
int
NCD4_get_vars(int ncid, int varid,
const size_t *start, const size_t *edges, const ptrdiff_t* stride,
void *memoryin, nc_type xtype)
{
int i,ret;
NCD4INFO* info;
NCD4meta* meta;
NCD4node* ncvar;
NCD4node* nctype;
D4odometer* odom = NULL;
nc_type nc4type;
size_t nc4size, xsize;
void* instance = NULL; /* Staging area in case we have to convert */
NClist* blobs = NULL;
int rank;
size_t dimsizes[NC_MAX_VAR_DIMS];
d4size_t dimproduct;
size_t dstcount;
if((ret=getvarx(ncid, varid, &info, &ncvar, &xtype, &xsize, &nc4type, &nc4size)))
{goto done;}
meta = info->substrate.metadata;
nctype = ncvar->basetype;
rank = nclistlength(ncvar->dims);
blobs = nclistnew();
instance = malloc(nc4size);
if(instance == NULL)
{ret = THROW(NC_ENOMEM); goto done;}
dimproduct = NCD4_dimproduct(ncvar);
/* build size vector */
for(i=0;i<rank;i++) {
NCD4node* dim = nclistget(ncvar->dims,i);
dimsizes[i] = (size_t)dim->dim.size;
}
/* Extract and desired subset of data */
if(rank > 0)
odom = d4odom_new(rank,start,edges,stride,dimsizes);
else
odom = d4scalarodom_new();
dstcount = 0; /* We always write into dst starting at position 0*/
for(;d4odom_more(odom);dstcount++) {
void* xpos;
void* offset;
void* dst;
d4size_t count;
count = d4odom_next(odom);
if(count >= dimproduct) {
ret = THROW(NC_EINVALCOORDS);
goto done;
}
xpos = INCR(memoryin,(xsize * dstcount)); /* ultimate destination */
/* We need to compute the offset in the dap4 data of this instance;
for fixed size types, this is easy, otherwise we have to walk
the variable size type
*/
if(nctype->meta.isfixedsize) {
offset = INCR(ncvar->data.dap4data.memory,(nc4size * count));
} else {
offset = ncvar->data.dap4data.memory;
/* We have to walk to the count'th location in the data */
if((ret=NCD4_moveto(meta,ncvar,count,&offset)))
{goto done;}
}
dst = instance;
if((ret=NCD4_fillinstance(meta,nctype,&offset,&dst,blobs)))
{goto done;}
if(xtype == nc4type) {
/* We can just copy out the data */
memcpy(xpos,instance,nc4size);
} else { /* Need to convert */
if((ret=NCD4_convert(nc4type,xtype,xpos,instance,1)))
{goto done;}
}
}
done:
/* cleanup */
if(odom != NULL)
d4odom_free(odom);
if(instance != NULL)
free(instance);
if(ret != NC_NOERR) { /* reclaim all malloc'd data if there is an error*/
for(i=0;i<nclistlength(blobs);i++) {
nullfree(nclistget(blobs,i));
}
}
if(blobs) nclistfree(blobs);
return (ret);
}
static int
getvarx(int ncid, int varid, NCD4INFO** infop, NCD4node** varp,
nc_type* xtypep, size_t* xsizep, nc_type* nc4typep, size_t* nc4sizep)
{
int ret = NC_NOERR;
NC* ncp;
NCD4INFO* info;
NCD4meta* meta;
NCD4node* group;
NCD4node* var;
NCD4node* type;
nc_type xtype, actualtype;
size_t instancesize, xsize;
if((ret = NC_check_id(ncid, (NC**)&ncp)) != NC_NOERR)
goto done;
info = getdap(ncp);
meta = info->substrate.metadata;
/* If the data has not already been read and processed, then do so. */
if(meta->serial.dap == NULL) {
size_t len = 0;
void* content = NULL;
/* (Re)Build the meta data; sets serial.rawdata */
NCD4_resetMeta(info->substrate.metadata);
meta->controller = info;
meta->ncid = info->substrate.nc4id; /* Transfer netcdf ncid */
if((ret=NCD4_readDAP(info, info->controls.flags.flags))) goto done;
len = ncbyteslength(info->curl->packet);
content = ncbytesextract(info->curl->packet);
NCD4_resetSerial(&meta->serial, len, content);
/* Process the data part */
if((ret=NCD4_dechunk(meta))) goto done;
if((ret = NCD4_processdata(info->substrate.metadata))) goto done;
}
if((ret = NCD4_findvar(ncp,ncid,varid,&var,&group))) goto done;
type = var->basetype;
actualtype = type->meta.id;
instancesize = type->meta.memsize;
/* Figure out the type conversion, if any */
xtype = *xtypep;
if(xtype == NC_NAT)
xtype = actualtype;
if(xtype != actualtype && xtype > NC_MAX_ATOMIC_TYPE)
return THROW(NC_EBADTYPE);
if((xtype == NC_CHAR || xtype == NC_STRING)
&& (actualtype != NC_CHAR && actualtype != NC_STRING))
return THROW(NC_ECHAR);
if(xtype <= NC_MAX_ATOMIC_TYPE)
xsize = NCD4_typesize(xtype);
else
xsize = instancesize;
/* Return relevant info */
if(infop) *infop = info;
if(xtypep) *xtypep = xtype;
if(xsizep) *xsizep = xsize;
if(nc4typep) *nc4typep = actualtype;
if(nc4sizep) *nc4sizep = instancesize;
if(varp) *varp = var;
done:
return THROW(ret);
}