mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-01-18 15:55:12 +08:00
Fix infinite loop in file inferencing
re: Issue https://github.com/Unidata/netcdf-c/issues/2573 The file type inferencer in libdispatch/dinference.c has a simple forward inference mechanism so that the occurrence of certain mode values in a URL fragment implies inclusion of additional mode values. This kind of inference is notorious for leading to cycles if not careful. Unfortunately, this occurred in the one in dinference.c. This was fixed by providing a more complicated, but more reliable inference mechanism. ## Misc. Other Changes * Found and fixed a couple of memory leaks. * There is a recent problem in building HDF4 support on github actions. Fixed by using the internal HDF4 xdr capability. * Some filter-related code was not being properly ifdef'd with ENABLE_NCZARRA_FILTERS.
This commit is contained in:
parent
0fc2c817b2
commit
a03bb5e601
2
.github/workflows/run_tests_osx.yml
vendored
2
.github/workflows/run_tests_osx.yml
vendored
@ -7,7 +7,7 @@
|
|||||||
name: Run macOS-based netCDF Tests
|
name: Run macOS-based netCDF Tests
|
||||||
|
|
||||||
|
|
||||||
on: [pull_request, workflow_dispatch]
|
on: [pull_request,workflow_dispatch]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
|
6
.github/workflows/run_tests_ubuntu.yml
vendored
6
.github/workflows/run_tests_ubuntu.yml
vendored
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
name: Run Ubuntu/Linux netCDF Tests
|
name: Run Ubuntu/Linux netCDF Tests
|
||||||
|
|
||||||
on: [pull_request, workflow_dispatch]
|
on: [pull_request,workflow_dispatch]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ jobs:
|
|||||||
wget https://support.hdfgroup.org/ftp/HDF/releases/HDF4.2.15/src/hdf-4.2.15.tar.bz2
|
wget https://support.hdfgroup.org/ftp/HDF/releases/HDF4.2.15/src/hdf-4.2.15.tar.bz2
|
||||||
tar -jxf hdf-4.2.15.tar.bz2
|
tar -jxf hdf-4.2.15.tar.bz2
|
||||||
pushd hdf-4.2.15
|
pushd hdf-4.2.15
|
||||||
./configure --prefix=${HOME}/environments/${{ matrix.hdf5 }} --disable-static --enable-shared --disable-fortran --disable-netcdf --with-szlib
|
./configure --prefix=${HOME}/environments/${{ matrix.hdf5 }} --disable-static --enable-shared --disable-fortran --disable-netcdf --with-szlib --enable-hdf4-xdr
|
||||||
make -j
|
make -j
|
||||||
make install -j
|
make install -j
|
||||||
popd
|
popd
|
||||||
@ -89,7 +89,7 @@ jobs:
|
|||||||
wget https://support.hdfgroup.org/ftp/HDF/releases/HDF4.2.15/src/hdf-4.2.15.tar.bz2
|
wget https://support.hdfgroup.org/ftp/HDF/releases/HDF4.2.15/src/hdf-4.2.15.tar.bz2
|
||||||
tar -jxf hdf-4.2.15.tar.bz2
|
tar -jxf hdf-4.2.15.tar.bz2
|
||||||
pushd hdf-4.2.15
|
pushd hdf-4.2.15
|
||||||
CC=mpicc ./configure --prefix=${HOME}/environments/${{ matrix.hdf5 }} --disable-static --enable-shared --disable-fortran --disable-netcdf --with-szlib --enable-parallel
|
CC=mpicc ./configure --prefix=${HOME}/environments/${{ matrix.hdf5 }} --disable-static --enable-shared --disable-fortran --disable-netcdf --with-szlib --enable-parallel --enable-hdf4-xdr
|
||||||
make -j
|
make -j
|
||||||
make install -j
|
make install -j
|
||||||
popd
|
popd
|
||||||
|
2
.github/workflows/run_tests_win_cygwin.yml
vendored
2
.github/workflows/run_tests_win_cygwin.yml
vendored
@ -1,6 +1,6 @@
|
|||||||
name: Run Cygwin-based tests
|
name: Run Cygwin-based tests
|
||||||
|
|
||||||
on: [pull_request, workflow_dispatch]
|
on: [pull_request,workflow_dispatch]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
SHELLOPTS: igncr
|
SHELLOPTS: igncr
|
||||||
|
2
.github/workflows/run_tests_win_mingw.yml
vendored
2
.github/workflows/run_tests_win_mingw.yml
vendored
@ -9,7 +9,7 @@ name: Run MSYS2, MinGW64-based Tests
|
|||||||
env:
|
env:
|
||||||
CPPFLAGS: "-D_BSD_SOURCE"
|
CPPFLAGS: "-D_BSD_SOURCE"
|
||||||
|
|
||||||
on: [pull_request, workflow_dispatch]
|
on: [pull_request,workflow_dispatch]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
|
@ -1839,19 +1839,16 @@ NC_create(const char *path0, int cmode, size_t initialsz,
|
|||||||
|
|
||||||
TRACE(nc_create);
|
TRACE(nc_create);
|
||||||
if(path0 == NULL)
|
if(path0 == NULL)
|
||||||
return NC_EINVAL;
|
{stat = NC_EINVAL; goto done;}
|
||||||
|
|
||||||
/* Check mode flag for sanity. */
|
/* Check mode flag for sanity. */
|
||||||
if ((stat = check_create_mode(cmode)))
|
if ((stat = check_create_mode(cmode))) goto done;
|
||||||
return stat;
|
|
||||||
|
|
||||||
/* Initialize the library. The available dispatch tables
|
/* Initialize the library. The available dispatch tables
|
||||||
* will depend on how netCDF was built
|
* will depend on how netCDF was built
|
||||||
* (with/without netCDF-4, DAP, CDMREMOTE). */
|
* (with/without netCDF-4, DAP, CDMREMOTE). */
|
||||||
if(!NC_initialized)
|
if(!NC_initialized) {
|
||||||
{
|
if ((stat = nc_initialize())) goto done;
|
||||||
if ((stat = nc_initialize()))
|
|
||||||
return stat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -1863,10 +1860,7 @@ NC_create(const char *path0, int cmode, size_t initialsz,
|
|||||||
|
|
||||||
memset(&model,0,sizeof(model));
|
memset(&model,0,sizeof(model));
|
||||||
newpath = NULL;
|
newpath = NULL;
|
||||||
if((stat = NC_infermodel(path,&cmode,1,useparallel,NULL,&model,&newpath))) {
|
if((stat = NC_infermodel(path,&cmode,1,useparallel,NULL,&model,&newpath))) goto done;
|
||||||
nullfree(newpath);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if(newpath) {
|
if(newpath) {
|
||||||
nullfree(path);
|
nullfree(path);
|
||||||
path = newpath;
|
path = newpath;
|
||||||
@ -1918,7 +1912,7 @@ NC_create(const char *path0, int cmode, size_t initialsz,
|
|||||||
dispatcher = NC3_dispatch_table;
|
dispatcher = NC3_dispatch_table;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NC_ENOTNC;
|
{stat = NC_ENOTNC; goto done;}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the NC* instance and insert its dispatcher and model */
|
/* Create the NC* instance and insert its dispatcher and model */
|
||||||
@ -1937,6 +1931,7 @@ NC_create(const char *path0, int cmode, size_t initialsz,
|
|||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
nullfree(path);
|
nullfree(path);
|
||||||
|
nullfree(newpath);
|
||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1980,12 +1975,12 @@ NC_open(const char *path0, int omode, int basepe, size_t *chunksizehintp,
|
|||||||
TRACE(nc_open);
|
TRACE(nc_open);
|
||||||
if(!NC_initialized) {
|
if(!NC_initialized) {
|
||||||
stat = nc_initialize();
|
stat = nc_initialize();
|
||||||
if(stat) return stat;
|
if(stat) goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check inputs. */
|
/* Check inputs. */
|
||||||
if (!path0)
|
if (!path0)
|
||||||
return NC_EINVAL;
|
{stat = NC_EINVAL; goto done;}
|
||||||
|
|
||||||
/* Capture the inmemory related flags */
|
/* Capture the inmemory related flags */
|
||||||
mmap = ((omode & NC_MMAP) == NC_MMAP);
|
mmap = ((omode & NC_MMAP) == NC_MMAP);
|
||||||
|
@ -143,7 +143,15 @@ static const struct MACRODEF {
|
|||||||
{NULL,NULL,{NULL}}
|
{NULL,NULL,{NULL}}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mode inferences: if mode contains key, then add the inference and infer again */
|
/*
|
||||||
|
Mode inferences: if mode contains key value, then add the inferred value;
|
||||||
|
Warning: be careful how this list is constructed to avoid infinite inferences.
|
||||||
|
In order to (mostly) avoid that consequence, any attempt to
|
||||||
|
infer a value that is already present will be ignored.
|
||||||
|
This effectively means that the inference graph
|
||||||
|
must be a DAG and may not have cycles.
|
||||||
|
You have been warned.
|
||||||
|
*/
|
||||||
static const struct MODEINFER {
|
static const struct MODEINFER {
|
||||||
char* key;
|
char* key;
|
||||||
char* inference;
|
char* inference;
|
||||||
@ -151,6 +159,7 @@ static const struct MODEINFER {
|
|||||||
{"zarr","nczarr"},
|
{"zarr","nczarr"},
|
||||||
{"xarray","zarr"},
|
{"xarray","zarr"},
|
||||||
{"noxarray","nczarr"},
|
{"noxarray","nczarr"},
|
||||||
|
{"noxarray","zarr"},
|
||||||
{NULL,NULL}
|
{NULL,NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -202,6 +211,7 @@ static int processmacros(NClist** fraglistp);
|
|||||||
static char* envvlist2string(NClist* pairs, const char*);
|
static char* envvlist2string(NClist* pairs, const char*);
|
||||||
static void set_default_mode(int* cmodep);
|
static void set_default_mode(int* cmodep);
|
||||||
static int parseonchar(const char* s, int ch, NClist* segments);
|
static int parseonchar(const char* s, int ch, NClist* segments);
|
||||||
|
static int mergelist(NClist** valuesp);
|
||||||
|
|
||||||
static int openmagic(struct MagicFile* file);
|
static int openmagic(struct MagicFile* file);
|
||||||
static int readmagic(struct MagicFile* file, long pos, char* magic);
|
static int readmagic(struct MagicFile* file, long pos, char* magic);
|
||||||
@ -217,8 +227,9 @@ static int parsepair(const char* pair, char** keyp, char** valuep);
|
|||||||
static NClist* parsemode(const char* modeval);
|
static NClist* parsemode(const char* modeval);
|
||||||
static const char* getmodekey(const NClist* envv);
|
static const char* getmodekey(const NClist* envv);
|
||||||
static int replacemode(NClist* envv, const char* newval);
|
static int replacemode(NClist* envv, const char* newval);
|
||||||
static int inferone(const char* mode, NClist* newmodes);
|
static void infernext(NClist* current, NClist* next);
|
||||||
static int negateone(const char* mode, NClist* modes);
|
static int negateone(const char* mode, NClist* modes);
|
||||||
|
static void cleanstringlist(NClist* strs, int caseinsensitive);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If the path looks like a URL, then parse it, reformat it.
|
If the path looks like a URL, then parse it, reformat it.
|
||||||
@ -416,28 +427,6 @@ envvlist2string(NClist* envv, const char* delim)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert a list into a comma'd string */
|
|
||||||
static char*
|
|
||||||
list2string(NClist* list)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
NCbytes* buf = NULL;
|
|
||||||
char* result = NULL;
|
|
||||||
|
|
||||||
if(list == NULL || nclistlength(list)==0) return strdup("");
|
|
||||||
buf = ncbytesnew();
|
|
||||||
for(i=0;i<nclistlength(list);i++) {
|
|
||||||
const char* m = nclistget(list,i);
|
|
||||||
if(m == NULL || strlen(m) == 0) continue;
|
|
||||||
if(i > 0) ncbytescat(buf,",");
|
|
||||||
ncbytescat(buf,m);
|
|
||||||
}
|
|
||||||
result = ncbytesextract(buf);
|
|
||||||
ncbytesfree(buf);
|
|
||||||
if(result == NULL) result = strdup("");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Given a mode= argument, fill in the impl */
|
/* Given a mode= argument, fill in the impl */
|
||||||
static int
|
static int
|
||||||
processmodearg(const char* arg, NCmodel* model)
|
processmodearg(const char* arg, NCmodel* model)
|
||||||
@ -504,9 +493,10 @@ processinferences(NClist* fraglenv)
|
|||||||
{
|
{
|
||||||
int stat = NC_NOERR;
|
int stat = NC_NOERR;
|
||||||
const char* modeval = NULL;
|
const char* modeval = NULL;
|
||||||
NClist* modes = NULL;
|
|
||||||
NClist* newmodes = nclistnew();
|
NClist* newmodes = nclistnew();
|
||||||
int i,inferred = 0;
|
NClist* currentmodes = NULL;
|
||||||
|
NClist* nextmodes = nclistnew();
|
||||||
|
int i;
|
||||||
char* newmodeval = NULL;
|
char* newmodeval = NULL;
|
||||||
|
|
||||||
if(fraglenv == NULL || nclistlength(fraglenv) == 0) goto done;
|
if(fraglenv == NULL || nclistlength(fraglenv) == 0) goto done;
|
||||||
@ -515,22 +505,53 @@ processinferences(NClist* fraglenv)
|
|||||||
if((modeval = getmodekey(fraglenv))==NULL) goto done;
|
if((modeval = getmodekey(fraglenv))==NULL) goto done;
|
||||||
|
|
||||||
/* Get the mode as list */
|
/* Get the mode as list */
|
||||||
modes = parsemode(modeval);
|
currentmodes = parsemode(modeval);
|
||||||
|
|
||||||
/* Repeatedly walk the mode list until no more new positive inferences */
|
#ifdef DEBUG
|
||||||
do {
|
printlist(currentmodes,"processinferences: initial mode list");
|
||||||
for(i=0;i<nclistlength(modes);i++) {
|
#endif
|
||||||
const char* mode = nclistget(modes,i);
|
|
||||||
inferred = inferone(mode,newmodes);
|
/* Do what amounts to breadth first inferencing down the inference DAG. */
|
||||||
nclistpush(newmodes,strdup(mode)); /* keep key */
|
|
||||||
if(!inferred) nclistpush(newmodes,strdup(mode));
|
for(;;) {
|
||||||
|
NClist* tmp = NULL;
|
||||||
|
/* Compute the next set of inferred modes */
|
||||||
|
#ifdef DEBUG
|
||||||
|
printlist(currentmodes,"processinferences: current mode list");
|
||||||
|
#endif
|
||||||
|
infernext(currentmodes,nextmodes);
|
||||||
|
#ifdef DEBUG
|
||||||
|
printlist(nextmodes,"processinferences: next mode list");
|
||||||
|
#endif
|
||||||
|
/* move current modes into list of newmodes */
|
||||||
|
for(i=0;i<nclistlength(currentmodes);i++) {
|
||||||
|
nclistpush(newmodes,nclistget(currentmodes,i));
|
||||||
}
|
}
|
||||||
} while(inferred);
|
nclistsetlength(currentmodes,0); /* clear current mode list */
|
||||||
|
if(nclistlength(nextmodes) == 0) break; /* nothing more to do */
|
||||||
|
#ifdef DEBUG
|
||||||
|
printlist(newmodes,"processinferences: new mode list");
|
||||||
|
#endif
|
||||||
|
/* Swap current and next */
|
||||||
|
tmp = currentmodes;
|
||||||
|
currentmodes = nextmodes;
|
||||||
|
nextmodes = tmp;
|
||||||
|
tmp = NULL;
|
||||||
|
}
|
||||||
|
/* cleanup any unused elements in currenmodes */
|
||||||
|
nclistclearall(currentmodes);
|
||||||
|
|
||||||
|
/* Ensure no duplicates */
|
||||||
|
cleanstringlist(newmodes,1);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printlist(newmodes,"processinferences: final inferred mode list");
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Remove negative inferences */
|
/* Remove negative inferences */
|
||||||
for(i=0;i<nclistlength(modes);i++) {
|
for(i=0;i<nclistlength(newmodes);i++) {
|
||||||
const char* mode = nclistget(modes,i);
|
const char* mode = nclistget(newmodes,i);
|
||||||
inferred = negateone(mode,newmodes);
|
negateone(mode,newmodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store new mode value */
|
/* Store new mode value */
|
||||||
@ -541,11 +562,13 @@ processinferences(NClist* fraglenv)
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
nullfree(newmodeval);
|
nullfree(newmodeval);
|
||||||
nclistfreeall(modes);
|
|
||||||
nclistfreeall(newmodes);
|
nclistfreeall(newmodes);
|
||||||
|
nclistfreeall(currentmodes);
|
||||||
|
nclistfreeall(nextmodes);
|
||||||
return check(stat);
|
return check(stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
negateone(const char* mode, NClist* newmodes)
|
negateone(const char* mode, NClist* newmodes)
|
||||||
{
|
{
|
||||||
@ -568,23 +591,28 @@ negateone(const char* mode, NClist* newmodes)
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
inferone(const char* mode, NClist* newmodes)
|
infernext(NClist* current, NClist* next)
|
||||||
{
|
{
|
||||||
const struct MODEINFER* tests = modeinferences;
|
int i;
|
||||||
int changed = 0;
|
for(i=0;i<nclistlength(current);i++) {
|
||||||
for(;tests->key;tests++) {
|
const struct MODEINFER* tests = NULL;
|
||||||
if(strcasecmp(tests->key,mode)==0) {
|
const char* cur = nclistget(current,i);
|
||||||
/* Append the inferred mode; dups removed later */
|
for(tests=modeinferences;tests->key;tests++) {
|
||||||
nclistpush(newmodes,strdup(tests->inference));
|
if(strcasecmp(tests->key,cur)==0) {
|
||||||
changed = 1;
|
/* Append the inferred mode unless dup */
|
||||||
|
if(!nclistmatch(next,tests->inference,1))
|
||||||
|
nclistpush(next,strdup(tests->inference));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return changed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Given a list of strings, remove nulls and duplicates
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
mergekey(NClist** valuesp)
|
mergelist(NClist** valuesp)
|
||||||
{
|
{
|
||||||
int i,j;
|
int i,j;
|
||||||
int stat = NC_NOERR;
|
int stat = NC_NOERR;
|
||||||
@ -686,12 +714,12 @@ cleanfragments(NClist** fraglenvp)
|
|||||||
|
|
||||||
/* collect all unique keys */
|
/* collect all unique keys */
|
||||||
collectallkeys(fraglenv,allkeys);
|
collectallkeys(fraglenv,allkeys);
|
||||||
/* Collect all values for same key across all fragments */
|
/* Collect all values for same key across all fragment pairs */
|
||||||
for(i=0;i<nclistlength(allkeys);i++) {
|
for(i=0;i<nclistlength(allkeys);i++) {
|
||||||
key = nclistget(allkeys,i);
|
key = nclistget(allkeys,i);
|
||||||
collectvaluesbykey(fraglenv,key,tmp);
|
collectvaluesbykey(fraglenv,key,tmp);
|
||||||
/* merge the key values, remove duplicate */
|
/* merge the key values, remove duplicate */
|
||||||
if((stat=mergekey(&tmp))) goto done;
|
if((stat=mergelist(&tmp))) goto done;
|
||||||
/* Construct key,value pair and insert into newlist */
|
/* Construct key,value pair and insert into newlist */
|
||||||
key = strdup(key);
|
key = strdup(key);
|
||||||
nclistpush(newlist,key);
|
nclistpush(newlist,key);
|
||||||
@ -923,7 +951,7 @@ NC_infermodel(const char* path, int* omodep, int iscreate, int useparallel, void
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {/* Not URL */
|
} else {/* Not URL */
|
||||||
if(*newpathp) *newpathp = NULL;
|
if(newpathp) *newpathp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Phase 8: mode inference from mode flags */
|
/* Phase 8: mode inference from mode flags */
|
||||||
@ -1101,6 +1129,71 @@ parsemode(const char* modeval)
|
|||||||
return modes;
|
return modes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert a list into a comma'd string */
|
||||||
|
static char*
|
||||||
|
list2string(NClist* list)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
NCbytes* buf = NULL;
|
||||||
|
char* result = NULL;
|
||||||
|
|
||||||
|
if(list == NULL || nclistlength(list)==0) return strdup("");
|
||||||
|
buf = ncbytesnew();
|
||||||
|
for(i=0;i<nclistlength(list);i++) {
|
||||||
|
const char* m = nclistget(list,i);
|
||||||
|
if(m == NULL || strlen(m) == 0) continue;
|
||||||
|
if(i > 0) ncbytescat(buf,",");
|
||||||
|
ncbytescat(buf,m);
|
||||||
|
}
|
||||||
|
result = ncbytesextract(buf);
|
||||||
|
ncbytesfree(buf);
|
||||||
|
if(result == NULL) result = strdup("");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Given a comma separated string, remove duplicates; mostly used to cleanup mode list */
|
||||||
|
static char*
|
||||||
|
cleancommalist(const char* commalist, int caseinsensitive)
|
||||||
|
{
|
||||||
|
NClist* tmp = nclistnew();
|
||||||
|
char* newlist = NULL;
|
||||||
|
if(commalist == NULL || strlen(commalist)==0) return nulldup(commalist);
|
||||||
|
(void)parseonchar(commalist,',',tmp);/* split on commas */
|
||||||
|
cleanstringlist(tmp,caseinsensitive);
|
||||||
|
newlist = list2string(tmp);
|
||||||
|
nclistfreeall(tmp);
|
||||||
|
return newlist;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Given a list of strings, remove nulls and duplicated */
|
||||||
|
static void
|
||||||
|
cleanstringlist(NClist* strs, int caseinsensitive)
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
if(nclistlength(strs) == 0) return;
|
||||||
|
/* Remove nulls */
|
||||||
|
for(i=nclistlength(strs)-1;i>=0;i--) {
|
||||||
|
if(nclistget(strs,i)==NULL) nclistremove(strs,i);
|
||||||
|
}
|
||||||
|
/* Remove duplicates*/
|
||||||
|
for(i=0;i<nclistlength(strs);i++) {
|
||||||
|
const char* value = nclistget(strs,i);
|
||||||
|
/* look ahead for duplicates */
|
||||||
|
for(j=nclistlength(strs)-1;j>i;j--) {
|
||||||
|
int match;
|
||||||
|
const char* candidate = nclistget(strs,j);
|
||||||
|
if(caseinsensitive)
|
||||||
|
match = (strcasecmp(value,candidate) == 0);
|
||||||
|
else
|
||||||
|
match = (strcmp(value,candidate) == 0);
|
||||||
|
if(match) {char* dup = nclistremove(strs,j); nullfree(dup);}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************/
|
/**************************************************/
|
||||||
/**
|
/**
|
||||||
* @internal Given an existing file, figure out its format and return
|
* @internal Given an existing file, figure out its format and return
|
||||||
@ -1502,8 +1595,10 @@ printlist(NClist* list, const char* tag)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
fprintf(stderr,"%s:",tag);
|
fprintf(stderr,"%s:",tag);
|
||||||
for(i=0;i<nclistlength(list);i++)
|
for(i=0;i<nclistlength(list);i++) {
|
||||||
fprintf(stderr," %s",(char*)nclistget(list,i));
|
fprintf(stderr," %s",(char*)nclistget(list,i));
|
||||||
|
fprintf(stderr,"[%p]",(char*)nclistget(list,i));
|
||||||
|
}
|
||||||
fprintf(stderr,"\n");
|
fprintf(stderr,"\n");
|
||||||
dbgflush();
|
dbgflush();
|
||||||
}
|
}
|
||||||
|
@ -122,9 +122,7 @@ ncbytesappend(NCbytes* bb, char elem)
|
|||||||
int
|
int
|
||||||
ncbytescat(NCbytes* bb, const char* s)
|
ncbytescat(NCbytes* bb, const char* s)
|
||||||
{
|
{
|
||||||
if(s == NULL) {
|
if(s == NULL) return 1;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
ncbytesappendn(bb,(void*)s,strlen(s)+1); /* include trailing null*/
|
ncbytesappendn(bb,(void*)s,strlen(s)+1); /* include trailing null*/
|
||||||
/* back up over the trailing null*/
|
/* back up over the trailing null*/
|
||||||
if(bb->length == 0) return ncbytesfail();
|
if(bb->length == 0) return ncbytesfail();
|
||||||
|
@ -183,6 +183,7 @@ nclistremove(NClist* l, size_t i)
|
|||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Match on == */
|
||||||
int
|
int
|
||||||
nclistcontains(NClist* l, void* elem)
|
nclistcontains(NClist* l, void* elem)
|
||||||
{
|
{
|
||||||
@ -193,7 +194,7 @@ nclistcontains(NClist* l, void* elem)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return 1/0 */
|
/* Match on str(case)cmp */
|
||||||
int
|
int
|
||||||
nclistmatch(NClist* l, const char* elem, int casesensitive)
|
nclistmatch(NClist* l, const char* elem, int casesensitive)
|
||||||
{
|
{
|
||||||
@ -230,7 +231,6 @@ nclistelemremove(NClist* l, void* elem)
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Extends nclist to include a unique operator
|
/* Extends nclist to include a unique operator
|
||||||
which remove duplicate values; NULL values removed
|
which remove duplicate values; NULL values removed
|
||||||
return value is always 1.
|
return value is always 1.
|
||||||
|
@ -1429,6 +1429,7 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
|
|||||||
char* varpath = NULL;
|
char* varpath = NULL;
|
||||||
char* key = NULL;
|
char* key = NULL;
|
||||||
NCZ_FILE_INFO_T* zinfo = NULL;
|
NCZ_FILE_INFO_T* zinfo = NULL;
|
||||||
|
NC_VAR_INFO_T* var = NULL;
|
||||||
NCZ_VAR_INFO_T* zvar = NULL;
|
NCZ_VAR_INFO_T* zvar = NULL;
|
||||||
NCZMAP* map = NULL;
|
NCZMAP* map = NULL;
|
||||||
NCjson* jvar = NULL;
|
NCjson* jvar = NULL;
|
||||||
@ -1460,7 +1461,6 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
|
|||||||
|
|
||||||
/* Load each var in turn */
|
/* Load each var in turn */
|
||||||
for(i = 0; i < nclistlength(varnames); i++) {
|
for(i = 0; i < nclistlength(varnames); i++) {
|
||||||
NC_VAR_INFO_T* var;
|
|
||||||
const char* varname = nclistget(varnames,i);
|
const char* varname = nclistget(varnames,i);
|
||||||
if((stat = nc4_var_list_add2(grp, varname, &var)))
|
if((stat = nc4_var_list_add2(grp, varname, &var)))
|
||||||
goto done;
|
goto done;
|
||||||
@ -1477,10 +1477,6 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
|
|||||||
/* Indicate we do not have quantizer yet */
|
/* Indicate we do not have quantizer yet */
|
||||||
var->quantize_mode = -1;
|
var->quantize_mode = -1;
|
||||||
|
|
||||||
/* Set filter list */
|
|
||||||
assert(var->filters == NULL);
|
|
||||||
var->filters = (void*)nclistnew();
|
|
||||||
|
|
||||||
/* Construct var path */
|
/* Construct var path */
|
||||||
if((stat = NCZ_varkey(var,&varpath)))
|
if((stat = NCZ_varkey(var,&varpath)))
|
||||||
goto done;
|
goto done;
|
||||||
@ -1697,9 +1693,9 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
|
|||||||
object MUST contain a "id" key identifying the codec to be used. */
|
object MUST contain a "id" key identifying the codec to be used. */
|
||||||
/* Do filters key before compressor key so final filter chain is in correct order */
|
/* Do filters key before compressor key so final filter chain is in correct order */
|
||||||
{
|
{
|
||||||
|
#ifdef ENABLE_NCZARR_FILTERS
|
||||||
if(var->filters == NULL) var->filters = (void*)nclistnew();
|
if(var->filters == NULL) var->filters = (void*)nclistnew();
|
||||||
if(zvar->incompletefilters == NULL) zvar->incompletefilters = (void*)nclistnew();
|
if(zvar->incompletefilters == NULL) zvar->incompletefilters = (void*)nclistnew();
|
||||||
#ifdef ENABLE_NCZARR_FILTERS
|
|
||||||
{ int k;
|
{ int k;
|
||||||
chainindex = 0; /* track location of filter in the chain */
|
chainindex = 0; /* track location of filter in the chain */
|
||||||
if((stat = NCZ_filter_initialize())) goto done;
|
if((stat = NCZ_filter_initialize())) goto done;
|
||||||
@ -1722,8 +1718,8 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
|
|||||||
/* From V2 Spec: A JSON object identifying the primary compression codec and providing
|
/* From V2 Spec: A JSON object identifying the primary compression codec and providing
|
||||||
configuration parameters, or ``null`` if no compressor is to be used. */
|
configuration parameters, or ``null`` if no compressor is to be used. */
|
||||||
{
|
{
|
||||||
if(var->filters == NULL) var->filters = (void*)nclistnew();
|
|
||||||
#ifdef ENABLE_NCZARR_FILTERS
|
#ifdef ENABLE_NCZARR_FILTERS
|
||||||
|
if(var->filters == NULL) var->filters = (void*)nclistnew();
|
||||||
if((stat = NCZ_filter_initialize())) goto done;
|
if((stat = NCZ_filter_initialize())) goto done;
|
||||||
if((stat = NCJdictget(jvar,"compressor",&jfilter))) goto done;
|
if((stat = NCJdictget(jvar,"compressor",&jfilter))) goto done;
|
||||||
if(jfilter != NULL && NCJsort(jfilter) != NCJ_NULL) {
|
if(jfilter != NULL && NCJsort(jfilter) != NCJ_NULL) {
|
||||||
@ -1752,6 +1748,7 @@ define_vars(NC_FILE_INFO_T* file, NC_GRP_INFO_T* grp, NClist* varnames)
|
|||||||
nullfree(shapes); shapes = NULL;
|
nullfree(shapes); shapes = NULL;
|
||||||
if(formatv1) {NCJreclaim(jncvar); jncvar = NULL;}
|
if(formatv1) {NCJreclaim(jncvar); jncvar = NULL;}
|
||||||
NCJreclaim(jvar); jvar = NULL;
|
NCJreclaim(jvar); jvar = NULL;
|
||||||
|
var = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -391,9 +391,11 @@ NCZ_def_var(int ncid, const char *name, nc_type xtype, int ndims,
|
|||||||
var->meta_read = NC_TRUE;
|
var->meta_read = NC_TRUE;
|
||||||
var->atts_read = NC_TRUE;
|
var->atts_read = NC_TRUE;
|
||||||
|
|
||||||
|
#ifdef ENABLE_NCZARR_FILTERS
|
||||||
/* Set the filter list */
|
/* Set the filter list */
|
||||||
assert(var->filters == NULL);
|
assert(var->filters == NULL);
|
||||||
var->filters = (void*)nclistnew();
|
var->filters = (void*)nclistnew();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Point to the type, and increment its ref. count */
|
/* Point to the type, and increment its ref. count */
|
||||||
var->type_info = type;
|
var->type_info = type;
|
||||||
@ -558,10 +560,12 @@ ncz_def_var_extra(int ncid, int varid, int *shuffle, int *unused1,
|
|||||||
|
|
||||||
/* Can't turn on parallel and deflate/fletcher32/szip/shuffle
|
/* Can't turn on parallel and deflate/fletcher32/szip/shuffle
|
||||||
* before HDF5 1.10.3. */
|
* before HDF5 1.10.3. */
|
||||||
|
#ifdef ENABLE_NCZARR_FILTERS
|
||||||
#ifndef HDF5_SUPPORTS_PAR_FILTERS
|
#ifndef HDF5_SUPPORTS_PAR_FILTERS
|
||||||
if (h5->parallel == NC_TRUE)
|
if (h5->parallel == NC_TRUE)
|
||||||
if (nclistlength(((NClist*)var->filters)) > 0 || fletcher32 || shuffle)
|
if (nclistlength(((NClist*)var->filters)) > 0 || fletcher32 || shuffle)
|
||||||
{retval = NC_EINVAL; goto done;}
|
{retval = NC_EINVAL; goto done;}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If the HDF5 dataset has already been created, then it is too
|
/* If the HDF5 dataset has already been created, then it is too
|
||||||
@ -628,8 +632,10 @@ ncz_def_var_extra(int ncid, int varid, int *shuffle, int *unused1,
|
|||||||
* no filters in use for this data. */
|
* no filters in use for this data. */
|
||||||
if (storage != NC_CHUNKED)
|
if (storage != NC_CHUNKED)
|
||||||
{
|
{
|
||||||
|
#ifdef NCZARR_FILTERS
|
||||||
if (nclistlength(((NClist*)var->filters)) > 0)
|
if (nclistlength(((NClist*)var->filters)) > 0)
|
||||||
{retval = NC_EINVAL; goto done;}
|
{retval = NC_EINVAL; goto done;}
|
||||||
|
#endif
|
||||||
for (d = 0; d < var->ndims; d++)
|
for (d = 0; d < var->ndims; d++)
|
||||||
if (var->dim[d]->unlimited)
|
if (var->dim[d]->unlimited)
|
||||||
{retval = NC_EINVAL; goto done;}
|
{retval = NC_EINVAL; goto done;}
|
||||||
|
Loading…
Reference in New Issue
Block a user