Coverage Report

Created: 2024-06-18 06:29

/src/matio/src/mat.c
Line
Count
Source (jump to first uncovered line)
1
/** @file mat.c
2
 * Matlab MAT file functions
3
 * @ingroup MAT
4
 */
5
/*
6
 * Copyright (c) 2015-2024, The matio contributors
7
 * Copyright (c) 2005-2014, Christopher C. Hulbert
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions are met:
12
 *
13
 * 1. Redistributions of source code must retain the above copyright notice, this
14
 *    list of conditions and the following disclaimer.
15
 *
16
 * 2. Redistributions in binary form must reproduce the above copyright notice,
17
 *    this list of conditions and the following disclaimer in the documentation
18
 *    and/or other materials provided with the distribution.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
 */
31
32
/* FIXME: Implement Unicode support */
33
#include "matio_private.h"
34
#include "mat5.h"
35
#include "mat4.h"
36
#if defined(MAT73) && MAT73
37
#include "mat73.h"
38
#endif
39
#include "safe-math.h"
40
#include <stdlib.h>
41
#include <string.h>
42
#include <stdio.h>
43
#include <math.h>
44
#include <time.h>
45
#if HAVE_INTTYPES_H
46
#define __STDC_FORMAT_MACROS
47
#include <inttypes.h>
48
#endif
49
#if ( defined(_WIN64) || defined(_WIN32) ) && !defined(__CYGWIN__)
50
#include <io.h>
51
#endif
52
#if defined(_MSC_VER) || defined(__MINGW32__)
53
#define SIZE_T_FMTSTR "Iu"
54
#define strdup _strdup
55
#else
56
7.97k
#define SIZE_T_FMTSTR "zu"
57
#endif
58
59
/*
60
 *===================================================================
61
 *                 Private Functions
62
 *===================================================================
63
 */
64
65
0
#define MAT_MKTEMP_DIR "/tmp/"
66
0
#define MAT_MKTEMP_TPL "XXXXXX"
67
0
#define MAT_MKTEMP_FILE "/temp.mat"
68
69
#define MAT_MKTEMP_BUF_SIZE \
70
0
    (sizeof(MAT_MKTEMP_DIR) + sizeof(MAT_MKTEMP_TPL) + sizeof(MAT_MKTEMP_FILE) - 2)
71
72
static char *
73
Mat_mktemp(char *path_buf, char *dir_buf)
74
0
{
75
0
    char *ret = NULL;
76
77
0
    *path_buf = '\0';
78
0
    *dir_buf = '\0';
79
80
#if ( defined(_WIN64) || defined(_WIN32) ) && !defined(__CYGWIN__)
81
    strncpy(path_buf, MAT_MKTEMP_TPL, MAT_MKTEMP_BUF_SIZE - 1);
82
    path_buf[MAT_MKTEMP_BUF_SIZE - 1] = '\0';
83
    if ( NULL != _mktemp(path_buf) )
84
        ret = path_buf;
85
#else
86
    /* On Linux, using mktemp() causes annoying linker errors that can't be
87
       suppressed. So, create a temporary directory with mkdtemp() instead,
88
       and then just always use the same hardcoded filename inside that temp dir.
89
     */
90
0
    strncpy(dir_buf, MAT_MKTEMP_DIR MAT_MKTEMP_TPL, MAT_MKTEMP_BUF_SIZE - 1);
91
0
    dir_buf[MAT_MKTEMP_BUF_SIZE - 1] = '\0';
92
0
    if ( NULL != mkdtemp(dir_buf) ) {
93
0
        strncpy(path_buf, dir_buf, MAT_MKTEMP_BUF_SIZE - 1);
94
0
        path_buf[MAT_MKTEMP_BUF_SIZE - 1] = '\0';
95
0
        strncat(path_buf, MAT_MKTEMP_FILE, MAT_MKTEMP_BUF_SIZE - strlen(path_buf) - 1);
96
0
        ret = path_buf;
97
0
    }
98
0
#endif
99
100
0
    return ret;
101
0
}
102
103
static int
104
ReadData(mat_t *mat, matvar_t *matvar)
105
1.17k
{
106
1.17k
    if ( mat == NULL || matvar == NULL || mat->fp == NULL )
107
0
        return MATIO_E_BAD_ARGUMENT;
108
1.17k
    else if ( mat->version == MAT_FT_MAT5 )
109
1.15k
        return Mat_VarRead5(mat, matvar);
110
25
#if defined(MAT73) && MAT73
111
25
    else if ( mat->version == MAT_FT_MAT73 )
112
25
        return Mat_VarRead73(mat, matvar);
113
0
#endif
114
0
    else if ( mat->version == MAT_FT_MAT4 )
115
0
        return Mat_VarRead4(mat, matvar);
116
0
    return MATIO_E_FAIL_TO_IDENTIFY;
117
1.17k
}
118
119
static void
120
Mat_PrintNumber(enum matio_types type, const void *data)
121
38.5k
{
122
38.5k
    switch ( type ) {
123
4.35k
        case MAT_T_DOUBLE:
124
4.35k
            printf("%g", *(double *)data);
125
4.35k
            break;
126
570
        case MAT_T_SINGLE:
127
570
            printf("%g", *(float *)data);
128
570
            break;
129
0
#ifdef HAVE_MAT_INT64_T
130
2.77k
        case MAT_T_INT64:
131
2.77k
#if HAVE_INTTYPES_H
132
2.77k
            printf("%" PRIi64, *(mat_int64_t *)data);
133
#elif defined(_MSC_VER) && _MSC_VER >= 1200
134
            printf("%I64i", *(mat_int64_t *)data);
135
#elif defined(HAVE_LONG_LONG_INT)
136
            printf("%lld", (long long)(*(mat_int64_t *)data));
137
#else
138
            printf("%ld", (long)(*(mat_int64_t *)data));
139
#endif
140
2.77k
            break;
141
0
#endif
142
0
#ifdef HAVE_MAT_UINT64_T
143
8.10k
        case MAT_T_UINT64:
144
8.10k
#if HAVE_INTTYPES_H
145
8.10k
            printf("%" PRIu64, *(mat_uint64_t *)data);
146
#elif defined(_MSC_VER) && _MSC_VER >= 1200
147
            printf("%I64u", *(mat_uint64_t *)data);
148
#elif defined(HAVE_UNSIGNED_LONG_LONG_INT)
149
            printf("%llu", (unsigned long long)(*(mat_uint64_t *)data));
150
#else
151
            printf("%lu", (unsigned long)(*(mat_uint64_t *)data));
152
#endif
153
8.10k
            break;
154
0
#endif
155
2.70k
        case MAT_T_INT32:
156
2.70k
            printf("%d", *(mat_int32_t *)data);
157
2.70k
            break;
158
4.87k
        case MAT_T_UINT32:
159
4.87k
            printf("%u", *(mat_uint32_t *)data);
160
4.87k
            break;
161
3.60k
        case MAT_T_INT16:
162
3.60k
            printf("%hd", *(mat_int16_t *)data);
163
3.60k
            break;
164
7.05k
        case MAT_T_UINT16:
165
7.05k
            printf("%hu", *(mat_uint16_t *)data);
166
7.05k
            break;
167
450
        case MAT_T_INT8:
168
450
            printf("%hhd", *(mat_int8_t *)data);
169
450
            break;
170
4.05k
        case MAT_T_UINT8:
171
4.05k
            printf("%hhu", *(mat_uint8_t *)data);
172
4.05k
            break;
173
0
        default:
174
0
            break;
175
38.5k
    }
176
38.5k
}
177
178
mat_complex_split_t *
179
ComplexMalloc(size_t nbytes)
180
735
{
181
735
    mat_complex_split_t *complex_data = (mat_complex_split_t *)malloc(sizeof(*complex_data));
182
735
    if ( NULL != complex_data ) {
183
735
        complex_data->Re = malloc(nbytes);
184
735
        if ( NULL != complex_data->Re ) {
185
734
            complex_data->Im = malloc(nbytes);
186
734
            if ( NULL == complex_data->Im ) {
187
0
                free(complex_data->Re);
188
0
                free(complex_data);
189
0
                complex_data = NULL;
190
0
            }
191
734
        } else {
192
1
            free(complex_data);
193
1
            complex_data = NULL;
194
1
        }
195
735
    }
196
197
735
    return complex_data;
198
735
}
199
200
void
201
ComplexFree(mat_complex_split_t *complex_data)
202
897
{
203
897
    free(complex_data->Re);
204
897
    free(complex_data->Im);
205
897
    free(complex_data);
206
897
}
207
208
enum matio_types
209
ClassType2DataType(enum matio_classes class_type)
210
40
{
211
40
    switch ( class_type ) {
212
7
        case MAT_C_DOUBLE:
213
7
            return MAT_T_DOUBLE;
214
7
        case MAT_C_SINGLE:
215
7
            return MAT_T_SINGLE;
216
0
#ifdef HAVE_MAT_INT64_T
217
0
        case MAT_C_INT64:
218
0
            return MAT_T_INT64;
219
0
#endif
220
0
#ifdef HAVE_MAT_UINT64_T
221
0
        case MAT_C_UINT64:
222
0
            return MAT_T_UINT64;
223
0
#endif
224
6
        case MAT_C_INT32:
225
6
            return MAT_T_INT32;
226
0
        case MAT_C_UINT32:
227
0
            return MAT_T_UINT32;
228
4
        case MAT_C_INT16:
229
4
            return MAT_T_INT16;
230
0
        case MAT_C_UINT16:
231
0
            return MAT_T_UINT16;
232
4
        case MAT_C_INT8:
233
4
            return MAT_T_INT8;
234
0
        case MAT_C_CHAR:
235
0
            return MAT_T_UINT8;
236
0
        case MAT_C_UINT8:
237
0
            return MAT_T_UINT8;
238
9
        case MAT_C_CELL:
239
9
            return MAT_T_CELL;
240
3
        case MAT_C_STRUCT:
241
3
            return MAT_T_STRUCT;
242
0
        default:
243
0
            return MAT_T_UNKNOWN;
244
40
    }
245
40
}
246
247
/** @brief Gets number of elements from a variable
248
 *
249
 * Gets number of elements from a variable by overflow-safe
250
 * multiplication
251
 * @ingroup MAT
252
 * @param matvar MAT variable information
253
 * @param nelems Number of elements
254
 * @retval 0 on success
255
 */
256
int
257
Mat_MulDims(const matvar_t *matvar, size_t *nelems)
258
5.19k
{
259
5.19k
    int i;
260
261
5.19k
    if ( matvar->rank == 0 ) {
262
47
        *nelems = 0;
263
47
        return MATIO_E_NO_ERROR;
264
47
    }
265
266
38.5k
    for ( i = 0; i < matvar->rank; i++ ) {
267
33.3k
        if ( !psnip_safe_size_mul(nelems, *nelems, matvar->dims[i]) ) {
268
4
            *nelems = 0;
269
4
            return MATIO_E_INDEX_TOO_BIG;
270
4
        }
271
33.3k
    }
272
273
5.14k
    return MATIO_E_NO_ERROR;
274
5.14k
}
275
276
/** @brief Multiplies two unsigned integers
277
 *
278
 * @param res Result
279
 * @param a First operand
280
 * @param b Second operand
281
 * @retval 0 on success
282
 */
283
int
284
Mul(size_t *res, size_t a, size_t b)
285
1.69k
{
286
1.69k
    if ( !psnip_safe_size_mul(res, a, b) ) {
287
4
        *res = 0;
288
4
        return MATIO_E_INDEX_TOO_BIG;
289
4
    }
290
291
1.69k
    return MATIO_E_NO_ERROR;
292
1.69k
}
293
294
/** @brief Adds two unsigned integers
295
 *
296
 * @param res Result
297
 * @param a First operand
298
 * @param b Second operand
299
 * @retval 0 on success
300
 */
301
int
302
Add(size_t *res, size_t a, size_t b)
303
82
{
304
82
    if ( !psnip_safe_size_add(res, a, b) ) {
305
0
        *res = 0;
306
0
        return MATIO_E_INDEX_TOO_BIG;
307
0
    }
308
309
82
    return MATIO_E_NO_ERROR;
310
82
}
311
312
/** @brief Read from file and check success
313
 *
314
 * @param buf Buffer for reading
315
 * @param size Element size in bytes
316
 * @param count Element count
317
 * @param fp File pointer
318
 * @param[out] bytesread Number of bytes read from the file
319
 * @retval 0 on success
320
 */
321
int
322
Read(void *buf, size_t size, size_t count, FILE *fp, size_t *bytesread)
323
636k
{
324
636k
    const size_t readcount = fread(buf, size, count, fp);
325
636k
    int err = readcount != count;
326
636k
    if ( NULL != bytesread ) {
327
626k
        *bytesread += readcount * size;
328
626k
    }
329
636k
    if ( err ) {
330
232
        Mat_Warning(
331
232
            "Unexpected end-of-file: Read %zu"
332
232
            " bytes, expected %zu"
333
232
            " bytes",
334
232
            readcount * size, count * size);
335
232
        memset(buf, 0, count * size);
336
232
    }
337
636k
    return err;
338
636k
}
339
340
/** @brief Check for End of file
341
 *
342
 * @param fp File pointer
343
 * @param[out] fpos Current file position
344
 * @retval 0 on success
345
 */
346
int
347
IsEndOfFile(FILE *fp, mat_off_t *fpos)
348
3.77k
{
349
3.77k
    int isEOF = feof(fp);
350
3.77k
    mat_off_t fPos = ftello(fp);
351
3.77k
    if ( !isEOF ) {
352
3.76k
        if ( fPos == -1L ) {
353
0
            Mat_Critical("Couldn't determine file position");
354
3.76k
        } else {
355
3.76k
            (void)fseeko(fp, 0, SEEK_END);
356
3.76k
            isEOF = fPos == ftello(fp);
357
3.76k
            if ( !isEOF ) {
358
3.76k
                (void)fseeko(fp, fPos, SEEK_SET);
359
3.76k
            }
360
3.76k
        }
361
3.76k
    }
362
3.77k
    if ( NULL != fpos ) {
363
2.68k
        *fpos = fPos;
364
2.68k
    }
365
3.77k
    return isEOF;
366
3.77k
}
367
368
/** @brief Check for End of file
369
 *
370
 * @param fp File pointer
371
 * @param[out] offset Desired offset from current file position
372
 * @retval 0 on success
373
 */
374
int
375
CheckSeekFile(FILE *fp, mat_off_t offset)
376
1.04k
{
377
1.04k
    int err;
378
1.04k
    mat_off_t fPos;
379
1.04k
    uint8_t c;
380
381
1.04k
    if ( offset <= 0 ) {
382
0
        return MATIO_E_NO_ERROR;
383
0
    }
384
385
1.04k
    fPos = ftello(fp);
386
1.04k
    if ( fPos == -1L ) {
387
0
        Mat_Critical("Couldn't determine file position");
388
0
        return MATIO_E_GENERIC_READ_ERROR;
389
0
    }
390
391
1.04k
    (void)fseeko(fp, offset - 1, SEEK_CUR);
392
1.04k
    err = 1 != fread(&c, 1, 1, fp);
393
1.04k
    (void)fseeko(fp, fPos, SEEK_SET);
394
1.04k
    if ( err ) {
395
0
        Mat_Critical("Couldn't set file position");
396
0
        return MATIO_E_GENERIC_READ_ERROR;
397
0
    }
398
399
1.04k
    return MATIO_E_NO_ERROR;
400
1.04k
}
401
402
/*
403
 *===================================================================
404
 *                 Public Functions
405
 *===================================================================
406
 */
407
408
/** @brief Get the version of the library
409
 *
410
 * Gets the version number of the library
411
 * @param major Pointer to store the library major version number
412
 * @param minor Pointer to store the library minor version number
413
 * @param release Pointer to store the library release version number
414
 */
415
void
416
Mat_GetLibraryVersion(int *major, int *minor, int *release)
417
0
{
418
0
    if ( NULL != major )
419
0
        *major = MATIO_MAJOR_VERSION;
420
0
    if ( NULL != minor )
421
0
        *minor = MATIO_MINOR_VERSION;
422
0
    if ( NULL != release )
423
0
        *release = MATIO_RELEASE_LEVEL;
424
0
}
425
426
/** @brief Creates a new Matlab MAT file
427
 *
428
 * Tries to create a new Matlab MAT file with the given name and optional
429
 * header string.  If no header string is given, the default string
430
 * is used containing the software, version, and date in it.  If a header
431
 * string is given, at most the first 116 characters is written to the file.
432
 * The given header string need not be the full 116 characters, but MUST be
433
 * NULL terminated.
434
 * @ingroup MAT
435
 * @param matname Name of MAT file to create
436
 * @param hdr_str Optional header string, NULL to use default
437
 * @param mat_file_ver MAT file version to create
438
 * @return A pointer to the MAT file or NULL if it failed.  This is not a
439
 * simple FILE * and should not be used as one.
440
 */
441
mat_t *
442
Mat_CreateVer(const char *matname, const char *hdr_str, enum mat_ft mat_file_ver)
443
0
{
444
0
    mat_t *mat;
445
446
0
    switch ( mat_file_ver ) {
447
0
        case MAT_FT_MAT4:
448
0
            mat = Mat_Create4(matname);
449
0
            break;
450
0
        case MAT_FT_MAT5:
451
0
            mat = Mat_Create5(matname, hdr_str);
452
0
            break;
453
0
        case MAT_FT_MAT73:
454
0
#if defined(MAT73) && MAT73
455
0
            mat = Mat_Create73(matname, hdr_str);
456
#else
457
            mat = NULL;
458
#endif
459
0
            break;
460
0
        default:
461
0
            mat = NULL;
462
0
            break;
463
0
    }
464
465
0
    return mat;
466
0
}
467
468
/** @brief Opens an existing Matlab MAT file
469
 *
470
 * Tries to open a Matlab MAT file with the given name
471
 * @ingroup MAT
472
 * @param matname Name of MAT file to open
473
 * @param mode File access mode (MAT_ACC_RDONLY,MAT_ACC_RDWR,etc).
474
 * @return A pointer to the MAT file or NULL if it failed.  This is not a
475
 * simple FILE * and should not be used as one.
476
 */
477
mat_t *
478
Mat_Open(const char *matname, int mode)
479
70
{
480
70
    FILE *fp = NULL;
481
70
    mat_int16_t tmp, tmp2;
482
70
    mat_t *mat = NULL;
483
70
    size_t bytesread = 0;
484
485
70
    if ( (mode & 0x01) == MAT_ACC_RDONLY ) {
486
#if defined(_WIN32)
487
        wchar_t *wname = utf82u(matname);
488
        if ( NULL != wname ) {
489
            fp = _wfopen(wname, L"rb");
490
            free(wname);
491
        }
492
#else
493
70
        fp = fopen(matname, "rb");
494
70
#endif
495
70
        if ( !fp ) {
496
0
            Mat_Warning("Cannot open file \"%s\" in read-only mode", matname);
497
0
            return NULL;
498
0
        }
499
70
    } else if ( (mode & 0x01) == MAT_ACC_RDWR ) {
500
#if defined(_WIN32)
501
        wchar_t *wname = utf82u(matname);
502
        if ( NULL != wname ) {
503
            fp = _wfopen(wname, L"r+b");
504
            free(wname);
505
        }
506
#else
507
0
        fp = fopen(matname, "r+b");
508
0
#endif
509
0
        if ( !fp ) {
510
0
            mat = Mat_CreateVer(matname, NULL, (enum mat_ft)(mode & 0xfffffffe));
511
0
            return mat;
512
0
        }
513
0
    } else {
514
0
        Mat_Critical("Invalid file open mode");
515
0
        return NULL;
516
0
    }
517
518
70
    mat = (mat_t *)malloc(sizeof(*mat));
519
70
    if ( NULL == mat ) {
520
0
        fclose(fp);
521
0
        Mat_Critical("Couldn't allocate memory for the MAT file");
522
0
        return NULL;
523
0
    }
524
525
70
    mat->fp = fp;
526
70
    mat->header = (char *)calloc(128, sizeof(char));
527
70
    if ( NULL == mat->header ) {
528
0
        free(mat);
529
0
        fclose(fp);
530
0
        Mat_Critical("Couldn't allocate memory for the MAT file header");
531
0
        return NULL;
532
0
    }
533
70
    mat->subsys_offset = (char *)calloc(8, sizeof(char));
534
70
    if ( NULL == mat->subsys_offset ) {
535
0
        free(mat->header);
536
0
        free(mat);
537
0
        fclose(fp);
538
0
        Mat_Critical("Couldn't allocate memory for the MAT file subsys offset");
539
0
        return NULL;
540
0
    }
541
70
    mat->filename = NULL;
542
70
    mat->version = 0;
543
70
    mat->byteswap = 0;
544
70
    mat->num_datasets = 0;
545
70
#if defined(MAT73) && MAT73
546
70
    mat->refs_id = -1;
547
70
#endif
548
70
    mat->dir = NULL;
549
550
70
    bytesread += fread(mat->header, 1, 116, fp);
551
70
    mat->header[116] = '\0';
552
70
    bytesread += fread(mat->subsys_offset, 1, 8, fp);
553
70
    bytesread += 2 * fread(&tmp2, 2, 1, fp);
554
70
    bytesread += fread(&tmp, 1, 2, fp);
555
556
70
    if ( 128 == bytesread ) {
557
        /* v5 and v7.3 files have at least 128 byte header */
558
70
        mat->byteswap = -1;
559
70
        if ( tmp == 0x4d49 )
560
54
            mat->byteswap = 0;
561
16
        else if ( tmp == 0x494d ) {
562
16
            mat->byteswap = 1;
563
16
            Mat_int16Swap(&tmp2);
564
16
        }
565
566
70
        mat->version = (int)tmp2;
567
70
        if ( (mat->version == 0x0100 || mat->version == 0x0200) && -1 != mat->byteswap ) {
568
70
            mat->bof = ftello((FILE *)mat->fp);
569
70
            if ( mat->bof == -1L ) {
570
0
                free(mat->header);
571
0
                free(mat->subsys_offset);
572
0
                free(mat);
573
0
                fclose(fp);
574
0
                Mat_Critical("Couldn't determine file position");
575
0
                return NULL;
576
0
            }
577
70
            mat->next_index = 0;
578
70
        } else {
579
0
            mat->version = 0;
580
0
        }
581
70
    }
582
583
70
    if ( 0 == mat->version ) {
584
        /* Maybe a V4 MAT file */
585
0
        matvar_t *var;
586
587
0
        free(mat->header);
588
0
        free(mat->subsys_offset);
589
590
0
        mat->header = NULL;
591
0
        mat->subsys_offset = NULL;
592
0
        mat->fp = fp;
593
0
        mat->version = MAT_FT_MAT4;
594
0
        mat->byteswap = 0;
595
0
        mat->mode = mode;
596
0
        mat->bof = 0;
597
0
        mat->next_index = 0;
598
0
#if defined(MAT73) && MAT73
599
0
        mat->refs_id = -1;
600
0
#endif
601
602
0
        Mat_Rewind(mat);
603
0
        var = Mat_VarReadNextInfo4(mat);
604
0
        if ( NULL == var && bytesread != 0 ) { /* Accept 0 bytes files as a valid V4 file */
605
            /* Does not seem to be a valid V4 file */
606
0
            Mat_Close(mat);
607
0
            mat = NULL;
608
0
            Mat_Critical("\"%s\" does not seem to be a valid MAT file", matname);
609
0
        } else {
610
0
            Mat_VarFree(var);
611
0
            Mat_Rewind(mat);
612
0
        }
613
0
    }
614
615
70
    if ( NULL == mat )
616
0
        return mat;
617
618
70
    mat->filename = strdup(matname);
619
70
    mat->mode = mode;
620
621
70
    if ( mat->version == 0x0200 ) {
622
10
        fclose((FILE *)mat->fp);
623
10
#if defined(MAT73) && MAT73
624
10
        mat->fp = malloc(sizeof(hid_t));
625
626
10
        if ( (mode & 0x01) == MAT_ACC_RDONLY )
627
10
            *(hid_t *)mat->fp = H5Fopen(matname, H5F_ACC_RDONLY, H5P_DEFAULT);
628
0
        else if ( (mode & 0x01) == MAT_ACC_RDWR ) {
629
0
            hid_t plist_ap;
630
0
            plist_ap = H5Pcreate(H5P_FILE_ACCESS);
631
0
#if H5_VERSION_GE(1, 10, 2)
632
0
            H5Pset_libver_bounds(plist_ap, H5F_LIBVER_EARLIEST, H5F_LIBVER_V18);
633
0
#endif
634
0
            *(hid_t *)mat->fp = H5Fopen(matname, H5F_ACC_RDWR, plist_ap);
635
0
            H5Pclose(plist_ap);
636
0
        } else {
637
0
            mat->fp = NULL;
638
0
            Mat_Close(mat);
639
0
            mat = NULL;
640
0
        }
641
642
10
        if ( NULL == mat )
643
0
            return mat;
644
645
10
        if ( -1 < *(hid_t *)mat->fp ) {
646
7
            H5G_info_t group_info;
647
7
            herr_t herr;
648
7
            memset(&group_info, 0, sizeof(group_info));
649
7
            herr = H5Gget_info(*(hid_t *)mat->fp, &group_info);
650
7
            if ( herr < 0 ) {
651
1
                Mat_Close(mat);
652
1
                mat = NULL;
653
6
            } else {
654
6
                mat->num_datasets = (size_t)group_info.nlinks;
655
6
                mat->refs_id = H5I_INVALID_HID;
656
6
            }
657
7
        }
658
#else
659
        mat->fp = NULL;
660
        Mat_Close(mat);
661
        mat = NULL;
662
        Mat_Critical(
663
            "No HDF5 support which is required to read the v7.3 "
664
            "MAT file \"%s\"",
665
            matname);
666
#endif
667
10
    }
668
669
70
    return mat;
670
70
}
671
672
/** @brief Closes an open Matlab MAT file
673
 *
674
 * Closes the given Matlab MAT file and frees any memory with it.
675
 * @ingroup MAT
676
 * @param mat Pointer to the MAT file
677
 * @retval 0 on success
678
 */
679
int
680
Mat_Close(mat_t *mat)
681
70
{
682
70
    int err = MATIO_E_NO_ERROR;
683
684
70
    if ( NULL != mat ) {
685
70
#if defined(MAT73) && MAT73
686
70
        if ( mat->version == 0x0200 ) {
687
10
            err = Mat_Close73(mat);
688
10
        }
689
70
#endif
690
70
        if ( NULL != mat->fp ) {
691
60
            err = fclose((FILE *)mat->fp);
692
60
            if ( 0 == err ) {
693
60
                err = MATIO_E_NO_ERROR;
694
60
            } else {
695
0
                err = MATIO_E_FILESYSTEM_ERROR_ON_CLOSE;
696
0
            }
697
60
        }
698
70
        if ( NULL != mat->header )
699
70
            free(mat->header);
700
70
        if ( NULL != mat->subsys_offset )
701
70
            free(mat->subsys_offset);
702
70
        if ( NULL != mat->filename )
703
70
            free(mat->filename);
704
70
        if ( NULL != mat->dir ) {
705
53
            size_t i;
706
414
            for ( i = 0; i < mat->num_datasets; i++ ) {
707
361
                if ( NULL != mat->dir[i] )
708
341
                    free(mat->dir[i]);
709
361
            }
710
53
            free(mat->dir);
711
53
        }
712
70
        free(mat);
713
70
    } else {
714
0
        err = MATIO_E_BAD_ARGUMENT;
715
0
    }
716
717
70
    return err;
718
70
}
719
720
/** @brief Gets the file access mode of the given MAT file
721
 *
722
 * Gets the file access mode of the given MAT file
723
 * @ingroup MAT
724
 * @param mat Pointer to the MAT file
725
 * @return MAT file access mode
726
 */
727
enum mat_acc
728
Mat_GetFileAccessMode(const mat_t *mat)
729
69
{
730
69
    enum mat_acc mode = MAT_ACC_RDONLY;
731
69
    if ( NULL != mat && (mat->mode & 0x01) == MAT_ACC_RDWR )
732
0
        mode = MAT_ACC_RDWR;
733
69
    return mode;
734
69
}
735
736
/** @brief Gets the filename for the given MAT file
737
 *
738
 * Gets the filename for the given MAT file
739
 * @ingroup MAT
740
 * @param mat Pointer to the MAT file
741
 * @return MAT filename
742
 */
743
const char *
744
Mat_GetFilename(const mat_t *mat)
745
69
{
746
69
    const char *filename = NULL;
747
69
    if ( NULL != mat )
748
69
        filename = mat->filename;
749
69
    return filename;
750
69
}
751
752
/** @brief Gets the header for the given MAT file
753
 *
754
 * Gets the header for the given MAT file
755
 * @ingroup MAT
756
 * @param mat Pointer to the MAT file
757
 * @return MAT header
758
 */
759
const char *
760
Mat_GetHeader(const mat_t *mat)
761
69
{
762
69
    const char *header = NULL;
763
69
    if ( NULL != mat )
764
69
        header = mat->header;
765
69
    return header;
766
69
}
767
768
/** @brief Gets the version of the given MAT file
769
 *
770
 * Gets the version of the given MAT file
771
 * @ingroup MAT
772
 * @param mat Pointer to the MAT file
773
 * @return MAT file version
774
 */
775
enum mat_ft
776
Mat_GetVersion(const mat_t *mat)
777
69
{
778
69
    enum mat_ft file_type = MAT_FT_UNDEFINED;
779
69
    if ( NULL != mat )
780
69
        file_type = (enum mat_ft)mat->version;
781
69
    return file_type;
782
69
}
783
784
/** @brief Gets a list of the variables of a MAT file
785
 *
786
 * Gets a list of the variables of a MAT file
787
 * @ingroup MAT
788
 * @param mat Pointer to the MAT file
789
 * @param[out] n Number of variables in the given MAT file
790
 * @return Array of variable names
791
 */
792
char *const *
793
Mat_GetDir(mat_t *mat, size_t *n)
794
69
{
795
69
    char **dir = NULL;
796
797
69
    if ( NULL == n )
798
0
        return dir;
799
800
69
    if ( NULL == mat ) {
801
0
        *n = 0;
802
0
        return dir;
803
0
    }
804
805
69
    if ( NULL == mat->dir ) {
806
69
        if ( mat->version == MAT_FT_MAT73 ) {
807
9
#if defined(MAT73) && MAT73
808
9
            int err = Mat_CalcDir73(mat, n);
809
9
            if ( err ) {
810
2
                *n = 0;
811
2
                return dir;
812
2
            }
813
#else
814
            *n = 0;
815
#endif
816
60
        } else {
817
60
            matvar_t *matvar = NULL;
818
60
            mat_off_t fpos = ftello((FILE *)mat->fp);
819
60
            if ( fpos == -1L ) {
820
0
                *n = 0;
821
0
                Mat_Critical("Couldn't determine file position");
822
0
                return dir;
823
0
            }
824
60
            (void)fseeko((FILE *)mat->fp, mat->bof, SEEK_SET);
825
60
            mat->num_datasets = 0;
826
604
            do {
827
604
                matvar = Mat_VarReadNextInfo(mat);
828
604
                if ( NULL != matvar ) {
829
544
                    if ( NULL != matvar->name ) {
830
277
                        if ( NULL == mat->dir ) {
831
44
                            dir = (char **)malloc(sizeof(char *));
832
233
                        } else {
833
233
                            dir = (char **)realloc(mat->dir,
834
233
                                                   (mat->num_datasets + 1) * (sizeof(char *)));
835
233
                        }
836
277
                        if ( NULL != dir ) {
837
277
                            mat->dir = dir;
838
277
                            mat->dir[mat->num_datasets++] = strdup(matvar->name);
839
277
                        } else {
840
0
                            Mat_Critical("Couldn't allocate memory for the directory");
841
0
                            break;
842
0
                        }
843
277
                    }
844
544
                    Mat_VarFree(matvar);
845
544
                } else if ( !IsEndOfFile((FILE *)mat->fp, NULL) ) {
846
59
                    Mat_Critical("An error occurred in reading the MAT file");
847
59
                    break;
848
59
                }
849
604
            } while ( !IsEndOfFile((FILE *)mat->fp, NULL) );
850
0
            (void)fseeko((FILE *)mat->fp, fpos, SEEK_SET);
851
60
            *n = mat->num_datasets;
852
60
        }
853
69
    } else {
854
0
        if ( mat->version == MAT_FT_MAT73 ) {
855
0
            *n = 0;
856
0
            while ( *n < mat->num_datasets && NULL != mat->dir[*n] ) {
857
0
                (*n)++;
858
0
            }
859
0
        } else {
860
0
            *n = mat->num_datasets;
861
0
        }
862
0
    }
863
67
    dir = mat->dir;
864
67
    return dir;
865
69
}
866
867
/** @brief Rewinds a Matlab MAT file to the first variable
868
 *
869
 * Rewinds a Matlab MAT file to the first variable
870
 * @ingroup MAT
871
 * @param mat Pointer to the MAT file
872
 * @retval 0 on success
873
 */
874
int
875
Mat_Rewind(mat_t *mat)
876
138
{
877
138
    int err = MATIO_E_NO_ERROR;
878
879
138
    switch ( mat->version ) {
880
18
        case MAT_FT_MAT73:
881
18
            mat->next_index = 0;
882
18
            break;
883
0
        case MAT_FT_MAT4:
884
120
        case MAT_FT_MAT5:
885
120
            (void)fseeko((FILE *)mat->fp, mat->bof, SEEK_SET);
886
120
            break;
887
0
        default:
888
0
            err = MATIO_E_FAIL_TO_IDENTIFY;
889
0
            break;
890
138
    }
891
892
138
    return err;
893
138
}
894
895
/** @brief Returns the size of a Matlab Class
896
 *
897
 * Returns the size (in bytes) of the matlab class class_type
898
 * @ingroup MAT
899
 * @param class_type Matlab class type (MAT_C_*)
900
 * @returns Size of the class
901
 */
902
size_t
903
Mat_SizeOfClass(int class_type)
904
486
{
905
486
    switch ( class_type ) {
906
56
        case MAT_C_DOUBLE:
907
56
            return sizeof(double);
908
26
        case MAT_C_SINGLE:
909
26
            return sizeof(float);
910
0
#ifdef HAVE_MAT_INT64_T
911
59
        case MAT_C_INT64:
912
59
            return sizeof(mat_int64_t);
913
0
#endif
914
0
#ifdef HAVE_MAT_UINT64_T
915
53
        case MAT_C_UINT64:
916
53
            return sizeof(mat_uint64_t);
917
0
#endif
918
85
        case MAT_C_INT32:
919
85
            return sizeof(mat_int32_t);
920
45
        case MAT_C_UINT32:
921
45
            return sizeof(mat_uint32_t);
922
36
        case MAT_C_INT16:
923
36
            return sizeof(mat_int16_t);
924
67
        case MAT_C_UINT16:
925
67
            return sizeof(mat_uint16_t);
926
25
        case MAT_C_INT8:
927
25
            return sizeof(mat_int8_t);
928
24
        case MAT_C_UINT8:
929
24
            return sizeof(mat_uint8_t);
930
0
        case MAT_C_CHAR:
931
0
            return sizeof(mat_int16_t);
932
10
        default:
933
10
            return 0;
934
486
    }
935
486
}
936
937
/*
938
 *===================================================================
939
 *    MAT Variable Functions
940
 *===================================================================
941
 */
942
943
/** @brief Allocates memory for a new matvar_t and initializes all the fields
944
 *
945
 * @ingroup MAT
946
 * @return A newly allocated matvar_t
947
 */
948
matvar_t *
949
Mat_VarCalloc(void)
950
2.88k
{
951
2.88k
    matvar_t *matvar;
952
953
2.88k
    matvar = (matvar_t *)malloc(sizeof(*matvar));
954
955
2.88k
    if ( NULL != matvar ) {
956
2.88k
        matvar->nbytes = 0;
957
2.88k
        matvar->rank = 0;
958
2.88k
        matvar->data_type = MAT_T_UNKNOWN;
959
2.88k
        matvar->data_size = 0;
960
2.88k
        matvar->class_type = MAT_C_EMPTY;
961
2.88k
        matvar->isComplex = 0;
962
2.88k
        matvar->isGlobal = 0;
963
2.88k
        matvar->isLogical = 0;
964
2.88k
        matvar->dims = NULL;
965
2.88k
        matvar->name = NULL;
966
2.88k
        matvar->data = NULL;
967
2.88k
        matvar->mem_conserve = 0;
968
2.88k
        matvar->compression = MAT_COMPRESSION_NONE;
969
2.88k
        matvar->internal = (struct matvar_internal *)malloc(sizeof(*matvar->internal));
970
2.88k
        if ( NULL == matvar->internal ) {
971
0
            free(matvar);
972
0
            matvar = NULL;
973
2.88k
        } else {
974
2.88k
#if defined(MAT73) && MAT73
975
2.88k
            matvar->internal->hdf5_ref = 0;
976
2.88k
            matvar->internal->id = H5I_INVALID_HID;
977
2.88k
#endif
978
2.88k
            matvar->internal->datapos = 0;
979
2.88k
            matvar->internal->num_fields = 0;
980
2.88k
            matvar->internal->fieldnames = NULL;
981
2.88k
#if HAVE_ZLIB
982
2.88k
            matvar->internal->z = NULL;
983
2.88k
            matvar->internal->data = NULL;
984
2.88k
#endif
985
2.88k
        }
986
2.88k
    }
987
988
2.88k
    return matvar;
989
2.88k
}
990
991
/** @brief Creates a MAT Variable with the given name and (optionally) data
992
 *
993
 * Creates a MAT variable that can be written to a Matlab MAT file with the
994
 * given name, data type, dimensions and data.  Rank should always be 2 or more.
995
 * i.e. Scalar values would have rank=2 and dims[2] = {1,1}.  Data type is
996
 * one of the MAT_T types.  MAT adds MAT_T_STRUCT and MAT_T_CELL to create
997
 * Structures and Cell Arrays respectively.  For MAT_T_STRUCT, data should be a
998
 * NULL terminated array of matvar_t * variables (i.e. for a 3x2 structure with
999
 * 10 fields, there should be 61 matvar_t * variables where the last one is
1000
 * NULL).  For cell arrays, the NULL termination isn't necessary.  So to create
1001
 * a cell array of size 3x2, data would be the address of an array of 6
1002
 * matvar_t * variables.
1003
 *
1004
 * EXAMPLE:
1005
 *   To create a struct of size 3x2 with 3 fields:
1006
 * @code
1007
 *     int rank=2, dims[2] = {3,2}, nfields = 3;
1008
 *     matvar_t **vars;
1009
 *
1010
 *     vars = malloc((3*2*nfields+1)*sizeof(matvar_t *));
1011
 *     vars[0]             = Mat_VarCreate(...);
1012
 *        :
1013
 *     vars[3*2*nfields-1] = Mat_VarCreate(...);
1014
 *     vars[3*2*nfields]   = NULL;
1015
 * @endcode
1016
 *
1017
 * EXAMPLE:
1018
 *   To create a cell array of size 3x2:
1019
 * @code
1020
 *     int rank=2, dims[2] = {3,2};
1021
 *     matvar_t **vars;
1022
 *
1023
 *     vars = malloc(3*2*sizeof(matvar_t *));
1024
 *     vars[0]             = Mat_VarCreate(...);
1025
 *        :
1026
 *     vars[5] = Mat_VarCreate(...);
1027
 * @endcode
1028
 *
1029
 * @ingroup MAT
1030
 * @param name Name of the variable to create
1031
 * @param class_type class type of the variable in Matlab(one of the mx Classes)
1032
 * @param data_type data type of the variable (one of the MAT_T_ Types)
1033
 * @param rank Rank of the variable
1034
 * @param dims array of dimensions of the variable of size rank
1035
 * @param data pointer to the data
1036
 * @param opt 0, or bitwise or of the following options:
1037
 * - MAT_F_DONT_COPY_DATA to just use the pointer to the data and not copy the
1038
 *       data itself. Note that the pointer should not be freed until you are
1039
 *       done with the mat variable.  The Mat_VarFree function will NOT free
1040
 *       data that was created with MAT_F_DONT_COPY_DATA, so free it yourself.
1041
 * - MAT_F_COMPLEX to specify that the data is complex.  The data variable
1042
 *       should be a pointer to a mat_complex_split_t type.
1043
 * - MAT_F_GLOBAL to assign the variable as a global variable
1044
 * - MAT_F_LOGICAL to specify that it is a logical variable
1045
 * @return A MAT variable that can be written to a file or otherwise used
1046
 */
1047
matvar_t *
1048
Mat_VarCreate(const char *name, enum matio_classes class_type, enum matio_types data_type, int rank,
1049
              const size_t *dims, const void *data, int opt)
1050
0
{
1051
0
    size_t nelems = 1, data_size;
1052
0
    matvar_t *matvar = NULL;
1053
0
    int j, err;
1054
1055
0
    if ( dims == NULL )
1056
0
        return NULL;
1057
1058
0
    matvar = Mat_VarCalloc();
1059
0
    if ( NULL == matvar )
1060
0
        return NULL;
1061
1062
0
    matvar->compression = MAT_COMPRESSION_NONE;
1063
0
    matvar->isComplex = opt & MAT_F_COMPLEX;
1064
0
    matvar->isGlobal = opt & MAT_F_GLOBAL;
1065
0
    matvar->isLogical = opt & MAT_F_LOGICAL;
1066
0
    if ( name )
1067
0
        matvar->name = strdup(name);
1068
0
    matvar->rank = rank;
1069
0
    matvar->dims = (size_t *)malloc(matvar->rank * sizeof(*matvar->dims));
1070
0
    for ( j = 0; j < matvar->rank; j++ ) {
1071
0
        matvar->dims[j] = dims[j];
1072
0
        nelems *= dims[j];
1073
0
    }
1074
0
    matvar->class_type = class_type;
1075
0
    matvar->data_type = data_type;
1076
0
    switch ( data_type ) {
1077
0
        case MAT_T_INT8:
1078
0
            data_size = 1;
1079
0
            break;
1080
0
        case MAT_T_UINT8:
1081
0
            data_size = 1;
1082
0
            break;
1083
0
        case MAT_T_INT16:
1084
0
            data_size = 2;
1085
0
            break;
1086
0
        case MAT_T_UINT16:
1087
0
            data_size = 2;
1088
0
            break;
1089
0
        case MAT_T_INT64:
1090
0
            data_size = 8;
1091
0
            break;
1092
0
        case MAT_T_UINT64:
1093
0
            data_size = 8;
1094
0
            break;
1095
0
        case MAT_T_INT32:
1096
0
            data_size = 4;
1097
0
            break;
1098
0
        case MAT_T_UINT32:
1099
0
            data_size = 4;
1100
0
            break;
1101
0
        case MAT_T_SINGLE:
1102
0
            data_size = sizeof(float);
1103
0
            break;
1104
0
        case MAT_T_DOUBLE:
1105
0
            data_size = sizeof(double);
1106
0
            break;
1107
0
        case MAT_T_UTF8:
1108
0
            data_size = 1;
1109
0
            break;
1110
0
        case MAT_T_UTF16:
1111
0
            data_size = 2;
1112
0
            break;
1113
0
        case MAT_T_UTF32:
1114
0
            data_size = 4;
1115
0
            break;
1116
0
        case MAT_T_CELL:
1117
0
            data_size = sizeof(matvar_t **);
1118
0
            break;
1119
0
        case MAT_T_STRUCT: {
1120
0
            data_size = sizeof(matvar_t **);
1121
0
            if ( data != NULL ) {
1122
0
                matvar_t *const *const fields = (matvar_t *const *const)data;
1123
0
                size_t nfields = 0;
1124
0
                while ( fields[nfields] != NULL )
1125
0
                    nfields++;
1126
0
                if ( nelems )
1127
0
                    nfields /= nelems;
1128
0
                matvar->internal->num_fields = nfields;
1129
0
                if ( nfields ) {
1130
0
                    size_t i;
1131
0
                    matvar->internal->fieldnames =
1132
0
                        (char **)calloc(nfields, sizeof(*matvar->internal->fieldnames));
1133
0
                    for ( i = 0; i < nfields; i++ )
1134
0
                        matvar->internal->fieldnames[i] = strdup(fields[i]->name);
1135
0
                    err = Mul(&nelems, nelems, nfields);
1136
0
                    if ( err ) {
1137
0
                        Mat_VarFree(matvar);
1138
0
                        Mat_Critical("Integer multiplication overflow");
1139
0
                        return NULL;
1140
0
                    }
1141
0
                }
1142
0
            }
1143
0
            break;
1144
0
        }
1145
0
        default:
1146
0
            Mat_VarFree(matvar);
1147
0
            Mat_Critical("Unrecognized data_type");
1148
0
            return NULL;
1149
0
    }
1150
0
    if ( matvar->class_type == MAT_C_SPARSE ) {
1151
0
        matvar->data_size = sizeof(mat_sparse_t);
1152
0
        matvar->nbytes = matvar->data_size;
1153
0
    } else if ( matvar->class_type == MAT_C_CHAR && matvar->data_type == MAT_T_UTF8 ) {
1154
0
        size_t k = 0;
1155
0
        if ( data != NULL ) {
1156
0
            size_t i;
1157
0
            const mat_uint8_t *ptr = (const mat_uint8_t *)data;
1158
0
            for ( i = 0; i < nelems; i++ ) {
1159
0
                const mat_uint8_t c = ptr[k];
1160
0
                if ( c <= 0x7F ) {
1161
0
                    k++;
1162
0
                } else if ( (c & 0xE0) == 0xC0 ) {
1163
0
                    k += 2;
1164
0
                } else if ( (c & 0xF0) == 0xE0 ) {
1165
0
                    k += 3;
1166
0
                } else if ( (c & 0xF8) == 0xF0 ) {
1167
0
                    k += 4;
1168
0
                }
1169
0
            }
1170
0
        }
1171
0
        matvar->nbytes = k;
1172
0
        matvar->data_size = (int)data_size;
1173
0
    } else {
1174
0
        matvar->data_size = (int)data_size;
1175
0
        err = Mul(&matvar->nbytes, nelems, matvar->data_size);
1176
0
        if ( err ) {
1177
0
            Mat_VarFree(matvar);
1178
0
            Mat_Critical("Integer multiplication overflow");
1179
0
            return NULL;
1180
0
        }
1181
0
    }
1182
0
    if ( data == NULL ) {
1183
0
        if ( MAT_C_CELL == matvar->class_type && nelems > 0 )
1184
0
            matvar->data = calloc(nelems, sizeof(matvar_t *));
1185
0
    } else if ( opt & MAT_F_DONT_COPY_DATA ) {
1186
0
        matvar->data = (void *)data;
1187
0
        matvar->mem_conserve = 1;
1188
0
    } else if ( MAT_C_SPARSE == matvar->class_type ) {
1189
0
        mat_sparse_t *sparse_data;
1190
0
        const mat_sparse_t *sparse_data_in;
1191
1192
0
        sparse_data_in = (const mat_sparse_t *)data;
1193
0
        sparse_data = (mat_sparse_t *)malloc(sizeof(mat_sparse_t));
1194
0
        if ( NULL != sparse_data ) {
1195
0
            sparse_data->nzmax = sparse_data_in->nzmax;
1196
0
            sparse_data->nir = sparse_data_in->nir;
1197
0
            sparse_data->njc = sparse_data_in->njc;
1198
0
            sparse_data->ndata = sparse_data_in->ndata;
1199
0
            sparse_data->ir = (mat_uint32_t *)malloc(sparse_data->nir * sizeof(*sparse_data->ir));
1200
0
            if ( NULL != sparse_data->ir )
1201
0
                memcpy(sparse_data->ir, sparse_data_in->ir,
1202
0
                       sparse_data->nir * sizeof(*sparse_data->ir));
1203
0
            sparse_data->jc = (mat_uint32_t *)malloc(sparse_data->njc * sizeof(*sparse_data->jc));
1204
0
            if ( NULL != sparse_data->jc )
1205
0
                memcpy(sparse_data->jc, sparse_data_in->jc,
1206
0
                       sparse_data->njc * sizeof(*sparse_data->jc));
1207
0
            if ( matvar->isComplex ) {
1208
0
                sparse_data->data = malloc(sizeof(mat_complex_split_t));
1209
0
                if ( NULL != sparse_data->data ) {
1210
0
                    mat_complex_split_t *complex_data = (mat_complex_split_t *)sparse_data->data;
1211
0
                    const mat_complex_split_t *complex_data_in =
1212
0
                        (mat_complex_split_t *)sparse_data_in->data;
1213
0
                    complex_data->Re = malloc(sparse_data->ndata * data_size);
1214
0
                    complex_data->Im = malloc(sparse_data->ndata * data_size);
1215
0
                    if ( NULL != complex_data->Re )
1216
0
                        memcpy(complex_data->Re, complex_data_in->Re,
1217
0
                               sparse_data->ndata * data_size);
1218
0
                    if ( NULL != complex_data->Im )
1219
0
                        memcpy(complex_data->Im, complex_data_in->Im,
1220
0
                               sparse_data->ndata * data_size);
1221
0
                }
1222
0
            } else {
1223
0
                sparse_data->data = malloc(sparse_data->ndata * data_size);
1224
0
                if ( NULL != sparse_data->data )
1225
0
                    memcpy(sparse_data->data, sparse_data_in->data, sparse_data->ndata * data_size);
1226
0
            }
1227
0
        }
1228
0
        matvar->data = sparse_data;
1229
0
    } else {
1230
0
        if ( matvar->isComplex ) {
1231
0
            matvar->data = malloc(sizeof(mat_complex_split_t));
1232
0
            if ( NULL != matvar->data && matvar->nbytes > 0 ) {
1233
0
                mat_complex_split_t *complex_data = (mat_complex_split_t *)matvar->data;
1234
0
                const mat_complex_split_t *complex_data_in = (const mat_complex_split_t *)data;
1235
1236
0
                complex_data->Re = malloc(matvar->nbytes);
1237
0
                complex_data->Im = malloc(matvar->nbytes);
1238
0
                if ( NULL != complex_data->Re )
1239
0
                    memcpy(complex_data->Re, complex_data_in->Re, matvar->nbytes);
1240
0
                if ( NULL != complex_data->Im )
1241
0
                    memcpy(complex_data->Im, complex_data_in->Im, matvar->nbytes);
1242
0
            }
1243
0
        } else if ( matvar->nbytes > 0 ) {
1244
0
            matvar->data = malloc(matvar->nbytes);
1245
0
            if ( NULL != matvar->data )
1246
0
                memcpy(matvar->data, data, matvar->nbytes);
1247
0
        }
1248
0
        matvar->mem_conserve = 0;
1249
0
    }
1250
1251
0
    return matvar;
1252
0
}
1253
1254
/** @brief Copies a file
1255
 *
1256
 * @param src source file path
1257
 * @param dst destination file path
1258
 * @retval 0 on success
1259
 */
1260
static int
1261
Mat_CopyFile(const char *src, const char *dst)
1262
0
{
1263
0
    size_t len;
1264
0
    char buf[BUFSIZ] = {'\0'};
1265
0
    FILE *in;
1266
0
    FILE *out = NULL;
1267
1268
#if defined(_WIN32)
1269
    {
1270
        wchar_t *wname = utf82u(src);
1271
        if ( NULL != wname ) {
1272
            in = _wfopen(wname, L"rb");
1273
            free(wname);
1274
        } else {
1275
            in = NULL;
1276
        }
1277
    }
1278
#else
1279
0
    in = fopen(src, "rb");
1280
0
#endif
1281
0
    if ( in == NULL ) {
1282
0
        Mat_Critical("Cannot open file \"%s\" for reading", src);
1283
0
        return MATIO_E_FILESYSTEM_COULD_NOT_OPEN;
1284
0
    }
1285
1286
#if defined(_WIN32)
1287
    {
1288
        wchar_t *wname = utf82u(dst);
1289
        if ( NULL != wname ) {
1290
            out = _wfopen(wname, L"wb");
1291
            free(wname);
1292
        }
1293
    }
1294
#else
1295
0
    out = fopen(dst, "wb");
1296
0
#endif
1297
0
    if ( out == NULL ) {
1298
0
        fclose(in);
1299
0
        Mat_Critical("Cannot open file \"%s\" for writing", dst);
1300
0
        return MATIO_E_FILESYSTEM_COULD_NOT_OPEN;
1301
0
    }
1302
1303
0
    while ( (len = fread(buf, sizeof(char), BUFSIZ, in)) > 0 ) {
1304
0
        if ( len != fwrite(buf, sizeof(char), len, out) ) {
1305
0
            fclose(in);
1306
0
            fclose(out);
1307
0
            Mat_Critical("Error writing to file \"%s\"", dst);
1308
0
            return MATIO_E_GENERIC_WRITE_ERROR;
1309
0
        }
1310
0
    }
1311
0
    fclose(in);
1312
0
    fclose(out);
1313
0
    return MATIO_E_NO_ERROR;
1314
0
}
1315
1316
/** @brief Deletes a variable from a file
1317
 *
1318
 * @ingroup MAT
1319
 * @param mat Pointer to the mat_t file structure
1320
 * @param name Name of the variable to delete
1321
 * @returns 0 on success
1322
 */
1323
int
1324
Mat_VarDelete(mat_t *mat, const char *name)
1325
0
{
1326
0
    int err = MATIO_E_BAD_ARGUMENT;
1327
0
    char path_buf[MAT_MKTEMP_BUF_SIZE];
1328
0
    char dir_buf[MAT_MKTEMP_BUF_SIZE];
1329
1330
0
    if ( NULL == mat || NULL == name )
1331
0
        return err;
1332
1333
0
    if ( (mat->mode & 0x01) == MAT_ACC_RDONLY )
1334
0
        return MATIO_E_OPERATION_PROHIBITED_IN_READ_MODE;
1335
1336
0
    if ( NULL != Mat_mktemp(path_buf, dir_buf) ) {
1337
0
        enum mat_ft mat_file_ver;
1338
0
        mat_t *tmp;
1339
1340
0
        switch ( mat->version ) {
1341
0
            case 0x0100:
1342
0
                mat_file_ver = MAT_FT_MAT5;
1343
0
                break;
1344
0
            case 0x0200:
1345
0
                mat_file_ver = MAT_FT_MAT73;
1346
0
                break;
1347
0
            case 0x0010:
1348
0
                mat_file_ver = MAT_FT_MAT4;
1349
0
                break;
1350
0
            default:
1351
0
                mat_file_ver = MAT_FT_DEFAULT;
1352
0
                break;
1353
0
        }
1354
1355
0
        tmp = Mat_CreateVer(path_buf, mat->header, mat_file_ver);
1356
0
        if ( tmp != NULL ) {
1357
0
            matvar_t *matvar;
1358
0
            char **dir;
1359
0
            size_t n;
1360
1361
0
            Mat_Rewind(mat);
1362
0
            while ( NULL != (matvar = Mat_VarReadNext(mat)) ) {
1363
0
                if ( 0 != strcmp(matvar->name, name) )
1364
0
                    err = Mat_VarWrite(tmp, matvar, matvar->compression);
1365
0
                else
1366
0
                    err = MATIO_E_NO_ERROR;
1367
0
                Mat_VarFree(matvar);
1368
0
            }
1369
0
            dir = tmp->dir; /* Keep directory for later assignment */
1370
0
            tmp->dir = NULL;
1371
0
            n = tmp->num_datasets;
1372
0
            Mat_Close(tmp);
1373
1374
0
            if ( MATIO_E_NO_ERROR == err ) {
1375
0
                char *new_name = strdup(mat->filename);
1376
0
#if defined(MAT73) && MAT73
1377
0
                if ( mat_file_ver == MAT_FT_MAT73 ) {
1378
0
                    /* err = */ Mat_Close73(mat);
1379
0
                }
1380
0
#endif
1381
0
                if ( mat->fp != NULL ) {
1382
0
                    fclose((FILE *)mat->fp);
1383
0
                    mat->fp = NULL;
1384
0
                }
1385
1386
0
                if ( (err = Mat_CopyFile(path_buf, new_name)) != MATIO_E_NO_ERROR ) {
1387
0
                    if ( NULL != dir ) {
1388
0
                        size_t i;
1389
0
                        for ( i = 0; i < n; i++ ) {
1390
0
                            if ( dir[i] )
1391
0
                                free(dir[i]);
1392
0
                        }
1393
0
                        free(dir);
1394
0
                    }
1395
0
                    Mat_Critical("Cannot copy file from \"%s\" to \"%s\"", path_buf, new_name);
1396
0
                } else if ( (err = remove(path_buf)) != 0 ) {
1397
0
                    err = MATIO_E_UNKNOWN_ERROR;
1398
0
                    if ( NULL != dir ) {
1399
0
                        size_t i;
1400
0
                        for ( i = 0; i < n; i++ ) {
1401
0
                            if ( dir[i] )
1402
0
                                free(dir[i]);
1403
0
                        }
1404
0
                        free(dir);
1405
0
                    }
1406
0
                    Mat_Critical("Cannot remove file \"%s\"", path_buf);
1407
0
                } else if ( *dir_buf != '\0' && (err = remove(dir_buf)) != 0 ) {
1408
0
                    err = MATIO_E_UNKNOWN_ERROR;
1409
0
                    if ( NULL != dir ) {
1410
0
                        size_t i;
1411
0
                        for ( i = 0; i < n; i++ ) {
1412
0
                            if ( dir[i] )
1413
0
                                free(dir[i]);
1414
0
                        }
1415
0
                        free(dir);
1416
0
                    }
1417
0
                    Mat_Critical("Cannot remove directory \"%s\"", dir_buf);
1418
0
                } else {
1419
0
                    tmp = Mat_Open(new_name, mat->mode);
1420
0
                    if ( NULL != tmp ) {
1421
0
                        if ( mat->header )
1422
0
                            free(mat->header);
1423
0
                        if ( mat->subsys_offset )
1424
0
                            free(mat->subsys_offset);
1425
0
                        if ( mat->filename )
1426
0
                            free(mat->filename);
1427
0
                        if ( mat->dir ) {
1428
0
                            size_t i;
1429
0
                            for ( i = 0; i < mat->num_datasets; i++ ) {
1430
0
                                if ( mat->dir[i] )
1431
0
                                    free(mat->dir[i]);
1432
0
                            }
1433
0
                            free(mat->dir);
1434
0
                        }
1435
0
                        memcpy(mat, tmp, sizeof(mat_t));
1436
0
                        free(tmp);
1437
0
                        mat->num_datasets = n;
1438
0
                        mat->dir = dir;
1439
0
                    } else {
1440
0
                        Mat_Critical("Cannot open file \"%s\"", new_name);
1441
0
                        err = MATIO_E_FILESYSTEM_COULD_NOT_OPEN;
1442
0
                    }
1443
0
                }
1444
0
                free(new_name);
1445
0
            } else if ( (err = remove(path_buf)) != 0 ) {
1446
0
                err = MATIO_E_UNKNOWN_ERROR;
1447
0
                Mat_Critical("Cannot remove file \"%s\"", path_buf);
1448
0
            } else if ( *dir_buf != '\0' && (err = remove(dir_buf)) != 0 ) {
1449
0
                err = MATIO_E_UNKNOWN_ERROR;
1450
0
                Mat_Critical("Cannot remove directory \"%s\"", dir_buf);
1451
0
            }
1452
0
        } else {
1453
0
            err = MATIO_E_UNKNOWN_ERROR;
1454
0
        }
1455
0
    } else {
1456
0
        Mat_Critical("Cannot create a unique file name");
1457
0
        err = MATIO_E_FILESYSTEM_COULD_NOT_OPEN_TEMPORARY;
1458
0
    }
1459
1460
0
    return err;
1461
0
}
1462
1463
/** @brief Duplicates a matvar_t structure
1464
 *
1465
 * Provides a clean function for duplicating a matvar_t structure.
1466
 * @ingroup MAT
1467
 * @param in pointer to the matvar_t structure to be duplicated
1468
 * @param opt 0 does a shallow duplicate and only assigns the data pointer to
1469
 *            the duplicated array.  1 will do a deep duplicate and actually
1470
 *            duplicate the contents of the data.  Warning: If you do a shallow
1471
 *            copy and free both structures, the data will be freed twice and
1472
 *            memory will be corrupted.  This may be fixed in a later release.
1473
 * @returns Pointer to the duplicated matvar_t structure.
1474
 */
1475
matvar_t *
1476
Mat_VarDuplicate(const matvar_t *in, int opt)
1477
570
{
1478
570
    matvar_t *out;
1479
570
    size_t i;
1480
1481
570
    if ( in == NULL )
1482
11
        return NULL;
1483
1484
559
    out = Mat_VarCalloc();
1485
559
    if ( out == NULL )
1486
0
        return NULL;
1487
1488
559
    out->nbytes = in->nbytes;
1489
559
    out->rank = in->rank;
1490
559
    out->data_type = in->data_type;
1491
559
    out->data_size = in->data_size;
1492
559
    out->class_type = in->class_type;
1493
559
    out->isComplex = in->isComplex;
1494
559
    out->isGlobal = in->isGlobal;
1495
559
    out->isLogical = in->isLogical;
1496
559
    out->mem_conserve = in->mem_conserve;
1497
559
    out->compression = in->compression;
1498
1499
559
    if ( NULL != in->name ) {
1500
280
        size_t len = strlen(in->name) + 1;
1501
280
        out->name = (char *)malloc(len);
1502
280
        if ( NULL != out->name )
1503
280
            memcpy(out->name, in->name, len);
1504
280
    }
1505
1506
559
    out->dims = (size_t *)malloc(in->rank * sizeof(*out->dims));
1507
559
    if ( out->dims != NULL )
1508
559
        memcpy(out->dims, in->dims, in->rank * sizeof(*out->dims));
1509
1510
559
    if ( NULL != in->internal ) {
1511
551
#if defined(MAT73) && MAT73
1512
551
        out->internal->hdf5_ref = in->internal->hdf5_ref;
1513
551
        out->internal->id = in->internal->id;
1514
551
        if ( out->internal->id >= 0 ) {
1515
0
            H5Iinc_ref(out->internal->id);
1516
0
        }
1517
551
#endif
1518
551
        out->internal->datapos = in->internal->datapos;
1519
551
#if HAVE_ZLIB
1520
551
        out->internal->z = NULL;
1521
551
        out->internal->data = NULL;
1522
551
#endif
1523
551
        out->internal->num_fields = in->internal->num_fields;
1524
551
        if ( NULL != in->internal->fieldnames && in->internal->num_fields > 0 ) {
1525
1
            out->internal->fieldnames =
1526
1
                (char **)calloc(in->internal->num_fields, sizeof(*in->internal->fieldnames));
1527
1
            if ( NULL != out->internal->fieldnames ) {
1528
7
                for ( i = 0; i < in->internal->num_fields; i++ ) {
1529
6
                    if ( NULL != in->internal->fieldnames[i] )
1530
6
                        out->internal->fieldnames[i] = strdup(in->internal->fieldnames[i]);
1531
6
                }
1532
1
            }
1533
1
        }
1534
1535
551
#if HAVE_ZLIB
1536
551
        if ( in->internal->z != NULL ) {
1537
6
            out->internal->z = (z_streamp)malloc(sizeof(z_stream));
1538
6
            if ( NULL != out->internal->z ) {
1539
6
                int err = inflateCopy(out->internal->z, in->internal->z);
1540
6
                if ( err != Z_OK ) {
1541
0
                    free(out->internal->z);
1542
0
                    out->internal->z = NULL;
1543
0
                }
1544
6
            }
1545
6
        }
1546
551
        if ( in->internal->data != NULL ) {
1547
0
            if ( in->class_type == MAT_C_SPARSE ) {
1548
0
                out->internal->data = malloc(sizeof(mat_sparse_t));
1549
0
                if ( out->internal->data != NULL ) {
1550
0
                    mat_sparse_t *out_sparse = (mat_sparse_t *)out->internal->data;
1551
0
                    mat_sparse_t *in_sparse = (mat_sparse_t *)in->internal->data;
1552
0
                    out_sparse->nzmax = in_sparse->nzmax;
1553
0
                    out_sparse->nir = in_sparse->nir;
1554
0
                    out_sparse->ir =
1555
0
                        (mat_uint32_t *)malloc(in_sparse->nir * sizeof(*out_sparse->ir));
1556
0
                    if ( out_sparse->ir != NULL )
1557
0
                        memcpy(out_sparse->ir, in_sparse->ir,
1558
0
                               in_sparse->nir * sizeof(*out_sparse->ir));
1559
0
                    out_sparse->njc = in_sparse->njc;
1560
0
                    out_sparse->jc =
1561
0
                        (mat_uint32_t *)malloc(in_sparse->njc * sizeof(*out_sparse->jc));
1562
0
                    if ( out_sparse->jc != NULL )
1563
0
                        memcpy(out_sparse->jc, in_sparse->jc,
1564
0
                               in_sparse->njc * sizeof(*out_sparse->jc));
1565
0
                    out_sparse->ndata = in_sparse->ndata;
1566
0
                    if ( out->isComplex && NULL != in_sparse->data ) {
1567
0
                        out_sparse->data = malloc(sizeof(mat_complex_split_t));
1568
0
                        if ( out_sparse->data != NULL ) {
1569
0
                            mat_complex_split_t *out_data = (mat_complex_split_t *)out_sparse->data;
1570
0
                            const mat_complex_split_t *in_data =
1571
0
                                (mat_complex_split_t *)in_sparse->data;
1572
0
                            out_data->Re = malloc(in_sparse->ndata * Mat_SizeOf(in->data_type));
1573
0
                            if ( NULL != out_data->Re )
1574
0
                                memcpy(out_data->Re, in_data->Re,
1575
0
                                       in_sparse->ndata * Mat_SizeOf(in->data_type));
1576
0
                            out_data->Im = malloc(in_sparse->ndata * Mat_SizeOf(in->data_type));
1577
0
                            if ( NULL != out_data->Im )
1578
0
                                memcpy(out_data->Im, in_data->Im,
1579
0
                                       in_sparse->ndata * Mat_SizeOf(in->data_type));
1580
0
                        }
1581
0
                    } else if ( in_sparse->data != NULL ) {
1582
0
                        out_sparse->data = malloc(in_sparse->ndata * Mat_SizeOf(in->data_type));
1583
0
                        if ( NULL != out_sparse->data )
1584
0
                            memcpy(out_sparse->data, in_sparse->data,
1585
0
                                   in_sparse->ndata * Mat_SizeOf(in->data_type));
1586
0
                    } else {
1587
0
                        out_sparse->data = NULL;
1588
0
                    }
1589
0
                }
1590
0
            } else if ( out->isComplex ) {
1591
0
                out->internal->data = malloc(sizeof(mat_complex_split_t));
1592
0
                if ( out->internal->data != NULL ) {
1593
0
                    mat_complex_split_t *out_data = (mat_complex_split_t *)out->internal->data;
1594
0
                    const mat_complex_split_t *in_data = (mat_complex_split_t *)in->internal->data;
1595
0
                    out_data->Re = malloc(out->nbytes);
1596
0
                    if ( NULL != out_data->Re )
1597
0
                        memcpy(out_data->Re, in_data->Re, out->nbytes);
1598
0
                    out_data->Im = malloc(out->nbytes);
1599
0
                    if ( NULL != out_data->Im )
1600
0
                        memcpy(out_data->Im, in_data->Im, out->nbytes);
1601
0
                }
1602
0
            } else if ( NULL != (out->internal->data = malloc(in->nbytes)) ) {
1603
0
                memcpy(out->internal->data, in->internal->data, in->nbytes);
1604
0
            }
1605
0
        }
1606
551
#endif
1607
551
    } else {
1608
8
        free(out->internal);
1609
8
        out->internal = NULL;
1610
8
    }
1611
1612
559
    if ( !opt ) {
1613
0
        out->data = in->data;
1614
559
    } else if ( in->data != NULL &&
1615
559
                (in->class_type == MAT_C_STRUCT || in->class_type == MAT_C_CELL ||
1616
365
                 in->class_type == MAT_C_FUNCTION) ) {
1617
3
        out->data = malloc(in->nbytes);
1618
3
        if ( out->data != NULL && in->data_size > 0 ) {
1619
3
            const size_t ndata = in->nbytes / in->data_size;
1620
3
            const matvar_t *const *indata = (const matvar_t *const *)in->data;
1621
3
            const matvar_t **outdata = (const matvar_t **)out->data;
1622
29
            for ( i = 0; i < ndata; i++ ) {
1623
26
                outdata[i] = Mat_VarDuplicate(indata[i], opt);
1624
26
            }
1625
3
        }
1626
556
    } else if ( in->data != NULL && in->class_type == MAT_C_SPARSE ) {
1627
42
        out->data = malloc(sizeof(mat_sparse_t));
1628
42
        if ( out->data != NULL ) {
1629
42
            mat_sparse_t *out_sparse = (mat_sparse_t *)out->data;
1630
42
            const mat_sparse_t *in_sparse = (mat_sparse_t *)in->data;
1631
42
            out_sparse->nzmax = in_sparse->nzmax;
1632
42
            out_sparse->nir = in_sparse->nir;
1633
42
            out_sparse->ir = (mat_uint32_t *)malloc(in_sparse->nir * sizeof(*out_sparse->ir));
1634
42
            if ( out_sparse->ir != NULL )
1635
42
                memcpy(out_sparse->ir, in_sparse->ir, in_sparse->nir * sizeof(*out_sparse->ir));
1636
42
            out_sparse->njc = in_sparse->njc;
1637
42
            out_sparse->jc = (mat_uint32_t *)malloc(in_sparse->njc * sizeof(*out_sparse->jc));
1638
42
            if ( out_sparse->jc != NULL )
1639
42
                memcpy(out_sparse->jc, in_sparse->jc, in_sparse->njc * sizeof(*out_sparse->jc));
1640
42
            out_sparse->ndata = in_sparse->ndata;
1641
42
            if ( out->isComplex && NULL != in_sparse->data ) {
1642
12
                out_sparse->data = malloc(sizeof(mat_complex_split_t));
1643
12
                if ( out_sparse->data != NULL ) {
1644
12
                    mat_complex_split_t *out_data = (mat_complex_split_t *)out_sparse->data;
1645
12
                    const mat_complex_split_t *in_data =
1646
12
                        (const mat_complex_split_t *)in_sparse->data;
1647
12
                    out_data->Re = malloc(in_sparse->ndata * Mat_SizeOf(in->data_type));
1648
12
                    if ( NULL != out_data->Re )
1649
12
                        memcpy(out_data->Re, in_data->Re,
1650
12
                               in_sparse->ndata * Mat_SizeOf(in->data_type));
1651
12
                    out_data->Im = malloc(in_sparse->ndata * Mat_SizeOf(in->data_type));
1652
12
                    if ( NULL != out_data->Im )
1653
12
                        memcpy(out_data->Im, in_data->Im,
1654
12
                               in_sparse->ndata * Mat_SizeOf(in->data_type));
1655
12
                }
1656
30
            } else if ( in_sparse->data != NULL ) {
1657
0
                out_sparse->data = malloc(in_sparse->ndata * Mat_SizeOf(in->data_type));
1658
0
                if ( NULL != out_sparse->data )
1659
0
                    memcpy(out_sparse->data, in_sparse->data,
1660
0
                           in_sparse->ndata * Mat_SizeOf(in->data_type));
1661
30
            } else {
1662
30
                out_sparse->data = NULL;
1663
30
            }
1664
42
        }
1665
514
    } else if ( in->data != NULL && in->nbytes != 0 ) {
1666
260
        if ( out->isComplex ) {
1667
151
            out->data = malloc(sizeof(mat_complex_split_t));
1668
151
            if ( out->data != NULL ) {
1669
151
                mat_complex_split_t *out_data = (mat_complex_split_t *)out->data;
1670
151
                const mat_complex_split_t *in_data = (const mat_complex_split_t *)in->data;
1671
151
                out_data->Re = malloc(out->nbytes);
1672
151
                if ( NULL != out_data->Re )
1673
151
                    memcpy(out_data->Re, in_data->Re, out->nbytes);
1674
151
                out_data->Im = malloc(out->nbytes);
1675
151
                if ( NULL != out_data->Im )
1676
151
                    memcpy(out_data->Im, in_data->Im, out->nbytes);
1677
151
            }
1678
151
        } else {
1679
109
            out->data = malloc(in->nbytes);
1680
109
            if ( out->data != NULL )
1681
109
                memcpy(out->data, in->data, in->nbytes);
1682
109
        }
1683
260
    }
1684
1685
559
    return out;
1686
559
}
1687
1688
/** @brief Frees all the allocated memory associated with the structure
1689
 *
1690
 * Frees memory used by a MAT variable.  Frees the data associated with a
1691
 * MAT variable if it's non-NULL and MAT_F_DONT_COPY_DATA was not used.
1692
 * @ingroup MAT
1693
 * @param matvar Pointer to the matvar_t structure
1694
 */
1695
void
1696
Mat_VarFree(matvar_t *matvar)
1697
3.43k
{
1698
3.43k
    size_t nelems = 0;
1699
3.43k
    int err;
1700
1701
3.43k
    if ( NULL == matvar )
1702
552
        return;
1703
2.88k
    if ( NULL != matvar->dims ) {
1704
2.55k
        nelems = 1;
1705
2.55k
        err = Mat_MulDims(matvar, &nelems);
1706
2.55k
        free(matvar->dims);
1707
2.55k
    } else {
1708
329
        err = MATIO_E_BAD_ARGUMENT;
1709
329
    }
1710
2.88k
    if ( NULL != matvar->data ) {
1711
1.20k
        switch ( matvar->class_type ) {
1712
5
            case MAT_C_STRUCT:
1713
5
                if ( !matvar->mem_conserve ) {
1714
5
                    if ( MATIO_E_NO_ERROR == err ) {
1715
5
                        matvar_t **fields = (matvar_t **)matvar->data;
1716
5
                        size_t nelems_x_nfields;
1717
5
                        err = Mul(&nelems_x_nfields, nelems, matvar->internal->num_fields);
1718
5
                        if ( MATIO_E_NO_ERROR == err && nelems_x_nfields > 0 ) {
1719
5
                            size_t i;
1720
35
                            for ( i = 0; i < nelems_x_nfields; i++ )
1721
30
                                Mat_VarFree(fields[i]);
1722
5
                        }
1723
5
                    }
1724
5
                    free(matvar->data);
1725
5
                }
1726
5
                break;
1727
19
            case MAT_C_CELL:
1728
19
                if ( !matvar->mem_conserve ) {
1729
19
                    if ( MATIO_E_NO_ERROR == err ) {
1730
19
                        matvar_t **cells = (matvar_t **)matvar->data;
1731
19
                        size_t i;
1732
173
                        for ( i = 0; i < nelems; i++ )
1733
154
                            Mat_VarFree(cells[i]);
1734
19
                    }
1735
19
                    free(matvar->data);
1736
19
                }
1737
19
                break;
1738
122
            case MAT_C_SPARSE:
1739
122
                if ( !matvar->mem_conserve ) {
1740
122
                    mat_sparse_t *sparse;
1741
122
                    sparse = (mat_sparse_t *)matvar->data;
1742
122
                    if ( sparse->ir != NULL )
1743
122
                        free(sparse->ir);
1744
122
                    if ( sparse->jc != NULL )
1745
120
                        free(sparse->jc);
1746
122
                    if ( matvar->isComplex && NULL != sparse->data ) {
1747
36
                        ComplexFree((mat_complex_split_t *)sparse->data);
1748
86
                    } else if ( sparse->data != NULL ) {
1749
0
                        free(sparse->data);
1750
0
                    }
1751
122
                    free(sparse);
1752
122
                }
1753
122
                break;
1754
141
            case MAT_C_DOUBLE:
1755
214
            case MAT_C_SINGLE:
1756
412
            case MAT_C_INT64:
1757
528
            case MAT_C_UINT64:
1758
596
            case MAT_C_INT32:
1759
769
            case MAT_C_UINT32:
1760
836
            case MAT_C_INT16:
1761
915
            case MAT_C_UINT16:
1762
961
            case MAT_C_INT8:
1763
1.05k
            case MAT_C_UINT8:
1764
1.05k
            case MAT_C_CHAR:
1765
1.05k
                if ( !matvar->mem_conserve ) {
1766
1.05k
                    if ( matvar->isComplex ) {
1767
632
                        ComplexFree((mat_complex_split_t *)matvar->data);
1768
632
                    } else {
1769
422
                        free(matvar->data);
1770
422
                    }
1771
1.05k
                }
1772
1.05k
                break;
1773
0
            case MAT_C_FUNCTION:
1774
0
                if ( !matvar->mem_conserve ) {
1775
0
                    size_t i;
1776
0
                    matvar_t **functions = (matvar_t **)matvar->data;
1777
0
                    for ( i = 0; i < nelems; i++ ) {
1778
0
                        Mat_VarFree(functions[i]);
1779
0
                    }
1780
0
                    free(matvar->data);
1781
0
                }
1782
0
                break;
1783
0
            case MAT_C_EMPTY:
1784
0
            case MAT_C_OBJECT:
1785
0
            case MAT_C_OPAQUE:
1786
0
                break;
1787
1.20k
        }
1788
1.20k
    }
1789
1790
2.88k
    if ( NULL != matvar->internal ) {
1791
2.83k
#if HAVE_ZLIB
1792
2.83k
        if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
1793
36
            inflateEnd(matvar->internal->z);
1794
36
            free(matvar->internal->z);
1795
36
            if ( matvar->class_type == MAT_C_SPARSE && NULL != matvar->internal->data ) {
1796
0
                mat_sparse_t *sparse;
1797
0
                sparse = (mat_sparse_t *)matvar->internal->data;
1798
0
                if ( sparse->ir != NULL )
1799
0
                    free(sparse->ir);
1800
0
                if ( sparse->jc != NULL )
1801
0
                    free(sparse->jc);
1802
0
                if ( matvar->isComplex && NULL != sparse->data ) {
1803
0
                    ComplexFree((mat_complex_split_t *)sparse->data);
1804
0
                } else if ( sparse->data != NULL ) {
1805
0
                    free(sparse->data);
1806
0
                }
1807
0
                free(sparse);
1808
36
            } else if ( matvar->isComplex && NULL != matvar->internal->data ) {
1809
1
                ComplexFree((mat_complex_split_t *)matvar->internal->data);
1810
35
            } else if ( NULL != matvar->internal->data ) {
1811
0
                free(matvar->internal->data);
1812
0
            }
1813
36
        }
1814
2.83k
#endif
1815
2.83k
#if defined(MAT73) && MAT73
1816
2.83k
        if ( H5I_INVALID_HID != matvar->internal->id ) {
1817
57
            switch ( H5Iget_type(matvar->internal->id) ) {
1818
8
                case H5I_GROUP:
1819
8
                    H5Gclose(matvar->internal->id);
1820
8
                    matvar->internal->id = H5I_INVALID_HID;
1821
8
                    break;
1822
49
                case H5I_DATASET:
1823
49
                    H5Dclose(matvar->internal->id);
1824
49
                    matvar->internal->id = H5I_INVALID_HID;
1825
49
                    break;
1826
0
                default:
1827
0
                    break;
1828
57
            }
1829
57
        }
1830
2.83k
#endif
1831
2.83k
        if ( NULL != matvar->internal->fieldnames && matvar->internal->num_fields > 0 ) {
1832
5
            size_t i;
1833
35
            for ( i = 0; i < matvar->internal->num_fields; i++ ) {
1834
30
                if ( NULL != matvar->internal->fieldnames[i] )
1835
30
                    free(matvar->internal->fieldnames[i]);
1836
30
            }
1837
5
            free(matvar->internal->fieldnames);
1838
5
        }
1839
2.83k
        free(matvar->internal);
1840
2.83k
        matvar->internal = NULL;
1841
2.83k
    }
1842
2.88k
    if ( NULL != matvar->name )
1843
1.56k
        free(matvar->name);
1844
2.88k
    free(matvar);
1845
2.88k
}
1846
1847
/** @brief Calculate a single subscript from a set of subscript values
1848
 *
1849
 * Calculates a single linear subscript (0-relative) given a 1-relative
1850
 * subscript for each dimension.  The calculation uses the formula below where
1851
 * index is the linear index, s is an array of length RANK where each element
1852
 * is the subscript for the corresponding dimension, D is an array whose
1853
 * elements are the dimensions of the variable.
1854
 * \f[
1855
 *   index = \sum\limits_{k=0}^{RANK-1} [(s_k - 1) \prod\limits_{l=0}^{k} D_l ]
1856
 * \f]
1857
 * @ingroup MAT
1858
 * @param rank Rank of the variable
1859
 * @param dims Dimensions of the variable
1860
 * @param subs Array of dimension subscripts
1861
 * @return Single (linear) subscript
1862
 */
1863
int
1864
Mat_CalcSingleSubscript(int rank, const int *dims, const int *subs)
1865
0
{
1866
0
    int index = 0, i, j, err = MATIO_E_NO_ERROR;
1867
1868
0
    for ( i = 0; i < rank; i++ ) {
1869
0
        int k = subs[i];
1870
0
        if ( k > dims[i] ) {
1871
0
            err = MATIO_E_BAD_ARGUMENT;
1872
0
            Mat_Critical("Mat_CalcSingleSubscript: index out of bounds");
1873
0
            break;
1874
0
        } else if ( k < 1 ) {
1875
0
            err = MATIO_E_BAD_ARGUMENT;
1876
0
            break;
1877
0
        }
1878
0
        k--;
1879
0
        for ( j = i; j--; )
1880
0
            k *= dims[j];
1881
0
        index += k;
1882
0
    }
1883
0
    if ( err )
1884
0
        index = -1;
1885
1886
0
    return index;
1887
0
}
1888
1889
/** @brief Calculate a single subscript from a set of subscript values
1890
 *
1891
 * Calculates a single linear subscript (0-relative) given a 1-relative
1892
 * subscript for each dimension.  The calculation uses the formula below where
1893
 * index is the linear index, s is an array of length RANK where each element
1894
 * is the subscript for the corresponding dimension, D is an array whose
1895
 * elements are the dimensions of the variable.
1896
 * \f[
1897
 *   index = \sum\limits_{k=0}^{RANK-1} [(s_k - 1) \prod\limits_{l=0}^{k} D_l ]
1898
 * \f]
1899
 * @ingroup MAT
1900
 * @param rank Rank of the variable
1901
 * @param dims Dimensions of the variable
1902
 * @param subs Array of dimension subscripts
1903
 * @param[out] index Single (linear) subscript
1904
 * @retval 0 on success
1905
 */
1906
int
1907
Mat_CalcSingleSubscript2(int rank, const size_t *dims, const size_t *subs, size_t *index)
1908
0
{
1909
0
    int i, err = MATIO_E_NO_ERROR;
1910
1911
0
    for ( i = 0; i < rank; i++ ) {
1912
0
        int j;
1913
0
        size_t k = subs[i];
1914
0
        if ( k > dims[i] ) {
1915
0
            err = MATIO_E_BAD_ARGUMENT;
1916
0
            Mat_Critical("Mat_CalcSingleSubscript2: index out of bounds");
1917
0
            break;
1918
0
        } else if ( k < 1 ) {
1919
0
            err = MATIO_E_BAD_ARGUMENT;
1920
0
            break;
1921
0
        }
1922
0
        k--;
1923
0
        for ( j = i; j--; )
1924
0
            k *= dims[j];
1925
0
        *index += k;
1926
0
    }
1927
1928
0
    return err;
1929
0
}
1930
1931
/** @brief Calculate a set of subscript values from a single(linear) subscript
1932
 *
1933
 * Calculates 1-relative subscripts for each dimension given a 0-relative
1934
 * linear index.  Subscripts are calculated as follows where s is the array
1935
 * of dimension subscripts, D is the array of dimensions, and index is the
1936
 * linear index.
1937
 * \f[
1938
 *   s_k = \lfloor\frac{1}{L} \prod\limits_{l = 0}^{k} D_l\rfloor + 1
1939
 * \f]
1940
 * \f[
1941
 *   L = index - \sum\limits_{l = k}^{RANK - 1} s_k \prod\limits_{m = 0}^{k} D_m
1942
 * \f]
1943
 * @ingroup MAT
1944
 * @param rank Rank of the variable
1945
 * @param dims Dimensions of the variable
1946
 * @param index Linear index
1947
 * @return Array of dimension subscripts
1948
 */
1949
int *
1950
Mat_CalcSubscripts(int rank, const int *dims, int index)
1951
0
{
1952
0
    int i, j, *subs;
1953
0
    double l;
1954
1955
0
    subs = (int *)malloc(rank * sizeof(int));
1956
0
    if ( NULL == subs ) {
1957
0
        return subs;
1958
0
    }
1959
1960
0
    l = index;
1961
0
    for ( i = rank; i--; ) {
1962
0
        int k = 1;
1963
0
        for ( j = i; j--; )
1964
0
            k *= dims[j];
1965
0
        subs[i] = (int)floor(l / (double)k);
1966
0
        l -= subs[i] * k;
1967
0
        subs[i]++;
1968
0
    }
1969
1970
0
    return subs;
1971
0
}
1972
1973
/** @brief Calculate a set of subscript values from a single(linear) subscript
1974
 *
1975
 * Calculates 1-relative subscripts for each dimension given a 0-relative
1976
 * linear index.  Subscripts are calculated as follows where s is the array
1977
 * of dimension subscripts, D is the array of dimensions, and index is the
1978
 * linear index.
1979
 * \f[
1980
 *   s_k = \lfloor\frac{1}{L} \prod\limits_{l = 0}^{k} D_l\rfloor + 1
1981
 * \f]
1982
 * \f[
1983
 *   L = index - \sum\limits_{l = k}^{RANK - 1} s_k \prod\limits_{m = 0}^{k} D_m
1984
 * \f]
1985
 * @ingroup MAT
1986
 * @param rank Rank of the variable
1987
 * @param dims Dimensions of the variable
1988
 * @param index Linear index
1989
 * @return Array of dimension subscripts
1990
 */
1991
size_t *
1992
Mat_CalcSubscripts2(int rank, const size_t *dims, size_t index)
1993
0
{
1994
0
    int i;
1995
0
    size_t *subs;
1996
0
    double l;
1997
1998
0
    subs = (size_t *)malloc(rank * sizeof(size_t));
1999
0
    if ( NULL == subs ) {
2000
0
        return subs;
2001
0
    }
2002
2003
0
    l = (double)index;
2004
0
    for ( i = rank; i--; ) {
2005
0
        int j;
2006
0
        size_t k = 1;
2007
0
        for ( j = i; j--; )
2008
0
            k *= dims[j];
2009
0
        subs[i] = (size_t)floor(l / (double)k);
2010
0
        l -= (double)(subs[i] * k);
2011
0
        subs[i]++;
2012
0
    }
2013
2014
0
    return subs;
2015
0
}
2016
2017
/** @brief Calculates the size of a matlab variable in bytes
2018
 *
2019
 * @ingroup MAT
2020
 * @param matvar matlab variable
2021
 * @returns size of the variable in bytes, or 0 on error
2022
 */
2023
size_t
2024
Mat_VarGetSize(const matvar_t *matvar)
2025
551
{
2026
551
    int err;
2027
551
    size_t i;
2028
551
    size_t bytes = 0, overhead = 0, ptr = 0;
2029
2030
551
#if defined(_WIN64) || (defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 8)) || \
2031
551
    (defined(SIZEOF_VOID_P) && (SIZEOF_VOID_P == 8))
2032
    /* 112 bytes cell/struct overhead for 64-bit system */
2033
551
    overhead = 112;
2034
551
    ptr = 8;
2035
#elif defined(_WIN32) || (defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4)) || \
2036
    (defined(SIZEOF_VOID_P) && (SIZEOF_VOID_P == 4))
2037
    /* 60 bytes cell/struct overhead for 32-bit system */
2038
    overhead = 60;
2039
    ptr = 4;
2040
#endif
2041
2042
551
    if ( matvar->class_type == MAT_C_STRUCT ) {
2043
1
        matvar_t **fields = (matvar_t **)matvar->data;
2044
1
        size_t field_name_length;
2045
1
        if ( NULL != fields ) {
2046
1
            size_t nelems_x_nfields = matvar->internal->num_fields;
2047
1
            err = Mat_MulDims(matvar, &nelems_x_nfields);
2048
1
            err |= Mul(&bytes, nelems_x_nfields, overhead);
2049
1
            if ( err )
2050
0
                return 0;
2051
2052
7
            for ( i = 0; i < nelems_x_nfields; i++ ) {
2053
6
                if ( NULL != fields[i] ) {
2054
3
                    if ( MAT_C_EMPTY != fields[i]->class_type ) {
2055
3
                        err = Add(&bytes, bytes, Mat_VarGetSize(fields[i]));
2056
3
                        if ( err )
2057
0
                            return 0;
2058
3
                    } else {
2059
0
                        bytes -= overhead;
2060
0
                        bytes += ptr;
2061
0
                    }
2062
3
                }
2063
6
            }
2064
1
        }
2065
1
        err = Mul(&field_name_length, 64 /* max field name length */, matvar->internal->num_fields);
2066
1
        err |= Add(&bytes, bytes, field_name_length);
2067
1
        if ( err )
2068
0
            return 0;
2069
550
    } else if ( matvar->class_type == MAT_C_CELL ) {
2070
2
        matvar_t **cells = (matvar_t **)matvar->data;
2071
2
        if ( NULL != cells ) {
2072
2
            size_t nelems = matvar->nbytes / matvar->data_size;
2073
2
            err = Mul(&bytes, nelems, overhead);
2074
2
            if ( err )
2075
0
                return 0;
2076
2077
22
            for ( i = 0; i < nelems; i++ ) {
2078
20
                if ( NULL != cells[i] ) {
2079
12
                    if ( MAT_C_EMPTY != cells[i]->class_type ) {
2080
4
                        err = Add(&bytes, bytes, Mat_VarGetSize(cells[i]));
2081
4
                        if ( err )
2082
0
                            return 0;
2083
8
                    } else {
2084
8
                        bytes -= overhead;
2085
8
                        bytes += ptr;
2086
8
                    }
2087
12
                }
2088
20
            }
2089
2
        }
2090
548
    } else if ( matvar->class_type == MAT_C_SPARSE ) {
2091
43
        const mat_sparse_t *sparse = (const mat_sparse_t *)matvar->data;
2092
43
        if ( NULL != sparse ) {
2093
42
            size_t sparse_size = 0;
2094
42
            err = Mul(&bytes, sparse->ndata, Mat_SizeOf(matvar->data_type));
2095
42
            if ( err )
2096
0
                return 0;
2097
2098
42
            if ( matvar->isComplex ) {
2099
42
                err = Mul(&bytes, bytes, 2);
2100
42
                if ( err )
2101
0
                    return 0;
2102
42
            }
2103
2104
42
#if defined(_WIN64) || (defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 8)) || \
2105
42
    (defined(SIZEOF_VOID_P) && (SIZEOF_VOID_P == 8))
2106
            /* 8 byte integers for 64-bit system (as displayed in MATLAB (x64) whos) */
2107
42
            err = Mul(&sparse_size, sparse->nir + sparse->njc, 8);
2108
#elif defined(_WIN32) || (defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4)) || \
2109
    (defined(SIZEOF_VOID_P) && (SIZEOF_VOID_P == 4))
2110
            /* 4 byte integers for 32-bit system (as defined by mat_sparse_t) */
2111
            err = Mul(&sparse_size, sparse->nir + sparse->njc, 4);
2112
#endif
2113
42
            err |= Add(&bytes, bytes, sparse_size);
2114
42
            if ( err )
2115
0
                return 0;
2116
2117
42
            if ( sparse->ndata == 0 || sparse->nir == 0 || sparse->njc == 0 ) {
2118
32
                err = Add(&bytes, bytes, matvar->isLogical ? 1 : 8);
2119
32
                if ( err )
2120
0
                    return 0;
2121
32
            }
2122
42
        }
2123
505
    } else {
2124
505
        if ( matvar->rank > 0 ) {
2125
467
            bytes = Mat_SizeOfClass(matvar->class_type);
2126
467
            err = Mat_MulDims(matvar, &bytes);
2127
467
            if ( err )
2128
4
                return 0;
2129
2130
463
            if ( matvar->isComplex ) {
2131
347
                err = Mul(&bytes, bytes, 2);
2132
347
                if ( err )
2133
0
                    return 0;
2134
347
            }
2135
463
        }
2136
505
    }
2137
2138
547
    return bytes;
2139
551
}
2140
2141
/** @brief Prints the variable information
2142
 *
2143
 * Prints to stdout the values of the @ref matvar_t structure
2144
 * @ingroup MAT
2145
 * @param matvar Pointer to the matvar_t structure
2146
 * @param printdata set to 1 if the Variables data should be printed, else 0
2147
 */
2148
void
2149
Mat_VarPrint(const matvar_t *matvar, int printdata)
2150
1.13k
{
2151
1.13k
    size_t nelems = 0, i, j;
2152
1.13k
    const char *class_type_desc[18] = {"Undefined",
2153
1.13k
                                       "Cell Array",
2154
1.13k
                                       "Structure",
2155
1.13k
                                       "Object",
2156
1.13k
                                       "Character Array",
2157
1.13k
                                       "Sparse Array",
2158
1.13k
                                       "Double Precision Array",
2159
1.13k
                                       "Single Precision Array",
2160
1.13k
                                       "8-bit, signed integer array",
2161
1.13k
                                       "8-bit, unsigned integer array",
2162
1.13k
                                       "16-bit, signed integer array",
2163
1.13k
                                       "16-bit, unsigned integer array",
2164
1.13k
                                       "32-bit, signed integer array",
2165
1.13k
                                       "32-bit, unsigned integer array",
2166
1.13k
                                       "64-bit, signed integer array",
2167
1.13k
                                       "64-bit, unsigned integer array",
2168
1.13k
                                       "Function",
2169
1.13k
                                       "Opaque"};
2170
2171
1.13k
    if ( matvar == NULL )
2172
16
        return;
2173
1.11k
    if ( NULL != matvar->name )
2174
560
        printf("      Name: %s\n", matvar->name);
2175
1.11k
    printf("      Rank: %d\n", matvar->rank);
2176
1.11k
    if ( matvar->rank <= 0 )
2177
94
        return;
2178
1.02k
    if ( NULL != matvar->dims ) {
2179
1.02k
        int err;
2180
1.02k
        nelems = 1;
2181
1.02k
        err = Mat_MulDims(matvar, &nelems);
2182
1.02k
        printf("Dimensions: %" SIZE_T_FMTSTR, matvar->dims[0]);
2183
1.02k
        if ( MATIO_E_NO_ERROR == err ) {
2184
1.02k
            int k;
2185
7.97k
            for ( k = 1; k < matvar->rank; k++ ) {
2186
6.95k
                printf(" x %" SIZE_T_FMTSTR, matvar->dims[k]);
2187
6.95k
            }
2188
1.02k
        }
2189
1.02k
        printf("\n");
2190
1.02k
    }
2191
1.02k
    printf("Class Type: %s", class_type_desc[matvar->class_type]);
2192
1.02k
    if ( matvar->isComplex )
2193
786
        printf(" (complex)");
2194
238
    else if ( matvar->isLogical )
2195
20
        printf(" (logical)");
2196
1.02k
    printf("\n");
2197
1.02k
    if ( matvar->data_type ) {
2198
958
        const char *data_type_desc[25] = {"Unknown",
2199
958
                                          "8-bit, signed integer",
2200
958
                                          "8-bit, unsigned integer",
2201
958
                                          "16-bit, signed integer",
2202
958
                                          "16-bit, unsigned integer",
2203
958
                                          "32-bit, signed integer",
2204
958
                                          "32-bit, unsigned integer",
2205
958
                                          "IEEE 754 single-precision",
2206
958
                                          "RESERVED",
2207
958
                                          "IEEE 754 double-precision",
2208
958
                                          "RESERVED",
2209
958
                                          "RESERVED",
2210
958
                                          "64-bit, signed integer",
2211
958
                                          "64-bit, unsigned integer",
2212
958
                                          "Matlab Array",
2213
958
                                          "Compressed Data",
2214
958
                                          "Unicode UTF-8 Encoded Character Data",
2215
958
                                          "Unicode UTF-16 Encoded Character Data",
2216
958
                                          "Unicode UTF-32 Encoded Character Data",
2217
958
                                          "RESERVED",
2218
958
                                          "String",
2219
958
                                          "Cell Array",
2220
958
                                          "Structure",
2221
958
                                          "Array",
2222
958
                                          "Function"};
2223
958
        printf(" Data Type: %s\n", data_type_desc[matvar->data_type]);
2224
958
    }
2225
2226
1.02k
    if ( MAT_C_STRUCT == matvar->class_type ) {
2227
2
        matvar_t **fields = (matvar_t **)matvar->data;
2228
2
        size_t nfields = matvar->internal->num_fields;
2229
2
        size_t nelems_x_nfields = 1;
2230
2
        int err = Mul(&nelems_x_nfields, nelems, nfields);
2231
2
        if ( MATIO_E_NO_ERROR == err && nelems_x_nfields > 0 ) {
2232
2
            printf("Fields[%" SIZE_T_FMTSTR "] {\n", nelems_x_nfields);
2233
14
            for ( i = 0; i < nelems_x_nfields; i++ ) {
2234
12
                if ( NULL == fields[i] ) {
2235
6
                    printf("      Name: %s\n      Rank: %d\n",
2236
6
                           matvar->internal->fieldnames[i % nfields], 0);
2237
6
                } else {
2238
6
                    Mat_VarPrint(fields[i], printdata);
2239
6
                }
2240
12
            }
2241
2
            printf("}\n");
2242
2
        } else {
2243
0
            printf("Fields[%" SIZE_T_FMTSTR "] {\n", nfields);
2244
0
            for ( i = 0; i < nfields; i++ )
2245
0
                printf("      Name: %s\n      Rank: %d\n", matvar->internal->fieldnames[i], 0);
2246
0
            printf("}\n");
2247
0
        }
2248
2
        return;
2249
1.02k
    } else if ( matvar->data == NULL || matvar->data_size < 1 ) {
2250
294
        if ( printdata )
2251
147
            printf("{\n}\n");
2252
294
        return;
2253
728
    } else if ( MAT_C_CELL == matvar->class_type ) {
2254
4
        matvar_t **cells = (matvar_t **)matvar->data;
2255
4
        nelems = matvar->nbytes / matvar->data_size;
2256
4
        printf("{\n");
2257
44
        for ( i = 0; i < nelems; i++ )
2258
40
            Mat_VarPrint(cells[i], printdata);
2259
4
        printf("}\n");
2260
4
        return;
2261
724
    } else if ( !printdata ) {
2262
362
        return;
2263
362
    }
2264
2265
362
    printf("{\n");
2266
2267
362
    if ( matvar->rank > 2 ) {
2268
14
        printf("I can't print more than 2 dimensions\n");
2269
348
    } else if ( matvar->rank == 1 && NULL != matvar->dims && matvar->dims[0] > 15 ) {
2270
79
        printf("I won't print more than 15 elements in a vector\n");
2271
269
    } else if ( matvar->rank == 2 && NULL != matvar->dims ) {
2272
269
        switch ( matvar->class_type ) {
2273
49
            case MAT_C_DOUBLE:
2274
67
            case MAT_C_SINGLE:
2275
67
#ifdef HAVE_MAT_INT64_T
2276
96
            case MAT_C_INT64:
2277
96
#endif
2278
96
#ifdef HAVE_MAT_UINT64_T
2279
136
            case MAT_C_UINT64:
2280
136
#endif
2281
155
            case MAT_C_INT32:
2282
200
            case MAT_C_UINT32:
2283
222
            case MAT_C_INT16:
2284
249
            case MAT_C_UINT16:
2285
251
            case MAT_C_INT8:
2286
269
            case MAT_C_UINT8: {
2287
269
                size_t stride = Mat_SizeOf(matvar->data_type);
2288
269
                if ( matvar->isComplex ) {
2289
163
                    mat_complex_split_t *complex_data = (mat_complex_split_t *)matvar->data;
2290
163
                    const char *rp = (const char *)complex_data->Re;
2291
163
                    const char *ip = (const char *)complex_data->Im;
2292
2.41k
                    for ( i = 0; i < matvar->dims[0] && i < 15; i++ ) {
2293
14.4k
                        for ( j = 0; j < matvar->dims[1] && j < 15; j++ ) {
2294
12.1k
                            size_t idx = matvar->dims[0] * j + i;
2295
12.1k
                            Mat_PrintNumber(matvar->data_type, rp + idx * stride);
2296
12.1k
                            printf(" + ");
2297
12.1k
                            Mat_PrintNumber(matvar->data_type, ip + idx * stride);
2298
12.1k
                            printf("i ");
2299
12.1k
                        }
2300
2.24k
                        if ( j < matvar->dims[1] )
2301
284
                            printf("...");
2302
2.24k
                        printf("\n");
2303
2.24k
                    }
2304
163
                    if ( i < matvar->dims[0] )
2305
141
                        printf(".\n.\n.\n");
2306
163
                } else {
2307
106
                    const char *data = (const char *)matvar->data;
2308
1.29k
                    for ( i = 0; i < matvar->dims[0] && i < 15; i++ ) {
2309
15.3k
                        for ( j = 0; j < matvar->dims[1] && j < 15; j++ ) {
2310
14.1k
                            size_t idx = matvar->dims[0] * j + i;
2311
14.1k
                            Mat_PrintNumber(matvar->data_type, data + idx * stride);
2312
14.1k
                            printf(" ");
2313
14.1k
                        }
2314
1.19k
                        if ( j < matvar->dims[1] )
2315
830
                            printf("...");
2316
1.19k
                        printf("\n");
2317
1.19k
                    }
2318
106
                    if ( i < matvar->dims[0] )
2319
66
                        printf(".\n.\n.\n");
2320
106
                }
2321
269
                break;
2322
251
            }
2323
0
            case MAT_C_CHAR: {
2324
0
                switch ( matvar->data_type ) {
2325
0
                    case MAT_T_UINT16:
2326
0
                    case MAT_T_UTF16: {
2327
0
                        const mat_uint16_t *data = (const mat_uint16_t *)matvar->data;
2328
0
                        for ( i = 0; i < matvar->dims[0]; i++ ) {
2329
0
                            for ( j = 0; j < matvar->dims[1]; j++ ) {
2330
0
                                const mat_uint16_t c = data[j * matvar->dims[0] + i];
2331
#if defined VARPRINT_UTF16
2332
                                printf("%c%c", c & 0xFF, (c >> 8) & 0xFF);
2333
#elif defined VARPRINT_UTF16_DECIMAL
2334
                                Mat_PrintNumber(MAT_T_UINT16, &c);
2335
                                printf(" ");
2336
#else
2337
                                /* Convert to UTF-8 */
2338
0
                                if ( c <= 0x7F ) {
2339
0
                                    printf("%c", c);
2340
0
                                } else if ( c <= 0x7FF ) {
2341
0
                                    printf("%c%c", 0xC0 | (c >> 6), 0x80 | (c & 0x3F));
2342
0
                                } else /* if (c <= 0xFFFF) */ {
2343
0
                                    printf("%c%c%c", 0xE0 | (c >> 12), 0x80 | ((c >> 6) & 0x3F),
2344
0
                                           0x80 | (c & 0x3F));
2345
0
                                }
2346
0
#endif
2347
0
                            }
2348
0
                            printf("\n");
2349
0
                        }
2350
0
                        break;
2351
0
                    }
2352
0
                    case MAT_T_UTF8: {
2353
0
                        const mat_uint8_t *data = (const mat_uint8_t *)matvar->data;
2354
0
                        size_t k = 0;
2355
0
                        size_t *idxOffset;
2356
0
                        if ( matvar->nbytes == 0 ) {
2357
0
                            break;
2358
0
                        }
2359
0
                        idxOffset = (size_t *)calloc(nelems, sizeof(size_t));
2360
0
                        if ( idxOffset == NULL ) {
2361
0
                            break;
2362
0
                        }
2363
0
                        for ( i = 0; i < matvar->dims[0]; i++ ) {
2364
0
                            for ( j = 0; j < matvar->dims[1]; j++ ) {
2365
0
                                mat_uint8_t c;
2366
0
                                if ( k >= matvar->nbytes ) {
2367
0
                                    break;
2368
0
                                }
2369
0
                                idxOffset[i * matvar->dims[1] + j] = k;
2370
0
                                c = data[k];
2371
0
                                if ( c <= 0x7F ) {
2372
0
                                } else if ( (c & 0xE0) == 0xC0 && k + 1 < matvar->nbytes ) {
2373
0
                                    k = k + 1;
2374
0
                                } else if ( (c & 0xF0) == 0xE0 && k + 2 < matvar->nbytes ) {
2375
0
                                    k = k + 2;
2376
0
                                } else if ( (c & 0xF8) == 0xF0 && k + 3 < matvar->nbytes ) {
2377
0
                                    k = k + 3;
2378
0
                                }
2379
0
                                ++k;
2380
0
                            }
2381
0
                        }
2382
0
                        for ( i = 0; i < matvar->dims[0]; i++ ) {
2383
0
                            for ( j = 0; j < matvar->dims[1]; j++ ) {
2384
0
                                mat_uint8_t c;
2385
0
                                k = idxOffset[j * matvar->dims[0] + i];
2386
0
                                c = data[k];
2387
0
                                if ( c <= 0x7F ) {
2388
0
                                    printf("%c", c);
2389
0
                                } else if ( (c & 0xE0) == 0xC0 ) {
2390
0
                                    printf("%c%c", c, data[k + 1]);
2391
0
                                } else if ( (c & 0xF0) == 0xE0 ) {
2392
0
                                    printf("%c%c%c", c, data[k + 1], data[k + 2]);
2393
0
                                } else if ( (c & 0xF8) == 0xF0 ) {
2394
0
                                    printf("%c%c%c%c", c, data[k + 1], data[k + 2], data[k + 3]);
2395
0
                                }
2396
0
                            }
2397
0
                            printf("\n");
2398
0
                        }
2399
0
                        free(idxOffset);
2400
0
                        break;
2401
0
                    }
2402
0
                    default: {
2403
0
                        const char *data = (const char *)matvar->data;
2404
0
                        for ( i = 0; i < matvar->dims[0]; i++ ) {
2405
0
                            for ( j = 0; j < matvar->dims[1]; j++ )
2406
0
                                printf("%c", data[j * matvar->dims[0] + i]);
2407
0
                            printf("\n");
2408
0
                        }
2409
0
                        break;
2410
0
                    }
2411
0
                }
2412
0
                break;
2413
0
            }
2414
0
            case MAT_C_SPARSE: {
2415
0
                mat_sparse_t *sparse;
2416
0
                size_t stride = Mat_SizeOf(matvar->data_type);
2417
#if !defined(EXTENDED_SPARSE)
2418
                if ( MAT_T_DOUBLE != matvar->data_type )
2419
                    break;
2420
#endif
2421
0
                sparse = (mat_sparse_t *)matvar->data;
2422
0
                if ( sparse == NULL || sparse->ndata == 0 || sparse->nir == 0 || sparse->njc == 0 ||
2423
0
                     sparse->data == NULL ) {
2424
0
                    break;
2425
0
                }
2426
0
                if ( matvar->isComplex ) {
2427
0
                    mat_complex_split_t *complex_data = (mat_complex_split_t *)sparse->data;
2428
0
                    const char *re = (const char *)complex_data->Re;
2429
0
                    const char *im = (const char *)complex_data->Im;
2430
0
                    for ( i = 0; i < (size_t)sparse->njc - 1; i++ ) {
2431
0
                        for ( j = sparse->jc[i];
2432
0
                              j < (size_t)sparse->jc[i + 1] && j < (size_t)sparse->ndata; j++ ) {
2433
0
                            printf("    (%u,%" SIZE_T_FMTSTR ")  ", sparse->ir[j] + 1, i + 1);
2434
0
                            Mat_PrintNumber(matvar->data_type, re + j * stride);
2435
0
                            printf(" + ");
2436
0
                            Mat_PrintNumber(matvar->data_type, im + j * stride);
2437
0
                            printf("i\n");
2438
0
                        }
2439
0
                    }
2440
0
                } else {
2441
0
                    const char *data = (const char *)sparse->data;
2442
0
                    for ( i = 0; i < (size_t)sparse->njc - 1; i++ ) {
2443
0
                        for ( j = sparse->jc[i];
2444
0
                              j < (size_t)sparse->jc[i + 1] && j < (size_t)sparse->ndata; j++ ) {
2445
0
                            printf("    (%u,%" SIZE_T_FMTSTR ")  ", sparse->ir[j] + 1, i + 1);
2446
0
                            Mat_PrintNumber(matvar->data_type, data + j * stride);
2447
0
                            printf("\n");
2448
0
                        }
2449
0
                    }
2450
0
                }
2451
0
                break;
2452
0
            } /* case MAT_C_SPARSE: */
2453
0
            default:
2454
0
                break;
2455
269
        } /* switch( matvar->class_type ) */
2456
269
    }
2457
2458
362
    printf("}\n");
2459
362
}
2460
2461
/** @brief Reads MAT variable data from a file
2462
 *
2463
 * Reads data from a MAT variable.  The variable must have been read by
2464
 * Mat_VarReadInfo.
2465
 * @ingroup MAT
2466
 * @param mat MAT file to read data from
2467
 * @param matvar MAT variable information
2468
 * @param data pointer to store data in (must be pre-allocated)
2469
 * @param start array of starting indices
2470
 * @param stride stride of data
2471
 * @param edge array specifying the number to read in each direction
2472
 * @retval 0 on success
2473
 */
2474
int
2475
Mat_VarReadData(mat_t *mat, matvar_t *matvar, void *data, const int *start, const int *stride,
2476
                const int *edge)
2477
0
{
2478
0
    int err = MATIO_E_NO_ERROR;
2479
2480
0
    switch ( matvar->class_type ) {
2481
0
        case MAT_C_DOUBLE:
2482
0
        case MAT_C_SINGLE:
2483
0
        case MAT_C_INT64:
2484
0
        case MAT_C_UINT64:
2485
0
        case MAT_C_INT32:
2486
0
        case MAT_C_UINT32:
2487
0
        case MAT_C_INT16:
2488
0
        case MAT_C_UINT16:
2489
0
        case MAT_C_INT8:
2490
0
        case MAT_C_UINT8:
2491
0
            break;
2492
0
        default:
2493
0
            return MATIO_E_OPERATION_NOT_SUPPORTED;
2494
0
    }
2495
2496
0
    switch ( mat->version ) {
2497
0
        case MAT_FT_MAT5:
2498
0
            err = Mat_VarReadData5(mat, matvar, data, start, stride, edge);
2499
0
            break;
2500
0
        case MAT_FT_MAT73:
2501
0
#if defined(MAT73) && MAT73
2502
0
            err = Mat_VarReadData73(mat, matvar, data, start, stride, edge);
2503
#else
2504
            err = MATIO_E_OPERATION_NOT_SUPPORTED;
2505
#endif
2506
0
            break;
2507
0
        case MAT_FT_MAT4:
2508
0
            err = Mat_VarReadData4(mat, matvar, data, start, stride, edge);
2509
0
            break;
2510
0
        default:
2511
0
            err = MATIO_E_FAIL_TO_IDENTIFY;
2512
0
            break;
2513
0
    }
2514
2515
0
    return err;
2516
0
}
2517
2518
/** @brief Reads all the data for a matlab variable
2519
 *
2520
 * Allocates memory and reads the data for a given matlab variable.
2521
 * @ingroup MAT
2522
 * @param mat Matlab MAT file structure pointer
2523
 * @param matvar Variable whose data is to be read
2524
 * @returns non-zero on error
2525
 */
2526
int
2527
Mat_VarReadDataAll(mat_t *mat, matvar_t *matvar)
2528
544
{
2529
544
    int err = MATIO_E_NO_ERROR;
2530
2531
544
    if ( mat == NULL || matvar == NULL )
2532
0
        err = MATIO_E_BAD_ARGUMENT;
2533
544
    else
2534
544
        err = ReadData(mat, matvar);
2535
2536
544
    return err;
2537
544
}
2538
2539
/** @brief Reads a subset of a MAT variable using a 1-D indexing
2540
 *
2541
 * Reads data from a MAT variable using a linear (1-D) indexing mode. The
2542
 * variable must have been read by Mat_VarReadInfo.
2543
 * @ingroup MAT
2544
 * @param mat MAT file to read data from
2545
 * @param matvar MAT variable information
2546
 * @param data pointer to store data in (must be pre-allocated)
2547
 * @param start starting index
2548
 * @param stride stride of data
2549
 * @param edge number of elements to read
2550
 * @retval 0 on success
2551
 */
2552
int
2553
Mat_VarReadDataLinear(mat_t *mat, matvar_t *matvar, void *data, int start, int stride, int edge)
2554
0
{
2555
0
    int err = MATIO_E_NO_ERROR;
2556
2557
0
    switch ( matvar->class_type ) {
2558
0
        case MAT_C_DOUBLE:
2559
0
        case MAT_C_SINGLE:
2560
0
        case MAT_C_INT64:
2561
0
        case MAT_C_UINT64:
2562
0
        case MAT_C_INT32:
2563
0
        case MAT_C_UINT32:
2564
0
        case MAT_C_INT16:
2565
0
        case MAT_C_UINT16:
2566
0
        case MAT_C_INT8:
2567
0
        case MAT_C_UINT8:
2568
0
            break;
2569
0
        default:
2570
0
            return MATIO_E_OPERATION_NOT_SUPPORTED;
2571
0
    }
2572
2573
0
    switch ( mat->version ) {
2574
0
        case MAT_FT_MAT5:
2575
0
            err = Mat_VarReadDataLinear5(mat, matvar, data, start, stride, edge);
2576
0
            break;
2577
0
        case MAT_FT_MAT73:
2578
0
#if defined(MAT73) && MAT73
2579
0
            err = Mat_VarReadDataLinear73(mat, matvar, data, start, stride, edge);
2580
#else
2581
            err = MATIO_E_OPERATION_NOT_SUPPORTED;
2582
#endif
2583
0
            break;
2584
0
        case MAT_FT_MAT4:
2585
0
            err = Mat_VarReadDataLinear4(mat, matvar, data, start, stride, edge);
2586
0
            break;
2587
0
        default:
2588
0
            err = MATIO_E_FAIL_TO_IDENTIFY;
2589
0
            break;
2590
0
    }
2591
2592
0
    return err;
2593
0
}
2594
2595
/** @brief Reads the information of the next variable in a MAT file
2596
 *
2597
 * Reads the next variable's information (class,flags-complex/global/logical,
2598
 * rank,dimensions, name, etc) from the Matlab MAT file. After reading, the MAT
2599
 * file is positioned past the current variable.
2600
 * @ingroup MAT
2601
 * @param mat Pointer to the MAT file
2602
 * @return Pointer to the @ref matvar_t structure containing the MAT
2603
 * variable information
2604
 */
2605
matvar_t *
2606
Mat_VarReadNextInfo(mat_t *mat)
2607
1.97k
{
2608
1.97k
    return Mat_VarReadNextInfoPredicate(mat, NULL, NULL);
2609
1.97k
}
2610
2611
/** @brief Reads the information of the next variable in a filtered MAT file
2612
 *
2613
 * Reads the next variable's information (class,flags-complex/global/logical,
2614
 * rank,dimensions, name, etc) from the Matlab MAT file. Calls a user callback
2615
 * to check where the variable has to be fully read or skipped.
2616
 * If skipped tries to read next till accepted or EOF.
2617
 * After reading, the MAT file is positioned past the current variable.
2618
 * @ingroup MAT
2619
 * @param mat Pointer to the MAT file
2620
 * @param pred User callback function
2621
 * @param user_data User data to be passed to the callback function
2622
 * @return Pointer to the @ref matvar_t structure containing the MAT
2623
 * variable information
2624
 */
2625
matvar_t *
2626
Mat_VarReadNextInfoPredicate(mat_t *mat, mat_iter_pred_t pred, const void *user_data)
2627
2.40k
{
2628
2.40k
    matvar_t *matvar;
2629
2.40k
    if ( mat == NULL )
2630
0
        return NULL;
2631
2632
2.40k
    switch ( mat->version ) {
2633
2.32k
        case MAT_FT_MAT5:
2634
2.32k
            matvar = Mat_VarReadNextInfo5(mat);
2635
2.32k
            break;
2636
82
        case MAT_FT_MAT73:
2637
82
#if defined(MAT73) && MAT73
2638
82
            matvar = Mat_VarReadNextInfo73(mat, pred, user_data);
2639
#else
2640
            matvar = NULL;
2641
#endif
2642
82
            break;
2643
0
        case MAT_FT_MAT4:
2644
0
            matvar = Mat_VarReadNextInfo4(mat);
2645
0
            break;
2646
0
        default:
2647
0
            matvar = NULL;
2648
0
            break;
2649
2.40k
    }
2650
2651
2.40k
    return matvar;
2652
2.40k
}
2653
2654
#if defined(MAT73) && MAT73
2655
static int
2656
Mat_IteratorNameAcceptor(const char *name, const void *user_data)
2657
601
{
2658
601
    const char *required_name = (const char *)user_data;
2659
601
    return (NULL != name) && (NULL != required_name) && 0 == strcmp(name, required_name);
2660
601
}
2661
#endif
2662
2663
/** @brief Reads the information of a variable with the given name from a MAT file
2664
 *
2665
 * Reads the named variable (or the next variable if name is NULL) information
2666
 * (class,flags-complex/global/logical,rank,dimensions,and name) from the
2667
 * Matlab MAT file
2668
 * @ingroup MAT
2669
 * @param mat Pointer to the MAT file
2670
 * @param name Name of the variable to read
2671
 * @return Pointer to the @ref matvar_t structure containing the MAT
2672
 * variable information
2673
 */
2674
matvar_t *
2675
Mat_VarReadInfo(mat_t *mat, const char *name)
2676
341
{
2677
341
    matvar_t *matvar = NULL;
2678
2679
341
    if ( mat == NULL || name == NULL )
2680
0
        return NULL;
2681
2682
341
    if ( mat->version == MAT_FT_MAT73 ) {
2683
64
        size_t fpos = mat->next_index;
2684
64
        mat->next_index = 0;
2685
89
        while ( NULL == matvar && mat->next_index < mat->num_datasets ) {
2686
64
#if defined(MAT73) && MAT73
2687
64
            matvar = Mat_VarReadNextInfoPredicate(mat, Mat_IteratorNameAcceptor, name);
2688
64
            if ( NULL == matvar ) {
2689
39
                Mat_Critical("An error occurred in reading the MAT file");
2690
39
                break;
2691
39
            }
2692
#else
2693
            matvar = Mat_VarReadNextInfo(mat);
2694
            if ( matvar != NULL ) {
2695
                if ( matvar->name == NULL || 0 != strcmp(matvar->name, name) ) {
2696
                    Mat_VarFree(matvar);
2697
                    matvar = NULL;
2698
                }
2699
            } else {
2700
                Mat_Critical("An error occurred in reading the MAT file");
2701
                break;
2702
            }
2703
#endif
2704
64
        }
2705
64
        mat->next_index = fpos;
2706
277
    } else {
2707
277
        mat_off_t fpos = ftello((FILE *)mat->fp);
2708
277
        if ( fpos != -1L ) {
2709
277
            (void)fseeko((FILE *)mat->fp, mat->bof, SEEK_SET);
2710
761
            do {
2711
761
                matvar = Mat_VarReadNextInfo(mat);
2712
761
                if ( matvar != NULL ) {
2713
761
                    if ( matvar->name == NULL || 0 != strcmp(matvar->name, name) ) {
2714
484
                        Mat_VarFree(matvar);
2715
484
                        matvar = NULL;
2716
484
                    }
2717
761
                } else if ( !IsEndOfFile((FILE *)mat->fp, NULL) ) {
2718
0
                    Mat_Critical("An error occurred in reading the MAT file");
2719
0
                    break;
2720
0
                }
2721
761
            } while ( NULL == matvar && !IsEndOfFile((FILE *)mat->fp, NULL) );
2722
0
            (void)fseeko((FILE *)mat->fp, fpos, SEEK_SET);
2723
277
        } else {
2724
0
            Mat_Critical("Couldn't determine file position");
2725
0
        }
2726
277
    }
2727
2728
0
    return matvar;
2729
341
}
2730
2731
/** @brief Reads the variable with the given name from a MAT file
2732
 *
2733
 * Reads the next variable in the Matlab MAT file
2734
 * @ingroup MAT
2735
 * @param mat Pointer to the MAT file
2736
 * @param name Name of the variable to read
2737
 * @return Pointer to the @ref matvar_t structure containing the MAT
2738
 * variable information
2739
 */
2740
matvar_t *
2741
Mat_VarRead(mat_t *mat, const char *name)
2742
341
{
2743
341
    matvar_t *matvar = NULL;
2744
2745
341
    if ( mat == NULL || name == NULL )
2746
0
        return NULL;
2747
2748
341
    if ( MAT_FT_MAT73 != mat->version ) {
2749
277
        mat_off_t fpos = ftello((FILE *)mat->fp);
2750
277
        if ( fpos == -1L ) {
2751
0
            Mat_Critical("Couldn't determine file position");
2752
0
            return NULL;
2753
0
        }
2754
277
        matvar = Mat_VarReadInfo(mat, name);
2755
277
        if ( matvar != NULL ) {
2756
277
            const int err = ReadData(mat, matvar);
2757
277
            if ( err ) {
2758
59
                Mat_VarFree(matvar);
2759
59
                matvar = NULL;
2760
59
            }
2761
277
        }
2762
277
        (void)fseeko((FILE *)mat->fp, fpos, SEEK_SET);
2763
277
    } else {
2764
64
        size_t fpos = mat->next_index;
2765
64
        mat->next_index = 0;
2766
64
        matvar = Mat_VarReadInfo(mat, name);
2767
64
        if ( matvar != NULL ) {
2768
25
            const int err = ReadData(mat, matvar);
2769
25
            if ( err ) {
2770
3
                Mat_VarFree(matvar);
2771
3
                matvar = NULL;
2772
3
            }
2773
25
        }
2774
64
        mat->next_index = fpos;
2775
64
    }
2776
2777
341
    return matvar;
2778
341
}
2779
2780
/** @brief Reads the next variable in a MAT file
2781
 *
2782
 * Reads the next variable in the Matlab MAT file
2783
 * @ingroup MAT
2784
 * @param mat Pointer to the MAT file
2785
 * @return Pointer to the @ref matvar_t structure containing the MAT
2786
 * variable information
2787
 */
2788
matvar_t *
2789
Mat_VarReadNext(mat_t *mat)
2790
365
{
2791
365
    return Mat_VarReadNextPredicate(mat, NULL, NULL);
2792
365
}
2793
2794
/** @brief Reads the next variable in a filtered MAT file
2795
 *
2796
 * Reads the next variable in the Matlab MAT file. Calls a user callback
2797
 * to check where the variable has to be fully read of skipped.
2798
 * If skipped tries to read next till accepted or EOF.
2799
 *
2800
 * @ingroup MAT
2801
 * @param mat Pointer to the MAT file
2802
 * @return Pointer to the @ref matvar_t structure containing the MAT
2803
 * variable information
2804
 */
2805
matvar_t *
2806
Mat_VarReadNextPredicate(mat_t *mat, mat_iter_pred_t pred, const void *user_data)
2807
365
{
2808
365
    mat_off_t fpos = 0;
2809
365
    matvar_t *matvar = NULL;
2810
2811
365
    do {
2812
365
        Mat_VarFree(matvar);
2813
365
        if ( mat->version != MAT_FT_MAT73 ) {
2814
356
            if ( IsEndOfFile((FILE *)mat->fp, &fpos) )
2815
0
                return NULL;
2816
356
            if ( fpos == -1L ) {
2817
0
                return NULL;
2818
0
            }
2819
356
        }
2820
365
        matvar = Mat_VarReadNextInfoPredicate(mat, pred, user_data);
2821
365
        if ( matvar ) {
2822
332
            const int err = ReadData(mat, matvar);
2823
332
            if ( err ) {
2824
36
                Mat_VarFree(matvar);
2825
36
                matvar = NULL;
2826
36
                break;
2827
36
            }
2828
332
        } else {
2829
33
            if ( mat->version != MAT_FT_MAT73 ) {
2830
                /* Reset the file position */
2831
24
                (void)fseeko((FILE *)mat->fp, fpos, SEEK_SET);
2832
24
            }
2833
33
            break;
2834
33
        }
2835
365
    } while ( (NULL != pred) && 0 == pred(matvar->name, user_data) );
2836
    /* for 7.3 the predicate will be called one extra time */
2837
2838
365
    return matvar;
2839
365
}
2840
2841
/** @brief Writes the given MAT variable to a MAT file
2842
 *
2843
 * Writes the MAT variable information stored in matvar to the given MAT file.
2844
 * The variable will be written to the end of the file.
2845
 * @ingroup MAT
2846
 * @param mat MAT file to write to
2847
 * @param matvar MAT variable information to write
2848
 * @retval 1
2849
 * @deprecated
2850
 * @see Mat_VarWrite/Mat_VarWriteAppend
2851
 */
2852
int
2853
Mat_VarWriteInfo(const mat_t *mat, matvar_t *matvar)
2854
0
{
2855
0
    Mat_Critical(
2856
0
        "Mat_VarWriteInfo/Mat_VarWriteData is not supported. "
2857
0
        "Use %s instead!",
2858
0
        mat->version == MAT_FT_MAT73 ? "Mat_VarWrite/Mat_VarWriteAppend" : "Mat_VarWrite");
2859
0
    return MATIO_E_OPERATION_NOT_SUPPORTED;
2860
0
}
2861
2862
/** @brief Writes the given data to the MAT variable
2863
 *
2864
 * Writes data to a MAT variable.  The variable must have previously been
2865
 * written with Mat_VarWriteInfo.
2866
 * @ingroup MAT
2867
 * @param mat MAT file to write to
2868
 * @param matvar MAT variable information to write
2869
 * @param data pointer to the data to write
2870
 * @param start array of starting indices
2871
 * @param stride stride of data
2872
 * @param edge array specifying the number to read in each direction
2873
 * @retval 1
2874
 * @deprecated
2875
 * @see Mat_VarWrite/Mat_VarWriteAppend
2876
 */
2877
int
2878
Mat_VarWriteData(const mat_t *mat, matvar_t *matvar, void *data, const int *start,
2879
                 const int *stride, const int *edge)
2880
0
{
2881
0
    Mat_Critical(
2882
0
        "Mat_VarWriteInfo/Mat_VarWriteData is not supported. "
2883
0
        "Use %s instead!",
2884
0
        mat->version == MAT_FT_MAT73 ? "Mat_VarWrite/Mat_VarWriteAppend" : "Mat_VarWrite");
2885
0
    return MATIO_E_OPERATION_NOT_SUPPORTED;
2886
0
}
2887
2888
/** @brief Writes the given MAT variable to a MAT file
2889
 *
2890
 * Writes the MAT variable information stored in matvar to the given MAT file.
2891
 * The variable will be written to the end of the file.
2892
 * @ingroup MAT
2893
 * @param mat MAT file to write to
2894
 * @param matvar MAT variable information to write
2895
 * @param compress Whether or not to compress the data
2896
 *        (Only valid for version 5 and 7.3 MAT files and variables with
2897
           numeric data)
2898
 * @retval 0 on success
2899
 */
2900
int
2901
Mat_VarWrite(mat_t *mat, matvar_t *matvar, enum matio_compression compress)
2902
0
{
2903
0
    int err;
2904
2905
0
    if ( NULL == mat || NULL == matvar )
2906
0
        return MATIO_E_BAD_ARGUMENT;
2907
2908
0
    if ( NULL == mat->dir ) {
2909
0
        size_t n = 0;
2910
0
        (void)Mat_GetDir(mat, &n);
2911
0
    }
2912
2913
0
    if ( NULL != mat->dir ) {
2914
        /* Error if MAT variable already exists in MAT file */
2915
0
        size_t i;
2916
0
        for ( i = 0; i < mat->num_datasets; i++ ) {
2917
0
            if ( NULL != mat->dir[i] && 0 == strcmp(mat->dir[i], matvar->name) ) {
2918
0
                Mat_Critical("Variable %s already exists", matvar->name);
2919
0
                return MATIO_E_OUTPUT_BAD_DATA;
2920
0
            }
2921
0
        }
2922
0
    }
2923
2924
0
    if ( mat->version == MAT_FT_MAT5 )
2925
0
        err = Mat_VarWrite5(mat, matvar, compress);
2926
0
    else if ( mat->version == MAT_FT_MAT73 )
2927
0
#if defined(MAT73) && MAT73
2928
0
        err = Mat_VarWrite73(mat, matvar, compress);
2929
#else
2930
        err = MATIO_E_OPERATION_NOT_SUPPORTED;
2931
#endif
2932
0
    else if ( mat->version == MAT_FT_MAT4 )
2933
0
        err = Mat_VarWrite4(mat, matvar);
2934
0
    else
2935
0
        err = MATIO_E_FAIL_TO_IDENTIFY;
2936
2937
0
    if ( err == MATIO_E_NO_ERROR ) {
2938
        /* Update directory */
2939
0
        char **dir;
2940
0
        if ( NULL == mat->dir ) {
2941
0
            dir = (char **)malloc(sizeof(char *));
2942
0
        } else {
2943
0
            dir = (char **)realloc(mat->dir, (mat->num_datasets + 1) * (sizeof(char *)));
2944
0
        }
2945
0
        if ( NULL != dir ) {
2946
0
            mat->dir = dir;
2947
0
            if ( NULL != matvar->name ) {
2948
0
                mat->dir[mat->num_datasets++] = strdup(matvar->name);
2949
0
            } else {
2950
0
                mat->dir[mat->num_datasets++] = NULL;
2951
0
            }
2952
0
        } else {
2953
0
            err = MATIO_E_OUT_OF_MEMORY;
2954
0
            Mat_Critical("Couldn't allocate memory for the directory");
2955
0
        }
2956
0
    }
2957
2958
0
    return err;
2959
0
}
2960
2961
/** @brief Writes/appends the given MAT variable to a version 7.3 MAT file
2962
 *
2963
 * Writes the numeric data of the MAT variable stored in matvar to the given
2964
 * MAT file. The variable will be written to the end of the file if it does
2965
 * not yet exist or appended to the existing variable.
2966
 * @ingroup MAT
2967
 * @param mat MAT file to write to
2968
 * @param matvar MAT variable information to write
2969
 * @param compress Whether or not to compress the data
2970
 *        (Only valid for version 7.3 MAT files and variables with numeric data)
2971
 * @param dim dimension to append data
2972
 *        (Only valid for version 7.3 MAT files and variables with numeric data)
2973
 * @retval 0 on success
2974
 */
2975
int
2976
Mat_VarWriteAppend(mat_t *mat, matvar_t *matvar, enum matio_compression compress, int dim)
2977
0
{
2978
0
    int err;
2979
2980
0
    if ( NULL == mat || NULL == matvar )
2981
0
        return MATIO_E_BAD_ARGUMENT;
2982
2983
0
    if ( NULL == mat->dir ) {
2984
0
        size_t n = 0;
2985
0
        (void)Mat_GetDir(mat, &n);
2986
0
    }
2987
2988
0
    if ( mat->version == MAT_FT_MAT73 ) {
2989
0
#if defined(MAT73) && MAT73
2990
0
        int append = 0;
2991
0
        {
2992
            /* Check if MAT variable already exists in MAT file */
2993
0
            size_t i;
2994
0
            for ( i = 0; i < mat->num_datasets; i++ ) {
2995
0
                if ( NULL != mat->dir[i] && 0 == strcmp(mat->dir[i], matvar->name) ) {
2996
0
                    append = 1;
2997
0
                    break;
2998
0
                }
2999
0
            }
3000
0
        }
3001
0
        err = Mat_VarWriteAppend73(mat, matvar, compress, dim);
3002
0
        if ( err == MATIO_E_NO_ERROR && 0 == append ) {
3003
            /* Update directory */
3004
0
            char **dir;
3005
0
            if ( NULL == mat->dir ) {
3006
0
                dir = (char **)malloc(sizeof(char *));
3007
0
            } else {
3008
0
                dir = (char **)realloc(mat->dir, (mat->num_datasets + 1) * (sizeof(char *)));
3009
0
            }
3010
0
            if ( NULL != dir ) {
3011
0
                mat->dir = dir;
3012
0
                if ( NULL != matvar->name ) {
3013
0
                    mat->dir[mat->num_datasets++] = strdup(matvar->name);
3014
0
                } else {
3015
0
                    mat->dir[mat->num_datasets++] = NULL;
3016
0
                }
3017
0
            } else {
3018
0
                err = MATIO_E_OUT_OF_MEMORY;
3019
0
                Mat_Critical("Couldn't allocate memory for the directory");
3020
0
            }
3021
0
        }
3022
#else
3023
        err = MATIO_E_OPERATION_NOT_SUPPORTED;
3024
#endif
3025
0
    } else if ( mat->version == MAT_FT_MAT4 || mat->version == MAT_FT_MAT5 ) {
3026
0
        err = MATIO_E_OPERATION_NOT_SUPPORTED;
3027
0
    } else {
3028
0
        err = MATIO_E_FAIL_TO_IDENTIFY;
3029
0
    }
3030
3031
0
    return err;
3032
0
}