From aa2cd9a74e43a4701619ceed302b96523990fda1 Mon Sep 17 00:00:00 2001
From: Uwe Schulzweida <uwe.schulzweida@mpimet.mpg.de>
Date: Mon, 17 Jun 2024 20:53:56 +0200
Subject: [PATCH] cdfDefVarFilter: added support for list of filterSpec

---
 ChangeLog       |  4 ++++
 src/cdf_write.c | 63 ++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 51 insertions(+), 16 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index eb990f483..809a37eb2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,10 @@
         * using EXSE library version 2.0.0
 	* Version 2.4.2 released
 
+2024-06-17  Uwe Schulzweida
+
+	* cdfDefVarFilter: added support for list of filterSpec
+
 2024-05-22  Uwe Schulzweida
 
 	* cdiInqContents: missing lock of non thread-safe netCDF4/HDF5 calls (bug fix)
diff --git a/src/cdf_write.c b/src/cdf_write.c
index e37d1cc44..38f7ebb9a 100644
--- a/src/cdf_write.c
+++ b/src/cdf_write.c
@@ -14,23 +14,49 @@
 #include "vlist_var.h"
 
 // #include <netcdf_filter.h>
+#ifdef HAVE_NETCDF4
+#include "netcdf_aux.h"
+#endif
 
-void
-cdf_def_var_filter(int ncid, int ncvarID, unsigned int id, size_t nparams, const unsigned int *params)
+static void
+cdf_def_var_filter(int ncid, int ncvarID, const char *filterSpec)
 {
 #ifdef HAVE_NETCDF4
-  int status;
-  if ((status = nc_def_var_filter(ncid, ncvarID, id, nparams, params)))
+  if (filterSpec)
     {
-      Message("filterId=%u  numParams=%zu", id, nparams);
-      Error("nc_def_var_filter failed; %s", nc_strerror(status));
+      size_t nfilters = 0;
+      NC_H5_Filterspec **filters = NULL;
+      int status = ncaux_h5filterspec_parselist(filterSpec, NULL, &nfilters, &filters);
+      if (status != NC_NOERR)
+        {
+          Message("filterSpec=%s", filterSpec);
+          Error("ncaux_h5filterspec_parselist failed; %s", nc_strerror(status));
+        }
+
+      if (filters != NULL)
+        {
+          for (size_t i = 0; i < nfilters; i++)
+            {
+              unsigned int filterid = filters[i]->filterid;
+              // printf("filter %zu id:%d nparams:%zu param1 %d\n", i + 1, filterid, filters[i]->nparams, filters[i]->params[0]);
+              status = nc_def_var_filter(ncid, ncvarID, filterid, filters[i]->nparams, filters[i]->params);
+              if (status != NC_NOERR)
+                {
+                  Message("filterid=%u  numParams=%zu", filterid, filters[i]->nparams);
+                  Error("nc_def_var_filter failed; %s", nc_strerror(status));
+                }
+            }
+
+          for (size_t i = 0; i < nfilters; i++) ncaux_h5filterspec_free(filters[i]);
+          free(filters);
+        }
     }
 #else
   static bool lwarn = true;
   if (lwarn)
     {
       lwarn = false;
-      Warning("filter failed, NetCDF4 not available!");
+      Warning("Filter failed, NetCDF4 not available!");
     }
 #endif
 }
@@ -460,13 +486,13 @@ xtype2ppb(nc_type xtype)
 }
 
 static void
-cdfDefVarFilter(const stream_t *s, int ncvarID)
+cdfDefVarFilter(int fileID, int fileType, int ncvarID, const char *filterSpec)
 {
-  if (s->filterId != 0)
+  if (filterSpec)
     {
-      if (s->filetype == CDI_FILETYPE_NC4 || s->filetype == CDI_FILETYPE_NC4C || s->filetype == CDI_FILETYPE_NCZARR)
+      if (fileType == CDI_FILETYPE_NC4 || fileType == CDI_FILETYPE_NC4C || fileType == CDI_FILETYPE_NCZARR)
         {
-          cdf_def_var_filter(s->fileID, ncvarID, s->filterId, s->numParams, s->params);
+          cdf_def_var_filter(fileID, ncvarID, filterSpec);
         }
       else
         {
@@ -920,6 +946,7 @@ cdfDefVar(stream_t *streamptr, int varID)
   if (streamptr->vars[varID].ncvarid != CDI_UNDEFID) return streamptr->vars[varID].ncvarid;
 
   int fileID = streamptr->fileID;
+  int fileType = streamptr->filetype;
   if (CDI_Debug) Message("streamID = %d, fileID = %d, varID = %d", streamptr->self, fileID, varID);
 
   int vlistID = streamptr->vlistID;
@@ -1002,14 +1029,18 @@ cdfDefVar(stream_t *streamptr, int varID)
     }
 #endif
 
-  if (useChunks
-      && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C
-          || streamptr->filetype == CDI_FILETYPE_NCZARR))
+  if (useChunks && (fileType == CDI_FILETYPE_NC4 || fileType == CDI_FILETYPE_NC4C || fileType == CDI_FILETYPE_NCZARR))
     cdf_def_var_chunking(fileID, ncvarID, NC_CHUNKED, chunks);
 #endif
 
   if (useChunks) cdfDefVarCompression(streamptr, ncvarID, xtype);
-  if (useChunks) cdfDefVarFilter(streamptr, ncvarID);
+  if (useChunks)
+    {
+      char filterSpec[CDI_MAX_NAME];
+      length = CDI_MAX_NAME;
+      if (cdiInqKeyString(vlistID, varID, CDI_KEY_FILTERSPEC, filterSpec, &length) == CDI_NOERR)
+        cdfDefVarFilter(fileID, fileType, ncvarID, filterSpec);
+    }
 
   if (*stdname) cdf_put_att_text(fileID, ncvarID, "standard_name", strlen(stdname), stdname);
   if (*longname) cdf_put_att_text(fileID, ncvarID, "long_name", strlen(longname), longname);
@@ -1056,7 +1087,7 @@ cdfDefVar(stream_t *streamptr, int varID)
   cdfDefineCellMethods(streamptr, vlistID, varID, fileID, ncvarID);
 
   // Attributes
-  cdfDefineAttributes(streamptr->filetype, vlistID, varID, fileID, ncvarID);
+  cdfDefineAttributes(fileType, vlistID, varID, fileID, ncvarID);
 
   // Institute
   if (vlistInqInstitut(vlistID) == CDI_UNDEFID) cdfDefineInstituteName(vlistID, varID, fileID, ncvarID);
-- 
GitLab