Coverage Report

Created: 2025-08-26 06:30

/src/hdf5/src/H5Tvlen.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 LICENSE 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
/*
14
 * Module Info: This module contains the functionality for variable-length
15
 *      datatypes in the H5T interface.
16
 */
17
18
/****************/
19
/* Module Setup */
20
/****************/
21
22
#include "H5Tmodule.h" /* This source code file is part of the H5T module */
23
24
/***********/
25
/* Headers */
26
/***********/
27
#include "H5private.h"   /* Generic Functions    */
28
#include "H5CXprivate.h" /* API Contexts         */
29
#include "H5Eprivate.h"  /* Error handling       */
30
#include "H5Iprivate.h"  /* IDs                  */
31
#include "H5MMprivate.h" /* Memory management    */
32
#include "H5Tpkg.h"      /* Datatypes            */
33
#include "H5VLprivate.h" /* Virtual Object Layer                     */
34
35
/****************/
36
/* Local Macros */
37
/****************/
38
39
/******************/
40
/* Local Typedefs */
41
/******************/
42
43
/********************/
44
/* Package Typedefs */
45
/********************/
46
47
/********************/
48
/* Local Prototypes */
49
/********************/
50
51
/* Memory-based VL sequence callbacks */
52
static herr_t H5T__vlen_mem_seq_getlen(H5VL_object_t *file, const void *_vl, size_t *len);
53
static void  *H5T__vlen_mem_seq_getptr(void *_vl);
54
static herr_t H5T__vlen_mem_seq_isnull(const H5VL_object_t *file, void *_vl, bool *isnull);
55
static herr_t H5T__vlen_mem_seq_setnull(H5VL_object_t *file, void *_vl, void *_bg);
56
static herr_t H5T__vlen_mem_seq_read(H5VL_object_t *file, void *_vl, void *_buf, size_t len);
57
static herr_t H5T__vlen_mem_seq_write(H5VL_object_t *file, const H5T_vlen_alloc_info_t *vl_alloc_info,
58
                                      void *_vl, void *_buf, void *_bg, size_t seq_len, size_t base_size);
59
60
/* Memory-based VL string callbacks */
61
static herr_t H5T__vlen_mem_str_getlen(H5VL_object_t *file, const void *_vl, size_t *len);
62
static void  *H5T__vlen_mem_str_getptr(void *_vl);
63
static herr_t H5T__vlen_mem_str_isnull(const H5VL_object_t *file, void *_vl, bool *isnull);
64
static herr_t H5T__vlen_mem_str_setnull(H5VL_object_t *file, void *_vl, void *_bg);
65
static herr_t H5T__vlen_mem_str_read(H5VL_object_t *file, void *_vl, void *_buf, size_t len);
66
static herr_t H5T__vlen_mem_str_write(H5VL_object_t *file, const H5T_vlen_alloc_info_t *vl_alloc_info,
67
                                      void *_vl, void *_buf, void *_bg, size_t seq_len, size_t base_size);
68
69
/* Disk-based VL sequence (and string) callbacks */
70
static herr_t H5T__vlen_disk_getlen(H5VL_object_t *file, const void *_vl, size_t *len);
71
static herr_t H5T__vlen_disk_isnull(const H5VL_object_t *file, void *_vl, bool *isnull);
72
static herr_t H5T__vlen_disk_setnull(H5VL_object_t *file, void *_vl, void *_bg);
73
static herr_t H5T__vlen_disk_read(H5VL_object_t *file, void *_vl, void *_buf, size_t len);
74
static herr_t H5T__vlen_disk_write(H5VL_object_t *file, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl,
75
                                   void *_buf, void *_bg, size_t seq_len, size_t base_size);
76
static herr_t H5T__vlen_disk_delete(H5VL_object_t *file, void *_vl);
77
78
/*********************/
79
/* Public Variables */
80
/*********************/
81
82
/*********************/
83
/* Package Variables */
84
/*********************/
85
86
/*****************************/
87
/* Library Private Variables */
88
/*****************************/
89
90
/*******************/
91
/* Local Variables */
92
/*******************/
93
94
/* Class for VL sequences in memory */
95
static const H5T_vlen_class_t H5T_vlen_mem_seq_g = {
96
    H5T__vlen_mem_seq_getlen,  /* 'getlen' */
97
    H5T__vlen_mem_seq_getptr,  /* 'getptr' */
98
    H5T__vlen_mem_seq_isnull,  /* 'isnull' */
99
    H5T__vlen_mem_seq_setnull, /* 'setnull' */
100
    H5T__vlen_mem_seq_read,    /* 'read' */
101
    H5T__vlen_mem_seq_write,   /* 'write' */
102
    NULL                       /* 'delete' */
103
};
104
105
/* Class for VL strings in memory */
106
static const H5T_vlen_class_t H5T_vlen_mem_str_g = {
107
    H5T__vlen_mem_str_getlen,  /* 'getlen' */
108
    H5T__vlen_mem_str_getptr,  /* 'getptr' */
109
    H5T__vlen_mem_str_isnull,  /* 'isnull' */
110
    H5T__vlen_mem_str_setnull, /* 'setnull' */
111
    H5T__vlen_mem_str_read,    /* 'read' */
112
    H5T__vlen_mem_str_write,   /* 'write' */
113
    NULL                       /* 'delete' */
114
};
115
116
/* Class for both VL strings and sequences in file */
117
static const H5T_vlen_class_t H5T_vlen_disk_g = {
118
    H5T__vlen_disk_getlen,  /* 'getlen' */
119
    NULL,                   /* 'getptr' */
120
    H5T__vlen_disk_isnull,  /* 'isnull' */
121
    H5T__vlen_disk_setnull, /* 'setnull' */
122
    H5T__vlen_disk_read,    /* 'read' */
123
    H5T__vlen_disk_write,   /* 'write' */
124
    H5T__vlen_disk_delete   /* 'delete' */
125
};
126
127
/*-------------------------------------------------------------------------
128
 * Function:    H5Tvlen_create
129
 *
130
 * Purpose:     Create a new variable-length datatype based on the
131
 *              specified base datatype ID.
132
 *
133
 * Return:      Success:    ID of new VL datatype
134
 *              Failure:    H5I_INVALID_HID
135
 *
136
 *-------------------------------------------------------------------------
137
 */
138
hid_t
139
H5Tvlen_create(hid_t base_id)
140
0
{
141
0
    H5T_t *base = NULL; /*base datatype */
142
0
    H5T_t *dt   = NULL; /*new datatype  */
143
0
    hid_t  ret_value;   /*return value      */
144
145
0
    FUNC_ENTER_API(H5I_INVALID_HID)
146
147
    /* Check args */
148
0
    if (NULL == (base = (H5T_t *)H5I_object_verify(base_id, H5I_DATATYPE)))
149
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not an valid base datatype");
150
151
    /* Create up VL datatype */
152
0
    if ((dt = H5T__vlen_create(base)) == NULL)
153
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, H5I_INVALID_HID, "invalid VL location");
154
155
    /* Register the type */
156
0
    if ((ret_value = H5I_register(H5I_DATATYPE, dt, true)) < 0)
157
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register datatype");
158
159
0
done:
160
0
    FUNC_LEAVE_API(ret_value)
161
0
} /* end H5Tvlen_create() */
162
163
/*-------------------------------------------------------------------------
164
 * Function:    H5T__vlen_create
165
 *
166
 * Purpose:     Create a new variable-length datatype based on the
167
 *              specified base datatype.
168
 *
169
 * Return:      Success:    new VL datatype
170
 *              Failure:    NULL
171
 *
172
 *-------------------------------------------------------------------------
173
 */
174
H5T_t *
175
H5T__vlen_create(const H5T_t *base)
176
1
{
177
1
    H5T_t *dt        = NULL; /* New VL datatype */
178
1
    H5T_t *ret_value = NULL; /* Return value */
179
180
1
    FUNC_ENTER_PACKAGE
181
182
    /* Check args */
183
1
    assert(base);
184
185
    /* Build new type */
186
1
    if (NULL == (dt = H5T__alloc()))
187
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, NULL, "memory allocation failed");
188
1
    dt->shared->type = H5T_VLEN;
189
190
    /*
191
     * Force conversions (i.e. memory to memory conversions should duplicate
192
     * data, not point to the same VL sequences)
193
     */
194
1
    dt->shared->force_conv = true;
195
1
    if (NULL == (dt->shared->parent = H5T_copy(base, H5T_COPY_ALL)))
196
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "can't copy base datatype");
197
198
    /* Inherit encoding version from base type */
199
1
    dt->shared->version = base->shared->version;
200
201
    /* This is a sequence, not a string */
202
1
    dt->shared->u.vlen.type = H5T_VLEN_SEQUENCE;
203
204
    /* Set up VL information */
205
1
    if (H5T_set_loc(dt, NULL, H5T_LOC_MEMORY) < 0)
206
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "invalid datatype location");
207
208
    /* Set return value */
209
1
    ret_value = dt;
210
211
1
done:
212
1
    if (!ret_value)
213
0
        if (dt && H5T_close_real(dt) < 0)
214
0
            HDONE_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, NULL, "unable to release datatype info");
215
216
1
    FUNC_LEAVE_NOAPI(ret_value)
217
1
} /* end H5T__vlen_create() */
218
219
/*-------------------------------------------------------------------------
220
 * Function: H5T__vlen_set_loc
221
 *
222
 * Purpose: Sets the location of a VL datatype to be either on disk or in memory
223
 *
224
 * Return:
225
 *  One of two values on success:
226
 *      true - If the location of any vlen types changed
227
 *      false - If the location of any vlen types is the same
228
 *  <0 is returned on failure
229
 *
230
 *-------------------------------------------------------------------------
231
 */
232
htri_t
233
H5T__vlen_set_loc(H5T_t *dt, H5VL_object_t *file, H5T_loc_t loc)
234
1
{
235
1
    htri_t ret_value = false; /* Indicate success, but no location change */
236
237
1
    FUNC_ENTER_PACKAGE
238
239
    /* check parameters */
240
1
    assert(dt);
241
1
    assert(loc >= H5T_LOC_BADLOC && loc < H5T_LOC_MAXLOC);
242
243
    /* Only change the location if it's different */
244
1
    if (loc != dt->shared->u.vlen.loc || file != dt->shared->u.vlen.file) {
245
1
        switch (loc) {
246
1
            case H5T_LOC_MEMORY: /* Memory based VL datatype */
247
1
                assert(NULL == file);
248
249
                /* Mark this type as being stored in memory */
250
1
                dt->shared->u.vlen.loc = H5T_LOC_MEMORY;
251
252
1
                if (dt->shared->u.vlen.type == H5T_VLEN_SEQUENCE) {
253
                    /* Size in memory, disk size is different */
254
1
                    dt->shared->size = sizeof(hvl_t);
255
256
                    /* Set up the function pointers to access the VL sequence in memory */
257
1
                    dt->shared->u.vlen.cls = &H5T_vlen_mem_seq_g;
258
1
                } /* end if */
259
0
                else if (dt->shared->u.vlen.type == H5T_VLEN_STRING) {
260
                    /* Size in memory, disk size is different */
261
0
                    dt->shared->size = sizeof(char *);
262
263
                    /* Set up the function pointers to access the VL string in memory */
264
0
                    dt->shared->u.vlen.cls = &H5T_vlen_mem_str_g;
265
0
                } /* end else-if */
266
0
                else
267
0
                    assert(0 && "Invalid VL type");
268
269
                /* Release owned file */
270
1
                if (dt->shared->owned_vol_obj) {
271
0
                    if (H5VL_free_object(dt->shared->owned_vol_obj) < 0)
272
0
                        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCLOSEOBJ, FAIL, "unable to close owned VOL object");
273
0
                    dt->shared->owned_vol_obj = NULL;
274
0
                } /* end if */
275
276
                /* Reset file pointer (since this VL is in memory) */
277
1
                dt->shared->u.vlen.file = NULL;
278
1
                break;
279
280
            /* Disk based VL datatype */
281
0
            case H5T_LOC_DISK: {
282
0
                H5VL_file_cont_info_t cont_info = {H5VL_CONTAINER_INFO_VERSION, 0, 0, 0};
283
0
                H5VL_file_get_args_t  vol_cb_args; /* Arguments to VOL callback */
284
285
0
                assert(file);
286
287
                /* Mark this type as being stored on disk */
288
0
                dt->shared->u.vlen.loc = H5T_LOC_DISK;
289
290
                /* Set up VOL callback arguments */
291
0
                vol_cb_args.op_type                 = H5VL_FILE_GET_CONT_INFO;
292
0
                vol_cb_args.args.get_cont_info.info = &cont_info;
293
294
                /* Get container info */
295
0
                if (H5VL_file_get(file, &vol_cb_args, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0)
296
0
                    HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "unable to get container info");
297
298
                /* The datatype size is equal to 4 bytes for the sequence length
299
                 * plus the size of a blob id */
300
0
                dt->shared->size = 4 + cont_info.blob_id_size;
301
302
                /* Set up the function pointers to access the VL information on disk */
303
                /* VL sequences and VL strings are stored identically on disk, so use the same functions */
304
0
                dt->shared->u.vlen.cls = &H5T_vlen_disk_g;
305
306
                /* Set file ID (since this VL is on disk) */
307
0
                dt->shared->u.vlen.file = file;
308
309
                /* dt now owns a reference to file */
310
0
                if (H5T_own_vol_obj(dt, file) < 0)
311
0
                    HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "can't give ownership of VOL object");
312
0
                break;
313
0
            }
314
315
0
            case H5T_LOC_BADLOC:
316
                /* Allow undefined location. In H5Odtype.c, H5O_dtype_decode sets undefined
317
                 * location for VL type and leaves it for the caller to decide.
318
                 */
319
0
                dt->shared->u.vlen.loc = H5T_LOC_BADLOC;
320
321
                /* Reset the function pointers to access the VL information */
322
0
                dt->shared->u.vlen.cls = NULL;
323
324
                /* Reset file pointer */
325
0
                dt->shared->u.vlen.file = NULL;
326
0
                break;
327
328
0
            case H5T_LOC_MAXLOC:
329
                /* MAXLOC is invalid */
330
0
            default:
331
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_BADRANGE, FAIL, "invalid VL datatype location");
332
1
        } /* end switch */
333
334
        /* Indicate that the location changed */
335
1
        ret_value = true;
336
1
    } /* end if */
337
338
1
done:
339
1
    FUNC_LEAVE_NOAPI(ret_value)
340
1
} /* end H5T__vlen_set_loc() */
341
342
/*-------------------------------------------------------------------------
343
 * Function:  H5T__vlen_mem_seq_getlen
344
 *
345
 * Purpose: Retrieves the length of a memory based VL element.
346
 *
347
 * Return:  Non-negative on success/Negative on failure
348
 *
349
 *-------------------------------------------------------------------------
350
 */
351
static herr_t
352
H5T__vlen_mem_seq_getlen(H5VL_object_t H5_ATTR_UNUSED *file, const void *_vl, size_t *len)
353
0
{
354
0
    hvl_t vl; /* User's hvl_t information */
355
356
0
    FUNC_ENTER_PACKAGE_NOERR
357
358
0
    assert(_vl);
359
0
    assert(len);
360
361
    /* Copy to ensure correct alignment */
362
0
    H5MM_memcpy(&vl, _vl, sizeof(hvl_t));
363
364
0
    *len = vl.len;
365
366
0
    FUNC_LEAVE_NOAPI(SUCCEED)
367
0
} /* end H5T__vlen_mem_seq_getlen() */
368
369
/*-------------------------------------------------------------------------
370
 * Function:  H5T__vlen_mem_seq_getptr
371
 *
372
 * Purpose: Retrieves the pointer for a memory based VL element.
373
 *
374
 * Return:  Non-NULL on success/NULL on failure
375
 *
376
 *-------------------------------------------------------------------------
377
 */
378
static void *
379
H5T__vlen_mem_seq_getptr(void *_vl)
380
0
{
381
0
    hvl_t vl; /* User's hvl_t information */
382
383
0
    FUNC_ENTER_PACKAGE_NOERR
384
385
0
    assert(_vl);
386
387
    /* Copy to ensure correct alignment */
388
0
    H5MM_memcpy(&vl, _vl, sizeof(hvl_t));
389
390
0
    FUNC_LEAVE_NOAPI(vl.p)
391
0
} /* end H5T__vlen_mem_seq_getptr() */
392
393
/*-------------------------------------------------------------------------
394
 * Function:  H5T__vlen_mem_seq_isnull
395
 *
396
 * Purpose: Checks if a memory sequence is the "null" sequence
397
 *
398
 * Return:  Non-negative on success / Negative on failure
399
 *
400
 *-------------------------------------------------------------------------
401
 */
402
static herr_t
403
H5T__vlen_mem_seq_isnull(const H5VL_object_t H5_ATTR_UNUSED *file, void *_vl, bool *isnull)
404
0
{
405
0
    hvl_t vl; /* User's hvl_t information */
406
407
0
    FUNC_ENTER_PACKAGE_NOERR
408
409
0
    assert(_vl);
410
411
    /* Copy to ensure correct alignment */
412
0
    H5MM_memcpy(&vl, _vl, sizeof(hvl_t));
413
414
0
    *isnull = ((vl.len == 0 || vl.p == NULL) ? true : false);
415
416
0
    FUNC_LEAVE_NOAPI(SUCCEED)
417
0
} /* end H5T__vlen_mem_seq_isnull() */
418
419
/*-------------------------------------------------------------------------
420
 * Function:  H5T__vlen_mem_seq_setnull
421
 *
422
 * Purpose: Sets a VL info object in memory to the "nil" value
423
 *
424
 * Return:  Non-negative on success/Negative on failure
425
 *
426
 *-------------------------------------------------------------------------
427
 */
428
static herr_t
429
H5T__vlen_mem_seq_setnull(H5VL_object_t H5_ATTR_UNUSED *file, void *_vl, void H5_ATTR_UNUSED *_bg)
430
0
{
431
0
    hvl_t vl; /* Temporary hvl_t to use during operation */
432
433
0
    FUNC_ENTER_PACKAGE_NOERR
434
435
    /* check parameters */
436
0
    assert(_vl);
437
438
    /* Set the "nil" hvl_t */
439
0
    vl.len = 0;
440
0
    vl.p   = NULL;
441
442
    /* Set pointer in user's buffer with memcpy, to avoid alignment issues */
443
0
    H5MM_memcpy(_vl, &vl, sizeof(hvl_t));
444
445
0
    FUNC_LEAVE_NOAPI(SUCCEED)
446
0
} /* end H5T__vlen_mem_seq_setnull() */
447
448
/*-------------------------------------------------------------------------
449
 * Function:  H5T__vlen_mem_seq_read
450
 *
451
 * Purpose: "Reads" the memory based VL sequence into a buffer
452
 *
453
 * Return:  Non-negative on success/Negative on failure
454
 *
455
 *-------------------------------------------------------------------------
456
 */
457
static herr_t
458
H5T__vlen_mem_seq_read(H5VL_object_t H5_ATTR_UNUSED *file, void *_vl, void *buf, size_t len)
459
0
{
460
0
    hvl_t vl; /* User's hvl_t information */
461
462
0
    FUNC_ENTER_PACKAGE_NOERR
463
464
0
    assert(buf);
465
0
    assert(_vl);
466
467
    /* Copy to ensure correct alignment */
468
0
    H5MM_memcpy(&vl, _vl, sizeof(hvl_t));
469
0
    assert(vl.p);
470
471
0
    H5MM_memcpy(buf, vl.p, len);
472
473
0
    FUNC_LEAVE_NOAPI(SUCCEED)
474
0
} /* end H5T__vlen_mem_seq_read() */
475
476
/*-------------------------------------------------------------------------
477
 * Function:  H5T__vlen_mem_seq_write
478
 *
479
 * Purpose: "Writes" the memory based VL sequence from a buffer
480
 *
481
 * Return:  Non-negative on success/Negative on failure
482
 *
483
 *-------------------------------------------------------------------------
484
 */
485
static herr_t
486
H5T__vlen_mem_seq_write(H5VL_object_t H5_ATTR_UNUSED *file, const H5T_vlen_alloc_info_t *vl_alloc_info,
487
                        void *_vl, void *buf, void H5_ATTR_UNUSED *_bg, size_t seq_len, size_t base_size)
488
0
{
489
0
    hvl_t  vl;                  /* Temporary hvl_t to use during operation */
490
0
    herr_t ret_value = SUCCEED; /* Return value */
491
492
0
    FUNC_ENTER_PACKAGE
493
494
    /* check parameters */
495
0
    assert(_vl);
496
0
    assert(buf);
497
498
0
    if (seq_len) {
499
0
        size_t len = seq_len * base_size; /* Sequence size */
500
501
        /* Use the user's memory allocation routine if one is defined */
502
0
        if (vl_alloc_info->alloc_func != NULL) {
503
            /* Prepare & restore library for user callback */
504
0
            H5_BEFORE_USER_CB(FAIL)
505
0
                {
506
0
                    vl.p = (vl_alloc_info->alloc_func)(len, vl_alloc_info->alloc_info);
507
0
                }
508
0
            H5_AFTER_USER_CB(FAIL)
509
0
            if (NULL == vl.p)
510
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL,
511
0
                            "application memory allocation routine failed for VL data");
512
0
        }    /* end if */
513
0
        else /* Default to system malloc */
514
0
            if (NULL == (vl.p = malloc(len)))
515
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "memory allocation failed for VL data");
516
517
        /* Copy the data into the newly allocated buffer */
518
0
        H5MM_memcpy(vl.p, buf, len);
519
0
    } /* end if */
520
0
    else
521
0
        vl.p = NULL;
522
523
    /* Set the sequence length */
524
0
    vl.len = seq_len;
525
526
    /* Set pointer in user's buffer with memcpy, to avoid alignment issues */
527
0
    H5MM_memcpy(_vl, &vl, sizeof(hvl_t));
528
529
0
done:
530
0
    FUNC_LEAVE_NOAPI(ret_value)
531
0
} /* end H5T__vlen_mem_seq_write() */
532
533
/*-------------------------------------------------------------------------
534
 * Function:  H5T__vlen_mem_str_getlen
535
 *
536
 * Purpose: Retrieves the length of a memory based VL string.
537
 *
538
 * Return:  Non-negative on success/Negative on failure
539
 *
540
 *-------------------------------------------------------------------------
541
 */
542
static herr_t
543
H5T__vlen_mem_str_getlen(H5VL_object_t H5_ATTR_UNUSED *file, const void *_vl, size_t *len)
544
0
{
545
0
    const char *s = NULL; /* Pointer to the user's string information */
546
547
0
    FUNC_ENTER_PACKAGE_NOERR
548
549
0
    assert(_vl);
550
551
    /* Copy to ensure correct alignment */
552
0
    H5MM_memcpy(&s, _vl, sizeof(char *));
553
554
0
    *len = strlen(s);
555
556
0
    FUNC_LEAVE_NOAPI(SUCCEED)
557
0
} /* end H5T__vlen_mem_str_getlen() */
558
559
/*-------------------------------------------------------------------------
560
 * Function:  H5T__vlen_mem_str_getptr
561
 *
562
 * Purpose: Retrieves the pointer for a memory based VL string.
563
 *
564
 * Return:  Non-NULL on success/NULL on failure
565
 *
566
 *-------------------------------------------------------------------------
567
 */
568
static void *
569
H5T__vlen_mem_str_getptr(void *_vl)
570
0
{
571
0
    char *s = NULL; /* Pointer to the user's string information */
572
573
0
    FUNC_ENTER_PACKAGE_NOERR
574
575
0
    assert(_vl);
576
577
    /* Copy to ensure correct alignment */
578
0
    H5MM_memcpy(&s, _vl, sizeof(char *));
579
580
0
    FUNC_LEAVE_NOAPI(s)
581
0
} /* end H5T__vlen_mem_str_getptr() */
582
583
/*-------------------------------------------------------------------------
584
 * Function:  H5T__vlen_mem_str_isnull
585
 *
586
 * Purpose: Checks if a memory string is a NULL pointer
587
 *
588
 * Return:  Non-negative on success / Negative on failure
589
 *
590
 *-------------------------------------------------------------------------
591
 */
592
static herr_t
593
H5T__vlen_mem_str_isnull(const H5VL_object_t H5_ATTR_UNUSED *file, void *_vl, bool *isnull)
594
0
{
595
0
    char *s = NULL; /* Pointer to the user's string information */
596
597
0
    FUNC_ENTER_PACKAGE_NOERR
598
599
    /* Copy to ensure correct alignment */
600
0
    H5MM_memcpy(&s, _vl, sizeof(char *));
601
602
0
    *isnull = (s == NULL ? true : false);
603
604
0
    FUNC_LEAVE_NOAPI(SUCCEED)
605
0
} /* end H5T__vlen_mem_str_isnull() */
606
607
/*-------------------------------------------------------------------------
608
 * Function:  H5T__vlen_mem_str_setnull
609
 *
610
 * Purpose: Sets a VL info object in memory to the "null" value
611
 *
612
 * Return:  Non-negative on success/Negative on failure
613
 *
614
 *-------------------------------------------------------------------------
615
 */
616
static herr_t
617
H5T__vlen_mem_str_setnull(H5VL_object_t H5_ATTR_UNUSED *file, void *_vl, void H5_ATTR_UNUSED *_bg)
618
0
{
619
0
    char *t = NULL; /* Pointer to temporary buffer allocated */
620
621
0
    FUNC_ENTER_PACKAGE_NOERR
622
623
    /* Set pointer in user's buffer with memcpy, to avoid alignment issues */
624
0
    H5MM_memcpy(_vl, &t, sizeof(char *));
625
626
0
    FUNC_LEAVE_NOAPI(SUCCEED)
627
0
} /* end H5T__vlen_mem_str_setnull() */
628
629
/*-------------------------------------------------------------------------
630
 * Function:  H5T__vlen_mem_str_read
631
 *
632
 * Purpose: "Reads" the memory based VL string into a buffer
633
 *
634
 * Return:  Non-negative on success/Negative on failure
635
 *
636
 *-------------------------------------------------------------------------
637
 */
638
static herr_t
639
H5T__vlen_mem_str_read(H5VL_object_t H5_ATTR_UNUSED *file, void *_vl, void *buf, size_t len)
640
0
{
641
0
    char *s; /* Pointer to the user's string information */
642
643
0
    FUNC_ENTER_PACKAGE_NOERR
644
645
0
    if (len > 0) {
646
0
        assert(buf);
647
0
        assert(_vl);
648
649
        /* Copy to ensure correct alignment */
650
0
        H5MM_memcpy(&s, _vl, sizeof(char *));
651
0
        H5MM_memcpy(buf, s, len);
652
0
    }
653
654
0
    FUNC_LEAVE_NOAPI(SUCCEED)
655
0
} /* end H5T__vlen_mem_str_read() */
656
657
/*-------------------------------------------------------------------------
658
 * Function:  H5T__vlen_mem_str_write
659
 *
660
 * Purpose: "Writes" the memory based VL string from a buffer
661
 *
662
 * Return:  Non-negative on success/Negative on failure
663
 *
664
 *-------------------------------------------------------------------------
665
 */
666
static herr_t
667
H5T__vlen_mem_str_write(H5VL_object_t H5_ATTR_UNUSED *file, const H5T_vlen_alloc_info_t *vl_alloc_info,
668
                        void *_vl, void *buf, void H5_ATTR_UNUSED *_bg, size_t seq_len, size_t base_size)
669
0
{
670
0
    char  *t;                   /* Pointer to temporary buffer allocated */
671
0
    size_t len;                 /* Maximum length of the string to copy */
672
0
    herr_t ret_value = SUCCEED; /* Return value */
673
674
0
    FUNC_ENTER_PACKAGE
675
676
    /* check parameters */
677
0
    assert(buf);
678
679
    /* Use the user's memory allocation routine if one is defined */
680
0
    if (vl_alloc_info->alloc_func != NULL) {
681
        /* Prepare & restore library for user callback */
682
0
        H5_BEFORE_USER_CB(FAIL)
683
0
            {
684
0
                t = (vl_alloc_info->alloc_func)((seq_len + 1) * base_size, vl_alloc_info->alloc_info);
685
0
            }
686
0
        H5_AFTER_USER_CB(FAIL)
687
0
        if (NULL == t)
688
0
            HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL,
689
0
                        "application memory allocation routine failed for VL data");
690
0
    }    /* end if */
691
0
    else /* Default to system malloc */
692
0
        if (NULL == (t = (char *)malloc((seq_len + 1) * base_size)))
693
0
            HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "memory allocation failed for VL data");
694
695
    /* 'write' the string into the buffer, with memcpy() */
696
0
    len = (seq_len * base_size);
697
0
    H5MM_memcpy(t, buf, len);
698
0
    t[len] = '\0';
699
700
    /* Set pointer in user's buffer with memcpy, to avoid alignment issues */
701
0
    H5MM_memcpy(_vl, &t, sizeof(char *));
702
703
0
done:
704
0
    FUNC_LEAVE_NOAPI(ret_value)
705
0
} /* end H5T__vlen_mem_str_write() */
706
707
/*-------------------------------------------------------------------------
708
 * Function:  H5T__vlen_disk_getlen
709
 *
710
 * Purpose: Retrieves the length of a disk based VL element.
711
 *
712
 * Return:  Non-negative on success/Negative on failure
713
 *
714
 *-------------------------------------------------------------------------
715
 */
716
static herr_t
717
H5T__vlen_disk_getlen(H5VL_object_t H5_ATTR_UNUSED *file, const void *_vl, size_t *seq_len)
718
0
{
719
0
    const uint8_t *vl = (const uint8_t *)_vl; /* Pointer to the user's hvl_t information */
720
721
0
    FUNC_ENTER_PACKAGE_NOERR
722
723
    /* Check parameters */
724
0
    assert(vl);
725
0
    assert(seq_len);
726
727
    /* Get length of sequence (different from blob size) */
728
0
    UINT32DECODE(vl, *seq_len);
729
730
0
    FUNC_LEAVE_NOAPI(SUCCEED)
731
0
} /* end H5T__vlen_disk_getlen() */
732
733
/*-------------------------------------------------------------------------
734
 * Function:  H5T__vlen_disk_isnull
735
 *
736
 * Purpose: Checks if a disk VL info object is the "nil" object
737
 *
738
 * Return:  Non-negative on success / Negative on failure
739
 *
740
 *-------------------------------------------------------------------------
741
 */
742
static herr_t
743
H5T__vlen_disk_isnull(const H5VL_object_t *file, void *_vl, bool *isnull)
744
0
{
745
0
    H5VL_blob_specific_args_t vol_cb_args;                /* Arguments to VOL callback */
746
0
    uint8_t                  *vl        = (uint8_t *)_vl; /* Pointer to the user's hvl_t information */
747
0
    herr_t                    ret_value = SUCCEED;        /* Return value */
748
749
0
    FUNC_ENTER_PACKAGE
750
751
    /* Check parameters */
752
0
    assert(file);
753
0
    assert(vl);
754
0
    assert(isnull);
755
756
    /* Skip the sequence's length */
757
0
    vl += 4;
758
759
    /* Set up VOL callback arguments */
760
0
    vol_cb_args.op_type             = H5VL_BLOB_ISNULL;
761
0
    vol_cb_args.args.is_null.isnull = isnull;
762
763
    /* Check if blob ID is "nil" */
764
0
    if (H5VL_blob_specific(file, vl, &vol_cb_args) < 0)
765
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "unable to check if a blob ID is 'nil'");
766
767
0
done:
768
0
    FUNC_LEAVE_NOAPI(ret_value)
769
0
} /* end H5T__vlen_disk_isnull() */
770
771
/*-------------------------------------------------------------------------
772
 * Function:  H5T__vlen_disk_setnull
773
 *
774
 * Purpose: Sets a VL info object on disk to the "nil" value
775
 *
776
 * Return:  Non-negative on success/Negative on failure
777
 *
778
 *-------------------------------------------------------------------------
779
 */
780
static herr_t
781
H5T__vlen_disk_setnull(H5VL_object_t *file, void *_vl, void *bg)
782
0
{
783
0
    H5VL_blob_specific_args_t vol_cb_args;                /* Arguments to VOL callback */
784
0
    uint8_t                  *vl        = (uint8_t *)_vl; /* Pointer to the user's hvl_t information */
785
0
    herr_t                    ret_value = SUCCEED;        /* Return value */
786
787
0
    FUNC_ENTER_PACKAGE
788
789
    /* check parameters */
790
0
    assert(file);
791
0
    assert(vl);
792
793
    /* Free heap object for old data */
794
0
    if (bg != NULL)
795
        /* Delete sequence in destination location */
796
0
        if (H5T__vlen_disk_delete(file, bg) < 0)
797
0
            HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREMOVE, FAIL, "unable to remove background heap object");
798
799
    /* Set the length of the sequence */
800
0
    UINT32ENCODE(vl, 0);
801
802
    /* Set up VOL callback arguments */
803
0
    vol_cb_args.op_type = H5VL_BLOB_SETNULL;
804
805
    /* Set blob ID to "nil" */
806
0
    if (H5VL_blob_specific(file, vl, &vol_cb_args) < 0)
807
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "unable to set a blob ID to 'nil'");
808
809
0
done:
810
0
    FUNC_LEAVE_NOAPI(ret_value)
811
0
} /* end H5T__vlen_disk_setnull() */
812
813
/*-------------------------------------------------------------------------
814
 * Function:  H5T__vlen_disk_read
815
 *
816
 * Purpose: Reads the disk based VL element into a buffer
817
 *
818
 * Return:  Non-negative on success/Negative on failure
819
 *
820
 *-------------------------------------------------------------------------
821
 */
822
static herr_t
823
H5T__vlen_disk_read(H5VL_object_t *file, void *_vl, void *buf, size_t len)
824
0
{
825
0
    const uint8_t *vl        = (const uint8_t *)_vl; /* Pointer to the user's hvl_t information */
826
0
    herr_t         ret_value = SUCCEED;              /* Return value */
827
828
0
    FUNC_ENTER_PACKAGE
829
830
    /* Check parameters */
831
0
    assert(file);
832
0
    assert(vl);
833
0
    assert(buf);
834
835
    /* Skip the length of the sequence */
836
0
    vl += 4;
837
838
    /* Retrieve blob */
839
0
    if (H5VL_blob_get(file, vl, buf, len, NULL) < 0)
840
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "unable to get blob");
841
842
0
done:
843
0
    FUNC_LEAVE_NOAPI(ret_value)
844
0
} /* end H5T__vlen_disk_read() */
845
846
/*-------------------------------------------------------------------------
847
 * Function:  H5T__vlen_disk_write
848
 *
849
 * Purpose: Writes the disk based VL element from a buffer
850
 *
851
 * Return:  Non-negative on success/Negative on failure
852
 *
853
 *-------------------------------------------------------------------------
854
 */
855
static herr_t
856
H5T__vlen_disk_write(H5VL_object_t *file, const H5T_vlen_alloc_info_t H5_ATTR_UNUSED *vl_alloc_info,
857
                     void *_vl, void *buf, void *_bg, size_t seq_len, size_t base_size)
858
0
{
859
0
    uint8_t *vl        = (uint8_t *)_vl; /* Pointer to the user's hvl_t information */
860
0
    uint8_t *bg        = (uint8_t *)_bg; /* Pointer to the old data hvl_t */
861
0
    herr_t   ret_value = SUCCEED;        /* Return value */
862
863
0
    FUNC_ENTER_PACKAGE
864
865
    /* check parameters */
866
0
    assert(vl);
867
0
    assert(seq_len == 0 || buf);
868
0
    assert(file);
869
870
    /* Free heap object for old data, if non-NULL */
871
0
    if (bg != NULL)
872
0
        if (H5T__vlen_disk_delete(file, bg) < 0)
873
0
            HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREMOVE, FAIL, "unable to remove background heap object");
874
875
    /* Set the length of the sequence */
876
0
    UINT32ENCODE(vl, seq_len);
877
878
    /* Store blob */
879
0
    if (H5VL_blob_put(file, buf, (seq_len * base_size), vl, NULL) < 0)
880
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "unable to put blob");
881
882
0
done:
883
0
    FUNC_LEAVE_NOAPI(ret_value)
884
0
} /* end H5T__vlen_disk_write() */
885
886
/*-------------------------------------------------------------------------
887
 * Function:  H5T__vlen_disk_delete
888
 *
889
 * Purpose: Deletes a disk-based VL element
890
 *
891
 * Return:  Non-negative on success / Negative on failure
892
 *
893
 *-------------------------------------------------------------------------
894
 */
895
static herr_t
896
H5T__vlen_disk_delete(H5VL_object_t *file, void *_vl)
897
0
{
898
0
    uint8_t *vl        = (uint8_t *)_vl; /* Pointer to the user's hvl_t information */
899
0
    herr_t   ret_value = SUCCEED;        /* Return value */
900
901
0
    FUNC_ENTER_PACKAGE
902
903
    /* Check parameters */
904
0
    assert(file);
905
906
    /* Free heap object for old data */
907
0
    if (vl != NULL) {
908
0
        size_t seq_len; /* VL sequence's length */
909
910
        /* Get length of sequence */
911
0
        UINT32DECODE(vl, seq_len);
912
913
        /* Delete object, if length > 0 */
914
0
        if (seq_len > 0) {
915
0
            H5VL_blob_specific_args_t vol_cb_args; /* Arguments to VOL callback */
916
917
            /* Set up VOL callback arguments */
918
0
            vol_cb_args.op_type = H5VL_BLOB_DELETE;
919
920
0
            if (H5VL_blob_specific(file, vl, &vol_cb_args) < 0)
921
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREMOVE, FAIL, "unable to delete blob");
922
0
        } /* end if */
923
0
    }     /* end if */
924
925
0
done:
926
0
    FUNC_LEAVE_NOAPI(ret_value)
927
0
} /* end H5T__vlen_disk_delete() */
928
929
/*-------------------------------------------------------------------------
930
 * Function:    H5T__vlen_reclaim
931
 *
932
 * Purpose: Internal recursive routine to free VL datatypes
933
 *
934
 * Return:  Non-negative on success / Negative on failure
935
 *
936
 *-------------------------------------------------------------------------
937
 */
938
herr_t
939
H5T__vlen_reclaim(void *elem, const H5T_t *dt, H5T_vlen_alloc_info_t *alloc_info)
940
0
{
941
0
    unsigned    u;                   /* Local index variable */
942
0
    H5MM_free_t free_func;           /* Free function */
943
0
    void       *free_info;           /* Free info */
944
0
    herr_t      ret_value = SUCCEED; /* Return value */
945
946
0
    FUNC_ENTER_PACKAGE
947
948
    /* Sanity checks */
949
0
    assert(elem);
950
0
    assert(dt);
951
0
    assert(alloc_info);
952
953
0
    free_func = alloc_info->free_func;
954
0
    free_info = alloc_info->free_info;
955
956
    /* Check the datatype of this element */
957
0
    switch (dt->shared->type) {
958
0
        case H5T_ARRAY:
959
            /* Recurse on each element, if the array's base type is array, VL, enum or compound */
960
0
            if (H5T_IS_COMPOSITE(dt->shared->parent->shared->type)) {
961
0
                void *off; /* offset of field */
962
963
                /* Calculate the offset member and recurse on it */
964
0
                for (u = 0; u < dt->shared->u.array.nelem; u++) {
965
0
                    off = ((uint8_t *)elem) + u * (dt->shared->parent->shared->size);
966
0
                    if (H5T_reclaim_cb(off, dt->shared->parent, 0, NULL, alloc_info) < 0)
967
0
                        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "unable to free array element");
968
0
                } /* end for */
969
0
            }     /* end if */
970
0
            break;
971
972
0
        case H5T_COMPOUND:
973
            /* Check each field and recurse on VL, compound, enum or array ones */
974
0
            for (u = 0; u < dt->shared->u.compnd.nmembs; u++) {
975
                /* Recurse if it's VL, compound, enum or array */
976
0
                if (H5T_IS_COMPOSITE(dt->shared->u.compnd.memb[u].type->shared->type)) {
977
0
                    void *off; /* offset of field */
978
979
                    /* Calculate the offset member and recurse on it */
980
0
                    off = ((uint8_t *)elem) + dt->shared->u.compnd.memb[u].offset;
981
0
                    if (H5T_reclaim_cb(off, dt->shared->u.compnd.memb[u].type, 0, NULL, alloc_info) < 0)
982
0
                        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "unable to free compound field");
983
0
                } /* end if */
984
0
            }     /* end for */
985
0
            break;
986
987
0
        case H5T_VLEN:
988
            /* Recurse on the VL information if it's VL, compound, enum or array, then free VL sequence */
989
0
            if (dt->shared->u.vlen.type == H5T_VLEN_SEQUENCE) {
990
0
                hvl_t *vl = (hvl_t *)elem; /* Temp. ptr to the vl info */
991
992
                /* Check if there is anything actually in this sequence */
993
0
                if (vl->len != 0) {
994
                    /* Recurse if it's VL, array, enum or compound */
995
0
                    if (H5T_IS_COMPOSITE(dt->shared->parent->shared->type)) {
996
0
                        void *off; /* offset of field */
997
998
                        /* Calculate the offset of each array element and recurse on it */
999
0
                        while (vl->len > 0) {
1000
0
                            off = ((uint8_t *)vl->p) + (vl->len - 1) * dt->shared->parent->shared->size;
1001
0
                            if (H5T_reclaim_cb(off, dt->shared->parent, 0, NULL, alloc_info) < 0)
1002
0
                                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "unable to free VL element");
1003
0
                            vl->len--;
1004
0
                        } /* end while */
1005
0
                    }     /* end if */
1006
1007
                    /* Free the VL sequence */
1008
0
                    if (free_func != NULL)
1009
0
                        (*free_func)(vl->p, free_info);
1010
0
                    else
1011
0
                        free(vl->p);
1012
0
                } /* end if */
1013
0
            }
1014
0
            else if (dt->shared->u.vlen.type == H5T_VLEN_STRING) {
1015
                /* Free the VL string */
1016
0
                if (free_func != NULL)
1017
0
                    (*free_func)(*(char **)elem, free_info);
1018
0
                else
1019
0
                    free(*(char **)elem);
1020
0
            }
1021
0
            else {
1022
0
                assert(0 && "Invalid VL type");
1023
0
            } /* end else */
1024
0
            break;
1025
1026
        /* Don't do anything for simple types */
1027
0
        case H5T_INTEGER:
1028
0
        case H5T_FLOAT:
1029
0
        case H5T_TIME:
1030
0
        case H5T_STRING:
1031
0
        case H5T_BITFIELD:
1032
0
        case H5T_OPAQUE:
1033
0
        case H5T_ENUM:
1034
0
        case H5T_COMPLEX:
1035
0
            break;
1036
1037
        /* Should never have these values */
1038
0
        case H5T_REFERENCE:
1039
0
        case H5T_NO_CLASS:
1040
0
        case H5T_NCLASSES:
1041
0
        default:
1042
0
            HGOTO_ERROR(H5E_DATATYPE, H5E_BADRANGE, FAIL, "invalid VL datatype class");
1043
0
            break;
1044
1045
0
    } /* end switch */
1046
1047
0
done:
1048
0
    FUNC_LEAVE_NOAPI(ret_value)
1049
0
} /* end H5T__vlen_reclaim() */
1050
1051
/*-------------------------------------------------------------------------
1052
 * Function:  H5T_vlen_reclaim_elmt
1053
 *
1054
 * Purpose: Alternative method to reclaim any VL data for a buffer element.
1055
 *
1056
 *          Use this function when the datatype is already available, but
1057
 *          the allocation info is needed from the context before jumping
1058
 *          into recursion.
1059
 *
1060
 * Return:  Non-negative on success/Negative on failure
1061
 *
1062
 *-------------------------------------------------------------------------
1063
 */
1064
herr_t
1065
H5T_vlen_reclaim_elmt(void *elem, const H5T_t *dt)
1066
0
{
1067
0
    H5T_vlen_alloc_info_t vl_alloc_info;       /* VL allocation info */
1068
0
    herr_t                ret_value = SUCCEED; /* return value */
1069
1070
0
    assert(dt);
1071
0
    assert(elem);
1072
1073
0
    FUNC_ENTER_NOAPI(FAIL)
1074
1075
    /* Get VL allocation info */
1076
0
    if (H5CX_get_vlen_alloc_info(&vl_alloc_info) < 0)
1077
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "unable to retrieve VL allocation info");
1078
1079
    /* Recurse on buffer to free dynamic fields */
1080
0
    if (H5T__vlen_reclaim(elem, dt, &vl_alloc_info) < 0)
1081
0
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "can't reclaim vlen elements");
1082
1083
0
done:
1084
0
    FUNC_LEAVE_NOAPI(ret_value)
1085
0
} /* H5T_vlen_reclaim_elmt() */