mirror of
https://github.com/HDFGroup/hdf5.git
synced 2026-09-25 04:09:44 +03:00
Add H5Pmodify_filter_by_idx
Implements the API specified in RFC-HDFG-2026-001 sec:modify-filter, which had no implementation on this branch. H5Pmodify_filter is the only existing way to change a filter's parameters, and it takes raw cd_values, so it always clears the entry's stored configuration string. The documented read-mutate-write pattern therefore silently downgrades an entry from an exact, plugin-free configuration string to get_config reconstruction, with no error and no diagnostic. The only workaround was H5Premove_filter plus a fresh H5Pappend_filter, which moves the entry to the end of the pipeline and so changes filter order -- for order-sensitive pipelines such as shuffle-then-deflate, that changes the compressed result. H5Pmodify_filter_by_idx replaces the configuration of the entry already at a given position, leaving its position and filter ID alone. It takes the same H5Z_params_t as H5Pappend_filter: the STRING form resolves through set_config (same two-pass protocol) and replaces both cd_values and the stored string, canonicalised as on the append path; the CDVALUES form replaces cd_values and clears the string, matching H5Pmodify_filter. Addressing is by index, not filter ID, because a pipeline may legally contain the same filter ID more than once and an ID-addressed modify silently edits the first match. The index is the one H5Pget_filter2 and H5Pget_filter_params_by_idx already use. All allocations are staged before the entry is touched, so a rejected edit -- bad index, invalid flags, set_config failure, or an allocation failure -- leaves the entry exactly as it was rather than holding a string that disagrees with its cd_values. H5Pmodify_filter is unchanged and undeprecated. Adds six tests: in-place string replacement, canonicalization on the modify path, cd_values clearing the string, index addressing with duplicate filter IDs, errors leaving the entry intact, and the replacement string reaching disk (RFC fmt-07). The duplicate-ID test was verified to fail against a deliberately ID-addressed implementation.
This commit is contained in:
+219
@@ -2027,6 +2027,225 @@ done:
|
||||
FUNC_LEAVE_API(ret_value)
|
||||
} /* end H5Pappend_filter() */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Function: H5Pmodify_filter_by_idx
|
||||
*
|
||||
* Purpose: Replaces the configuration of the filter already at position
|
||||
* FILTER_IDX in PLIST_ID's pipeline, leaving its position and
|
||||
* filter ID unchanged. PARAMS is interpreted exactly as
|
||||
* H5Pappend_filter interprets it:
|
||||
*
|
||||
* H5Z_PARAMS_STRING - resolved through the filter's
|
||||
* set_config callback; both the resulting
|
||||
* cd_values and the canonical string
|
||||
* replace the entry's current ones, so the
|
||||
* entry keeps a stored configuration
|
||||
* string.
|
||||
* H5Z_PARAMS_CDVALUES - the cd_values array replaces the
|
||||
* entry's current one and any stored
|
||||
* string is cleared, matching
|
||||
* H5Pmodify_filter.
|
||||
* NULL - equivalent to CDVALUES with
|
||||
* cd_nelmts = 0.
|
||||
*
|
||||
* This exists because H5Pmodify_filter takes only raw
|
||||
* cd_values and therefore always clears the stored string,
|
||||
* silently downgrading an entry from an exact, plugin-free
|
||||
* configuration string to get_config reconstruction. The only
|
||||
* alternative was H5Premove_filter plus a fresh
|
||||
* H5Pappend_filter, which moves the entry to the end of the
|
||||
* pipeline and so changes filter order.
|
||||
*
|
||||
* Addressing is by index rather than by filter ID because a
|
||||
* pipeline may legally contain the same filter ID more than
|
||||
* once, where an ID-addressed modify silently edits the first
|
||||
* match. The index is the same one H5Pget_filter2 and
|
||||
* H5Pget_filter_params_by_idx use.
|
||||
*
|
||||
* On failure the entry is left exactly as it was: the new
|
||||
* cd_values and string are staged and swapped in only after
|
||||
* set_config succeeds, so a rejected edit cannot leave an entry
|
||||
* holding a string that disagrees with its cd_values.
|
||||
*
|
||||
* Return: Non-negative on success / Negative on failure
|
||||
*
|
||||
* Since: 3.0.0
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
herr_t
|
||||
H5Pmodify_filter_by_idx(hid_t plist_id, unsigned filter_idx, unsigned flags, const H5Z_params_t *params)
|
||||
{
|
||||
H5P_genplist_t *plist;
|
||||
H5O_pline_t pline;
|
||||
H5Z_filter_info_t *fi;
|
||||
H5Z_entry_t *entry = NULL;
|
||||
const unsigned *cd_values = NULL;
|
||||
unsigned *allocated_cd_values = NULL; /* owns heap mem for string path */
|
||||
char *canon_config = NULL; /* owns the buffer retain_config points into */
|
||||
const char *retain_config = NULL; /* canonical string to persist (STRING path only) */
|
||||
unsigned *staged_cd_values = NULL; /* staged replacement for fi->cd_values */
|
||||
char *staged_config = NULL; /* staged replacement for fi->config */
|
||||
size_t cd_nelmts = 0;
|
||||
H5Z_filter_t filter;
|
||||
herr_t ret_value = SUCCEED;
|
||||
|
||||
FUNC_ENTER_API(FAIL)
|
||||
|
||||
/* Validate flags */
|
||||
if (flags & ~((unsigned)H5Z_FLAG_DEFMASK))
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid flags");
|
||||
|
||||
/* Get the plist and its pipeline. The entry's existing filter ID selects
|
||||
* the class whose set_config resolves a parameter string, so the index
|
||||
* must be validated before params can be interpreted. */
|
||||
if (NULL == (plist = H5P_object_verify(plist_id, H5P_OBJECT_CREATE, false)))
|
||||
HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for ID");
|
||||
if (H5P_peek(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
|
||||
HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline");
|
||||
if (filter_idx >= pline.nused)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "filter index out of range");
|
||||
|
||||
fi = &pline.filter[filter_idx];
|
||||
filter = fi->id;
|
||||
|
||||
if (params == NULL || params->type == H5Z_PARAMS_CDVALUES) {
|
||||
/* Raw cd_values path - behaves identically to H5Pmodify_filter */
|
||||
if (params) {
|
||||
cd_nelmts = params->u.raw.cd_nelmts;
|
||||
cd_values = params->u.raw.cd_values;
|
||||
if (cd_nelmts > 0 && cd_values == NULL)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cd_values is NULL but cd_nelmts > 0");
|
||||
}
|
||||
}
|
||||
else if (params->type == H5Z_PARAMS_STRING) {
|
||||
/* String path - invoke set_config to translate into cd_values, using
|
||||
* the same two-pass protocol as H5Pappend_filter. */
|
||||
const char *param_str = params->u.str;
|
||||
bool empty_input = (!param_str || *param_str == '\0');
|
||||
size_t cd_nelmts2 = 0;
|
||||
size_t alloc_nelmts = 0;
|
||||
|
||||
if (!empty_input && strlen(param_str) > H5Z_CONFIG_STRING_MAX)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "params string exceeds H5Z_CONFIG_STRING_MAX");
|
||||
|
||||
/* Trigger dynamic plugin load if filter is not already registered */
|
||||
{
|
||||
htri_t filter_avail;
|
||||
if ((filter_avail = H5Z_filter_avail(filter)) < 0)
|
||||
HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't check filter availability");
|
||||
if (!filter_avail)
|
||||
HGOTO_ERROR(H5E_PLINE, H5E_NOFILTER, FAIL, "filter not found; register or load it first");
|
||||
}
|
||||
|
||||
/* Get the internal entry to access v3 callbacks */
|
||||
if (H5Z_find_entry(false, filter, &entry) < 0 || entry == NULL)
|
||||
HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "filter entry not found after availability check");
|
||||
|
||||
if (!entry->set_config) {
|
||||
/* No set_config: empty input means "no parameters"; a non-empty
|
||||
* parameter string has nowhere to go and is an error. */
|
||||
if (!empty_input)
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL,
|
||||
"filter does not support string configuration (no set_config callback)");
|
||||
cd_nelmts = 0;
|
||||
cd_values = NULL;
|
||||
}
|
||||
else {
|
||||
const char *cfg_str = empty_input ? NULL : param_str;
|
||||
|
||||
/* Canonicalise the string that will be persisted, for the same
|
||||
* reasons as in H5Pappend_filter (valid TOML v1.0.0 on disk). */
|
||||
if (!empty_input) {
|
||||
if (NULL == (canon_config = H5Z_canonicalize_params(param_str)))
|
||||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
|
||||
"can't canonicalize filter parameter string");
|
||||
retain_config = canon_config;
|
||||
}
|
||||
|
||||
/* Pass 1: determine cd_nelmts (size-query; cd_values is NULL) */
|
||||
if (entry->set_config(cfg_str, &flags, &cd_nelmts, NULL, 0) < 0)
|
||||
HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "set_config size-query call failed");
|
||||
|
||||
if (cd_nelmts > H5Z_MAX_CD_NELMTS)
|
||||
HGOTO_ERROR(H5E_PLINE, H5E_BADVALUE, FAIL,
|
||||
"cd_nelmts from set_config exceeds H5Z_MAX_CD_NELMTS (%u)", H5Z_MAX_CD_NELMTS);
|
||||
|
||||
/* Allocate cd_values (at least 1 to avoid zero-length alloc) */
|
||||
alloc_nelmts = cd_nelmts ? cd_nelmts : 1;
|
||||
if (NULL == (allocated_cd_values = (unsigned *)H5MM_malloc(alloc_nelmts * sizeof(unsigned))))
|
||||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for cd_values");
|
||||
cd_values = allocated_cd_values;
|
||||
|
||||
cd_nelmts2 = cd_nelmts;
|
||||
|
||||
/* Pass 2: populate cd_values */
|
||||
if (entry->set_config(cfg_str, &flags, &cd_nelmts2, allocated_cd_values, alloc_nelmts) < 0)
|
||||
HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "set_config populate call failed");
|
||||
|
||||
if (cd_nelmts2 != cd_nelmts)
|
||||
HGOTO_ERROR(H5E_PLINE, H5E_BADVALUE, FAIL,
|
||||
"set_config returned different cd_nelmts on second call (contract violation)");
|
||||
|
||||
/* Re-validate flags: the callback may have modified them */
|
||||
if (flags & ~((unsigned)H5Z_FLAG_DEFMASK))
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "set_config callback returned invalid flags");
|
||||
}
|
||||
}
|
||||
else {
|
||||
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unrecognised H5Z_params_t type field");
|
||||
}
|
||||
|
||||
/* ---- Stage every allocation before disturbing the entry, so that an
|
||||
* allocation failure here leaves the entry exactly as it was. ---- */
|
||||
if (cd_nelmts > H5Z_COMMON_CD_VALUES) {
|
||||
if (NULL == (staged_cd_values = (unsigned *)H5MM_malloc(cd_nelmts * sizeof(unsigned))))
|
||||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for filter parameters");
|
||||
H5MM_memcpy(staged_cd_values, cd_values, cd_nelmts * sizeof(unsigned));
|
||||
}
|
||||
if (retain_config) {
|
||||
if (NULL == (staged_config = (char *)H5MM_strdup(retain_config)))
|
||||
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
|
||||
"memory allocation failed for filter config string");
|
||||
}
|
||||
|
||||
/* ---- Commit: nothing below can fail. ---- */
|
||||
|
||||
/* Release what the entry currently owns */
|
||||
if (fi->cd_values != NULL && fi->cd_values != fi->_cd_values)
|
||||
H5MM_xfree(fi->cd_values);
|
||||
H5MM_xfree(fi->config);
|
||||
|
||||
fi->flags = flags;
|
||||
fi->cd_nelmts = cd_nelmts;
|
||||
|
||||
if (cd_nelmts == 0)
|
||||
fi->cd_values = NULL;
|
||||
else if (staged_cd_values) {
|
||||
fi->cd_values = staged_cd_values; /* ownership transfers to the entry */
|
||||
staged_cd_values = NULL;
|
||||
}
|
||||
else {
|
||||
/* Fits the entry's internal buffer */
|
||||
fi->cd_values = fi->_cd_values;
|
||||
H5MM_memcpy(fi->cd_values, cd_values, cd_nelmts * sizeof(unsigned));
|
||||
}
|
||||
|
||||
/* NULL for the CDVALUES path, which clears the stored string */
|
||||
fi->config = staged_config; /* ownership transfers to the entry */
|
||||
staged_config = NULL;
|
||||
|
||||
/* Store the updated pipeline back in the property list */
|
||||
if (H5P_poke(plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
|
||||
HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set pipeline");
|
||||
|
||||
done:
|
||||
H5MM_xfree(staged_cd_values);
|
||||
H5MM_xfree(staged_config);
|
||||
H5MM_xfree(canon_config);
|
||||
H5MM_xfree(allocated_cd_values);
|
||||
FUNC_LEAVE_API(ret_value)
|
||||
} /* end H5Pmodify_filter_by_idx() */
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Function: H5Pget_filter_params_by_idx
|
||||
*
|
||||
|
||||
@@ -2852,6 +2852,58 @@ H5_DLL herr_t H5Pset_filter(hid_t plist_id, H5Z_filter_t filter, unsigned int fl
|
||||
*/
|
||||
H5_DLL herr_t H5Pappend_filter(hid_t plist_id, H5Z_filter_t filter, unsigned int flags,
|
||||
const H5Z_params_t *params);
|
||||
/**
|
||||
* \ingroup OCPL
|
||||
*
|
||||
* \brief Replaces the configuration of the filter at a given pipeline index
|
||||
*
|
||||
* \ocpl_id{plist_id}
|
||||
* \param[in] filter_idx Zero-based index of the filter in the pipeline
|
||||
* \param[in] flags Replacement flags for the entry, subject to the same
|
||||
* \c set_config adjustment rules as H5Pappend_filter()
|
||||
* \param[in] params New configuration, or NULL for a parameterless filter
|
||||
*
|
||||
* \return \herr_t
|
||||
*
|
||||
* \details H5Pmodify_filter_by_idx() replaces the configuration of the filter
|
||||
* already at position \p filter_idx in \p plist_id's pipeline, leaving
|
||||
* its position and filter ID unchanged. \p params is interpreted
|
||||
* exactly as H5Pappend_filter() interprets it:
|
||||
*
|
||||
* - #H5Z_PARAMS_STRING - the string is validated and resolved through
|
||||
* the filter's \c set_config callback, and both the resulting
|
||||
* \c cd_values and the stored configuration string are replaced, so
|
||||
* the entry keeps a stored string.
|
||||
* - #H5Z_PARAMS_CDVALUES - the \c cd_values array is replaced and any
|
||||
* stored string is cleared, matching H5Pmodify_filter().
|
||||
*
|
||||
* Use this in preference to H5Pmodify_filter() when the entry was
|
||||
* configured with a parameter string. H5Pmodify_filter() takes only
|
||||
* raw \c cd_values and therefore always clears the stored string,
|
||||
* silently downgrading the entry from an exact, plugin-free
|
||||
* configuration string to \c get_config reconstruction. The only
|
||||
* alternative was H5Premove_filter() followed by a fresh
|
||||
* H5Pappend_filter(), which moves the entry to the end of the pipeline
|
||||
* and so changes filter order.
|
||||
*
|
||||
* Entries are addressed by index rather than by filter ID because a
|
||||
* pipeline may legally contain the same filter ID more than once,
|
||||
* where an ID-addressed modify silently edits the first match. The
|
||||
* index is the same one H5Pget_filter2() and
|
||||
* H5Pget_filter_params_by_idx() use, so the index a caller reads a
|
||||
* configuration with is the index it writes one back with.
|
||||
*
|
||||
* It is an error if \p filter_idx is out of range, if \p params uses
|
||||
* #H5Z_PARAMS_STRING for a filter whose registered class does not
|
||||
* implement \c set_config, or if \c set_config rejects the string. On
|
||||
* any failure the entry is left exactly as it was.
|
||||
*
|
||||
* H5Pmodify_filter() is unchanged and remains supported.
|
||||
*
|
||||
* \since 3.0.0
|
||||
*/
|
||||
H5_DLL herr_t H5Pmodify_filter_by_idx(hid_t plist_id, unsigned filter_idx, unsigned flags,
|
||||
const H5Z_params_t *params);
|
||||
/**
|
||||
* \ingroup OCPL
|
||||
*
|
||||
|
||||
+234
@@ -2761,6 +2761,237 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* H5Pmodify_filter_by_idx (RFC-HDFG-2026-001 sec:modify-filter)
|
||||
*
|
||||
* Reuses the canon filter (CANON_FILTER_ID, one double "rate") so the
|
||||
* stored string and the recovered value can both be checked.
|
||||
* ---------------------------------------------------------------------- */
|
||||
static int
|
||||
test_modify_filter_by_idx(hid_t fapl)
|
||||
{
|
||||
hid_t dcpl = H5I_INVALID_HID, sid = H5I_INVALID_HID, file = H5I_INVALID_HID;
|
||||
hid_t dset = H5I_INVALID_HID, dcpl_out = H5I_INVALID_HID;
|
||||
hsize_t dims[2] = {8, 8};
|
||||
char filename[1024];
|
||||
char pbuf[H5Z_CONFIG_STRING_MAX + 1];
|
||||
size_t plen = 0;
|
||||
double got = 0.0;
|
||||
unsigned flags_out = 0;
|
||||
unsigned cd[8];
|
||||
size_t cd_nelmts = 8;
|
||||
char nm[64];
|
||||
unsigned cfg = 0;
|
||||
H5Z_params_t p;
|
||||
|
||||
if (H5Zregister(&canon_cls) < 0)
|
||||
TEST_ERROR;
|
||||
|
||||
/* --- mod-01: STRING replaces cd_values and keeps a stored string --- */
|
||||
TESTING("H5Pmodify_filter_by_idx: string form replaces config in place");
|
||||
if ((dcpl = canon_make_dcpl("rate = 1.5")) < 0)
|
||||
TEST_ERROR;
|
||||
p.type = H5Z_PARAMS_STRING;
|
||||
p.u.str = "rate = 2.5";
|
||||
if (H5Pmodify_filter_by_idx(dcpl, 0, H5Z_FLAG_MANDATORY, &p) < 0)
|
||||
TEST_ERROR;
|
||||
if (H5Pget_filter_params_by_idx(dcpl, 0, pbuf, sizeof(pbuf), &plen) < 0)
|
||||
TEST_ERROR;
|
||||
if (strcmp(pbuf, "rate = 2.5") != 0)
|
||||
TEST_ERROR;
|
||||
if (canon_stored_double(dcpl, &got) < 0)
|
||||
TEST_ERROR;
|
||||
if (memcmp(&got, &(double){2.5}, sizeof(got)) != 0)
|
||||
TEST_ERROR;
|
||||
/* Position and filter ID unchanged, and still exactly one entry */
|
||||
if (H5Pget_nfilters(dcpl) != 1)
|
||||
TEST_ERROR;
|
||||
cd_nelmts = 8;
|
||||
if (H5Pget_filter2(dcpl, 0, &flags_out, &cd_nelmts, cd, sizeof(nm), nm, &cfg) != CANON_FILTER_ID)
|
||||
TEST_ERROR;
|
||||
if (H5Pclose(dcpl) < 0)
|
||||
TEST_ERROR;
|
||||
dcpl = H5I_INVALID_HID;
|
||||
PASSED();
|
||||
|
||||
/* --- mod-02: canonicalization applies on the modify path too --- */
|
||||
TESTING("H5Pmodify_filter_by_idx: replacement string is canonicalized");
|
||||
if ((dcpl = canon_make_dcpl("rate = 1.5")) < 0)
|
||||
TEST_ERROR;
|
||||
p.type = H5Z_PARAMS_STRING;
|
||||
p.u.str = "{rate = 0x1.8p+1}";
|
||||
if (H5Pmodify_filter_by_idx(dcpl, 0, H5Z_FLAG_MANDATORY, &p) < 0)
|
||||
TEST_ERROR;
|
||||
if (H5Pget_filter_params_by_idx(dcpl, 0, pbuf, sizeof(pbuf), &plen) < 0)
|
||||
TEST_ERROR;
|
||||
if (strcmp(pbuf, "rate = 3.00000000000000000e+00") != 0)
|
||||
TEST_ERROR;
|
||||
if (H5Pclose(dcpl) < 0)
|
||||
TEST_ERROR;
|
||||
dcpl = H5I_INVALID_HID;
|
||||
PASSED();
|
||||
|
||||
/* --- mod-03: CDVALUES form clears the stored string --- */
|
||||
TESTING("H5Pmodify_filter_by_idx: cd_values form clears the stored string");
|
||||
if ((dcpl = canon_make_dcpl("rate = 1.5")) < 0)
|
||||
TEST_ERROR;
|
||||
{
|
||||
double v = 4.5;
|
||||
unsigned raw[2] = {0, 0};
|
||||
|
||||
memcpy(raw, &v, sizeof(v));
|
||||
p.type = H5Z_PARAMS_CDVALUES;
|
||||
p.u.raw.cd_nelmts = 2;
|
||||
p.u.raw.cd_values = raw;
|
||||
if (H5Pmodify_filter_by_idx(dcpl, 0, H5Z_FLAG_MANDATORY, &p) < 0)
|
||||
TEST_ERROR;
|
||||
}
|
||||
if (H5Pget_filter_params_by_idx(dcpl, 0, pbuf, sizeof(pbuf), &plen) < 0)
|
||||
TEST_ERROR;
|
||||
/* Stored string gone -> get_config reconstruction, which uses %.17e */
|
||||
if (strcmp(pbuf, "rate = 4.50000000000000000e+00") != 0) {
|
||||
fprintf(stderr, "\n got \"%s\"\n", pbuf);
|
||||
TEST_ERROR;
|
||||
}
|
||||
if (H5Pclose(dcpl) < 0)
|
||||
TEST_ERROR;
|
||||
dcpl = H5I_INVALID_HID;
|
||||
PASSED();
|
||||
|
||||
/* --- mod-04: index addressing distinguishes duplicate filter IDs --- */
|
||||
TESTING("H5Pmodify_filter_by_idx: duplicate filter IDs addressed by index");
|
||||
if ((dcpl = canon_make_dcpl("rate = 1.5")) < 0)
|
||||
TEST_ERROR;
|
||||
p.type = H5Z_PARAMS_STRING;
|
||||
p.u.str = "rate = 2.5";
|
||||
if (H5Pappend_filter(dcpl, CANON_FILTER_ID, H5Z_FLAG_MANDATORY, &p) < 0)
|
||||
TEST_ERROR;
|
||||
if (H5Pget_nfilters(dcpl) != 2)
|
||||
TEST_ERROR;
|
||||
/* Edit the second entry only */
|
||||
p.u.str = "rate = 9.5";
|
||||
if (H5Pmodify_filter_by_idx(dcpl, 1, H5Z_FLAG_MANDATORY, &p) < 0)
|
||||
TEST_ERROR;
|
||||
if (H5Pget_filter_params_by_idx(dcpl, 0, pbuf, sizeof(pbuf), &plen) < 0)
|
||||
TEST_ERROR;
|
||||
if (strcmp(pbuf, "rate = 1.5") != 0) /* entry 0 untouched */
|
||||
TEST_ERROR;
|
||||
if (H5Pget_filter_params_by_idx(dcpl, 1, pbuf, sizeof(pbuf), &plen) < 0)
|
||||
TEST_ERROR;
|
||||
if (strcmp(pbuf, "rate = 9.5") != 0)
|
||||
TEST_ERROR;
|
||||
if (H5Pclose(dcpl) < 0)
|
||||
TEST_ERROR;
|
||||
dcpl = H5I_INVALID_HID;
|
||||
PASSED();
|
||||
|
||||
/* --- mod-05: errors, and the entry survives a rejected edit --- */
|
||||
TESTING("H5Pmodify_filter_by_idx: errors leave the entry unchanged");
|
||||
if ((dcpl = canon_make_dcpl("rate = 1.5")) < 0)
|
||||
TEST_ERROR;
|
||||
|
||||
/* index out of range */
|
||||
p.type = H5Z_PARAMS_STRING;
|
||||
p.u.str = "rate = 2.5";
|
||||
H5E_BEGIN_TRY
|
||||
{
|
||||
if (H5Pmodify_filter_by_idx(dcpl, 1, H5Z_FLAG_MANDATORY, &p) >= 0)
|
||||
TEST_ERROR;
|
||||
}
|
||||
H5E_END_TRY
|
||||
|
||||
/* invalid flags */
|
||||
H5E_BEGIN_TRY
|
||||
{
|
||||
if (H5Pmodify_filter_by_idx(dcpl, 0, 0xFFFFFFFFu, &p) >= 0)
|
||||
TEST_ERROR;
|
||||
}
|
||||
H5E_END_TRY
|
||||
|
||||
/* set_config rejects the string (canon_set_config fails a type mismatch) */
|
||||
p.u.str = "rate = \"not a number\"";
|
||||
H5E_BEGIN_TRY
|
||||
{
|
||||
if (H5Pmodify_filter_by_idx(dcpl, 0, H5Z_FLAG_MANDATORY, &p) >= 0)
|
||||
TEST_ERROR;
|
||||
}
|
||||
H5E_END_TRY
|
||||
|
||||
/* After every rejected edit the original configuration is intact */
|
||||
if (H5Pget_filter_params_by_idx(dcpl, 0, pbuf, sizeof(pbuf), &plen) < 0)
|
||||
TEST_ERROR;
|
||||
if (strcmp(pbuf, "rate = 1.5") != 0) {
|
||||
fprintf(stderr, "\n entry was disturbed: \"%s\"\n", pbuf);
|
||||
TEST_ERROR;
|
||||
}
|
||||
if (canon_stored_double(dcpl, &got) < 0)
|
||||
TEST_ERROR;
|
||||
if (memcmp(&got, &(double){1.5}, sizeof(got)) != 0)
|
||||
TEST_ERROR;
|
||||
if (H5Pclose(dcpl) < 0)
|
||||
TEST_ERROR;
|
||||
dcpl = H5I_INVALID_HID;
|
||||
PASSED();
|
||||
|
||||
/* --- mod-06 (fmt-07): the replacement string is what reaches disk --- */
|
||||
TESTING("H5Pmodify_filter_by_idx: replacement string persists, not the original");
|
||||
h5_fixname(FILENAME[1], fapl, filename, sizeof(filename));
|
||||
if ((dcpl = canon_make_dcpl("rate = 1.5")) < 0)
|
||||
TEST_ERROR;
|
||||
p.type = H5Z_PARAMS_STRING;
|
||||
p.u.str = "rate = 7.25";
|
||||
if (H5Pmodify_filter_by_idx(dcpl, 0, H5Z_FLAG_MANDATORY, &p) < 0)
|
||||
TEST_ERROR;
|
||||
if ((sid = H5Screate_simple(2, dims, NULL)) < 0)
|
||||
TEST_ERROR;
|
||||
if ((file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0)
|
||||
TEST_ERROR;
|
||||
if ((dset = H5Dcreate2(file, "dset", H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
|
||||
TEST_ERROR;
|
||||
if (H5Dclose(dset) < 0 || H5Pclose(dcpl) < 0 || H5Fclose(file) < 0)
|
||||
TEST_ERROR;
|
||||
dset = dcpl = file = H5I_INVALID_HID;
|
||||
|
||||
/* Drop the plugin so only the persisted string can answer */
|
||||
if (H5Zunregister(CANON_FILTER_ID) < 0)
|
||||
TEST_ERROR;
|
||||
if ((file = H5Fopen(filename, H5F_ACC_RDONLY, fapl)) < 0)
|
||||
TEST_ERROR;
|
||||
if ((dset = H5Dopen2(file, "dset", H5P_DEFAULT)) < 0)
|
||||
TEST_ERROR;
|
||||
if ((dcpl_out = H5Dget_create_plist(dset)) < 0)
|
||||
TEST_ERROR;
|
||||
if (H5Pget_filter_params_by_idx(dcpl_out, 0, pbuf, sizeof(pbuf), &plen) < 0)
|
||||
TEST_ERROR;
|
||||
if (strcmp(pbuf, "rate = 7.25") != 0) {
|
||||
fprintf(stderr, "\n expected \"rate = 7.25\" on disk, got \"%s\"\n", pbuf);
|
||||
TEST_ERROR;
|
||||
}
|
||||
if (H5Pclose(dcpl_out) < 0 || H5Dclose(dset) < 0 || H5Fclose(file) < 0 || H5Sclose(sid) < 0)
|
||||
TEST_ERROR;
|
||||
dcpl_out = dset = file = sid = H5I_INVALID_HID;
|
||||
if (H5Zregister(&canon_cls) < 0)
|
||||
TEST_ERROR;
|
||||
PASSED();
|
||||
|
||||
if (H5Zunregister(CANON_FILTER_ID) < 0)
|
||||
TEST_ERROR;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
H5E_BEGIN_TRY
|
||||
{
|
||||
H5Pclose(dcpl);
|
||||
H5Pclose(dcpl_out);
|
||||
H5Dclose(dset);
|
||||
H5Fclose(file);
|
||||
H5Sclose(sid);
|
||||
H5Zunregister(CANON_FILTER_ID);
|
||||
}
|
||||
H5E_END_TRY
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
* main
|
||||
* ---------------------------------------------------------------------- */
|
||||
@@ -2831,6 +3062,9 @@ main(void)
|
||||
/* Canonicalization of the persisted configuration string */
|
||||
nerrors += test_config_canonicalization(fapl) < 0 ? 1 : 0;
|
||||
|
||||
/* H5Pmodify_filter_by_idx */
|
||||
nerrors += test_modify_filter_by_idx(fapl) < 0 ? 1 : 0;
|
||||
|
||||
if (H5Fclose(file) < 0)
|
||||
goto error;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user