Coverage Report

Created: 2024-06-18 06:29

/src/hdf5/src/H5Z.c
Line
Count
Source (jump to first uncovered line)
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the COPYING file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
#include "H5Zmodule.h" /* This source code file is part of the H5Z module */
14
15
#include "H5private.h"   /* Generic Functions   */
16
#include "H5Dprivate.h"  /* Dataset functions   */
17
#include "H5Eprivate.h"  /* Error handling      */
18
#include "H5Fprivate.h"  /* File                */
19
#include "H5Iprivate.h"  /* IDs                 */
20
#include "H5MMprivate.h" /* Memory management   */
21
#include "H5Oprivate.h"  /* Object headers      */
22
#include "H5Pprivate.h"  /* Property lists      */
23
#include "H5PLprivate.h" /* Plugins             */
24
#include "H5Sprivate.h"  /* Dataspace functions */
25
#include "H5Zpkg.h"      /* Data filters        */
26
27
#ifdef H5_HAVE_SZLIB_H
28
#include "szlib.h"
29
#endif
30
31
/* This module can collect and optionally dump some simple filter statistics
32
 * to stdout. If you want to do this, you need to define H5Z_DEBUG and set
33
 * the DUMP_DEBUG_STATS_g flag to true.
34
 */
35
36
/* Local typedefs */
37
#ifdef H5Z_DEBUG
38
typedef struct H5Z_stats_t {
39
    struct {
40
        hsize_t       total;  /* total number of bytes processed */
41
        hsize_t       errors; /* bytes of total attributable to errors */
42
        H5_timevals_t times;  /* execution time including errors */
43
    } stats[2];               /* 0 = output, 1 = input */
44
} H5Z_stats_t;
45
#endif /* H5Z_DEBUG */
46
47
typedef struct H5Z_object_t {
48
    H5Z_filter_t filter_id; /* ID of the filter we're looking for */
49
    htri_t       found;     /* Whether we find an object using the filter */
50
#ifdef H5_HAVE_PARALLEL
51
    bool sanity_checked; /* Whether the sanity check for collectively calling H5Zunregister has been done */
52
#endif                   /* H5_HAVE_PARALLEL */
53
} H5Z_object_t;
54
55
/* Enumerated type for dataset creation prelude callbacks */
56
typedef enum {
57
    H5Z_PRELUDE_CAN_APPLY, /* Call "can apply" callback */
58
    H5Z_PRELUDE_SET_LOCAL  /* Call "set local" callback */
59
} H5Z_prelude_type_t;
60
61
/* Local variables */
62
static size_t        H5Z_table_alloc_g = 0;
63
static size_t        H5Z_table_used_g  = 0;
64
static H5Z_class2_t *H5Z_table_g       = NULL;
65
#ifdef H5Z_DEBUG
66
static H5Z_stats_t *H5Z_stat_table_g = NULL;
67
/* Set to true if you want to dump compression statistics to stdout */
68
static const bool DUMP_DEBUG_STATS_g = false;
69
#endif /* H5Z_DEBUG */
70
71
/* Local functions */
72
static int H5Z__find_idx(H5Z_filter_t id);
73
static int H5Z__check_unregister_dset_cb(void *obj_ptr, hid_t obj_id, void *key);
74
static int H5Z__check_unregister_group_cb(void *obj_ptr, hid_t obj_id, void *key);
75
static int H5Z__flush_file_cb(void *obj_ptr, hid_t obj_id, void *key);
76
77
/*-------------------------------------------------------------------------
78
 * Function:    H5Z_init
79
 *
80
 * Purpose:     Initialize the interface from some other layer.
81
 *
82
 * Return:      Success:        non-negative
83
 *              Failure:        negative
84
 *-------------------------------------------------------------------------
85
 */
86
herr_t
87
H5Z_init(void)
88
1
{
89
1
    herr_t ret_value = SUCCEED; /* Return value */
90
91
1
    FUNC_ENTER_NOAPI(FAIL)
92
93
1
    if (H5_TERM_GLOBAL)
94
0
        HGOTO_DONE(SUCCEED);
95
96
    /* Internal filters */
97
1
    if (H5Z_register(H5Z_SHUFFLE) < 0)
98
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register shuffle filter");
99
1
    if (H5Z_register(H5Z_FLETCHER32) < 0)
100
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register fletcher32 filter");
101
1
    if (H5Z_register(H5Z_NBIT) < 0)
102
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register nbit filter");
103
1
    if (H5Z_register(H5Z_SCALEOFFSET) < 0)
104
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register scaleoffset filter");
105
106
        /* External filters */
107
1
#ifdef H5_HAVE_FILTER_DEFLATE
108
1
    if (H5Z_register(H5Z_DEFLATE) < 0)
109
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register deflate filter");
110
1
#endif /* H5_HAVE_FILTER_DEFLATE */
111
#ifdef H5_HAVE_FILTER_SZIP
112
    {
113
        int encoder_enabled = SZ_encoder_enabled();
114
        if (encoder_enabled < 0)
115
            HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "check for szip encoder failed");
116
117
        H5Z_SZIP->encoder_present = (unsigned)encoder_enabled;
118
        if (H5Z_register(H5Z_SZIP) < 0)
119
            HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register szip filter");
120
    }
121
#endif /* H5_HAVE_FILTER_SZIP */
122
123
1
done:
124
1
    FUNC_LEAVE_NOAPI(ret_value)
125
1
}
126
127
/*-------------------------------------------------------------------------
128
 * Function: H5Z_term_package
129
 *
130
 * Purpose:  Terminate the H5Z layer.
131
 *
132
 * Return:   void
133
 *-------------------------------------------------------------------------
134
 */
135
int
136
H5Z_term_package(void)
137
2
{
138
2
    int n = 0;
139
140
2
    FUNC_ENTER_NOAPI_NOINIT_NOERR
141
142
#ifdef H5Z_DEBUG
143
    char   comment[16], bandwidth[32];
144
    int    dir, nprint = 0;
145
    size_t i;
146
147
    if (DUMP_DEBUG_STATS_g) {
148
        for (i = 0; i < H5Z_table_used_g; i++) {
149
            for (dir = 0; dir < 2; dir++) {
150
                struct {
151
                    char *user;
152
                    char *system;
153
                    char *elapsed;
154
                } timestrs = {H5_timer_get_time_string(H5Z_stat_table_g[i].stats[dir].times.user),
155
                              H5_timer_get_time_string(H5Z_stat_table_g[i].stats[dir].times.system),
156
                              H5_timer_get_time_string(H5Z_stat_table_g[i].stats[dir].times.elapsed)};
157
                if (0 == H5Z_stat_table_g[i].stats[dir].total)
158
                    goto next;
159
160
                if (0 == nprint++) {
161
                    /* Print column headers */
162
                    fprintf(stdout, "H5Z: filter statistics "
163
                                    "accumulated over life of library:\n");
164
                    fprintf(stdout, "   %-16s %10s %10s %8s %8s %8s %10s\n", "Filter", "Total", "Errors",
165
                            "User", "System", "Elapsed", "Bandwidth");
166
                    fprintf(stdout, "   %-16s %10s %10s %8s %8s %8s %10s\n", "------", "-----", "------",
167
                            "----", "------", "-------", "---------");
168
                } /* end if */
169
170
                /* Truncate the comment to fit in the field */
171
                strncpy(comment, H5Z_table_g[i].name, sizeof comment);
172
                comment[sizeof(comment) - 1] = '\0';
173
174
                /*
175
                 * Format bandwidth to have four significant digits and
176
                 * units of `B/s', `kB/s', `MB/s', `GB/s', or `TB/s' or
177
                 * the word `Inf' if the elapsed time is zero.
178
                 */
179
                H5_bandwidth(bandwidth, sizeof(bandwidth), (double)(H5Z_stat_table_g[i].stats[dir].total),
180
                             H5Z_stat_table_g[i].stats[dir].times.elapsed);
181
182
                /* Print the statistics */
183
                fprintf(stdout, "   %s%-15s %10" PRIdHSIZE " %10" PRIdHSIZE " %8s %8s %8s %10s\n",
184
                        (dir ? "<" : ">"), comment, H5Z_stat_table_g[i].stats[dir].total,
185
                        H5Z_stat_table_g[i].stats[dir].errors, timestrs.user, timestrs.system,
186
                        timestrs.elapsed, bandwidth);
187
next:
188
                free(timestrs.user);
189
                free(timestrs.system);
190
                free(timestrs.elapsed);
191
            } /* end for */
192
        }     /* end for */
193
    }         /* end if */
194
#endif        /* H5Z_DEBUG */
195
196
    /* Free the table of filters */
197
2
    if (H5Z_table_g) {
198
1
        H5Z_table_g = (H5Z_class2_t *)H5MM_xfree(H5Z_table_g);
199
200
#ifdef H5Z_DEBUG
201
        H5Z_stat_table_g = (H5Z_stats_t *)H5MM_xfree(H5Z_stat_table_g);
202
#endif /* H5Z_DEBUG */
203
1
        H5Z_table_used_g = H5Z_table_alloc_g = 0;
204
205
1
        n++;
206
1
    } /* end if */
207
208
2
    FUNC_LEAVE_NOAPI(n)
209
2
} /* end H5Z_term_package() */
210
211
/*-------------------------------------------------------------------------
212
 * Function: H5Zregister
213
 *
214
 * Purpose:  This function registers a new filter
215
 *
216
 * Return:   Non-negative on success/Negative on failure
217
 *-------------------------------------------------------------------------
218
 */
219
herr_t
220
H5Zregister(const void *cls)
221
0
{
222
0
    const H5Z_class2_t *cls_real  = (const H5Z_class2_t *)cls; /* "Real" class pointer */
223
0
    herr_t              ret_value = SUCCEED;                   /* Return value */
224
#ifndef H5_NO_DEPRECATED_SYMBOLS
225
    H5Z_class2_t cls_new; /* Translated class struct */
226
#endif
227
228
0
    FUNC_ENTER_API(FAIL)
229
230
    /* Check args */
231
0
    if (cls_real == NULL)
232
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter class");
233
234
    /* Check H5Z_class_t version number; this is where a function to convert
235
     * from an outdated version should be called.
236
     *
237
     * If the version number is invalid, we assume that the target of cls is the
238
     * old style "H5Z_class1_t" structure, which did not contain a version
239
     * field.  In this structure, the first field is the id.  Since both version
240
     * and id are integers they will have the same value, and since id must be
241
     * at least 256, there should be no overlap and the version of the struct
242
     * can be determined by the value of the first field.
243
     */
244
0
    if (cls_real->version != H5Z_CLASS_T_VERS) {
245
#ifndef H5_NO_DEPRECATED_SYMBOLS
246
        /* Assume it is an old "H5Z_class1_t" instead */
247
        const H5Z_class1_t *cls_old = (const H5Z_class1_t *)cls;
248
249
        /* Translate to new H5Z_class2_t */
250
        cls_new.version         = H5Z_CLASS_T_VERS;
251
        cls_new.id              = cls_old->id;
252
        cls_new.encoder_present = 1;
253
        cls_new.decoder_present = 1;
254
        cls_new.name            = cls_old->name;
255
        cls_new.can_apply       = cls_old->can_apply;
256
        cls_new.set_local       = cls_old->set_local;
257
        cls_new.filter          = cls_old->filter;
258
259
        /* Set cls_real to point to the translated structure */
260
        cls_real = &cls_new;
261
262
#else  /* H5_NO_DEPRECATED_SYMBOLS */
263
        /* Deprecated symbols not allowed, throw an error */
264
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid H5Z_class_t version number");
265
0
#endif /* H5_NO_DEPRECATED_SYMBOLS */
266
0
    }  /* end if */
267
268
0
    if (cls_real->id < 0 || cls_real->id > H5Z_FILTER_MAX)
269
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identification number");
270
0
    if (cls_real->id < H5Z_FILTER_RESERVED)
271
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to modify predefined filters");
272
0
    if (cls_real->filter == NULL)
273
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no filter function specified");
274
275
    /* Do it */
276
0
    if (H5Z_register(cls_real) < 0)
277
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register filter");
278
279
0
done:
280
0
    FUNC_LEAVE_API(ret_value)
281
0
}
282
283
/*-------------------------------------------------------------------------
284
 * Function: H5Z_register
285
 *
286
 * Purpose:  Same as the public version except this one allows filters
287
 *           to be set for predefined method numbers < H5Z_FILTER_RESERVED
288
 *
289
 * Return:   Non-negative on success
290
 *           Negative on failure
291
 *-------------------------------------------------------------------------
292
 */
293
herr_t
294
H5Z_register(const H5Z_class2_t *cls)
295
5
{
296
5
    size_t i;
297
5
    herr_t ret_value = SUCCEED; /* Return value */
298
299
5
    FUNC_ENTER_NOAPI(FAIL)
300
301
5
    assert(cls);
302
5
    assert(cls->id >= 0 && cls->id <= H5Z_FILTER_MAX);
303
304
    /* Is the filter already registered? */
305
15
    for (i = 0; i < H5Z_table_used_g; i++)
306
10
        if (H5Z_table_g[i].id == cls->id)
307
0
            break;
308
309
    /* Filter not already registered */
310
5
    if (i >= H5Z_table_used_g) {
311
5
        if (H5Z_table_used_g >= H5Z_table_alloc_g) {
312
1
            size_t        n     = MAX(H5Z_MAX_NFILTERS, 2 * H5Z_table_alloc_g);
313
1
            H5Z_class2_t *table = (H5Z_class2_t *)H5MM_realloc(H5Z_table_g, n * sizeof(H5Z_class2_t));
314
#ifdef H5Z_DEBUG
315
            H5Z_stats_t *stat_table = (H5Z_stats_t *)H5MM_realloc(H5Z_stat_table_g, n * sizeof(H5Z_stats_t));
316
#endif /* H5Z_DEBUG */
317
1
            if (!table)
318
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to extend filter table");
319
1
            H5Z_table_g = table;
320
#ifdef H5Z_DEBUG
321
            if (!stat_table)
322
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to extend filter statistics table");
323
            H5Z_stat_table_g = stat_table;
324
#endif /* H5Z_DEBUG */
325
1
            H5Z_table_alloc_g = n;
326
1
        } /* end if */
327
328
        /* Initialize */
329
5
        i = H5Z_table_used_g++;
330
5
        H5MM_memcpy(H5Z_table_g + i, cls, sizeof(H5Z_class2_t));
331
#ifdef H5Z_DEBUG
332
        memset(H5Z_stat_table_g + i, 0, sizeof(H5Z_stats_t));
333
#endif /* H5Z_DEBUG */
334
5
    }  /* end if */
335
    /* Filter already registered */
336
0
    else {
337
        /* Replace old contents */
338
0
        H5MM_memcpy(H5Z_table_g + i, cls, sizeof(H5Z_class2_t));
339
0
    } /* end else */
340
341
5
done:
342
5
    FUNC_LEAVE_NOAPI(ret_value)
343
5
}
344
345
/*-------------------------------------------------------------------------
346
 * Function:    H5Zunregister
347
 *
348
 * Purpose:     This function unregisters a filter.
349
 *
350
 * Return:      Non-negative on success
351
 *              Negative on failure
352
 *-------------------------------------------------------------------------
353
 */
354
herr_t
355
H5Zunregister(H5Z_filter_t id)
356
0
{
357
0
    herr_t ret_value = SUCCEED; /* Return value */
358
359
0
    FUNC_ENTER_API(FAIL)
360
361
    /* Check args */
362
0
    if (id < 0 || id > H5Z_FILTER_MAX)
363
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identification number");
364
0
    if (id < H5Z_FILTER_RESERVED)
365
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to modify predefined filters");
366
367
    /* Do it */
368
0
    if (H5Z__unregister(id) < 0)
369
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to unregister filter");
370
371
0
done:
372
0
    FUNC_LEAVE_API(ret_value)
373
0
} /* end H5Zunregister() */
374
375
/*-------------------------------------------------------------------------
376
 * Function:    H5Z__unregister
377
 *
378
 * Purpose:     Same as the public version except this one allows filters
379
 *               to be unset for predefined method numbers <H5Z_FILTER_RESERVED
380
 *
381
 * Return:      SUCCEED/FAIL
382
 *
383
 *-------------------------------------------------------------------------
384
 */
385
herr_t
386
H5Z__unregister(H5Z_filter_t filter_id)
387
0
{
388
0
    size_t       filter_index;        /* Local index variable for filter */
389
0
    H5Z_object_t object;              /* Object to pass to callbacks */
390
0
    herr_t       ret_value = SUCCEED; /* Return value */
391
392
0
    FUNC_ENTER_PACKAGE
393
394
0
    assert(filter_id >= 0 && filter_id <= H5Z_FILTER_MAX);
395
396
    /* Is the filter already registered? */
397
0
    for (filter_index = 0; filter_index < H5Z_table_used_g; filter_index++)
398
0
        if (H5Z_table_g[filter_index].id == filter_id)
399
0
            break;
400
401
    /* Fail if filter not found */
402
0
    if (filter_index >= H5Z_table_used_g)
403
0
        HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "filter is not registered");
404
405
    /* Initialize the structure object for iteration */
406
0
    object.filter_id = filter_id;
407
0
    object.found     = false;
408
#ifdef H5_HAVE_PARALLEL
409
    object.sanity_checked = false;
410
#endif /* H5_HAVE_PARALLEL */
411
412
    /* Iterate through all opened datasets, returns a failure if any of them uses the filter */
413
0
    if (H5I_iterate(H5I_DATASET, H5Z__check_unregister_dset_cb, &object, false) < 0)
414
0
        HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed");
415
416
0
    if (object.found)
417
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTRELEASE, FAIL,
418
0
                    "can't unregister filter because a dataset is still using it");
419
420
    /* Iterate through all opened groups, returns a failure if any of them uses the filter */
421
0
    if (H5I_iterate(H5I_GROUP, H5Z__check_unregister_group_cb, &object, false) < 0)
422
0
        HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed");
423
424
0
    if (object.found)
425
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTRELEASE, FAIL,
426
0
                    "can't unregister filter because a group is still using it");
427
428
    /* Iterate through all opened files and flush them */
429
0
    if (H5I_iterate(H5I_FILE, H5Z__flush_file_cb, &object, false) < 0)
430
0
        HGOTO_ERROR(H5E_FILE, H5E_BADITER, FAIL, "iteration failed");
431
432
    /* Remove filter from table */
433
    /* Don't worry about shrinking table size (for now) */
434
0
    memmove(&H5Z_table_g[filter_index], &H5Z_table_g[filter_index + 1],
435
0
            sizeof(H5Z_class2_t) * ((H5Z_table_used_g - 1) - filter_index));
436
#ifdef H5Z_DEBUG
437
    memmove(&H5Z_stat_table_g[filter_index], &H5Z_stat_table_g[filter_index + 1],
438
            sizeof(H5Z_stats_t) * ((H5Z_table_used_g - 1) - filter_index));
439
#endif /* H5Z_DEBUG */
440
0
    H5Z_table_used_g--;
441
442
0
done:
443
0
    FUNC_LEAVE_NOAPI(ret_value)
444
0
} /* end H5Z__unregister() */
445
446
/*-------------------------------------------------------------------------
447
 * Function:    H5Z__check_unregister
448
 *
449
 * Purpose:     Check if an object uses the filter to be unregistered.
450
 *
451
 * Return:      true if the object uses the filter
452
 *              false if not
453
 *              NEGATIVE on error
454
 *
455
 *-------------------------------------------------------------------------
456
 */
457
static htri_t
458
H5Z__check_unregister(hid_t ocpl_id, H5Z_filter_t filter_id)
459
0
{
460
0
    H5P_genplist_t *plist;             /* Property list */
461
0
    htri_t          ret_value = false; /* Return value */
462
463
0
    FUNC_ENTER_PACKAGE
464
465
    /* Get the plist structure of object creation */
466
0
    if (NULL == (plist = H5P_object_verify(ocpl_id, H5P_OBJECT_CREATE)))
467
0
        HGOTO_ERROR(H5E_PLINE, H5E_BADID, FAIL, "can't find object for ID");
468
469
    /* Check if the object creation property list uses the filter */
470
0
    if ((ret_value = H5P_filter_in_pline(plist, filter_id)) < 0)
471
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't check filter in pipeline");
472
473
0
done:
474
0
    FUNC_LEAVE_NOAPI(ret_value)
475
0
} /* end H5Z__check_unregister() */
476
477
/*-------------------------------------------------------------------------
478
 * Function:    H5Z__check_unregister_group_cb
479
 *
480
 * Purpose:     The callback function for H5Z__unregister. It iterates
481
 *              through all opened objects.  If the object is a dataset
482
 *              or a group and it uses the filter to be unregistered, the
483
 *              function returns true.
484
 *
485
 * Return:      true if the object uses the filter
486
 *              false if not
487
 *              NEGATIVE on error
488
 *
489
 *-------------------------------------------------------------------------
490
 */
491
static int
492
H5Z__check_unregister_group_cb(void H5_ATTR_UNUSED *obj_ptr, hid_t obj_id, void *key)
493
0
{
494
0
    hid_t                 ocpl_id = -1;
495
0
    H5Z_object_t         *object  = (H5Z_object_t *)key;
496
0
    H5VL_object_t        *vol_obj;     /* Object for loc_id */
497
0
    H5VL_group_get_args_t vol_cb_args; /* Arguments to VOL callback */
498
0
    htri_t                filter_in_pline = false;
499
0
    int                   ret_value       = false; /* Return value */
500
501
0
    FUNC_ENTER_PACKAGE
502
503
    /* Get the group creation property */
504
0
    if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(obj_id, H5I_GROUP)))
505
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid group identifier");
506
507
    /* Set up VOL callback arguments */
508
0
    vol_cb_args.op_type               = H5VL_GROUP_GET_GCPL;
509
0
    vol_cb_args.args.get_gcpl.gcpl_id = H5I_INVALID_HID;
510
511
    /* Get the group creation property list */
512
0
    if (H5VL_group_get(vol_obj, &vol_cb_args, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0)
513
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, H5I_INVALID_HID, "unable to get group creation properties");
514
515
0
    if ((ocpl_id = vol_cb_args.args.get_gcpl.gcpl_id) < 0)
516
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get group creation property list");
517
518
    /* Check if the filter is in the group creation property list */
519
0
    if ((filter_in_pline = H5Z__check_unregister(ocpl_id, object->filter_id)) < 0)
520
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't check filter in pipeline");
521
522
    /* H5I_iterate expects true to stop the loop over objects. Stop the loop and
523
     * let H5Z__unregister return failure.
524
     */
525
0
    if (filter_in_pline) {
526
0
        object->found = true;
527
0
        ret_value     = true;
528
0
    }
529
530
0
done:
531
0
    if (ocpl_id > 0)
532
0
        if (H5I_dec_app_ref(ocpl_id) < 0)
533
0
            HDONE_ERROR(H5E_PLINE, H5E_CANTDEC, FAIL, "can't release plist");
534
535
0
    FUNC_LEAVE_NOAPI(ret_value)
536
0
} /* end H5Z__check_unregister_group_cb() */
537
538
/*-------------------------------------------------------------------------
539
 * Function:    H5Z__check_unregister_dset_cb
540
 *
541
 * Purpose:     The callback function for H5Z__unregister. It iterates
542
 *              through all opened objects.  If the object is a dataset
543
 *              or a group and it uses the filter to be unregistered, the
544
 *              function returns true.
545
 *
546
 * Return:      true if the object uses the filter
547
 *              false if not
548
 *              NEGATIVE on error
549
 *
550
 *-------------------------------------------------------------------------
551
 */
552
static int
553
H5Z__check_unregister_dset_cb(void H5_ATTR_UNUSED *obj_ptr, hid_t obj_id, void *key)
554
0
{
555
0
    hid_t                   ocpl_id = -1;
556
0
    H5Z_object_t           *object  = (H5Z_object_t *)key;
557
0
    H5VL_object_t          *vol_obj;     /* Object for loc_id */
558
0
    H5VL_dataset_get_args_t vol_cb_args; /* Arguments to VOL callback */
559
0
    htri_t                  filter_in_pline = false;
560
0
    int                     ret_value       = false; /* Return value */
561
562
0
    FUNC_ENTER_PACKAGE
563
564
    /* Get the dataset creation property */
565
0
    if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(obj_id, H5I_DATASET)))
566
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid dataset identifier");
567
568
    /* Set up VOL callback arguments */
569
0
    vol_cb_args.op_type               = H5VL_DATASET_GET_DCPL;
570
0
    vol_cb_args.args.get_dcpl.dcpl_id = H5I_INVALID_HID;
571
572
    /* Get the dataset creation property list */
573
0
    if (H5VL_dataset_get(vol_obj, &vol_cb_args, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0)
574
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, H5I_INVALID_HID, "unable to get dataset creation properties");
575
576
0
    if ((ocpl_id = vol_cb_args.args.get_dcpl.dcpl_id) < 0)
577
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get dataset creation property list");
578
579
    /* Check if the filter is in the dataset creation property list */
580
0
    if ((filter_in_pline = H5Z__check_unregister(ocpl_id, object->filter_id)) < 0)
581
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't check filter in pipeline");
582
583
    /* H5I_iterate expects true to stop the loop over objects. Stop the loop and
584
     * let H5Z__unregister return failure.
585
     */
586
0
    if (filter_in_pline) {
587
0
        object->found = true;
588
0
        ret_value     = true;
589
0
    }
590
591
0
done:
592
0
    if (ocpl_id > 0)
593
0
        if (H5I_dec_app_ref(ocpl_id) < 0)
594
0
            HDONE_ERROR(H5E_PLINE, H5E_CANTDEC, FAIL, "can't release plist");
595
596
0
    FUNC_LEAVE_NOAPI(ret_value)
597
0
} /* end H5Z__check_unregister_dset_cb() */
598
599
/*-------------------------------------------------------------------------
600
 * Function:    H5Z__flush_file_cb
601
 *
602
 * Purpose:     The callback function for H5Z__unregister. It iterates
603
 *              through all opened files and flush them.
604
 *
605
 * Return:      NON-NEGATIVE if finishes flushing and moves on
606
 *              NEGATIVE if there is an error
607
 *-------------------------------------------------------------------------
608
 */
609
static int
610
H5Z__flush_file_cb(void H5_ATTR_UNUSED *obj_ptr, hid_t obj_id, void H5_ATTR_PARALLEL_USED *key)
611
0
{
612
613
#ifdef H5_HAVE_PARALLEL
614
    H5Z_object_t *object = (H5Z_object_t *)key;
615
#endif                                              /* H5_HAVE_PARALLEL */
616
0
    int                       ret_value = false;    /* Return value */
617
0
    H5VL_file_specific_args_t vol_cb_args_specific; /* Arguments to VOL callback */
618
0
    H5VL_object_t            *vol_obj;              /* File for file_id */
619
0
    H5VL_file_get_args_t      vol_cb_args;          /* Arguments to VOL callback */
620
0
    bool                      is_native_vol_obj = true;
621
0
    unsigned int              intent            = 0;
622
623
0
    FUNC_ENTER_PACKAGE
624
625
    /* Sanity checks */
626
0
    assert(key);
627
628
    /* Get the internal file structure */
629
0
    if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(obj_id)))
630
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier");
631
632
    /* Get intent */
633
0
    vol_cb_args.op_type               = H5VL_FILE_GET_INTENT;
634
0
    vol_cb_args.args.get_intent.flags = &intent;
635
636
    /* Get the flags */
637
0
    if (H5VL_file_get(vol_obj, &vol_cb_args, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0)
638
0
        HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file's intent flags");
639
640
0
    if (H5VL_object_is_native(vol_obj, &is_native_vol_obj) < 0)
641
0
        HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5I_INVALID_HID,
642
0
                    "can't determine if VOL object is native connector object");
643
644
    /* Do a global flush if the file is opened for write */
645
0
    if (H5F_ACC_RDWR & intent) {
646
647
#ifdef H5_HAVE_PARALLEL
648
        /* Checking MPI flag requires native VOL */
649
        if (is_native_vol_obj) {
650
            H5F_t *f = (H5F_t *)obj_ptr; /* File object for native VOL operation */
651
652
            /* Check if MPIO driver is used */
653
            if (H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) {
654
655
                /* Sanity check for collectively calling H5Zunregister, if requested */
656
                /* (Sanity check assumes that a barrier on one file's comm
657
                 *  is sufficient (i.e. that there aren't different comms for
658
                 *  different files).  -QAK, 2018/02/14)
659
                 */
660
                if (H5_coll_api_sanity_check_g && !object->sanity_checked) {
661
                    MPI_Comm mpi_comm; /* File's communicator */
662
663
                    /* Retrieve the file communicator */
664
                    if (H5F_mpi_retrieve_comm(obj_id, H5P_DEFAULT, &mpi_comm) < 0)
665
                        HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get MPI communicator");
666
667
                    /* Issue the barrier */
668
                    if (mpi_comm != MPI_COMM_NULL)
669
                        MPI_Barrier(mpi_comm);
670
671
                    /* Set the "sanity checked" flag */
672
                    object->sanity_checked = true;
673
                } /* end if */
674
            }     /* end if */
675
        }
676
#endif /* H5_HAVE_PARALLEL */
677
678
        /* Call the flush routine for mounted file hierarchies */
679
0
        vol_cb_args_specific.op_type             = H5VL_FILE_FLUSH;
680
0
        vol_cb_args_specific.args.flush.obj_type = H5I_FILE;
681
0
        vol_cb_args_specific.args.flush.scope    = H5F_SCOPE_GLOBAL;
682
683
        /* Flush the object */
684
0
        if (H5VL_file_specific(vol_obj, &vol_cb_args_specific, H5P_DATASET_XFER_DEFAULT, NULL) < 0)
685
0
            HGOTO_ERROR(H5E_FILE, H5E_CANTFLUSH, FAIL, "unable to flush file hierarchy");
686
687
0
    } /* end if */
688
689
0
done:
690
0
    FUNC_LEAVE_NOAPI(ret_value)
691
0
} /* end H5Z__flush_file_cb() */
692
693
/*-------------------------------------------------------------------------
694
 * Function: H5Zfilter_avail
695
 *
696
 * Purpose:  Check if a filter is available
697
 *
698
 * Return:   Non-negative (true/false) on success/Negative on failure
699
 *-------------------------------------------------------------------------
700
 */
701
htri_t
702
H5Zfilter_avail(H5Z_filter_t id)
703
0
{
704
0
    htri_t ret_value = false; /* Return value */
705
706
0
    FUNC_ENTER_API(FAIL)
707
708
    /* Check args */
709
0
    if (id < 0 || id > H5Z_FILTER_MAX)
710
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identification number");
711
712
0
    if ((ret_value = H5Z_filter_avail(id)) < 0)
713
0
        HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "unable to check the availability of the filter");
714
715
0
done:
716
0
    FUNC_LEAVE_API(ret_value)
717
0
} /* end H5Zfilter_avail() */
718
719
/*-------------------------------------------------------------------------
720
 * Function: H5Z_filter_avail
721
 *
722
 * Purpose:  Private function to check if a filter is available
723
 *
724
 * Return:   Non-negative (true/false) on success/Negative on failure
725
 *-------------------------------------------------------------------------
726
 */
727
htri_t
728
H5Z_filter_avail(H5Z_filter_t id)
729
0
{
730
0
    H5PL_key_t          key;               /* Key for finding a plugin     */
731
0
    const H5Z_class2_t *filter_info;       /* Filter information           */
732
0
    size_t              i;                 /* Local index variable         */
733
0
    htri_t              ret_value = false; /* Return value                 */
734
735
0
    FUNC_ENTER_NOAPI(FAIL)
736
737
    /* Is the filter already registered? */
738
0
    for (i = 0; i < H5Z_table_used_g; i++)
739
0
        if (H5Z_table_g[i].id == id)
740
0
            HGOTO_DONE(true);
741
742
0
    key.id = (int)id;
743
0
    if (NULL != (filter_info = (const H5Z_class2_t *)H5PL_load(H5PL_TYPE_FILTER, &key))) {
744
0
        if (H5Z_register(filter_info) < 0)
745
0
            HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register loaded filter");
746
0
        HGOTO_DONE(true);
747
0
    } /* end if */
748
749
0
done:
750
0
    FUNC_LEAVE_NOAPI(ret_value)
751
0
} /* end H5Z_filter_avail() */
752
753
/*-------------------------------------------------------------------------
754
 * Function: H5Z__prelude_callback
755
 *
756
 * Purpose:  Makes a dataset creation "prelude" callback for the "can_apply"
757
 *           or "set_local" routines.
758
 *
759
 * Return:   Non-negative on success/Negative on failure
760
 *
761
 * Notes:    The chunk dimensions are used to create a dataspace, instead
762
 *           of passing in the dataset's dataspace, since the chunk
763
 *           dimensions are what the I/O filter will actually see
764
 *-------------------------------------------------------------------------
765
 */
766
static herr_t
767
H5Z__prelude_callback(const H5O_pline_t *pline, hid_t dcpl_id, hid_t type_id, hid_t space_id,
768
                      H5Z_prelude_type_t prelude_type)
769
0
{
770
0
    H5Z_class2_t *fclass;           /* Individual filter information */
771
0
    size_t        u;                /* Local index variable */
772
0
    htri_t        ret_value = true; /* Return value */
773
774
0
    FUNC_ENTER_PACKAGE
775
776
0
    assert(pline->nused > 0);
777
778
    /* Iterate over filters */
779
0
    for (u = 0; u < pline->nused; u++) {
780
        /* Get filter information */
781
0
        if (NULL == (fclass = H5Z_find(pline->filter[u].id))) {
782
            /* Ignore errors from optional filters */
783
0
            if (pline->filter[u].flags & H5Z_FLAG_OPTIONAL)
784
0
                H5E_clear_stack();
785
0
            else
786
0
                HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "required filter was not located");
787
0
        } /* end if */
788
0
        else {
789
            /* Make correct callback */
790
0
            switch (prelude_type) {
791
0
                case H5Z_PRELUDE_CAN_APPLY:
792
                    /* Check if filter is configured to be able to encode */
793
0
                    if (!fclass->encoder_present)
794
0
                        HGOTO_ERROR(H5E_PLINE, H5E_NOENCODER, FAIL,
795
0
                                    "Filter present but encoding is disabled.");
796
797
                    /* Check if there is a "can apply" callback */
798
0
                    if (fclass->can_apply) {
799
                        /* Make callback to filter's "can apply" function */
800
0
                        htri_t status = (fclass->can_apply)(dcpl_id, type_id, space_id);
801
802
                        /* Indicate error during filter callback */
803
0
                        if (status < 0)
804
0
                            HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "error during user callback");
805
806
                        /* Indicate filter can't apply to this combination of parameters.
807
                         * If the filter is NOT optional, returns failure. */
808
0
                        if (status == false && !(pline->filter[u].flags & H5Z_FLAG_OPTIONAL))
809
0
                            HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "filter parameters not appropriate");
810
0
                    } /* end if */
811
0
                    break;
812
813
0
                case H5Z_PRELUDE_SET_LOCAL:
814
                    /* Check if there is a "set local" callback */
815
0
                    if (fclass->set_local) {
816
                        /* Make callback to filter's "set local" function */
817
0
                        if ((fclass->set_local)(dcpl_id, type_id, space_id) < 0)
818
                            /* Indicate error during filter callback */
819
0
                            HGOTO_ERROR(H5E_PLINE, H5E_SETLOCAL, FAIL, "error during user callback");
820
0
                    } /* end if */
821
0
                    break;
822
823
0
                default:
824
0
                    assert("invalid prelude type" && 0);
825
0
            } /* end switch */
826
0
        }     /* end else */
827
0
    }         /* end for */
828
829
0
done:
830
831
0
    FUNC_LEAVE_NOAPI(ret_value)
832
0
} /* end H5Z__prelude_callback() */
833
834
/*-------------------------------------------------------------------------
835
 * Function: H5Z__prepare_prelude_callback_dcpl
836
 *
837
 * Purpose:  Prepares to make a dataset creation "prelude" callback
838
 *           for the "can_apply" or "set_local" routines.
839
 *
840
 * Return:   Non-negative on success/Negative on failure
841
 *
842
 * Notes:    The chunk dimensions are used to create a dataspace, instead
843
 *           of passing in the dataset's dataspace, since the chunk
844
 *           dimensions are what the I/O filter will actually see
845
 *-------------------------------------------------------------------------
846
 */
847
static herr_t
848
H5Z__prepare_prelude_callback_dcpl(hid_t dcpl_id, hid_t type_id, H5Z_prelude_type_t prelude_type)
849
0
{
850
0
    hid_t         space_id    = -1;      /* ID for dataspace describing chunk */
851
0
    H5O_layout_t *dcpl_layout = NULL;    /* Dataset's layout information */
852
0
    herr_t        ret_value   = SUCCEED; /* Return value */
853
854
0
    FUNC_ENTER_PACKAGE
855
856
0
    assert(H5I_GENPROP_LST == H5I_get_type(dcpl_id));
857
0
    assert(H5I_DATATYPE == H5I_get_type(type_id));
858
859
    /* Check if the property list is non-default */
860
0
    if (dcpl_id != H5P_DATASET_CREATE_DEFAULT) {
861
0
        H5P_genplist_t *dc_plist; /* Dataset creation property list object */
862
863
        /* Get memory for the layout */
864
0
        if (NULL == (dcpl_layout = (H5O_layout_t *)H5MM_calloc(sizeof(H5O_layout_t))))
865
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate dcpl layout buffer");
866
867
        /* Get dataset creation property list object */
868
0
        if (NULL == (dc_plist = (H5P_genplist_t *)H5I_object(dcpl_id)))
869
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get dataset creation property list");
870
871
        /* Peek at the layout information */
872
0
        if (H5P_peek(dc_plist, H5D_CRT_LAYOUT_NAME, dcpl_layout) < 0)
873
0
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve layout");
874
875
        /* Check if the dataset is chunked */
876
0
        if (H5D_CHUNKED == dcpl_layout->type) {
877
0
            H5O_pline_t dcpl_pline; /* Object's I/O pipeline information */
878
879
            /* Get I/O pipeline information */
880
0
            if (H5P_peek(dc_plist, H5O_CRT_PIPELINE_NAME, &dcpl_pline) < 0)
881
0
                HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't retrieve pipeline filter");
882
883
            /* Check if the chunks have filters */
884
0
            if (dcpl_pline.nused > 0) {
885
0
                hsize_t chunk_dims[H5O_LAYOUT_NDIMS]; /* Size of chunk dimensions */
886
0
                H5S_t  *space;                        /* Dataspace describing chunk */
887
0
                size_t  u;                            /* Local index variable */
888
889
                /* Create a dataspace for a chunk & set the extent */
890
0
                for (u = 0; u < dcpl_layout->u.chunk.ndims; u++)
891
0
                    chunk_dims[u] = dcpl_layout->u.chunk.dim[u];
892
0
                if (NULL == (space = H5S_create_simple(dcpl_layout->u.chunk.ndims, chunk_dims, NULL)))
893
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create simple dataspace");
894
895
                /* Get ID for dataspace to pass to filter routines */
896
0
                if ((space_id = H5I_register(H5I_DATASPACE, space, false)) < 0) {
897
0
                    (void)H5S_close(space);
898
0
                    HGOTO_ERROR(H5E_ID, H5E_CANTREGISTER, FAIL, "unable to register dataspace ID");
899
0
                }
900
901
                /* Make the callbacks */
902
0
                if (H5Z__prelude_callback(&dcpl_pline, dcpl_id, type_id, space_id, prelude_type) < 0)
903
0
                    HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "unable to apply filter");
904
0
            }
905
0
        }
906
0
    }
907
908
0
done:
909
0
    if (space_id > 0 && H5I_dec_ref(space_id) < 0)
910
0
        HDONE_ERROR(H5E_PLINE, H5E_CANTRELEASE, FAIL, "unable to close dataspace");
911
912
0
    if (dcpl_layout)
913
0
        dcpl_layout = (H5O_layout_t *)H5MM_xfree(dcpl_layout);
914
915
0
    FUNC_LEAVE_NOAPI(ret_value)
916
0
} /* end H5Z__prepare_prelude_callback_dcpl() */
917
918
/*-------------------------------------------------------------------------
919
 * Function: H5Z_can_apply
920
 *
921
 * Purpose:  Checks if all the filters defined in the dataset creation
922
 *           property list can be applied to a particular combination of
923
 *           datatype and dataspace for a dataset.
924
 *
925
 * Return:   Non-negative on success
926
 *           Negative on failure
927
 *
928
 * Notes:    The chunk dimensions are used to create a dataspace, instead
929
 *           of passing in the dataset's dataspace, since the chunk
930
 *           dimensions are what the I/O filter will actually see
931
 *-------------------------------------------------------------------------
932
 */
933
herr_t
934
H5Z_can_apply(hid_t dcpl_id, hid_t type_id)
935
0
{
936
0
    herr_t ret_value = SUCCEED; /* Return value */
937
938
0
    FUNC_ENTER_NOAPI(FAIL)
939
940
    /* Make "can apply" callbacks for filters in pipeline */
941
0
    if (H5Z__prepare_prelude_callback_dcpl(dcpl_id, type_id, H5Z_PRELUDE_CAN_APPLY) < 0)
942
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "unable to apply filter");
943
944
0
done:
945
0
    FUNC_LEAVE_NOAPI(ret_value)
946
0
} /* end H5Z_can_apply() */
947
948
/*-------------------------------------------------------------------------
949
 * Function: H5Z_set_local
950
 *
951
 * Purpose:  Makes callbacks to modify dataset creation list property
952
 *           settings for filters on a new dataset, based on the datatype
953
 *           and dataspace of that dataset (chunk).
954
 *
955
 * Return:   Non-negative on success
956
 *           Negative on failure
957
 *
958
 * Notes:    The chunk dimensions are used to create a dataspace, instead
959
 *           of passing in the dataset's dataspace, since the chunk
960
 *           dimensions are what the I/O filter will actually see
961
 *-------------------------------------------------------------------------
962
 */
963
herr_t
964
H5Z_set_local(hid_t dcpl_id, hid_t type_id)
965
0
{
966
0
    herr_t ret_value = SUCCEED; /* Return value */
967
968
0
    FUNC_ENTER_NOAPI(FAIL)
969
970
    /* Make "set local" callbacks for filters in pipeline */
971
0
    if (H5Z__prepare_prelude_callback_dcpl(dcpl_id, type_id, H5Z_PRELUDE_SET_LOCAL) < 0)
972
0
        HGOTO_ERROR(H5E_PLINE, H5E_SETLOCAL, FAIL, "local filter parameters not set");
973
974
0
done:
975
0
    FUNC_LEAVE_NOAPI(ret_value)
976
0
} /* end H5Z_set_local() */
977
978
/*-------------------------------------------------------------------------
979
 * Function: H5Z_can_apply_direct
980
 *
981
 * Purpose:  Checks if all the filters defined in the pipeline can be
982
 *           applied to an opaque byte stream (currently only a group).
983
 *           The pipeline is assumed to have at least one filter.
984
 *
985
 * Return:   Non-negative on success
986
 *           Negative on failure
987
 *-------------------------------------------------------------------------
988
 */
989
herr_t
990
H5Z_can_apply_direct(const H5O_pline_t *pline)
991
0
{
992
0
    herr_t ret_value = SUCCEED; /* Return value */
993
994
0
    FUNC_ENTER_NOAPI(FAIL)
995
996
0
    assert(pline->nused > 0);
997
998
    /* Make "can apply" callbacks for filters in pipeline */
999
0
    if (H5Z__prelude_callback(pline, (hid_t)-1, (hid_t)-1, (hid_t)-1, H5Z_PRELUDE_CAN_APPLY) < 0)
1000
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANAPPLY, FAIL, "unable to apply filter");
1001
1002
0
done:
1003
0
    FUNC_LEAVE_NOAPI(ret_value)
1004
0
} /* end H5Z_can_apply_direct() */
1005
1006
/*-------------------------------------------------------------------------
1007
 * Function: H5Z_set_local_direct
1008
 *
1009
 * Purpose:  Makes callbacks to modify local settings for filters on a
1010
 *           new opaque object.  The pipeline is assumed to have at
1011
 *           least one filter.
1012
 *
1013
 * Return:   Non-negative on success
1014
 *           Negative on failure
1015
 *
1016
 * Notes:    This callback will almost certainly not do anything
1017
 *           useful, other than to make certain that the filter will
1018
 *           accept opaque data.
1019
 *-------------------------------------------------------------------------
1020
 */
1021
herr_t
1022
H5Z_set_local_direct(const H5O_pline_t *pline)
1023
0
{
1024
0
    herr_t ret_value = SUCCEED; /* Return value */
1025
1026
0
    FUNC_ENTER_NOAPI(FAIL)
1027
1028
0
    assert(pline->nused > 0);
1029
1030
    /* Make "set local" callbacks for filters in pipeline */
1031
0
    if (H5Z__prelude_callback(pline, (hid_t)-1, (hid_t)-1, (hid_t)-1, H5Z_PRELUDE_SET_LOCAL) < 0)
1032
0
        HGOTO_ERROR(H5E_PLINE, H5E_SETLOCAL, FAIL, "local filter parameters not set");
1033
1034
0
done:
1035
0
    FUNC_LEAVE_NOAPI(ret_value)
1036
0
} /* end H5Z_set_local_direct() */
1037
1038
/*-------------------------------------------------------------------------
1039
 * Function: H5Z_ignore_filters
1040
 *
1041
 * Purpose:  Determine whether filters can be ignored.
1042
 *
1043
 * Description:
1044
 *      When the filters are optional (i.e., H5Z_FLAG_OPTIONAL is provided,)
1045
 *      if any of the following conditions is met, the filters will be ignored:
1046
 *          - dataspace is either H5S_NULL or H5S_SCALAR
1047
 *          - datatype is variable-length (string or non-string)
1048
 *      However, if any of these conditions exists and a filter is not
1049
 *      optional, the function will produce an error.
1050
 *
1051
 * Return:   Non-negative(true/false) on success
1052
 *           Negative on failure
1053
 *
1054
 *-------------------------------------------------------------------------
1055
 */
1056
htri_t
1057
H5Z_ignore_filters(hid_t dcpl_id, const H5T_t *type, const H5S_t *space)
1058
0
{
1059
0
    H5P_genplist_t *dc_plist;                /* Dataset creation property list object */
1060
0
    H5O_pline_t     pline;                   /* Object's I/O pipeline information */
1061
0
    H5S_class_t     space_class;             /* To check class of space */
1062
0
    H5T_class_t     type_class;              /* To check if type is VL */
1063
0
    bool            bad_for_filters = false; /* Suitable to have filters */
1064
0
    htri_t          ret_value       = false; /* true for ignoring filters */
1065
1066
0
    FUNC_ENTER_NOAPI(FAIL)
1067
1068
0
    if (NULL == (dc_plist = (H5P_genplist_t *)H5I_object(dcpl_id)))
1069
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "can't get dataset creation property list");
1070
1071
    /* Get pipeline information */
1072
0
    if (H5P_peek(dc_plist, H5O_CRT_PIPELINE_NAME, &pline) < 0)
1073
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't retrieve pipeline filter");
1074
1075
    /* Get datatype and dataspace classes for quick access */
1076
0
    space_class = H5S_GET_EXTENT_TYPE(space);
1077
0
    type_class  = H5T_get_class(type, false);
1078
1079
    /* These conditions are not suitable for filters */
1080
0
    bad_for_filters = (H5S_NULL == space_class || H5S_SCALAR == space_class || H5T_VLEN == type_class ||
1081
0
                       (H5T_STRING == type_class && true == H5T_is_variable_str(type)));
1082
1083
    /* When these conditions occur, if there are required filters in pline,
1084
       then report a failure, otherwise, set flag that they can be ignored */
1085
0
    if (bad_for_filters) {
1086
0
        size_t ii;
1087
0
        if (pline.nused > 0) {
1088
0
            for (ii = 0; ii < pline.nused; ii++) {
1089
0
                if (!(pline.filter[ii].flags & H5Z_FLAG_OPTIONAL))
1090
0
                    HGOTO_ERROR(H5E_PLINE, H5E_CANTFILTER, FAIL, "not suitable for filters");
1091
0
            }
1092
1093
            /* All filters are optional, we can ignore them */
1094
0
            ret_value = true;
1095
0
        }
1096
0
    } /* bad for filters */
1097
1098
0
done:
1099
0
    FUNC_LEAVE_NOAPI(ret_value)
1100
0
} /* end H5Z_ignore_filters() */
1101
1102
/*-------------------------------------------------------------------------
1103
 * Function: H5Z_modify
1104
 *
1105
 * Purpose:  Modify filter parameters for specified pipeline.
1106
 *
1107
 * Return:   Non-negative on success
1108
 *           Negative on failure
1109
 *-------------------------------------------------------------------------
1110
 */
1111
herr_t
1112
H5Z_modify(const H5O_pline_t *pline, H5Z_filter_t filter, unsigned flags, size_t cd_nelmts,
1113
           const unsigned int cd_values[/*cd_nelmts*/])
1114
0
{
1115
0
    size_t idx;                 /* Index of filter in pipeline */
1116
0
    herr_t ret_value = SUCCEED; /* Return value */
1117
1118
0
    FUNC_ENTER_NOAPI(FAIL)
1119
1120
0
    assert(pline);
1121
0
    assert(filter >= 0 && filter <= H5Z_FILTER_MAX);
1122
0
    assert(0 == (flags & ~((unsigned)H5Z_FLAG_DEFMASK)));
1123
0
    assert(0 == cd_nelmts || cd_values);
1124
1125
    /* Locate the filter in the pipeline */
1126
0
    for (idx = 0; idx < pline->nused; idx++)
1127
0
        if (pline->filter[idx].id == filter)
1128
0
            break;
1129
1130
    /* Check if the filter was not already in the pipeline */
1131
0
    if (idx > pline->nused)
1132
0
        HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "filter not in pipeline");
1133
1134
    /* Change parameters for filter */
1135
0
    pline->filter[idx].flags     = flags;
1136
0
    pline->filter[idx].cd_nelmts = cd_nelmts;
1137
1138
    /* Free any existing parameters */
1139
0
    if (pline->filter[idx].cd_values != NULL && pline->filter[idx].cd_values != pline->filter[idx]._cd_values)
1140
0
        H5MM_xfree(pline->filter[idx].cd_values);
1141
1142
    /* Set parameters */
1143
0
    if (cd_nelmts > 0) {
1144
0
        size_t i; /* Local index variable */
1145
1146
        /* Allocate memory or point at internal buffer */
1147
0
        if (cd_nelmts > H5Z_COMMON_CD_VALUES) {
1148
0
            pline->filter[idx].cd_values = (unsigned *)H5MM_malloc(cd_nelmts * sizeof(unsigned));
1149
0
            if (NULL == pline->filter[idx].cd_values)
1150
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
1151
0
                            "memory allocation failed for filter parameters");
1152
0
        } /* end if */
1153
0
        else
1154
0
            pline->filter[idx].cd_values = pline->filter[idx]._cd_values;
1155
1156
        /* Copy client data values */
1157
0
        for (i = 0; i < cd_nelmts; i++)
1158
0
            pline->filter[idx].cd_values[i] = cd_values[i];
1159
0
    } /* end if */
1160
0
    else
1161
0
        pline->filter[idx].cd_values = NULL;
1162
1163
0
done:
1164
0
    FUNC_LEAVE_NOAPI(ret_value)
1165
0
} /* end H5Z_modify() */
1166
1167
/*-------------------------------------------------------------------------
1168
 * Function: H5Z_append
1169
 *
1170
 * Purpose:  Append another filter to the specified pipeline.
1171
 *
1172
 * Return:   Non-negative on success
1173
 *           Negative on failure
1174
 *-------------------------------------------------------------------------
1175
 */
1176
herr_t
1177
H5Z_append(H5O_pline_t *pline, H5Z_filter_t filter, unsigned flags, size_t cd_nelmts,
1178
           const unsigned int cd_values[/*cd_nelmts*/])
1179
0
{
1180
0
    size_t idx;
1181
0
    herr_t ret_value = SUCCEED; /* Return value */
1182
1183
0
    FUNC_ENTER_NOAPI(FAIL)
1184
1185
0
    assert(pline);
1186
0
    assert(filter >= 0 && filter <= H5Z_FILTER_MAX);
1187
0
    assert(0 == (flags & ~((unsigned)H5Z_FLAG_DEFMASK)));
1188
0
    assert(0 == cd_nelmts || cd_values);
1189
1190
    /*
1191
     * Check filter limit.  We do it here for early warnings although we may
1192
     * decide to relax this restriction in the future.
1193
     */
1194
0
    if (pline->nused >= H5Z_MAX_NFILTERS)
1195
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "too many filters in pipeline");
1196
1197
    /* Check for freshly allocated filter pipeline */
1198
0
    if (pline->version == 0)
1199
0
        pline->version = H5O_PLINE_VERSION_1;
1200
1201
    /* Allocate additional space in the pipeline if it's full */
1202
0
    if (pline->nused >= pline->nalloc) {
1203
0
        H5O_pline_t x;
1204
0
        size_t      n;
1205
1206
        /* Each filter's data may be stored internally or may be
1207
         * a separate block of memory.
1208
         * For each filter, if cd_values points to the internal array
1209
         * _cd_values, the pointer will need to be updated when the
1210
         * filter struct is reallocated.  Set these pointers to ~NULL
1211
         * so that we can reset them after reallocating the filters array.
1212
         */
1213
0
        for (n = 0; n < pline->nalloc; ++n)
1214
0
            if (pline->filter[n].cd_values == pline->filter[n]._cd_values)
1215
0
                pline->filter[n].cd_values = (unsigned *)((void *)~((size_t)NULL));
1216
1217
0
        x.nalloc = MAX(H5Z_MAX_NFILTERS, 2 * pline->nalloc);
1218
0
        x.filter = (H5Z_filter_info_t *)H5MM_realloc(pline->filter, x.nalloc * sizeof(x.filter[0]));
1219
0
        if (NULL == x.filter)
1220
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for filter pipeline");
1221
1222
        /* Fix pointers in previous filters that need to point to their own
1223
         *      internal data.
1224
         */
1225
0
        for (n = 0; n < pline->nalloc; ++n)
1226
0
            if (x.filter[n].cd_values == (void *)~((size_t)NULL))
1227
0
                x.filter[n].cd_values = x.filter[n]._cd_values;
1228
1229
        /* Point to newly allocated buffer */
1230
0
        pline->nalloc = x.nalloc;
1231
0
        pline->filter = x.filter;
1232
0
    } /* end if */
1233
1234
    /* Add the new filter to the pipeline */
1235
0
    idx                          = pline->nused;
1236
0
    pline->filter[idx].id        = filter;
1237
0
    pline->filter[idx].flags     = flags;
1238
0
    pline->filter[idx].name      = NULL; /*we'll pick it up later*/
1239
0
    pline->filter[idx].cd_nelmts = cd_nelmts;
1240
0
    if (cd_nelmts > 0) {
1241
0
        size_t i; /* Local index variable */
1242
1243
        /* Allocate memory or point at internal buffer */
1244
0
        if (cd_nelmts > H5Z_COMMON_CD_VALUES) {
1245
0
            pline->filter[idx].cd_values = (unsigned *)H5MM_malloc(cd_nelmts * sizeof(unsigned));
1246
0
            if (NULL == pline->filter[idx].cd_values)
1247
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for filter");
1248
0
        } /* end if */
1249
0
        else
1250
0
            pline->filter[idx].cd_values = pline->filter[idx]._cd_values;
1251
1252
        /* Copy client data values */
1253
0
        for (i = 0; i < cd_nelmts; i++)
1254
0
            pline->filter[idx].cd_values[i] = cd_values[i];
1255
0
    } /* end if */
1256
0
    else
1257
0
        pline->filter[idx].cd_values = NULL;
1258
1259
0
    pline->nused++;
1260
1261
0
done:
1262
0
    FUNC_LEAVE_NOAPI(ret_value)
1263
0
} /* end H5Z_append() */
1264
1265
/*-------------------------------------------------------------------------
1266
 * Function: H5Z__find_idx
1267
 *
1268
 * Purpose:  Given a filter ID return the offset in the global array
1269
 *           that holds all the registered filters.
1270
 *
1271
 * Return:   Success:    Non-negative index of entry in global filter table.
1272
 *           Failure:    Negative
1273
 *-------------------------------------------------------------------------
1274
 */
1275
static int
1276
H5Z__find_idx(H5Z_filter_t id)
1277
0
{
1278
0
    size_t i;                /* Local index variable */
1279
0
    int    ret_value = FAIL; /* Return value */
1280
1281
0
    FUNC_ENTER_PACKAGE_NOERR
1282
1283
0
    for (i = 0; i < H5Z_table_used_g; i++)
1284
0
        if (H5Z_table_g[i].id == id)
1285
0
            HGOTO_DONE((int)i);
1286
1287
0
done:
1288
0
    FUNC_LEAVE_NOAPI(ret_value)
1289
0
} /* end H5Z__find_idx() */
1290
1291
/*-------------------------------------------------------------------------
1292
 * Function: H5Z_find
1293
 *
1294
 * Purpose:  Given a filter ID return a pointer to a global struct that
1295
 *           defines the filter.
1296
 *
1297
 * Return:   Success:    Ptr to entry in global filter table.
1298
 *           Failure:    NULL
1299
 *-------------------------------------------------------------------------
1300
 */
1301
H5Z_class2_t *
1302
H5Z_find(H5Z_filter_t id)
1303
0
{
1304
0
    int           idx;              /* Filter index in global table */
1305
0
    H5Z_class2_t *ret_value = NULL; /* Return value */
1306
1307
0
    FUNC_ENTER_NOAPI(NULL)
1308
1309
    /* Get the index in the global table */
1310
0
    if ((idx = H5Z__find_idx(id)) < 0)
1311
0
        HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, NULL, "required filter %d is not registered", id);
1312
1313
    /* Set return value */
1314
0
    ret_value = H5Z_table_g + idx;
1315
1316
0
done:
1317
0
    FUNC_LEAVE_NOAPI(ret_value)
1318
0
} /* H5Z_find() */
1319
1320
/*-------------------------------------------------------------------------
1321
 * Function: H5Z_pipeline
1322
 *
1323
 * Purpose:  Process data through the filter pipeline.  The FLAGS argument
1324
 *           is the filter invocation flags (definition flags come from
1325
 *           the PLINE->filter[].flags).  The filters are processed in
1326
 *           definition order unless the H5Z_FLAG_REVERSE is set.  The
1327
 *           FILTER_MASK is a bit-mask to indicate which filters to skip
1328
 *           and on exit will indicate which filters failed.  Each
1329
 *           filter has an index number in the pipeline and that index
1330
 *           number is the filter's bit in the FILTER_MASK.  NBYTES is the
1331
 *           number of bytes of data to filter and on exit should be the
1332
 *           number of resulting bytes while BUF_SIZE holds the total
1333
 *           allocated size of the buffer, which is pointed to BUF.
1334
 *
1335
 *           If the buffer must grow during processing of the pipeline
1336
 *           then the pipeline function should free the original buffer
1337
 *           and return a fresh buffer, adjusting BUF_SIZE accordingly.
1338
 *
1339
 * Return:   Non-negative on success
1340
 *           Negative on failure
1341
 *-------------------------------------------------------------------------
1342
 */
1343
herr_t
1344
H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*in,out*/, H5Z_EDC_t edc_read,
1345
             H5Z_cb_t cb_struct, size_t *nbytes /*in,out*/, size_t *buf_size /*in,out*/,
1346
             void **buf /*in,out*/)
1347
0
{
1348
0
    size_t        idx;
1349
0
    size_t        new_nbytes;
1350
0
    int           fclass_idx;    /* Index of filter class in global table */
1351
0
    H5Z_class2_t *fclass = NULL; /* Filter class pointer */
1352
#ifdef H5Z_DEBUG
1353
    H5Z_stats_t  *fstats = NULL; /* Filter stats pointer */
1354
    H5_timer_t    timer;         /* Timer for filter operations */
1355
    H5_timevals_t times;         /* Elapsed time for each operation */
1356
#endif
1357
0
    unsigned failed = 0;
1358
0
    unsigned tmp_flags;
1359
0
    size_t   i;
1360
0
    herr_t   ret_value = SUCCEED; /* Return value */
1361
1362
0
    FUNC_ENTER_NOAPI(FAIL)
1363
1364
0
    assert(0 == (flags & ~((unsigned)H5Z_FLAG_INVMASK)));
1365
0
    assert(filter_mask);
1366
0
    assert(nbytes && *nbytes > 0);
1367
0
    assert(buf_size && *buf_size > 0);
1368
0
    assert(buf && *buf);
1369
0
    assert(!pline || pline->nused < H5Z_MAX_NFILTERS);
1370
1371
#ifdef H5Z_DEBUG
1372
    H5_timer_init(&timer);
1373
#endif
1374
0
    if (pline && (flags & H5Z_FLAG_REVERSE)) { /* Read */
1375
0
        for (i = pline->nused; i > 0; --i) {
1376
0
            idx = i - 1;
1377
0
            if (*filter_mask & ((unsigned)1 << idx)) {
1378
0
                failed |= (unsigned)1 << idx;
1379
0
                continue; /* filter excluded */
1380
0
            }
1381
1382
            /* If the filter isn't registered and the application doesn't
1383
             * indicate no plugin through HDF5_PRELOAD_PLUG (using the symbol "::"),
1384
             * try to load it dynamically and register it.  Otherwise, return failure
1385
             */
1386
0
            if ((fclass_idx = H5Z__find_idx(pline->filter[idx].id)) < 0) {
1387
0
                H5PL_key_t          key;
1388
0
                const H5Z_class2_t *filter_info;
1389
0
                bool                issue_error = false;
1390
1391
                /* Try loading the filter */
1392
0
                key.id = (int)(pline->filter[idx].id);
1393
0
                if (NULL != (filter_info = (const H5Z_class2_t *)H5PL_load(H5PL_TYPE_FILTER, &key))) {
1394
                    /* Register the filter we loaded */
1395
0
                    if (H5Z_register(filter_info) < 0)
1396
0
                        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to register filter");
1397
1398
                    /* Search in the table of registered filters again to find the dynamic filter just loaded
1399
                     * and registered */
1400
0
                    if ((fclass_idx = H5Z__find_idx(pline->filter[idx].id)) < 0)
1401
0
                        issue_error = true;
1402
0
                }
1403
0
                else
1404
0
                    issue_error = true;
1405
1406
                /* Check for error */
1407
0
                if (issue_error) {
1408
                    /* Print out the filter name to give more info.  But the name is optional for
1409
                     * the filter */
1410
0
                    if (pline->filter[idx].name)
1411
0
                        HGOTO_ERROR(H5E_PLINE, H5E_READERROR, FAIL, "required filter '%s' is not registered",
1412
0
                                    pline->filter[idx].name);
1413
0
                    else
1414
0
                        HGOTO_ERROR(H5E_PLINE, H5E_READERROR, FAIL,
1415
0
                                    "required filter (name unavailable) is not registered");
1416
0
                }
1417
0
            } /* end if */
1418
1419
0
            fclass = &H5Z_table_g[fclass_idx];
1420
1421
#ifdef H5Z_DEBUG
1422
            fstats = &H5Z_stat_table_g[fclass_idx];
1423
            H5_timer_start(&timer);
1424
#endif
1425
1426
0
            tmp_flags = flags | (pline->filter[idx].flags);
1427
0
            tmp_flags |= (edc_read == H5Z_DISABLE_EDC) ? H5Z_FLAG_SKIP_EDC : 0;
1428
0
            new_nbytes = (fclass->filter)(tmp_flags, pline->filter[idx].cd_nelmts,
1429
0
                                          pline->filter[idx].cd_values, *nbytes, buf_size, buf);
1430
1431
#ifdef H5Z_DEBUG
1432
            H5_timer_stop(&timer);
1433
            H5_timer_get_times(timer, &times);
1434
            fstats->stats[1].times.elapsed += times.elapsed;
1435
            fstats->stats[1].times.system += times.system;
1436
            fstats->stats[1].times.user += times.user;
1437
1438
            fstats->stats[1].total += MAX(*nbytes, new_nbytes);
1439
            if (0 == new_nbytes)
1440
                fstats->stats[1].errors += *nbytes;
1441
#endif
1442
1443
0
            if (0 == new_nbytes) {
1444
0
                if ((cb_struct.func && (H5Z_CB_FAIL == cb_struct.func(pline->filter[idx].id, *buf, *buf_size,
1445
0
                                                                      cb_struct.op_data))) ||
1446
0
                    !cb_struct.func)
1447
0
                    HGOTO_ERROR(H5E_PLINE, H5E_READERROR, FAIL, "filter returned failure during read");
1448
1449
0
                *nbytes = *buf_size;
1450
0
                failed |= (unsigned)1 << idx;
1451
0
                H5E_clear_stack();
1452
0
            }
1453
0
            else
1454
0
                *nbytes = new_nbytes;
1455
0
        }
1456
0
    }
1457
0
    else if (pline) { /* Write */
1458
0
        for (idx = 0; idx < pline->nused; idx++) {
1459
0
            if (*filter_mask & ((unsigned)1 << idx)) {
1460
0
                failed |= (unsigned)1 << idx;
1461
0
                continue; /* filter excluded */
1462
0
            }
1463
0
            if ((fclass_idx = H5Z__find_idx(pline->filter[idx].id)) < 0) {
1464
                /* Check if filter is optional -- If it isn't, then error */
1465
0
                if ((pline->filter[idx].flags & H5Z_FLAG_OPTIONAL) == 0)
1466
0
                    HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "required filter is not registered");
1467
0
                failed |= (unsigned)1 << idx;
1468
0
                H5E_clear_stack();
1469
0
                continue; /* filter excluded */
1470
0
            }             /* end if */
1471
1472
0
            fclass = &H5Z_table_g[fclass_idx];
1473
1474
#ifdef H5Z_DEBUG
1475
            fstats = &H5Z_stat_table_g[fclass_idx];
1476
            H5_timer_start(&timer);
1477
#endif
1478
1479
0
            new_nbytes = (fclass->filter)(flags | (pline->filter[idx].flags), pline->filter[idx].cd_nelmts,
1480
0
                                          pline->filter[idx].cd_values, *nbytes, buf_size, buf);
1481
1482
#ifdef H5Z_DEBUG
1483
            H5_timer_stop(&timer);
1484
            H5_timer_get_times(timer, &times);
1485
            fstats->stats[0].times.elapsed += times.elapsed;
1486
            fstats->stats[0].times.system += times.system;
1487
            fstats->stats[0].times.user += times.user;
1488
1489
            fstats->stats[0].total += MAX(*nbytes, new_nbytes);
1490
            if (0 == new_nbytes)
1491
                fstats->stats[0].errors += *nbytes;
1492
#endif
1493
1494
0
            if (0 == new_nbytes) {
1495
0
                if (0 == (pline->filter[idx].flags & H5Z_FLAG_OPTIONAL)) {
1496
0
                    if ((cb_struct.func && (H5Z_CB_FAIL == cb_struct.func(pline->filter[idx].id, *buf,
1497
0
                                                                          *nbytes, cb_struct.op_data))) ||
1498
0
                        !cb_struct.func)
1499
0
                        HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "filter returned failure");
1500
1501
0
                    *nbytes = *buf_size;
1502
0
                }
1503
0
                failed |= (unsigned)1 << idx;
1504
0
                H5E_clear_stack();
1505
0
            }
1506
0
            else
1507
0
                *nbytes = new_nbytes;
1508
0
        } /* end for */
1509
0
    }
1510
1511
0
    *filter_mask = failed;
1512
1513
0
done:
1514
0
    FUNC_LEAVE_NOAPI(ret_value)
1515
0
}
1516
1517
/*-------------------------------------------------------------------------
1518
 * Function: H5Z_filter_info
1519
 *
1520
 * Purpose:  Get pointer to filter info for pipeline
1521
 *
1522
 * Return:   Non-negative on success
1523
 *           Negative on failure
1524
 *-------------------------------------------------------------------------
1525
 */
1526
H5Z_filter_info_t *
1527
H5Z_filter_info(const H5O_pline_t *pline, H5Z_filter_t filter)
1528
0
{
1529
0
    size_t             idx;              /* Index of filter in pipeline */
1530
0
    H5Z_filter_info_t *ret_value = NULL; /* Return value */
1531
1532
0
    FUNC_ENTER_NOAPI(NULL)
1533
1534
0
    assert(pline);
1535
0
    assert(filter >= 0 && filter <= H5Z_FILTER_MAX);
1536
1537
    /* Locate the filter in the pipeline */
1538
0
    for (idx = 0; idx < pline->nused; idx++)
1539
0
        if (pline->filter[idx].id == filter)
1540
0
            break;
1541
1542
    /* Check if the filter was not already in the pipeline */
1543
0
    if (idx >= pline->nused)
1544
0
        HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, NULL, "filter not in pipeline");
1545
1546
    /* Set return value */
1547
0
    ret_value = &pline->filter[idx];
1548
1549
0
done:
1550
0
    FUNC_LEAVE_NOAPI(ret_value)
1551
0
} /* end H5Z_filter_info() */
1552
1553
/*-------------------------------------------------------------------------
1554
 * Function: H5Z_filter_in_pline
1555
 *
1556
 * Purpose:  Check whether a filter is in the filter pipeline using the
1557
 *           filter ID.  This function is very similar to H5Z_filter_info
1558
 *
1559
 * Return:   true   - found filter
1560
 *           false  - not found
1561
 *           FAIL   - error
1562
 *-------------------------------------------------------------------------
1563
 */
1564
htri_t
1565
H5Z_filter_in_pline(const H5O_pline_t *pline, H5Z_filter_t filter)
1566
0
{
1567
0
    size_t idx;              /* Index of filter in pipeline */
1568
0
    htri_t ret_value = true; /* Return value */
1569
1570
0
    FUNC_ENTER_NOAPI_NOERR
1571
1572
0
    assert(pline);
1573
0
    assert(filter >= 0 && filter <= H5Z_FILTER_MAX);
1574
1575
    /* Locate the filter in the pipeline */
1576
0
    for (idx = 0; idx < pline->nused; idx++)
1577
0
        if (pline->filter[idx].id == filter)
1578
0
            break;
1579
1580
    /* Check if the filter was not already in the pipeline */
1581
0
    if (idx >= pline->nused)
1582
0
        ret_value = false;
1583
1584
0
    FUNC_LEAVE_NOAPI(ret_value)
1585
0
} /* end H5Z_filter_in_pline() */
1586
1587
/*-------------------------------------------------------------------------
1588
 * Function: H5Z_all_filters_avail
1589
 *
1590
 * Purpose:  Verify that all the filters in a pipeline are currently
1591
 *           available (i.e. registered)
1592
 *
1593
 * Return:   Non-negative (true/false) on success
1594
 *           Negative on failure
1595
 *-------------------------------------------------------------------------
1596
 */
1597
htri_t
1598
H5Z_all_filters_avail(const H5O_pline_t *pline)
1599
0
{
1600
0
    size_t i, j;             /* Local index variable */
1601
0
    htri_t ret_value = true; /* Return value */
1602
1603
0
    FUNC_ENTER_NOAPI_NOERR
1604
1605
    /* Check args */
1606
0
    assert(pline);
1607
1608
    /* Iterate through all the filters in pipeline */
1609
0
    for (i = 0; i < pline->nused; i++) {
1610
        /* Look for each filter in the list of registered filters */
1611
0
        for (j = 0; j < H5Z_table_used_g; j++)
1612
0
            if (H5Z_table_g[j].id == pline->filter[i].id)
1613
0
                break;
1614
1615
        /* Check if we didn't find the filter */
1616
0
        if (j == H5Z_table_used_g)
1617
0
            HGOTO_DONE(false);
1618
0
    } /* end for */
1619
1620
0
done:
1621
0
    FUNC_LEAVE_NOAPI(ret_value)
1622
0
} /* end H5Z_all_filters_avail() */
1623
1624
/*-------------------------------------------------------------------------
1625
 * Function: H5Z_delete
1626
 *
1627
 * Purpose:  Delete filter FILTER from pipeline PLINE;
1628
 *           deletes all filters if FILTER is H5Z_FILTER_ALL
1629
 *
1630
 * Return:   Non-negative on success
1631
 *           Negative on failure
1632
 *-------------------------------------------------------------------------
1633
 */
1634
herr_t
1635
H5Z_delete(H5O_pline_t *pline, H5Z_filter_t filter)
1636
0
{
1637
0
    herr_t ret_value = SUCCEED; /* Return value */
1638
1639
0
    FUNC_ENTER_NOAPI(FAIL)
1640
1641
    /* Check args */
1642
0
    assert(pline);
1643
0
    assert(filter >= 0 && filter <= H5Z_FILTER_MAX);
1644
1645
    /* if the pipeline has no filters, just return */
1646
0
    if (pline->nused == 0)
1647
0
        HGOTO_DONE(SUCCEED);
1648
1649
    /* Delete all filters */
1650
0
    if (H5Z_FILTER_ALL == filter) {
1651
0
        if (H5O_msg_reset(H5O_PLINE_ID, pline) < 0)
1652
0
            HGOTO_ERROR(H5E_PLINE, H5E_CANTFREE, FAIL, "can't release pipeline info");
1653
0
    }
1654
    /* Delete filter */
1655
0
    else {
1656
0
        size_t idx;           /* Index of filter in pipeline */
1657
0
        bool   found = false; /* Indicate filter was found in pipeline */
1658
1659
        /* Locate the filter in the pipeline */
1660
0
        for (idx = 0; idx < pline->nused; idx++)
1661
0
            if (pline->filter[idx].id == filter) {
1662
0
                found = true;
1663
0
                break;
1664
0
            }
1665
1666
        /* filter was not found in the pipeline */
1667
0
        if (!found)
1668
0
            HGOTO_ERROR(H5E_PLINE, H5E_NOTFOUND, FAIL, "filter not in pipeline");
1669
1670
        /* Free information for deleted filter */
1671
0
        if (pline->filter[idx].name && pline->filter[idx].name != pline->filter[idx]._name)
1672
0
            assert((strlen(pline->filter[idx].name) + 1) > H5Z_COMMON_NAME_LEN);
1673
0
        if (pline->filter[idx].name != pline->filter[idx]._name)
1674
0
            pline->filter[idx].name = (char *)H5MM_xfree(pline->filter[idx].name);
1675
0
        if (pline->filter[idx].cd_values && pline->filter[idx].cd_values != pline->filter[idx]._cd_values)
1676
0
            assert(pline->filter[idx].cd_nelmts > H5Z_COMMON_CD_VALUES);
1677
0
        if (pline->filter[idx].cd_values != pline->filter[idx]._cd_values)
1678
0
            pline->filter[idx].cd_values = (unsigned *)H5MM_xfree(pline->filter[idx].cd_values);
1679
1680
        /* Remove filter from pipeline array */
1681
0
        if ((idx + 1) < pline->nused) {
1682
            /* Copy filters down & fix up any client data value arrays using internal storage */
1683
0
            for (; (idx + 1) < pline->nused; idx++) {
1684
0
                pline->filter[idx] = pline->filter[idx + 1];
1685
0
                if (pline->filter[idx].name && (strlen(pline->filter[idx].name) + 1) <= H5Z_COMMON_NAME_LEN)
1686
0
                    pline->filter[idx].name = pline->filter[idx]._name;
1687
0
                if (pline->filter[idx].cd_nelmts <= H5Z_COMMON_CD_VALUES)
1688
0
                    pline->filter[idx].cd_values = pline->filter[idx]._cd_values;
1689
0
            }
1690
0
        }
1691
1692
        /* Decrement number of used filters */
1693
0
        pline->nused--;
1694
1695
        /* Reset information for previous last filter in pipeline */
1696
0
        memset(&pline->filter[pline->nused], 0, sizeof(H5Z_filter_info_t));
1697
0
    } /* end else */
1698
1699
0
done:
1700
0
    FUNC_LEAVE_NOAPI(ret_value)
1701
0
} /* end H5Z_delete() */
1702
1703
/*-------------------------------------------------------------------------
1704
 * Function: H5Zget_filter_info
1705
 *
1706
 * Purpose:  Gets information about a pipeline data filter and stores it
1707
 *           in filter_config_flags.
1708
 *
1709
 * Return:   zero on success
1710
 *           negative on failure
1711
 *-------------------------------------------------------------------------
1712
 */
1713
herr_t
1714
H5Zget_filter_info(H5Z_filter_t filter, unsigned *filter_config_flags /*out*/)
1715
0
{
1716
0
    herr_t ret_value = SUCCEED;
1717
1718
0
    FUNC_ENTER_API(FAIL)
1719
1720
    /* Get the filter info */
1721
0
    if (H5Z_get_filter_info(filter, filter_config_flags) < 0)
1722
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "Filter info not retrieved");
1723
1724
0
done:
1725
0
    FUNC_LEAVE_API(ret_value)
1726
0
} /* end H5Zget_filter_info() */
1727
1728
/*-------------------------------------------------------------------------
1729
 * Function: H5Z_get_filter_info
1730
 *
1731
 * Purpose:  Gets information about a pipeline data filter and stores it
1732
 *           in filter_config_flags.
1733
 *
1734
 * Return:   zero on success
1735
 *           negative on failure
1736
 *-------------------------------------------------------------------------
1737
 */
1738
herr_t
1739
H5Z_get_filter_info(H5Z_filter_t filter, unsigned int *filter_config_flags)
1740
0
{
1741
0
    H5Z_class2_t *fclass;
1742
0
    herr_t        ret_value = SUCCEED;
1743
1744
0
    FUNC_ENTER_NOAPI(FAIL)
1745
1746
    /* Look up the filter class info */
1747
0
    if (NULL == (fclass = H5Z_find(filter)))
1748
0
        HGOTO_ERROR(H5E_PLINE, H5E_BADVALUE, FAIL, "Filter not defined");
1749
1750
    /* Set the filter config flags for the application */
1751
0
    if (filter_config_flags != NULL) {
1752
0
        *filter_config_flags = 0;
1753
1754
0
        if (fclass->encoder_present)
1755
0
            *filter_config_flags |= H5Z_FILTER_CONFIG_ENCODE_ENABLED;
1756
0
        if (fclass->decoder_present)
1757
0
            *filter_config_flags |= H5Z_FILTER_CONFIG_DECODE_ENABLED;
1758
0
    } /* end if */
1759
1760
0
done:
1761
0
    FUNC_LEAVE_NOAPI(ret_value)
1762
0
} /* end H5Z_get_filter_info() */