1 /*
2 * Copyright 2018, University Corporation for Atmospheric Research
3 * See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 */
5
6 #include "config.h"
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #ifdef _MSC_VER
11 #include <io.h>
12 #endif
13
14 #include "netcdf.h"
15 #include "netcdf_filter.h"
16 #include "ncdispatch.h"
17 #include "nc4internal.h"
18
19 #ifdef USE_HDF5
20 #include "hdf5internal.h"
21 #endif
22
23 /*
24 Unified filter related code
25 */
26
27 #ifndef H5Z_FILTER_SZIP
28 /** ID of HDF SZIP filter. */
29 #define H5Z_FILTER_SZIP 4
30 #endif
31
32 #define LPAREN '('
33 #define RPAREN ')'
34 #define LBRACK '['
35 #define RBRACK ']'
36
37 #define NUMCHAR "0123456789"
38 #define NAMECHAR1 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
39 #define NAMECHARN (NAMECHAR1 NUMCHAR "_-")
40
41 /* Forward */
42 static int gettype(const int q0, const int q1, int* unsignedp);
43
44 const struct LegalFormat {
45 const char* tag;
46 int format;
47 } legalformats[] = {
48 {"hdf5", NC_FILTER_FORMAT_HDF5},
49 {NULL, 0},
50 };
51
52 const struct FilterName {
53 const char* name; /* name or alias as assigned by HDF group*/
54 unsigned int id; /* id as assigned by HDF group*/
55 } known_filters[] = {
56 {"zip", 2}, /* Standard zlib compression */
57 {"zlib", 2}, /* alias */
58 {"deflate", 2}, /* alias */
59 {"szip", 4}, /* Standard szip compression */
60 {"bzip2", 307}, /* BZIP2 lossless compression used by PyTables */
61 {"lzf", 32000}, /* LZF lossless compression used by H5Py project */
62 {"blosc", 32001}, /* Blosc lossless compression used by PyTables */
63 {"mafisc", 32002}, /* Modified LZMA compression filter, MAFISC (Multidimensional Adaptive Filtering Improved Scientific data Compression) */
64 {"snappy", 32003}, /* Snappy lossless compression. */
65 {"lz4", 32004}, /* LZ4 fast lossless compression algorithm */
66 {"apax", 32005}, /* Samplify's APAX Numerical Encoding Technology */
67 {"cbf", 32006}, /* All imgCIF/CBF compressions and decompressions, including Canonical, Packed, Packed Vesrsion 2, Byte Offset and Nibble Offset. */
68 {"jpeg-xr", 32007}, /* Enables images to be compressed/decompressed with JPEG-XR compression */
69 {"bitshuffle", 32008}, /* Extreme version of shuffle filter that shuffles data at bit level instead of byte level. */
70 {"spdp", 32009}, /* SPDP fast lossless compression algorithm for single- and double-precision floating-point data. */
71 {"lpc-rice", 32010}, /* LPC-Rice multi-threaded lossless compression */
72 {"ccsds-123", 32011}, /* ESA CCSDS-123 multi-threaded compression filter */
73 {"jpeg-ls", 32012}, /* CharLS JPEG-LS multi-threaded compression filter */
74 {"zfp", 32013}, /* Rate, accuracy or precision bounded compression for floating-point arrays */
75 {"fpzip", 32014}, /* Fast and Efficient Lossy or Lossless Compressor for Floating-Point Data */
76 {"zstandard", 32015}, /* Real-time compression algorithm with wide range of compression / speed trade-off and fast decoder */
77 {"b3d", 32016}, /* GPU based image compression method developed for light-microscopy applications */
78 {"sz", 32017}, /* An error-bounded lossy compressor for scientific floating-point data */
79 {"fcidecomp", 32018}, /* EUMETSAT CharLS compression filter for use with netCDF */
80 {"user-defined", 32768}, /* First user-defined filter */
81 {NULL,0}
82 };
83
84 /**************************************************/
85 /*
86 Parse a filter spec string into a NC_FILTER_SPEC*
87
88 @param txt - a string containing the spec as a sequence of
89 constants separated by commas.
90 @param specp - store the parsed filter here -- caller frees
91 @return NC_NOERR if parse succeeded
92 @return NC_EINVAL otherwise
93 */
94
95 EXTERNL int
NC_parsefilterspec(const char * txt,int format,NC_Filterspec ** specp)96 NC_parsefilterspec(const char* txt, int format, NC_Filterspec** specp)
97 {
98 int stat = NC_NOERR;
99 int sstat; /* for scanf */
100 char* p;
101 char* sdata0 = NULL; /* what to free */
102 char* sdata = NULL; /* sdata0 with leading prefix skipped */
103 unsigned int id;
104 size_t count; /* no. of comma delimited params */
105 size_t nparams; /* final no. of unsigned ints */
106 size_t len;
107 int i;
108 unsigned int* ulist = NULL;
109 unsigned char mem[8];
110
111 if(txt == NULL) goto fail;
112 len = strlen(txt);
113 if(len == 0) goto fail;
114
115 sdata0 = (char*)calloc(1,len+1+1);
116 if(sdata0 == NULL) return 0;
117 memcpy(sdata0,txt,len);
118 sdata = sdata0;
119
120 /* Count number of parameters + id and delimit */
121 p=sdata;
122 for(count=0;;count++) {
123 char* q = strchr(p,',');
124 if(q == NULL) break;
125 *q++ = '\0';
126 p = q;
127 }
128 count++; /* for final piece */
129
130 if(count == 0)
131 goto fail; /* no id and no parameters */
132
133 /* Extract the filter id */
134 p = sdata;
135 if(strchr(NAMECHAR1,*p) != NULL) {
136 const struct FilterName* candidate = known_filters;
137 char* q = p+1;
138 while(*q && strchr(NAMECHARN,*q) != NULL) {
139 q++;
140 }
141 if(*q) goto fail; /*name has bad char*/
142 /* Lookup name */
143 id = 0; /* => not found */
144 for(;candidate->name;candidate++) {
145 if(strcasecmp(candidate->name,p)==0) {id = candidate->id; break;}
146 }
147 if(id == 0) goto fail; /* unknown name */
148 } else if(strchr(NUMCHAR,*p) != NULL) {
149 sstat = sscanf(p,"%u",&id);
150 if(sstat != 1) goto fail;
151 } else goto fail; /* unparseable id */
152 count--;
153
154 /* skip past the filter id */
155 p = p + strlen(p) + 1;
156
157 /* Allocate the max needed space; *2 in case the params are all doubles */
158 ulist = (unsigned int*)malloc(sizeof(unsigned int)*(count)*2);
159 if(ulist == NULL) goto fail;
160
161 /* walk and convert */
162 nparams = 0; /* actual count */
163 for(i=0;i<count;i++) { /* step thru param strings */
164 unsigned long long val64u;
165 unsigned int val32u;
166 double vald;
167 float valf;
168 unsigned int *vector;
169 int isunsigned = 0;
170 int isnegative = 0;
171 int type = 0;
172 char* q;
173
174 len = strlen(p);
175 /* skip leading white space */
176 while(strchr(" ",*p) != NULL) {p++; len--;}
177 /* Get leading sign character, if any */
178 if(*p == '-') isnegative = 1;
179 /* Get trailing type tag characters */
180 switch (len) {
181 case 0:
182 goto fail; /* empty parameter */
183 case 1:
184 case 2:
185 q = (p + len) - 1; /* point to last char */
186 type = gettype(*q,'\0',&isunsigned);
187 break;
188 default: /* > 2 => we might have a two letter tag */
189 q = (p + len) - 2;
190 type = gettype(*q,*(q+1),&isunsigned);
191 break;
192 }
193
194 /* Now parse */
195 switch (type) {
196 case 'b':
197 case 's':
198 case 'i':
199 /* special case for a positive integer;for back compatibility.*/
200 if(!isnegative)
201 sstat = sscanf(p,"%u",&val32u);
202 else
203 sstat = sscanf(p,"%d",(int*)&val32u);
204 if(sstat != 1) goto fail;
205 switch(type) {
206 case 'b': val32u = (val32u & 0xFF); break;
207 case 's': val32u = (val32u & 0xFFFF); break;
208 }
209 ulist[nparams++] = val32u;
210 break;
211
212 case 'f':
213 sstat = sscanf(p,"%lf",&vald);
214 if(sstat != 1) goto fail;
215 valf = (float)vald;
216 ulist[nparams++] = *(unsigned int*)&valf;
217 break;
218
219 /* The following are 8-byte values, so we must swap pieces if this
220 is a little endian machine */
221 case 'd':
222 sstat = sscanf(p,"%lf",&vald);
223 if(sstat != 1) goto fail;
224 memcpy(mem,&vald,sizeof(mem));
225 NC4_filterfix8(mem,0);
226 vector = (unsigned int*)mem;
227 ulist[nparams++] = vector[0];
228 ulist[nparams++] = vector[1];
229 break;
230 case 'l': /* long long */
231 if(isunsigned)
232 sstat = sscanf(p,"%llu",&val64u);
233 else
234 sstat = sscanf(p,"%lld",(long long*)&val64u);
235 if(sstat != 1) goto fail;
236 memcpy(mem,&val64u,sizeof(mem));
237 NC4_filterfix8(mem,0);
238 vector = (unsigned int*)&mem;
239 ulist[nparams++] = vector[0];
240 ulist[nparams++] = vector[1];
241 break;
242 default:
243 goto fail;
244 }
245 p = p + strlen(p) + 1; /* move to next param */
246 }
247 /* Now return results */
248 if(specp != NULL) {
249 NC4_Filterspec* pfs = calloc(1,sizeof(NC4_Filterspec));
250 if(pfs == NULL) {stat = NC_ENOMEM; goto done;}
251 pfs->hdr.hdr.format = format;
252 pfs->filterid = id;
253 pfs->nparams = nparams;
254 pfs->params = ulist; ulist = NULL;
255 *specp = (NC_Filterspec*)pfs;
256 }
257
258 done:
259 if(sdata) free(sdata);
260 if(ulist) free(ulist);
261 return stat;
262 fail:
263 stat = NC_EINVAL;
264 goto done;
265 }
266
267 /*
268 Parse a string containing multiple '|' separated filter specs.
269
270 @param spec0 - a string containing the list of filter specs.
271 @param nspecsp - # of parsed specs
272 @param specsp - pointer to hold vector of parsed specs. Caller frees
273 @return NC_NOERR if parse succeeded
274 @return NC_EINVAL if bad parameters or parse failed
275 */
276
277 EXTERNL int
NC_parsefilterlist(const char * txt0,int * formatp,size_t * nspecsp,NC_Filterspec *** vectorp)278 NC_parsefilterlist(const char* txt0, int* formatp, size_t* nspecsp, NC_Filterspec*** vectorp)
279 {
280 int stat = NC_NOERR;
281 int format = NC_FILTER_FORMAT_HDF5; /* default */
282 size_t len = 0;
283 size_t nspecs = 0;
284 NC4_Filterspec** vector = NULL;
285 char* spec0 = NULL; /* with prefix */
286 char* spec = NULL; /* without prefix */
287 char* p = NULL;
288 char* q = NULL;
289
290 if(txt0 == NULL) return NC_EINVAL;
291 /* Duplicate txt0 so we can modify it */
292 len = strlen(txt0);
293 if((spec = calloc(1,len+1+1)) == NULL) return NC_ENOMEM;
294 memcpy(spec,txt0,len); /* Note double ending nul */
295 spec0 = spec; /* Save for later free */
296
297 /* See if there is a prefix '[format]' tag */
298 if(spec[0] == LBRACK) {
299 int found = 0;
300 const struct LegalFormat* candidates = legalformats;
301 p = spec + 1;
302 q = strchr(p,RBRACK);
303 if(q == NULL) {stat = NC_EINVAL; goto done;}
304 *q++ = '\0'; /* delimit tag */
305 while(candidates->tag != NULL) {
306 if(strcasecmp(p,candidates->tag) == 0) {
307 found = 1;
308 format = candidates->format;
309 }
310 }
311 if(found == 0) {stat = NC_EINVAL; goto done;}
312 spec = q; /* skip tag wrt later processing */
313 }
314 if(formatp) *formatp = format;
315
316 if(format != NC_FILTER_FORMAT_HDF5) {stat = NC_EINVAL; goto done;} /* for now */
317
318 /* pass 1: count number of specs */
319 p = spec;
320 nspecs = 0;
321 while(*p) {
322 q = strchr(p,'|');
323 if(q == NULL) q = p + strlen(p); /* fake it */
324 nspecs++;
325 p = q + 1;
326 }
327 if(nspecs > 0) {
328 int count = 0;
329 if((vector = (NC4_Filterspec**)malloc(sizeof(NC4_Filterspec*)*nspecs)) == NULL)
330 {stat = NC_ENOMEM; goto done;}
331 /* pass 2: parse */
332 p = spec;
333 for(count=0;count<nspecs;count++) {
334 NC4_Filterspec* aspec = NULL;
335 q = strchr(p,'|');
336 if(q == NULL) q = p + strlen(p); /* fake it */
337 *q = '\0';
338 if(NC_parsefilterspec(p,format,(NC_Filterspec**)&aspec))
339 {stat = NC_EINVAL; goto done;}
340 vector[count] = aspec; aspec = NULL;
341 p = q+1; /* ok because of double nul */
342 }
343 }
344 if(nspecsp) *nspecsp = nspecs;
345 if(vectorp) *vectorp = (nspecs == 0 ? NULL : (NC_Filterspec**)vector);
346 vector = NULL;
347 done:
348 nullfree(spec0);
349 if(vector != NULL) {
350 int k;
351 for(k=0;k<nspecs;k++) {
352 NC4_Filterspec* nfs = vector[k];
353 if(nfs->params) free(nfs->params);
354 nullfree(nfs);
355 }
356 free(vector);
357 }
358 return stat;
359 }
360
361
362 #ifdef WORDS_BIGENDIAN
363 /* Byte swap an 8-byte integer in place */
364 static void
byteswap8(unsigned char * mem)365 byteswap8(unsigned char* mem)
366 {
367 unsigned char c;
368 c = mem[0];
369 mem[0] = mem[7];
370 mem[7] = c;
371 c = mem[1];
372 mem[1] = mem[6];
373 mem[6] = c;
374 c = mem[2];
375 mem[2] = mem[5];
376 mem[5] = c;
377 c = mem[3];
378 mem[3] = mem[4];
379 mem[4] = c;
380 }
381
382 /* Byte swap an 8-byte integer in place */
383 static void
byteswap4(unsigned char * mem)384 byteswap4(unsigned char* mem)
385 {
386 unsigned char c;
387 c = mem[0];
388 mem[0] = mem[3];
389 mem[3] = c;
390 c = mem[1];
391 mem[1] = mem[2];
392 mem[2] = c;
393 }
394 #endif
395
396
397 EXTERNL void
NC4_filterfix8(unsigned char * mem,int decode)398 NC4_filterfix8(unsigned char* mem, int decode)
399 {
400 #ifdef WORDS_BIGENDIAN
401 if(decode) { /* Apply inverse of the encode case */
402 byteswap4(mem); /* step 1: byte-swap each piece */
403 byteswap4(mem+4);
404 byteswap8(mem); /* step 2: convert to little endian format */
405 } else { /* encode */
406 byteswap8(mem); /* step 1: convert to little endian format */
407 byteswap4(mem); /* step 2: byte-swap each piece */
408 byteswap4(mem+4);
409 }
410 #else /* Little endian */
411 /* No action is necessary */
412 #endif
413 }
414
415
416 /* Support direct user defined filters */
417
418 /* Use void* to avoid having to include hdf.h*/
419 EXTERNL int
nc_filter_client_register(unsigned int id,void * info)420 nc_filter_client_register(unsigned int id, void* info)
421 {
422 int stat = NC_NOERR;
423 if(id == 0 ||info == NULL)
424 return NC_EINVAL;
425 #ifdef USE_HDF5
426 NC_FILTER_OBJ_HDF5 client;
427 memset(&client,0,sizeof(client));
428 client.hdr.format = NC_FILTER_FORMAT_HDF5;
429 client.sort = NC_FILTER_SORT_CLIENT;
430 client.u.client.id = id;
431 client.u.client.info = info;
432 /* Note use of a global function, not part of the dispatch table */
433 stat = nc4_global_filter_action(NCFILTER_CLIENT_REG, id, &client);
434 #else
435 stat = NC_ENOTBUILT;
436 #endif
437 return stat;
438 }
439
440 EXTERNL int
nc_filter_client_unregister(unsigned int id)441 nc_filter_client_unregister(unsigned int id)
442 {
443 int stat = NC_NOERR;
444 #ifdef USE_HDF5
445 stat = nc4_global_filter_action(NCFILTER_CLIENT_UNREG, id, NULL);
446 #else
447 stat = NC_ENOTBUILT;
448 #endif
449 return stat;
450 }
451
452 /* Use void* to avoid having to include hdf.h*/
453 EXTERNL int
nc_filter_client_inq(unsigned int id,void * infop)454 nc_filter_client_inq(unsigned int id, void* infop)
455 {
456 int stat = NC_NOERR;
457 #ifdef USE_HDF5
458 H5Z_class2_t* hct = (H5Z_class2_t*)infop;
459 NC_FILTER_OBJ_HDF5 client;
460 if(id == 0 ||infop == NULL)
461 return NC_EINVAL;
462 memset(&client,0,sizeof(client));
463 client.hdr.format = NC_FILTER_FORMAT_HDF5;
464 client.sort = NC_FILTER_SORT_CLIENT;
465 client.u.client.id = id;
466 client.u.client.info = hct;
467 /* Note use of a global function, not part of the dispatch table */
468 stat = nc4_global_filter_action(NCFILTER_CLIENT_INQ, id, &client);
469 if(stat == NC_NOERR) {
470 *hct = *(H5Z_class2_t*)client.u.client.info;
471 }
472 #else
473 stat = NC_ENOTBUILT;
474 #endif
475 return stat;
476 }
477
478 /**
479 Find the set of filters (if any) associated with a variable.
480
481 \param ncid NetCDF or group ID, from a previous call to nc_open(),
482 nc_create(), nc_def_grp(), or associated inquiry functions such as
483 nc_inq_ncid().
484
485 \param varid Variable ID
486 \param nfilters return no. of filters
487 \param ids return the filter ids (caller allocates)
488
489 \returns ::NC_NOERR No error.
490 \returns ::NC_ENOTNC4 Not a netCDF-4 file.
491 \returns ::NC_EBADID Bad ncid.
492 \returns ::NC_ENOTVAR Invalid variable ID.
493 \returns ::NC_EINVAL Invalid arguments
494 \ingroup variables
495 \author Dennis Heimbigner
496 */
497 EXTERNL int
nc_inq_var_filterids(int ncid,int varid,size_t * nfiltersp,unsigned int * ids)498 nc_inq_var_filterids(int ncid, int varid, size_t* nfiltersp, unsigned int* ids)
499 {
500 NC* ncp;
501 int stat = NC_check_id(ncid,&ncp);
502 NC_FILTER_OBJ_HDF5 ncids;
503
504 if(stat != NC_NOERR) return stat;
505 TRACE(nc_inq_var_filterids);
506
507 memset(&ncids,0,sizeof(ncids));
508 ncids.hdr.format = NC_FILTER_FORMAT_HDF5;
509 ncids.sort = NC_FILTER_SORT_IDS;
510 ncids.u.ids.nfilters = (nfiltersp?*nfiltersp:0);
511 ncids.u.ids.filterids = ids;
512
513 if((stat = ncp->dispatch->filter_actions(ncid,varid, NCFILTER_FILTERIDS, (NC_Filterobject*)&ncids)) == NC_NOERR) {
514 if(nfiltersp) *nfiltersp = ncids.u.ids.nfilters;
515 }
516 return stat;
517 }
518
519 /**
520 Find the the param info about filter (if any)
521 associated with a variable and with specified id.
522
523 This is a wrapper for nc_inq_var_all().
524
525 \param ncid NetCDF or group ID, from a previous call to nc_open(),
526 nc_create(), nc_def_grp(), or associated inquiry functions such as
527 nc_inq_ncid().
528
529 \param varid Variable ID
530 \param id The filter id of interest
531 \param formatp (Out) Storage for the filter format
532 \param nparamsp (Out) Storage which will get the number of parameters to the filter
533 \param params (Out) Storage which will get associated parameters.
534 Note: the caller must allocate and free.
535
536 \returns ::NC_NOERR No error.
537 \returns ::NC_ENOTNC4 Not a netCDF-4 file.
538 \returns ::NC_EBADID Bad ncid.
539 \returns ::NC_ENOTVAR Invalid variable ID.
540 \returns ::NC_ENOFILTER No filter defined.
541 \ingroup variables
542 \author Dennis Heimbigner
543 */
544 EXTERNL int
nc_inq_var_filter_info(int ncid,int varid,unsigned int id,size_t * nparamsp,unsigned int * params)545 nc_inq_var_filter_info(int ncid, int varid, unsigned int id, size_t* nparamsp, unsigned int* params)
546 {
547 NC* ncp;
548 int stat = NC_check_id(ncid,&ncp);
549 NC_FILTER_OBJ_HDF5 spec;
550
551 if(stat != NC_NOERR) return stat;
552 TRACE(nc_inq_var_filter_info_hdf5);
553
554 memset(&spec,0,sizeof(spec));
555 spec.hdr.format = NC_FILTER_FORMAT_HDF5;
556 spec.sort = NC_FILTER_SORT_SPEC;
557 spec.u.spec.filterid = id;
558 spec.u.spec.nparams = (nparamsp?*nparamsp:0);
559 spec.u.spec.params = params;
560
561 if((stat = ncp->dispatch->filter_actions(ncid,varid,NCFILTER_INFO,(NC_Filterobject*)&spec)) == NC_NOERR) {
562 if(nparamsp) *nparamsp = spec.u.spec.nparams;
563 }
564 return stat;
565 }
566
567 /**
568 Find the first filter (if any) associated with a variable.
569
570 \param ncid NetCDF or group ID, from a previous call to nc_open(),
571 nc_create(), nc_def_grp(), or associated inquiry functions such as
572 nc_inq_ncid().
573
574 \param varid Variable ID
575
576 \param idp Storage which will get the filter id; a return value of zero means no filter
577
578 \param nparamsp Storage which will get the number of parameters to the
579 filter
580
581 \param params Storage which will get associated parameters.
582 Note: the caller must allocate and free.
583
584 \returns ::NC_NOERR No error.
585 \returns ::NC_ENOTNC4 Not a netCDF-4 file.
586 \returns ::NC_EBADID Bad ncid.
587 \returns ::NC_ENOTVAR Invalid variable ID.
588 \returns ::NC_ENOFILTER No filter defined.
589 \ingroup variables
590 \author Dennis Heimbigner
591 */
592 EXTERNL int
nc_inq_var_filter(int ncid,int varid,unsigned int * idp,size_t * nparamsp,unsigned int * params)593 nc_inq_var_filter(int ncid, int varid, unsigned int* idp, size_t* nparamsp, unsigned int* params)
594 {
595 NC* ncp;
596 NC_FILTER_OBJ_HDF5 spec;
597 int stat = NC_check_id(ncid,&ncp);
598
599 if(stat != NC_NOERR) return stat;
600 TRACE(nc_inq_var_filter);
601
602 memset(&spec,0,sizeof(spec));
603 spec.hdr.format = NC_FILTER_FORMAT_HDF5;
604 spec.sort = NC_FILTER_SORT_SPEC;
605 spec.u.spec.filterid = (idp?*idp:0);
606 spec.u.spec.nparams = (nparamsp?*nparamsp:0);
607 spec.u.spec.params = params;
608
609 if((stat=ncp->dispatch->filter_actions(ncid,varid,NCFILTER_INQ,(NC_Filterobject*)&spec)))
610 return stat;
611 if(idp) *idp = spec.u.spec.filterid;
612 if(nparamsp) *nparamsp = spec.u.spec.nparams;
613 return stat;
614 }
615
616 /**
617 Define a new variable hdf5 filter.
618
619 Only variables with chunked storage can use filters.
620
621 @param ncid File and group ID.
622 @param varid Variable ID.
623 @param id Filter ID.
624 @param nparams Number of filter parameters.
625 @param parms Filter parameters.
626
627 @return ::NC_NOERR No error.
628 @return ::NC_EINVAL Variable must be chunked.
629 @return ::NC_EBADID Bad ID.
630 @author Dennis Heimbigner
631 */
632
633 EXTERNL int
nc_def_var_filter(int ncid,int varid,unsigned int id,size_t nparams,const unsigned int * params)634 nc_def_var_filter(int ncid, int varid, unsigned int id, size_t nparams, const unsigned int* params)
635 {
636 NC* ncp;
637 NC_FILTER_OBJ_HDF5 spec;
638 int stat = NC_check_id(ncid,&ncp);
639
640 if(stat != NC_NOERR) return stat;
641 TRACE(nc_def_var_filter_hdf5);
642
643 memset(&spec,0,sizeof(spec));
644 spec.hdr.format = NC_FILTER_FORMAT_HDF5;
645 spec.sort = NC_FILTER_SORT_SPEC;
646 spec.u.spec.filterid = id;
647 spec.u.spec.nparams = nparams;
648 spec.u.spec.params = (unsigned int*)params; /* discard const */
649 return ncp->dispatch->filter_actions(ncid,varid,NCFILTER_DEF,(NC_Filterobject*)&spec);
650 }
651
652 /**
653 Remove all filters with specified id from a variable
654
655 @param ncid File and group ID.
656 @param varid Variable ID.
657 @param id filter to remove
658
659 @return ::NC_NOERR No error.
660 @return ::NC_EBADID Bad ID.
661 @author Dennis Heimbigner
662 */
663 EXTERNL int
nc_var_filter_remove(int ncid,int varid,unsigned int id)664 nc_var_filter_remove(int ncid, int varid, unsigned int id)
665 {
666 NC* ncp;
667 int stat = NC_check_id(ncid,&ncp);
668 NC_FILTER_OBJ_HDF5 spec;
669
670 if(stat != NC_NOERR) return stat;
671 TRACE(nc_var_filter_hdf5_remove);
672
673 memset(&spec,0,sizeof(spec));
674 spec.hdr.format = NC_FILTER_FORMAT_HDF5;
675 spec.sort = NC_FILTER_SORT_SPEC;
676 spec.u.spec.filterid = id;
677 return ncp->dispatch->filter_actions(ncid,varid,NCFILTER_REMOVE,(NC_Filterobject*)&spec);
678 }
679
680 /**************************************************/
681 /* Utilities */
682
683 /* Look at q0 and q1) to determine type */
684 static int
gettype(const int q0,const int q1,int * isunsignedp)685 gettype(const int q0, const int q1, int* isunsignedp)
686 {
687 int type = 0;
688 int isunsigned = 0;
689 char typechar;
690
691 isunsigned = (q0 == 'u' || q0 == 'U');
692 if(q1 == '\0')
693 typechar = q0; /* we were given only a single char */
694 else if(isunsigned)
695 typechar = q1; /* we have something like Ux as the tag */
696 else
697 typechar = q1; /* look at last char for tag */
698 switch (typechar) {
699 case 'f': case 'F': case '.': type = 'f'; break; /* float */
700 case 'd': case 'D': type = 'd'; break; /* double */
701 case 'b': case 'B': type = 'b'; break; /* byte */
702 case 's': case 'S': type = 's'; break; /* short */
703 case 'l': case 'L': type = 'l'; break; /* long long */
704 case '0': case '1': case '2': case '3': case '4':
705 case '5': case '6': case '7': case '8': case '9': type = 'i'; break;
706 case 'u': case 'U': type = 'i'; isunsigned = 1; break; /* unsigned int */
707 case '\0': type = 'i'; break;
708 default: break;
709 }
710 if(isunsignedp) *isunsignedp = isunsigned;
711 return type;
712 }
713