Coverage Report

Created: 2026-06-10 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/c-blosc2/blosc/blosc-private.h
Line
Count
Source
1
/*********************************************************************
2
  Blosc - Blocked Shuffling and Compression Library
3
4
  Copyright (c) 2021  Blosc Development Team <blosc@blosc.org>
5
  https://blosc.org
6
  License: BSD 3-Clause (see LICENSE.txt)
7
8
  See LICENSE.txt for details about copyright and rights to use.
9
**********************************************************************/
10
11
12
#ifndef BLOSC_BLOSC_PRIVATE_H
13
#define BLOSC_BLOSC_PRIVATE_H
14
15
#include "blosc2/blosc2-common.h"
16
#include "blosc2.h"
17
18
#include <stdbool.h>
19
#include <stdlib.h>
20
#include <stdint.h>
21
#include <ctype.h>
22
23
/*********************************************************************
24
25
  Utility functions meant to be used internally.
26
27
*********************************************************************/
28
29
int blosc2_decompress_block_ctx(blosc2_context* context, const void* src,
30
                                int32_t srcsize, int32_t nblock, void* dest,
31
                                int32_t destsize);
32
int blosc2_run_parallel(int16_t nthreads, void (*dojob)(void *),
33
                        size_t jobdata_elsize, void *jobdata);
34
35
0
#define to_little(dest, src, itemsize)    endian_handler(true, dest, src, itemsize)
36
#define from_little(dest, src, itemsize)  endian_handler(true, dest, src, itemsize)
37
0
#define to_big(dest, src, itemsize)       endian_handler(false, dest, src, itemsize)
38
62.8k
#define from_big(dest, src, itemsize)     endian_handler(false, dest, src, itemsize)
39
40
41
// Return true if platform is little endian; else false
42
1.56M
static bool is_little_endian(void) {
43
1.56M
  static const int i = 1;
44
1.56M
  char* p = (char*)&i;
45
46
1.56M
  if (p[0] == 1) {
47
1.56M
    return true;
48
1.56M
  }
49
0
  else {
50
0
    return false;
51
0
  }
52
1.56M
}
blosc2.c:is_little_endian
Line
Count
Source
42
1.50M
static bool is_little_endian(void) {
43
1.50M
  static const int i = 1;
44
1.50M
  char* p = (char*)&i;
45
46
1.50M
  if (p[0] == 1) {
47
1.50M
    return true;
48
1.50M
  }
49
0
  else {
50
    return false;
51
0
  }
52
1.50M
}
Unexecuted instantiation: schunk.c:is_little_endian
frame.c:is_little_endian
Line
Count
Source
42
62.8k
static bool is_little_endian(void) {
43
62.8k
  static const int i = 1;
44
62.8k
  char* p = (char*)&i;
45
46
62.8k
  if (p[0] == 1) {
47
62.8k
    return true;
48
62.8k
  }
49
0
  else {
50
    return false;
51
0
  }
52
62.8k
}
Unexecuted instantiation: codecs-registry.c:is_little_endian
Unexecuted instantiation: tuners-registry.c:is_little_endian
Unexecuted instantiation: filters-registry.c:is_little_endian
53
54
55
static inline void endian_handler(bool little, void *dest, const void *pa, int size)
56
62.8k
{
57
62.8k
  bool little_endian = is_little_endian();
58
62.8k
  if (little_endian == little) {
59
0
    memcpy(dest, pa, size);
60
0
  }
61
62.8k
  else {
62
62.8k
    uint8_t* pa_ = (uint8_t*)pa;
63
62.8k
    uint8_t pa2_[8];
64
62.8k
    switch (size) {
65
25.6k
      case 8:
66
25.6k
        pa2_[0] = pa_[7];
67
25.6k
        pa2_[1] = pa_[6];
68
25.6k
        pa2_[2] = pa_[5];
69
25.6k
        pa2_[3] = pa_[4];
70
25.6k
        pa2_[4] = pa_[3];
71
25.6k
        pa2_[5] = pa_[2];
72
25.6k
        pa2_[6] = pa_[1];
73
25.6k
        pa2_[7] = pa_[0];
74
25.6k
        break;
75
31.4k
      case 4:
76
31.4k
        pa2_[0] = pa_[3];
77
31.4k
        pa2_[1] = pa_[2];
78
31.4k
        pa2_[2] = pa_[1];
79
31.4k
        pa2_[3] = pa_[0];
80
31.4k
        break;
81
771
      case 2:
82
771
        pa2_[0] = pa_[1];
83
771
        pa2_[1] = pa_[0];
84
771
        break;
85
4.94k
      case 1:
86
4.94k
        pa2_[0] = pa_[0];
87
4.94k
        break;
88
0
      default:
89
0
        BLOSC_TRACE_ERROR("Unhandled size: %d.", size);
90
62.8k
    }
91
62.8k
    memcpy(dest, pa2_, size);
92
62.8k
  }
93
62.8k
}
Unexecuted instantiation: blosc2.c:endian_handler
Unexecuted instantiation: schunk.c:endian_handler
frame.c:endian_handler
Line
Count
Source
56
62.8k
{
57
62.8k
  bool little_endian = is_little_endian();
58
62.8k
  if (little_endian == little) {
59
0
    memcpy(dest, pa, size);
60
0
  }
61
62.8k
  else {
62
62.8k
    uint8_t* pa_ = (uint8_t*)pa;
63
62.8k
    uint8_t pa2_[8];
64
62.8k
    switch (size) {
65
25.6k
      case 8:
66
25.6k
        pa2_[0] = pa_[7];
67
25.6k
        pa2_[1] = pa_[6];
68
25.6k
        pa2_[2] = pa_[5];
69
25.6k
        pa2_[3] = pa_[4];
70
25.6k
        pa2_[4] = pa_[3];
71
25.6k
        pa2_[5] = pa_[2];
72
25.6k
        pa2_[6] = pa_[1];
73
25.6k
        pa2_[7] = pa_[0];
74
25.6k
        break;
75
31.4k
      case 4:
76
31.4k
        pa2_[0] = pa_[3];
77
31.4k
        pa2_[1] = pa_[2];
78
31.4k
        pa2_[2] = pa_[1];
79
31.4k
        pa2_[3] = pa_[0];
80
31.4k
        break;
81
771
      case 2:
82
771
        pa2_[0] = pa_[1];
83
771
        pa2_[1] = pa_[0];
84
771
        break;
85
4.94k
      case 1:
86
4.94k
        pa2_[0] = pa_[0];
87
4.94k
        break;
88
0
      default:
89
0
        BLOSC_TRACE_ERROR("Unhandled size: %d.", size);
90
62.8k
    }
91
62.8k
    memcpy(dest, pa2_, size);
92
62.8k
  }
93
62.8k
}
Unexecuted instantiation: codecs-registry.c:endian_handler
Unexecuted instantiation: tuners-registry.c:endian_handler
Unexecuted instantiation: filters-registry.c:endian_handler
94
95
/*
96
 * Convert a chunk count to the serialized offsets payload size.
97
 *
98
 * Security rationale: frame metadata can be attacker-controlled, and the offsets payload
99
 * eventually flows into APIs that accept int32 byte lengths. This helper enforces a
100
 * single overflow-checked conversion so callers cannot accidentally truncate
101
 * nchunks * sizeof(int64_t) into a smaller signed length.
102
 */
103
15.8k
static inline bool blosc2_nchunks_to_offsets_nbytes(int64_t nchunks, int32_t *off_nbytes) {
104
15.8k
  const int64_t max_nchunks = INT32_MAX / (int64_t)sizeof(int64_t);
105
15.8k
  if (nchunks < 0 || nchunks > max_nchunks) {
106
5
    return false;
107
5
  }
108
15.8k
  if (off_nbytes != NULL) {
109
15.8k
    *off_nbytes = (int32_t)(nchunks * (int64_t)sizeof(int64_t));
110
15.8k
  }
111
15.8k
  return true;
112
15.8k
}
Unexecuted instantiation: blosc2.c:blosc2_nchunks_to_offsets_nbytes
Unexecuted instantiation: schunk.c:blosc2_nchunks_to_offsets_nbytes
frame.c:blosc2_nchunks_to_offsets_nbytes
Line
Count
Source
103
15.8k
static inline bool blosc2_nchunks_to_offsets_nbytes(int64_t nchunks, int32_t *off_nbytes) {
104
15.8k
  const int64_t max_nchunks = INT32_MAX / (int64_t)sizeof(int64_t);
105
15.8k
  if (nchunks < 0 || nchunks > max_nchunks) {
106
5
    return false;
107
5
  }
108
15.8k
  if (off_nbytes != NULL) {
109
15.8k
    *off_nbytes = (int32_t)(nchunks * (int64_t)sizeof(int64_t));
110
15.8k
  }
111
  return true;
112
15.8k
}
Unexecuted instantiation: codecs-registry.c:blosc2_nchunks_to_offsets_nbytes
Unexecuted instantiation: tuners-registry.c:blosc2_nchunks_to_offsets_nbytes
Unexecuted instantiation: filters-registry.c:blosc2_nchunks_to_offsets_nbytes
113
114
/* Copy 4 bytes from @p *pa to int32_t, changing endianness if necessary. */
115
153k
static inline int32_t sw32_(const void* pa) {
116
153k
  int32_t idest;
117
118
153k
  bool little_endian = is_little_endian();
119
153k
  if (little_endian) {
120
153k
    memcpy(&idest, pa, sizeof(idest));
121
153k
  }
122
0
  else {
123
0
#if defined (__GNUC__)
124
0
    return __builtin_bswap32(*(unsigned int *)pa);
125
#elif defined (_MSC_VER) /* Visual Studio */
126
    return _byteswap_ulong(*(unsigned int *)pa);
127
#else
128
    const uint8_t *pa_ = (const uint8_t *)pa;
129
    uint8_t *dest = (uint8_t *)&idest;
130
    dest[0] = pa_[3];
131
    dest[1] = pa_[2];
132
    dest[2] = pa_[1];
133
    dest[3] = pa_[0];
134
#endif
135
0
  }
136
153k
  return idest;
137
153k
}
blosc2.c:sw32_
Line
Count
Source
115
153k
static inline int32_t sw32_(const void* pa) {
116
153k
  int32_t idest;
117
118
153k
  bool little_endian = is_little_endian();
119
153k
  if (little_endian) {
120
153k
    memcpy(&idest, pa, sizeof(idest));
121
153k
  }
122
0
  else {
123
0
#if defined (__GNUC__)
124
0
    return __builtin_bswap32(*(unsigned int *)pa);
125
#elif defined (_MSC_VER) /* Visual Studio */
126
    return _byteswap_ulong(*(unsigned int *)pa);
127
#else
128
    const uint8_t *pa_ = (const uint8_t *)pa;
129
    uint8_t *dest = (uint8_t *)&idest;
130
    dest[0] = pa_[3];
131
    dest[1] = pa_[2];
132
    dest[2] = pa_[1];
133
    dest[3] = pa_[0];
134
#endif
135
0
  }
136
153k
  return idest;
137
153k
}
Unexecuted instantiation: schunk.c:sw32_
Unexecuted instantiation: frame.c:sw32_
Unexecuted instantiation: codecs-registry.c:sw32_
Unexecuted instantiation: tuners-registry.c:sw32_
Unexecuted instantiation: filters-registry.c:sw32_
138
139
/* Copy 4 bytes from int32_t to @p *dest, changing endianness if necessary. */
140
827k
static inline void _sw32(void* dest, int32_t a) {
141
827k
  uint8_t* dest_ = (uint8_t*)dest;
142
827k
  uint8_t* pa = (uint8_t*)&a;
143
144
827k
  bool little_endian = is_little_endian();
145
827k
  if (little_endian) {
146
827k
    memcpy(dest_, &a, sizeof(a));;
147
827k
  }
148
0
  else {
149
0
#if defined (__GNUC__)
150
0
    *(int32_t *)dest_ = __builtin_bswap32(*(unsigned int *)pa);
151
#elif defined (_MSC_VER) /* Visual Studio */
152
    *(int32_t *)dest_ = _byteswap_ulong(*(unsigned int *)pa);
153
#else
154
    dest_[0] = pa[3];
155
    dest_[1] = pa[2];
156
    dest_[2] = pa[1];
157
    dest_[3] = pa[0];
158
#endif
159
0
  }
160
827k
}
blosc2.c:_sw32
Line
Count
Source
140
827k
static inline void _sw32(void* dest, int32_t a) {
141
827k
  uint8_t* dest_ = (uint8_t*)dest;
142
827k
  uint8_t* pa = (uint8_t*)&a;
143
144
827k
  bool little_endian = is_little_endian();
145
827k
  if (little_endian) {
146
827k
    memcpy(dest_, &a, sizeof(a));;
147
827k
  }
148
0
  else {
149
0
#if defined (__GNUC__)
150
0
    *(int32_t *)dest_ = __builtin_bswap32(*(unsigned int *)pa);
151
#elif defined (_MSC_VER) /* Visual Studio */
152
    *(int32_t *)dest_ = _byteswap_ulong(*(unsigned int *)pa);
153
#else
154
    dest_[0] = pa[3];
155
    dest_[1] = pa[2];
156
    dest_[2] = pa[1];
157
    dest_[3] = pa[0];
158
#endif
159
0
  }
160
827k
}
Unexecuted instantiation: schunk.c:_sw32
Unexecuted instantiation: frame.c:_sw32
Unexecuted instantiation: codecs-registry.c:_sw32
Unexecuted instantiation: tuners-registry.c:_sw32
Unexecuted instantiation: filters-registry.c:_sw32
161
162
/* Reverse swap bits in a 32-bit integer */
163
0
static inline int32_t bswap32_(int32_t a) {
164
0
#if defined (__GNUC__)
165
0
  return __builtin_bswap32(a);
166
167
#elif defined (_MSC_VER) /* Visual Studio */
168
  return _byteswap_ulong(a);
169
#else
170
  a = ((a & 0x000000FF) << 24) |
171
      ((a & 0x0000FF00) <<  8) |
172
      ((a & 0x00FF0000) >>  8) |
173
      ((a & 0xFF000000) >> 24);
174
  return a;
175
#endif
176
0
}
Unexecuted instantiation: blosc2.c:bswap32_
Unexecuted instantiation: schunk.c:bswap32_
Unexecuted instantiation: frame.c:bswap32_
Unexecuted instantiation: codecs-registry.c:bswap32_
Unexecuted instantiation: tuners-registry.c:bswap32_
Unexecuted instantiation: filters-registry.c:bswap32_
177
178
/**
179
 * @brief Register a filter in Blosc.
180
 *
181
 * @param filter The filter to register.
182
 *
183
 * @return 0 if succeeds. Else a negative code is returned.
184
 */
185
int register_filter_private(blosc2_filter *filter);
186
187
/**
188
 * @brief Register a codec in Blosc.
189
 *
190
 * @param codec The codec to register.
191
 *
192
 * @return 0 if succeeds. Else a negative code is returned.
193
 */
194
int register_codec_private(blosc2_codec *codec);
195
196
197
/**
198
 * @brief Register a tune in Blosc.
199
 *
200
 * @param tune The tune to register.
201
 *
202
 * @return 0 if succeeds. Else a negative code is returned.
203
 */
204
int register_tuner_private(blosc2_tuner *tuner);
205
206
int fill_tuner(blosc2_tuner *tuner);
207
208
extern blosc2_tuner g_tuners[256];
209
extern int g_ntuners;
210
211
212
#if defined(_WIN32)
213
#include <windows.h>
214
#ifndef PATH_MAX
215
#define PATH_MAX MAX_PATH
216
#endif
217
#define RTLD_LAZY   0x000
218
#define popen _popen
219
#define pclose _pclose
220
221
static struct {
222
    long lasterror;
223
    const char *err_rutin;
224
}
225
var = {
226
    0,
227
    NULL
228
};
229
230
static inline void *dlopen (const char *filename, int flags) {
231
  BLOSC_UNUSED_PARAM(flags);
232
  HINSTANCE hInst;
233
  hInst = LoadLibrary(filename);
234
  if (hInst==NULL) {
235
    var.lasterror = GetLastError();
236
    var.err_rutin = "dlopen";
237
  }
238
239
  return hInst;
240
}
241
242
static inline void *dlsym(void *handle, const char *name) {
243
  FARPROC fp;
244
  fp = GetProcAddress((HINSTANCE)handle, name);
245
  if (!fp) {
246
    var.lasterror = GetLastError ();
247
    var.err_rutin = "dlsym";
248
  }
249
  return (void *)(intptr_t)fp;
250
}
251
252
static inline int dlclose(void *handle) {
253
  bool ok = FreeLibrary((HINSTANCE)handle);
254
  if (!ok) {
255
    var.lasterror = GetLastError();
256
    var.err_rutin = "dlclose";
257
    return BLOSC2_ERROR_FAILURE;
258
  }
259
  return BLOSC2_ERROR_SUCCESS;
260
}
261
262
static inline const char *dlerror (void) {
263
  static char errstr [88];
264
  if (var.lasterror) {
265
      snprintf(errstr, sizeof(errstr), "%s error #%ld", var.err_rutin, var.lasterror);
266
      return errstr;
267
  } else {
268
      return NULL;
269
  }
270
}
271
#else
272
#include <dlfcn.h>
273
#endif
274
275
15
static inline bool blosc2_valid_plugin_name(const char *plugin_name) {
276
15
  if (plugin_name == NULL || plugin_name[0] == '\0') {
277
0
    return false;
278
0
  }
279
93
  for (const unsigned char *p = (const unsigned char *)plugin_name; *p != '\0'; ++p) {
280
78
    if (!isalnum(*p) && *p != '_') {
281
0
      return false;
282
0
    }
283
78
  }
284
15
  return true;
285
15
}
blosc2.c:blosc2_valid_plugin_name
Line
Count
Source
275
15
static inline bool blosc2_valid_plugin_name(const char *plugin_name) {
276
15
  if (plugin_name == NULL || plugin_name[0] == '\0') {
277
0
    return false;
278
0
  }
279
93
  for (const unsigned char *p = (const unsigned char *)plugin_name; *p != '\0'; ++p) {
280
78
    if (!isalnum(*p) && *p != '_') {
281
0
      return false;
282
0
    }
283
78
  }
284
15
  return true;
285
15
}
Unexecuted instantiation: schunk.c:blosc2_valid_plugin_name
Unexecuted instantiation: frame.c:blosc2_valid_plugin_name
Unexecuted instantiation: codecs-registry.c:blosc2_valid_plugin_name
Unexecuted instantiation: tuners-registry.c:blosc2_valid_plugin_name
Unexecuted instantiation: filters-registry.c:blosc2_valid_plugin_name
286
287
288
10
static inline int get_libpath(char *plugin_name, char *libpath, char *python_version) {
289
10
  BLOSC_TRACE_INFO("Trying to get plugin path with python%s\n", python_version);
290
10
  char python_cmd[PATH_MAX] = {0};
291
10
  if (!blosc2_valid_plugin_name(plugin_name)) {
292
0
    BLOSC_TRACE_ERROR("Invalid plugin name");
293
0
    return BLOSC2_ERROR_INVALID_PARAM;
294
0
  }
295
10
  int written = snprintf(python_cmd, sizeof(python_cmd),
296
10
                         "python%s -c \"import blosc2_%s; blosc2_%s.print_libpath()\"",
297
10
                         python_version, plugin_name, plugin_name);
298
10
  if (written < 0 || (size_t)written >= sizeof(python_cmd)) {
299
0
    BLOSC_TRACE_ERROR("Python command is too long");
300
0
    return BLOSC2_ERROR_FAILURE;
301
0
  }
302
10
  FILE *fp = popen(python_cmd, "r");
303
10
  if (fp == NULL) {
304
0
    BLOSC_TRACE_ERROR("Could not run python");
305
0
    return BLOSC2_ERROR_FAILURE;
306
0
  }
307
10
  if (fgets(libpath, PATH_MAX, fp) == NULL) {
308
10
    BLOSC_TRACE_ERROR("Could not read python output");
309
10
    pclose(fp);
310
10
    return BLOSC2_ERROR_FAILURE;
311
10
  }
312
0
  pclose(fp);
313
314
0
  return BLOSC2_ERROR_SUCCESS;
315
10
}
blosc2.c:get_libpath
Line
Count
Source
288
10
static inline int get_libpath(char *plugin_name, char *libpath, char *python_version) {
289
10
  BLOSC_TRACE_INFO("Trying to get plugin path with python%s\n", python_version);
290
10
  char python_cmd[PATH_MAX] = {0};
291
10
  if (!blosc2_valid_plugin_name(plugin_name)) {
292
0
    BLOSC_TRACE_ERROR("Invalid plugin name");
293
0
    return BLOSC2_ERROR_INVALID_PARAM;
294
0
  }
295
10
  int written = snprintf(python_cmd, sizeof(python_cmd),
296
10
                         "python%s -c \"import blosc2_%s; blosc2_%s.print_libpath()\"",
297
10
                         python_version, plugin_name, plugin_name);
298
10
  if (written < 0 || (size_t)written >= sizeof(python_cmd)) {
299
0
    BLOSC_TRACE_ERROR("Python command is too long");
300
0
    return BLOSC2_ERROR_FAILURE;
301
0
  }
302
10
  FILE *fp = popen(python_cmd, "r");
303
10
  if (fp == NULL) {
304
0
    BLOSC_TRACE_ERROR("Could not run python");
305
0
    return BLOSC2_ERROR_FAILURE;
306
0
  }
307
10
  if (fgets(libpath, PATH_MAX, fp) == NULL) {
308
10
    BLOSC_TRACE_ERROR("Could not read python output");
309
10
    pclose(fp);
310
10
    return BLOSC2_ERROR_FAILURE;
311
10
  }
312
0
  pclose(fp);
313
314
0
  return BLOSC2_ERROR_SUCCESS;
315
10
}
Unexecuted instantiation: schunk.c:get_libpath
Unexecuted instantiation: frame.c:get_libpath
Unexecuted instantiation: codecs-registry.c:get_libpath
Unexecuted instantiation: tuners-registry.c:get_libpath
Unexecuted instantiation: filters-registry.c:get_libpath
316
317
5
static inline void* load_lib(char *plugin_name, char *libpath) {
318
5
  if (!blosc2_valid_plugin_name(plugin_name)) {
319
0
    BLOSC_TRACE_ERROR("Invalid plugin name");
320
0
    return NULL;
321
0
  }
322
    // Attempt to directly load the library by name
323
#if defined(_WIN32)
324
    // Windows dynamic library (DLL) format
325
    snprintf(libpath, PATH_MAX, "blosc2_%s.dll", plugin_name);
326
#else
327
    // Unix/Linux/Mac OS dynamic library (.so) format
328
5
    snprintf(libpath, PATH_MAX, "libblosc2_%s.so", plugin_name);
329
5
#endif
330
5
    void* loaded_lib = dlopen(libpath, RTLD_LAZY);
331
5
    if (loaded_lib != NULL) {
332
0
        BLOSC_TRACE_INFO("Successfully loaded %s directly\n", libpath);
333
0
        return loaded_lib;
334
5
    } else {
335
#if defined(_WIN32)
336
        BLOSC_TRACE_INFO("Failed to load %s directly, error: %lu\n", libpath, GetLastError());
337
#else
338
5
        BLOSC_TRACE_INFO("Failed to load %s directly, error: %s\n", libpath, dlerror());
339
5
#endif
340
5
    }
341
    // If direct loading fails, fallback to using Python to find the library path
342
5
    if (get_libpath(plugin_name, libpath, "") < 0 && get_libpath(plugin_name, libpath, "3") < 0) {
343
5
        BLOSC_TRACE_ERROR("Problems when running python or python3 for getting plugin path");
344
5
        return NULL;
345
5
    }
346
347
0
    if (strlen(libpath) == 0) {
348
0
        BLOSC_TRACE_ERROR("Could not find plugin libpath");
349
0
        return NULL;
350
0
    }
351
352
    // Try to load the library again with the path from Python
353
0
    loaded_lib = dlopen(libpath, RTLD_LAZY);
354
0
    if (loaded_lib == NULL) {
355
0
        BLOSC_TRACE_ERROR("Attempt to load plugin in path '%s' failed with error: %s", libpath, dlerror());
356
0
    } else {
357
0
        BLOSC_TRACE_INFO("Successfully loaded library with Python path: %s\n", libpath);
358
0
    }
359
360
0
    return loaded_lib;
361
0
}
blosc2.c:load_lib
Line
Count
Source
317
5
static inline void* load_lib(char *plugin_name, char *libpath) {
318
5
  if (!blosc2_valid_plugin_name(plugin_name)) {
319
0
    BLOSC_TRACE_ERROR("Invalid plugin name");
320
0
    return NULL;
321
0
  }
322
    // Attempt to directly load the library by name
323
#if defined(_WIN32)
324
    // Windows dynamic library (DLL) format
325
    snprintf(libpath, PATH_MAX, "blosc2_%s.dll", plugin_name);
326
#else
327
    // Unix/Linux/Mac OS dynamic library (.so) format
328
5
    snprintf(libpath, PATH_MAX, "libblosc2_%s.so", plugin_name);
329
5
#endif
330
5
    void* loaded_lib = dlopen(libpath, RTLD_LAZY);
331
5
    if (loaded_lib != NULL) {
332
0
        BLOSC_TRACE_INFO("Successfully loaded %s directly\n", libpath);
333
0
        return loaded_lib;
334
5
    } else {
335
#if defined(_WIN32)
336
        BLOSC_TRACE_INFO("Failed to load %s directly, error: %lu\n", libpath, GetLastError());
337
#else
338
5
        BLOSC_TRACE_INFO("Failed to load %s directly, error: %s\n", libpath, dlerror());
339
5
#endif
340
5
    }
341
    // If direct loading fails, fallback to using Python to find the library path
342
5
    if (get_libpath(plugin_name, libpath, "") < 0 && get_libpath(plugin_name, libpath, "3") < 0) {
343
5
        BLOSC_TRACE_ERROR("Problems when running python or python3 for getting plugin path");
344
5
        return NULL;
345
5
    }
346
347
0
    if (strlen(libpath) == 0) {
348
0
        BLOSC_TRACE_ERROR("Could not find plugin libpath");
349
0
        return NULL;
350
0
    }
351
352
    // Try to load the library again with the path from Python
353
0
    loaded_lib = dlopen(libpath, RTLD_LAZY);
354
0
    if (loaded_lib == NULL) {
355
0
        BLOSC_TRACE_ERROR("Attempt to load plugin in path '%s' failed with error: %s", libpath, dlerror());
356
0
    } else {
357
0
        BLOSC_TRACE_INFO("Successfully loaded library with Python path: %s\n", libpath);
358
0
    }
359
360
0
    return loaded_lib;
361
0
}
Unexecuted instantiation: schunk.c:load_lib
Unexecuted instantiation: frame.c:load_lib
Unexecuted instantiation: codecs-registry.c:load_lib
Unexecuted instantiation: tuners-registry.c:load_lib
Unexecuted instantiation: filters-registry.c:load_lib
362
363
364
#endif /* BLOSC_BLOSC_PRIVATE_H */