mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-12-09 08:11:38 +08:00
af566dd300
the libdap2 code to make it dap2 protocol + netcdf classic only.
503 lines
15 KiB
C
503 lines
15 KiB
C
/*********************************************************************
|
|
* Copyright 1993, UCAR/Unidata
|
|
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
|
*********************************************************************/
|
|
|
|
#include "ncdap.h"
|
|
|
|
#define OCCHECK(exp) if((ocstat = (exp))) {THROWCHK(ocstat); goto done;}
|
|
|
|
/* Forward */
|
|
static NCerror buildattribute(char*,nc_type,size_t,char**,NCattribute**);
|
|
|
|
/*
|
|
Invoke oc_merge_das and then extract special
|
|
attributes such as "strlen" and "dimname"
|
|
and stuff from DODS_EXTRA.
|
|
*/
|
|
int
|
|
dapmerge(NCDAPCOMMON* nccomm, CDFnode* ddsroot, OCddsnode dasroot)
|
|
{
|
|
int i,j;
|
|
NCerror ncstat = NC_NOERR;
|
|
OCerror ocstat = OC_NOERR;
|
|
NClist* allnodes;
|
|
OClink conn;
|
|
char* ocname = NULL;
|
|
char** values = NULL;
|
|
conn = nccomm->oc.conn;
|
|
|
|
if(ddsroot == NULL || dasroot == NULL)
|
|
return NC_NOERR;
|
|
/* Merge the das tree onto the dds tree */
|
|
ocstat = oc_merge_das(nccomm->oc.conn,dasroot,ddsroot->ocnode);
|
|
if(ocstat != OC_NOERR) goto done;
|
|
|
|
/* Create attributes on CDFnodes */
|
|
allnodes = ddsroot->tree->nodes;
|
|
for(i=0;i<nclistlength(allnodes);i++) {
|
|
CDFnode* node = (CDFnode*)nclistget(allnodes,i);
|
|
OCddsnode ocnode = node->ocnode;
|
|
size_t attrcount;
|
|
OCtype ocetype;
|
|
|
|
OCCHECK(oc_dds_attr_count(conn,ocnode,&attrcount));
|
|
for(j=0;j<attrcount;j++) {
|
|
size_t nvalues;
|
|
|
|
NCattribute* att = NULL;
|
|
|
|
if(ocname != NULL) {
|
|
free(ocname); ocname = NULL;
|
|
} /* from last loop */
|
|
|
|
OCCHECK(oc_dds_attr(conn,ocnode,j,&ocname,&ocetype,&nvalues,NULL));
|
|
if(nvalues > 0) {
|
|
values = (char**)malloc(sizeof(char*)*nvalues);
|
|
if(values == NULL) {ncstat = NC_ENOMEM; goto done;}
|
|
OCCHECK(oc_dds_attr(conn,ocnode,j,NULL,NULL,NULL,values));
|
|
}
|
|
ncstat = buildattribute(ocname,octypetonc(ocetype),nvalues,values,&att);
|
|
if(ncstat != NC_NOERR) goto done;
|
|
if(node->attributes == NULL)
|
|
node->attributes = nclistnew();
|
|
nclistpush(node->attributes,(void*)att);
|
|
if(strncmp(ocname,"DODS",strlen("DODS"))==0) {
|
|
att->invisible = 1;
|
|
/* Define extra semantics associated with
|
|
DODS and DODS_EXTRA attributes */
|
|
if(strcmp(ocname,"DODS.strlen")==0
|
|
|| strcmp(ocname,"DODS_EXTRA.strlen")==0) {
|
|
unsigned int maxstrlen = 0;
|
|
if(values != NULL) {
|
|
if(0==sscanf(values[0],"%u",&maxstrlen))
|
|
maxstrlen = 0;
|
|
}
|
|
node->dodsspecial.maxstrlen = maxstrlen;
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"%s.maxstrlen=%d\n",node->ocname,(int)node->dodsspecial.maxstrlen);
|
|
#endif
|
|
} else if(strcmp(ocname,"DODS.dimName")==0
|
|
|| strcmp(ocname,"DODS_EXTRA.dimName")==0) {
|
|
if(values != NULL) {
|
|
node->dodsspecial.dimname = nulldup(values[0]);
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"%s.dimname=%s\n",node->ocname,node->dodsspecial.dimname);
|
|
#endif
|
|
} else node->dodsspecial.dimname = NULL;
|
|
} else if(strcmp(ocname,"DODS.Unlimited_Dimension")==0
|
|
|| strcmp(ocname,"DODS_EXTRA.Unlimited_Dimension")==0) {
|
|
if(values != NULL) {
|
|
if(nccomm->cdf.recorddimname != NULL)
|
|
nclog(NCLOGWARN,"Duplicate DODS_EXTRA:Unlimited_Dimension specifications");
|
|
else
|
|
nccomm->cdf.recorddimname = nulldup(values[0]);
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"%s.Unlimited_Dimension=%s\n",node->ocname,nccomm->cdf.recorddimname);
|
|
#endif
|
|
}
|
|
|
|
}
|
|
}
|
|
/* clean up */
|
|
if(values) {
|
|
oc_reclaim_strings(nvalues,values);
|
|
free(values);
|
|
values = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
done:
|
|
if(values != NULL) free(values);
|
|
if(ocname != NULL) free(ocname);
|
|
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
|
|
return THROW(ncstat);
|
|
}
|
|
|
|
/* Build an NCattribute */
|
|
static NCerror
|
|
buildattribute(char* name, nc_type ptype,
|
|
size_t nvalues, char** values, NCattribute** attp)
|
|
{
|
|
int i;
|
|
NCerror ncstat = NC_NOERR;
|
|
NCattribute* att = NULL;
|
|
|
|
att = (NCattribute*)calloc(1,sizeof(NCattribute));
|
|
MEMCHECK(att,NC_ENOMEM);
|
|
att->name = nulldup(name);
|
|
att->etype = ptype;
|
|
|
|
att->values = nclistnew();
|
|
for(i=0;i<nvalues;i++)
|
|
nclistpush(att->values,(void*)nulldup(values[i]));
|
|
|
|
if(attp) *attp = att;
|
|
else
|
|
free(att);
|
|
|
|
return THROW(ncstat);
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
Given a das attribute walk it to see if it
|
|
has at least 1 actual attribute (no recursion)
|
|
*/
|
|
static int
|
|
hasattribute(OClink conn, OCdasnode dasnode)
|
|
{
|
|
int i;
|
|
OCerror ocstat = OC_NOERR;
|
|
int tf = 0; /* assume false */
|
|
OCtype ocsubtype;
|
|
NClist* subnodes = nclistnew();
|
|
|
|
OCCHECK(oc_dds_octype(conn,dasnode,&ocsubtype));
|
|
if(ocsubtype == OC_Attribute) return 1; /* this is an attribute */
|
|
ASSERT((ocsubtype == OC_Attributeset));
|
|
|
|
OCCHECK(collect_subnodes(conn,dasnode,subnodes));
|
|
for(i=0;i<nclistlength(subnodes);i++) {
|
|
OCdasnode subnode = (OCdasnode)nclistget(subnodes,i);
|
|
OCCHECK(oc_dds_class(conn,subnode,&ocsubtype));
|
|
if(ocsubtype == OC_Attribute) {tf=1; break;}
|
|
}
|
|
done:
|
|
nclistfree(subnodes);
|
|
return tf;
|
|
}
|
|
|
|
int
|
|
dapmerge(NCDAPCOMMON* nccomm, CDFnode* ddsroot, OCddsnode dasroot)
|
|
{
|
|
unsigned int i,j;
|
|
NCerror ncerr = NC_NOERR;
|
|
OCerror ocstat = OC_NOERR;
|
|
OClink conn = nccomm->oc.conn;
|
|
size_t nsubnodes;
|
|
NClist* dasglobals = nclistnew();
|
|
NClist* dasnodes = nclistnew();
|
|
NClist* dodsextra = nclistnew();
|
|
NClist* varnodes = nclistnew();
|
|
NClist* alldasnodes = nclistnew();
|
|
|
|
if(ddsroot == NULL || dasroot == NULL) return NC_NOERR;
|
|
|
|
ocstat = collect_alldasnodes(conn,dasroot,alldasnodes);
|
|
|
|
/* 1. collect all the relevant DAS nodes;
|
|
namely those that contain at least one
|
|
attribute value.
|
|
Simultaneously look for potential ambiguities
|
|
if found; complain but continue: result are indeterminate.
|
|
also collect globals and DODS_EXTRA separately.
|
|
*/
|
|
for(i=0;i<nclistlength(alldasnodes);i++) {
|
|
OCddsnode das = (OCddsnode)nclistget(alldasnodes,i);
|
|
OCtype octype;
|
|
char* ocname = NULL;
|
|
int isglobal = 0;
|
|
int hasattributes = 0;
|
|
|
|
OCCHECK(oc_dds_class(conn,das,&octype));
|
|
if(octype == OC_Attribute) continue; /* ignore these for now*/
|
|
|
|
OCCHECK(oc_dds_name(conn,das,&ocname));
|
|
OCCHECK(oc_dds_nsubnodes(conn,das,&nsubnodes));
|
|
|
|
isglobal = (ocname == NULL ? 0 : isglobalname(ocname));
|
|
|
|
/* catch DODS_EXTRA */
|
|
if(isglobal && ocname != NULL && strcmp(ocname,"DODS_EXTRA")==0) {
|
|
nclistpush(dodsextra,(void*)das);
|
|
nullfree(ocname);
|
|
continue;
|
|
}
|
|
if(ocname == NULL || isglobal) {
|
|
nclistpush(dasglobals,(void*)das);
|
|
nullfree(ocname);
|
|
continue;
|
|
}
|
|
hasattributes = hasattribute(conn,das);
|
|
if(hasattributes) {
|
|
/* Look for previously collected nodes with same name*/
|
|
for(j=0;j<nclistlength(dasnodes);j++) {
|
|
OCddsnode das2 = (OCddsnode)nclistget(dasnodes,j);
|
|
char* ocname2;
|
|
OCCHECK(oc_dds_name(conn,das2,&ocname2));
|
|
if(ocname2 == NULL || ocname == NULL) goto loop;
|
|
if(strcmp(ocname2,"DODS")==0) goto loop;
|
|
if(strcmp(ocname,ocname2)==0)
|
|
nclog(NCLOGWARN,"nc_mergedas: potentially ambiguous DAS name: %s",ocname2);
|
|
loop:
|
|
nullfree(ocname2);
|
|
}
|
|
nclistpush(dasnodes,(void*)das);
|
|
}
|
|
nullfree(ocname);
|
|
}
|
|
|
|
/* 2. collect all the leaf DDS nodes (of type NC_Atomic)*/
|
|
ocstat = collect_leaves(link,ddsroot,varnodes);
|
|
|
|
/* 3. For each das node, locate matching DDS node(s) and attach
|
|
attributes to the DDS node(s).
|
|
Match means:
|
|
1. DAS->fullname :: DDS->fullname
|
|
2. DAS->name :: DDS->fullname (support DAS names with embedded '.'
|
|
3. DAS->name :: DDS->name
|
|
4. special case for DODS. Apply 1-3 on DODS parent.
|
|
*/
|
|
for(i=0;i<nclistlength(dasnodes);i++) {
|
|
OCddsnode das = (OCddsnode)nclistget(dasnodes,i);
|
|
char* ocfullname = NULL;
|
|
char* ocbasename = NULL;
|
|
|
|
if(das == NULL) continue;
|
|
OCCHECK(oc_dds_name(conn,das,&ocbasename));
|
|
if(strcmp(ocbasename,"DODS")==0) {
|
|
OCddsnode container;
|
|
OCCHECK(oc_dds_container(conn,das,&container));
|
|
ASSERT(container != NULL);
|
|
ocfullname = makeocpathstring(conn,container,".");
|
|
} else {
|
|
ocfullname = makeocpathstring(conn,das,".");
|
|
}
|
|
for(j=0;j<nclistlength(varnodes);j++) {
|
|
CDFnode* dds = (CDFnode*)nclistget(varnodes,j);
|
|
char* ddsfullname = makecdfpathstring(dds,".");
|
|
if(strcmp(ocfullname,ddsfullname)==0
|
|
|| strcmp(ocbasename,ddsfullname)==0
|
|
|| strcmp(ocbasename,dds->ocname)==0) {
|
|
mergedas1(nccomm,conn,dds,das);
|
|
/* remove from dasnodes list*/
|
|
nclistset(dasnodes,i,(void*)NULL);
|
|
}
|
|
nullfree(ddsfullname);
|
|
}
|
|
nullfree(ocfullname);
|
|
nullfree(ocbasename);
|
|
}
|
|
|
|
/* 4. Assign globals */
|
|
for(i=0;i<nclistlength(dasglobals);i++) {
|
|
OCddsnode das = (OCddsnode)nclistget(dasglobals,i);
|
|
mergedas1(nccomm,conn,ddsroot,das);
|
|
}
|
|
|
|
/* 5. Assign DOD_EXTRA */
|
|
for(i=0;i<nclistlength(dodsextra);i++) {
|
|
OCddsnode das = (OCddsnode)nclistget(dodsextra,i);
|
|
mergedas1(nccomm,conn,ddsroot,das);
|
|
}
|
|
|
|
done: /* cleanup*/
|
|
nclistfree(dasglobals);
|
|
nclistfree(dasnodes);
|
|
nclistfree(alldasnodes);
|
|
nclistfree(dodsextra);
|
|
nclistfree(varnodes);
|
|
if(ocstat != OC_NOERR)
|
|
ncerr = ocerrtoncerr(ocstat);
|
|
return THROW(ncerr);
|
|
}
|
|
|
|
static int
|
|
mergedas1(NCDAPCOMMON* nccomm, OClink conn, CDFnode* dds, OCddsnode das)
|
|
{
|
|
NCerror ncstat = NC_NOERR;
|
|
OCerror ocstat = OC_NOERR;
|
|
unsigned int i,j,k;
|
|
unsigned int nsubnodes;
|
|
OCobject* subnodes = NULL;
|
|
OCobject* dodsnodes = NULL;
|
|
unsigned int ndodsnodes;
|
|
|
|
if(dds == NULL || das == OCNULL) return NC_NOERR; /* nothing to do */
|
|
if(dds->attributes == NULL) dds->attributes = nclistnew();
|
|
/* assign the simple attributes in the das set to this dds node*/
|
|
OCCHECK(oc_inq_nsubnodes(conn,das,&nsubnodes));
|
|
OCCHECK(oc_inq_subnodes(conn,das,&subnodes));
|
|
for(i=0;i<nsubnodes;i++) {
|
|
OCobject attnode = subnodes[i];
|
|
OCtype octype, ocetype;
|
|
char* ocname = NULL;
|
|
unsigned int ocnvalues;
|
|
OCCHECK(oc_inq_name(conn,attnode,&ocname));
|
|
OCCHECK(oc_inq_class(conn,attnode,&octype));
|
|
if(octype == OC_Attribute) {
|
|
NCattribute* att = NULL;
|
|
NClist* stringvalues;
|
|
OCCHECK(oc_inq_primtype(conn,attnode,&ocetype));
|
|
OCCHECK(oc_inq_dasattr_nvalues(conn,attnode,&ocnvalues));
|
|
stringvalues = nclistnew();
|
|
for(j=0;j<ocnvalues;j++) {
|
|
char* stringval;
|
|
OCCHECK(oc_inq_dasattr(conn,attnode,j,&ocetype,&stringval));
|
|
nclistpush(stringvalues,(void*)stringval);
|
|
}
|
|
ncstat = buildattribute(ocname,
|
|
octypetonc(ocetype),
|
|
stringvalues,
|
|
&att);
|
|
if(ncstat) goto done;
|
|
nclistpush(dds->attributes,(void*)att);
|
|
} else if(octype == OC_Attributeset
|
|
&& (strcmp(ocname,"DODS")==0
|
|
|| strcmp(ocname,"DODS_EXTRA")==0)) {
|
|
/* Turn the DODS special attributes into into
|
|
special attributes for dds node */
|
|
OCCHECK(oc_inq_nsubnodes(conn,attnode,&ndodsnodes));
|
|
OCCHECK(oc_inq_subnodes(conn,attnode,&dodsnodes));
|
|
for(j=0;j<ndodsnodes;j++) {
|
|
char* dodsname = NULL;
|
|
char newname[4096];
|
|
OCobject attnode = dodsnodes[j];
|
|
NCattribute* att = NULL;
|
|
NClist* stringvalues;
|
|
OCCHECK(oc_inq_class(conn,attnode,&octype));
|
|
if(octype != OC_Attribute) continue;
|
|
OCCHECK(oc_inq_primtype(conn,attnode,&ocetype));
|
|
OCCHECK(oc_inq_dasattr_nvalues(conn,attnode,&ocnvalues));
|
|
stringvalues = nclistnew();
|
|
for(k=0;k<ocnvalues;k++) {
|
|
char* stringval;
|
|
OCCHECK(oc_inq_dasattr(conn,attnode,k,&ocetype,&stringval));
|
|
nclistpush(stringvalues,(void*)stringval);
|
|
}
|
|
OCCHECK(oc_inq_name(conn,attnode,&dodsname));
|
|
/* Compute new special name */
|
|
strcpy(newname,"_DODS_");
|
|
strcat(newname,dodsname);
|
|
ncstat = buildattribute(newname,
|
|
octypetonc(ocetype),
|
|
stringvalues,
|
|
&att);
|
|
if(ncstat) goto done;
|
|
att->invisible = 1;
|
|
nclistpush(dds->attributes,(void*)att);
|
|
|
|
/* Define extra semantics associated with DODS and DODS_EXTRA attribute */
|
|
if(strcmp(dodsname,"strlen")==0) {
|
|
unsigned int maxstrlen = 0;
|
|
if(nclistlength(stringvalues) > 0) {
|
|
char* stringval = (char*)nclistget(stringvalues,0);
|
|
if(0==sscanf(stringval,"%u",&maxstrlen)) maxstrlen = 0;
|
|
}
|
|
dds->dodsspecial.maxstrlen = maxstrlen;
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"%s.maxstrlen=%d\n",dds->ocname,(int)dds->dodsspecial.maxstrlen);
|
|
#endif
|
|
} else if(strcmp(dodsname,"dimName")==0) {
|
|
if(nclistlength(stringvalues) > 0) {
|
|
char* stringval = (char*)nclistget(stringvalues,0);
|
|
dds->dodsspecial.dimname = nulldup(stringval);
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"%s.dimname=%s\n",dds->ocname,dds->dodsspecial.dimname);
|
|
#endif
|
|
} else dds->dodsspecial.dimname = NULL;
|
|
} else if(strcmp(dodsname,"Unlimited_Dimension")==0) {
|
|
if(nccomm->cdf.recorddimname != NULL) {
|
|
nclog(NCLOGWARN,"Duplicate DODS_EXTRA:Unlimited_Dimension specifications");
|
|
} else if(nclistlength(stringvalues) > 0) {
|
|
char* stringval = (char*)nclistget(stringvalues,0);
|
|
nccomm->cdf.recorddimname = nulldup(stringval);
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"%s.Unlimited_Dimension=%s\n",dds->ocname,nccomm->cdf.recorddimname);
|
|
#endif
|
|
}
|
|
} /* else ignore */
|
|
nullfree(dodsname);
|
|
}
|
|
nullfree(dodsnodes);
|
|
}
|
|
nullfree(ocname);
|
|
}
|
|
|
|
done:
|
|
nullfree(subnodes);
|
|
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
|
|
return THROW(ncstat);
|
|
}
|
|
|
|
static int
|
|
isglobalname(char* name)
|
|
{
|
|
int len = strlen(name);
|
|
int glen = strlen("global");
|
|
char* p;
|
|
if(len < glen) return 0;
|
|
p = name + (len - glen);
|
|
if(strcasecmp(p,"global") != 0)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
|
|
static OCerror
|
|
collect_alldasnodes(OClink link, OCddsnode dasnode, NClist* alldasnodes)
|
|
{
|
|
size_t nsubnodes,i;
|
|
OCerror ocstat = OC_NOERR;
|
|
nclistpush(alldasnodes,(void*)dasnode);
|
|
ocstat = oc_dds_nsubnodes(link,dasnode,&nsubnodes);
|
|
if(ocstat != OC_NOERR) goto done;
|
|
for(i=0;i<nsubnodes;i++) {
|
|
OCddsnode subnode;
|
|
ocstat = oc_dds_ithsubnode(link,dasnode,i,&subnode);
|
|
if(ocstat != OC_NOERR) goto done;
|
|
ocstat = collect_alldasnodes(link,subnode,alldasnodes);
|
|
if(ocstat != OC_NOERR) goto done;
|
|
}
|
|
|
|
done:
|
|
return ocstat;
|
|
}
|
|
|
|
static OCerror
|
|
collect_leaves(OClink link, OCddsnode ddsnode, NClist* leaves)
|
|
{
|
|
size_t nsubnodes,i;
|
|
OCerror ocstat = OC_NOERR;
|
|
OCtype octype;
|
|
ocstat = oc_dds_octype(link,ddsnode,&octype);
|
|
if(ocstat != OC_NOERR) goto done;
|
|
if(octype == OC_Atomic) {
|
|
nclistpush(leaves,(void*)ddsnode);
|
|
} else {
|
|
ocstat = oc_dds_nsubnodes(link,ddsnode,&nsubnodes);
|
|
if(ocstat != OC_NOERR) goto done;
|
|
for(i=0;i<nsubnodes;i++) {
|
|
OCddsnode subnode;
|
|
ocstat = oc_dds_ithsubnode(link,ddsnode,i,&subnode);
|
|
if(ocstat != OC_NOERR) goto done;
|
|
ocstat = collect_leaves(link,subnode,leaves);
|
|
if(ocstat != OC_NOERR) goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
return ocstat;
|
|
}
|
|
|
|
static OCerror
|
|
collect_subnodes(OClink link, OCddsnode ddsnode, NClist* subnodes)
|
|
{
|
|
size_t nsubnodes,i;
|
|
OCerror ocstat = OC_NOERR;
|
|
ocstat = oc_dds_nsubnodes(link,ddsnode,&nsubnodes);
|
|
if(ocstat != OC_NOERR) goto done;
|
|
for(i=0;i<nsubnodes;i++) {
|
|
OCddsnode subnode;
|
|
ocstat = oc_dds_ithsubnode(link,ddsnode,i,&subnode);
|
|
if(ocstat != OC_NOERR) goto done;
|
|
nclistpush(subnodes,(void*)subnode);
|
|
}
|
|
|
|
done:
|
|
return ocstat;
|
|
}
|
|
#endif /*0*/
|