Coverage Report

Created: 2026-10-28 18:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/matio/src/mat4.c
Line
Count
Source
1
/** @file mat4.c
2
 * Matlab MAT version 4 file functions
3
 * @ingroup MAT
4
 */
5
/*
6
 * Copyright (c) 2015-2026, The matio contributors
7
 * Copyright (c) 2005-2014, Christopher C. Hulbert
8
 * All rights reserved.
9
 *
10
 * SPDX-License-Identifier: BSD-2-Clause
11
 */
12
13
#include "matio_private.h"
14
#include "mat4.h"
15
#if defined(__GLIBC__)
16
#include <endian.h>
17
#endif
18
#include <stdlib.h>
19
#include <string.h>
20
#include <stdio.h>
21
#include <math.h>
22
#include <limits.h>
23
#if defined(_MSC_VER) || defined(__MINGW32__)
24
#define strdup _strdup
25
#endif
26
27
/** @if mat_devman
28
 * @brief Creates a new Matlab MAT version 4 file
29
 *
30
 * Tries to create a new Matlab MAT file with the given name.
31
 * @ingroup MAT
32
 * @param matname Name of MAT file to create
33
 * @return A pointer to the MAT file or NULL if it failed.  This is not a
34
 * simple FILE * and should not be used as one.
35
 * @endif
36
 */
37
mat_t *
38
Mat_Create4(const char *matname)
39
0
{
40
0
    FILE *fp;
41
0
    mat_t *mat = NULL;
42
43
#if defined(_WIN32)
44
    wchar_t *wname = utf82u(matname);
45
    if ( NULL != wname ) {
46
        fp = _wfopen(wname, L"w+b");
47
        free(wname);
48
    } else {
49
        fp = NULL;
50
    }
51
#else
52
0
    fp = fopen(matname, "w+b");
53
0
#endif
54
0
    if ( !fp )
55
0
        return NULL;
56
57
0
    mat = (mat_t *)malloc(sizeof(*mat));
58
0
    if ( NULL == mat ) {
59
0
        fclose(fp);
60
0
        Mat_Critical("Couldn't allocate memory for the MAT file");
61
0
        return NULL;
62
0
    }
63
64
0
    mat->memfile = NULL;
65
0
    mat->fp = fp;
66
0
    mat->header = NULL;
67
0
    mat->subsys_offset = NULL;
68
0
    mat->filename = strdup(matname);
69
0
    if ( NULL == mat->filename ) {
70
0
        Mat_Close(mat);
71
0
        return NULL;
72
0
    }
73
0
    mat->version = 0x0010;
74
0
    mat->byteswap = 0;
75
0
    mat->mode = MAT_ACC_RDWR;
76
0
    mat->bof = 0;
77
0
    mat->next_index = 0;
78
0
    mat->num_datasets = 0;
79
0
#if defined(MAT73) && MAT73
80
0
    mat->refs_id = -1;
81
0
#endif
82
0
    mat->dir = NULL;
83
0
#if defined(MCOS) && MCOS
84
0
    mat->mcos = NULL;
85
0
#endif
86
87
0
    Mat_Rewind(mat);
88
89
0
    return mat;
90
0
}
91
92
/** @if mat_devman
93
 * @brief Writes a matlab variable to a version 4 matlab file
94
 *
95
 * @ingroup mat_internal
96
 * @param mat MAT file pointer
97
 * @param matvar pointer to the mat variable
98
 * @retval 0 on success
99
 * @endif
100
 */
101
int
102
Mat_VarWrite4(const mat_t *mat, const matvar_t *matvar)
103
0
{
104
0
#if defined(MATIO_LE) || defined(MATIO_BE)
105
0
    typedef struct
106
0
    {
107
0
        mat_int32_t type;
108
0
        mat_int32_t mrows;
109
0
        mat_int32_t ncols;
110
0
        mat_int32_t imagf;
111
0
        mat_int32_t namelen;
112
0
    } Fmatrix;
113
114
0
    Fmatrix x;
115
116
0
    if ( NULL == mat || NULL == matvar )
117
0
        return MATIO_E_BAD_ARGUMENT;
118
0
    if ( NULL == matvar->name || matvar->rank != 2 )
119
0
        return MATIO_E_OUTPUT_BAD_DATA;
120
0
    if ( matvar->class_type == MAT_C_SPARSE ) {
121
0
        const mat_sparse_t *sparse = (const mat_sparse_t *)matvar->data;
122
0
        if ( NULL == matvar->data || sparse->njc == 0 )
123
0
            return MATIO_E_OUTPUT_BAD_DATA;
124
0
    }
125
126
0
    switch ( matvar->data_type ) {
127
0
        case MAT_T_DOUBLE:
128
0
            x.type = 0;
129
0
            break;
130
0
        case MAT_T_SINGLE:
131
0
            x.type = 10;
132
0
            break;
133
0
        case MAT_T_INT32:
134
0
            x.type = 20;
135
0
            break;
136
0
        case MAT_T_INT16:
137
0
            x.type = 30;
138
0
            break;
139
0
        case MAT_T_UINT16:
140
0
            x.type = 40;
141
0
            break;
142
0
        case MAT_T_UINT8:
143
0
            x.type = 50;
144
0
            break;
145
0
        default:
146
0
            return MATIO_E_OUTPUT_BAD_DATA;
147
0
    }
148
149
#if defined(MATIO_BE)
150
    x.type += 1000;
151
#endif
152
153
0
    x.namelen = (mat_int32_t)strlen(matvar->name) + 1;
154
155
    /* FIXME: SEEK_END is not Guaranteed by the C standard */
156
0
    (void)MatSeek(mat, 0, SEEK_END); /* Always write at end of file */
157
158
0
    switch ( matvar->class_type ) {
159
0
        case MAT_C_CHAR:
160
0
            x.type++;
161
            /* Fall through */
162
0
        case MAT_C_DOUBLE:
163
0
        case MAT_C_SINGLE:
164
0
        case MAT_C_INT32:
165
0
        case MAT_C_INT16:
166
0
        case MAT_C_UINT16:
167
0
        case MAT_C_UINT8: {
168
0
            size_t nelems = 1;
169
0
            int err = Mat_MulDims(matvar, &nelems);
170
0
            if ( err ) {
171
0
                Mat_Critical("Integer multiplication overflow");
172
0
                return err;
173
0
            }
174
175
0
            x.mrows = (mat_int32_t)matvar->dims[0];
176
0
            x.ncols = (mat_int32_t)matvar->dims[1];
177
0
            x.imagf = matvar->isComplex ? 1 : 0;
178
0
            fwrite(&x, sizeof(Fmatrix), 1, (FILE *)mat->fp);
179
0
            fwrite(matvar->name, sizeof(char), x.namelen, (FILE *)mat->fp);
180
0
            if ( matvar->isComplex ) {
181
0
                const mat_complex_split_t *complex_data = (mat_complex_split_t *)matvar->data;
182
0
                fwrite(complex_data->Re, matvar->data_size, nelems, (FILE *)mat->fp);
183
0
                fwrite(complex_data->Im, matvar->data_size, nelems, (FILE *)mat->fp);
184
0
            } else {
185
0
                fwrite(matvar->data, matvar->data_size, nelems, (FILE *)mat->fp);
186
0
            }
187
0
            break;
188
0
        }
189
0
        case MAT_C_SPARSE: {
190
0
            mat_sparse_t *sparse;
191
0
            double tmp;
192
0
            mat_uint32_t i, j;
193
0
            size_t stride = Mat_SizeOf(matvar->data_type);
194
#if !defined(EXTENDED_SPARSE)
195
            if ( MAT_T_DOUBLE != matvar->data_type )
196
                break;
197
#endif
198
199
0
            sparse = (mat_sparse_t *)matvar->data;
200
0
            x.type += 2;
201
0
            x.mrows = sparse->njc > 0 ? sparse->jc[sparse->njc - 1] + 1 : 1;
202
0
            x.ncols = matvar->isComplex ? 4 : 3;
203
0
            x.imagf = 0;
204
205
0
            fwrite(&x, sizeof(Fmatrix), 1, (FILE *)mat->fp);
206
0
            fwrite(matvar->name, sizeof(char), x.namelen, (FILE *)mat->fp);
207
208
0
            for ( i = 0; i < sparse->njc - 1; i++ ) {
209
0
                for ( j = sparse->jc[i];
210
0
                      j < sparse->jc[i + 1] && j < sparse->ndata && j < sparse->nir; j++ ) {
211
0
                    tmp = sparse->ir[j] + 1;
212
0
                    fwrite(&tmp, sizeof(double), 1, (FILE *)mat->fp);
213
0
                }
214
0
            }
215
0
            tmp = (double)matvar->dims[0];
216
0
            fwrite(&tmp, sizeof(double), 1, (FILE *)mat->fp);
217
0
            for ( i = 0; i < sparse->njc - 1; i++ ) {
218
0
                for ( j = sparse->jc[i];
219
0
                      j < sparse->jc[i + 1] && j < sparse->ndata && j < sparse->nir; j++ ) {
220
0
                    tmp = i + 1;
221
0
                    fwrite(&tmp, sizeof(double), 1, (FILE *)mat->fp);
222
0
                }
223
0
            }
224
0
            tmp = (double)matvar->dims[1];
225
0
            fwrite(&tmp, sizeof(double), 1, (FILE *)mat->fp);
226
0
            tmp = 0.;
227
0
            if ( matvar->isComplex ) {
228
0
                mat_complex_split_t *complex_data = (mat_complex_split_t *)sparse->data;
229
0
                const char *re = (char *)complex_data->Re;
230
0
                const char *im = (char *)complex_data->Im;
231
0
                for ( i = 0; i < sparse->njc - 1; i++ ) {
232
0
                    for ( j = sparse->jc[i];
233
0
                          j < sparse->jc[i + 1] && j < sparse->ndata && j < sparse->nir; j++ ) {
234
0
                        fwrite(re + j * stride, stride, 1, (FILE *)mat->fp);
235
0
                    }
236
0
                }
237
0
                fwrite(&tmp, stride, 1, (FILE *)mat->fp);
238
0
                for ( i = 0; i < sparse->njc - 1; i++ ) {
239
0
                    for ( j = sparse->jc[i];
240
0
                          j < sparse->jc[i + 1] && j < sparse->ndata && j < sparse->nir; j++ ) {
241
0
                        fwrite(im + j * stride, stride, 1, (FILE *)mat->fp);
242
0
                    }
243
0
                }
244
0
            } else {
245
0
                const char *data = (char *)sparse->data;
246
0
                for ( i = 0; i < sparse->njc - 1; i++ ) {
247
0
                    for ( j = sparse->jc[i];
248
0
                          j < sparse->jc[i + 1] && j < sparse->ndata && j < sparse->nir; j++ ) {
249
0
                        fwrite(data + j * stride, stride, 1, (FILE *)mat->fp);
250
0
                    }
251
0
                }
252
0
            }
253
0
            fwrite(&tmp, stride, 1, (FILE *)mat->fp);
254
0
            break;
255
0
        }
256
0
        default:
257
0
            break;
258
0
    }
259
260
0
    return MATIO_E_NO_ERROR;
261
#else
262
    return MATIO_E_OPERATION_NOT_SUPPORTED;
263
#endif
264
0
}
265
266
/** @if mat_devman
267
 * @brief Reads the data of a version 4 MAT file variable
268
 *
269
 * @ingroup mat_internal
270
 * @param mat MAT file pointer
271
 * @param matvar MAT variable pointer to read the data
272
 * @retval 0 on success
273
 * @endif
274
 */
275
int
276
Mat_VarRead4(mat_t *mat, matvar_t *matvar)
277
124
{
278
124
    int err;
279
124
    size_t nelems = 1;
280
281
124
    err = Mat_MulDims(matvar, &nelems);
282
124
    if ( err ) {
283
0
        Mat_Critical("Integer multiplication overflow");
284
0
        return err;
285
0
    }
286
287
124
    (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
288
289
124
    switch ( matvar->class_type ) {
290
65
        case MAT_C_DOUBLE:
291
65
            matvar->data_size = sizeof(double);
292
65
            err = Mul(&matvar->nbytes, nelems, matvar->data_size);
293
65
            if ( err ) {
294
1
                Mat_Critical("Integer multiplication overflow");
295
1
                return err;
296
1
            }
297
298
64
            if ( matvar->isComplex ) {
299
30
                mat_complex_split_t *complex_data = ComplexCalloc(matvar->nbytes);
300
30
                if ( NULL != complex_data ) {
301
30
                    err =
302
30
                        ReadDoubleData(mat, (double *)complex_data->Re, matvar->data_type, nelems);
303
30
                    if ( !err ) {
304
13
                        err = ReadDoubleData(mat, (double *)complex_data->Im, matvar->data_type,
305
13
                                             nelems);
306
13
                    }
307
30
                    if ( !err ) {
308
11
                        matvar->data = complex_data;
309
19
                    } else {
310
19
                        ComplexFree(complex_data);
311
19
                        return MATIO_E_FILE_FORMAT_VIOLATION;
312
19
                    }
313
30
                } else if ( matvar->nbytes > 0 ) {
314
0
                    Mat_Critical("Couldn't allocate memory for the complex data");
315
0
                    return MATIO_E_OUT_OF_MEMORY;
316
0
                }
317
34
            } else {
318
34
                matvar->data = matvar->nbytes > 0 ? malloc(matvar->nbytes) : NULL;
319
34
                if ( NULL != matvar->data ) {
320
31
                    err = ReadDoubleData(mat, (double *)matvar->data, matvar->data_type, nelems);
321
31
                    if ( err ) {
322
21
                        free(matvar->data);
323
21
                        matvar->data = NULL;
324
21
                        return MATIO_E_FILE_FORMAT_VIOLATION;
325
21
                    }
326
31
                } else if ( matvar->nbytes > 0 ) {
327
0
                    Mat_Critical("Couldn't allocate memory for the data");
328
0
                    return MATIO_E_OUT_OF_MEMORY;
329
0
                }
330
34
            }
331
            /* Update data type to match format of matvar->data */
332
24
            matvar->data_type = MAT_T_DOUBLE;
333
24
            break;
334
36
        case MAT_C_CHAR:
335
36
            matvar->data_size = 1;
336
36
            matvar->nbytes = nelems;
337
36
            matvar->data = matvar->nbytes > 0 ? malloc(matvar->nbytes) : NULL;
338
36
            if ( NULL != matvar->data ) {
339
36
                err = ReadUInt8Data(mat, (mat_uint8_t *)matvar->data, matvar->data_type, nelems);
340
36
                if ( err ) {
341
34
                    free(matvar->data);
342
34
                    matvar->data = NULL;
343
34
                    return MATIO_E_FILE_FORMAT_VIOLATION;
344
34
                }
345
36
            } else if ( matvar->nbytes > 0 ) {
346
0
                Mat_Critical("Couldn't allocate memory for the data");
347
0
                return MATIO_E_OUT_OF_MEMORY;
348
0
            }
349
2
            matvar->data_type = MAT_T_UINT8;
350
2
            break;
351
23
        case MAT_C_SPARSE:
352
23
            matvar->data_size = sizeof(mat_sparse_t);
353
23
            matvar->data = calloc(1, matvar->data_size);
354
23
            if ( NULL != matvar->data ) {
355
23
                double tmp;
356
23
                mat_uint32_t i;
357
23
                mat_sparse_t *sparse;
358
23
                mat_off_t fpos;
359
23
                enum matio_types data_type = MAT_T_DOUBLE;
360
23
                size_t nBytes;
361
362
                /* matvar->dims[1] either is 3 for real or 4 for complex sparse */
363
23
                matvar->isComplex = matvar->dims[1] == 4 ? 1 : 0;
364
23
                if ( 0 == matvar->dims[0] ) {
365
2
                    return MATIO_E_FILE_FORMAT_VIOLATION;
366
2
                }
367
21
                sparse = (mat_sparse_t *)matvar->data;
368
21
                sparse->nir = (mat_uint32_t)(matvar->dims[0] - 1);
369
21
                sparse->nzmax = sparse->nir;
370
21
                if ( sparse->nir > 0 ) {
371
21
                    err = Mul(&nBytes, sparse->nir, sizeof(mat_uint32_t));
372
21
                    if ( err ) {
373
0
                        Mat_Critical("Integer multiplication overflow");
374
0
                        return err;
375
0
                    }
376
21
                    sparse->ir = (mat_uint32_t *)malloc(nBytes);
377
21
                    if ( sparse->ir != NULL ) {
378
21
                        err = ReadUInt32Data(mat, sparse->ir, data_type, sparse->nir);
379
21
                        if ( err ) {
380
17
                            free(sparse->ir);
381
17
                            free(matvar->data);
382
17
                            matvar->data = NULL;
383
17
                            return MATIO_E_FILE_FORMAT_VIOLATION;
384
17
                        }
385
130
                        for ( i = 0; i < sparse->nir; i++ ) {
386
129
                            if ( 0 == sparse->ir[i] ) {
387
3
                                err = MATIO_E_FILE_FORMAT_VIOLATION;
388
3
                                break;
389
3
                            }
390
126
                            sparse->ir[i] = sparse->ir[i] - 1;
391
126
                        }
392
4
                        if ( err ) {
393
3
                            free(sparse->ir);
394
3
                            free(matvar->data);
395
3
                            matvar->data = NULL;
396
3
                            return err;
397
3
                        }
398
4
                    } else {
399
0
                        free(matvar->data);
400
0
                        matvar->data = NULL;
401
0
                        Mat_Critical("Couldn't allocate memory for the sparse row array");
402
0
                        return MATIO_E_OUT_OF_MEMORY;
403
0
                    }
404
21
                }
405
1
                err = ReadDoubleData(mat, &tmp, data_type, 1);
406
1
                if ( err || !(tmp >= 0 && tmp <= UINT_MAX - 1) ) {
407
1
                    free(sparse->ir);
408
1
                    free(matvar->data);
409
1
                    matvar->data = NULL;
410
1
                    Mat_Critical("Invalid row dimension for sparse matrix");
411
1
                    return MATIO_E_FILE_FORMAT_VIOLATION;
412
1
                }
413
0
                matvar->dims[0] = (size_t)tmp;
414
415
0
                fpos = MatTell(mat);
416
0
                if ( fpos == -1L ) {
417
0
                    free(sparse->ir);
418
0
                    free(matvar->data);
419
0
                    matvar->data = NULL;
420
0
                    Mat_Critical("Couldn't determine file position");
421
0
                    return MATIO_E_FILE_FORMAT_VIOLATION;
422
0
                }
423
0
                (void)MatSeek(mat, sparse->nir * Mat_SizeOf(data_type), SEEK_CUR);
424
0
                err = ReadDoubleData(mat, &tmp, data_type, 1);
425
0
                if ( err || !(tmp >= 0 && tmp <= UINT_MAX - 1) ) {
426
0
                    free(sparse->ir);
427
0
                    free(matvar->data);
428
0
                    matvar->data = NULL;
429
0
                    Mat_Critical("Invalid column dimension for sparse matrix");
430
0
                    return MATIO_E_FILE_FORMAT_VIOLATION;
431
0
                }
432
0
                matvar->dims[1] = (size_t)tmp;
433
0
                (void)MatSeek(mat, fpos, SEEK_SET);
434
0
                if ( matvar->dims[1] > UINT_MAX - 1 ) {
435
0
                    free(sparse->ir);
436
0
                    free(matvar->data);
437
0
                    matvar->data = NULL;
438
0
                    Mat_Critical("Invalid column dimension for sparse matrix");
439
0
                    return MATIO_E_FILE_FORMAT_VIOLATION;
440
0
                }
441
0
                sparse->njc = (mat_uint32_t)matvar->dims[1] + 1;
442
0
                err = Mul(&nBytes, sparse->njc, sizeof(mat_uint32_t));
443
0
                if ( err ) {
444
0
                    Mat_Critical("Integer multiplication overflow");
445
0
                    return err;
446
0
                }
447
0
                if ( sparse->nir > 0 ) {
448
0
                    sparse->jc = (mat_uint32_t *)malloc(nBytes);
449
0
                    if ( sparse->jc != NULL ) {
450
0
                        mat_uint32_t *jc;
451
0
                        err = Mul(&nBytes, sparse->nir, sizeof(mat_uint32_t));
452
0
                        if ( err ) {
453
0
                            Mat_Critical("Integer multiplication overflow");
454
0
                            return err;
455
0
                        }
456
0
                        jc = (mat_uint32_t *)malloc(nBytes);
457
0
                        if ( jc != NULL ) {
458
0
                            mat_uint32_t j = 0;
459
0
                            sparse->jc[0] = 0;
460
0
                            err = ReadUInt32Data(mat, jc, data_type, sparse->nir);
461
0
                            if ( err ) {
462
0
                                free(jc);
463
0
                                free(sparse->jc);
464
0
                                free(sparse->ir);
465
0
                                free(matvar->data);
466
0
                                matvar->data = NULL;
467
0
                                return MATIO_E_FILE_FORMAT_VIOLATION;
468
0
                            }
469
0
                            for ( i = 1; i < sparse->njc - 1; i++ ) {
470
0
                                while ( j < sparse->nir && jc[j] <= i )
471
0
                                    j++;
472
0
                                sparse->jc[i] = j;
473
0
                            }
474
0
                            free(jc);
475
                            /* terminating nnz */
476
0
                            sparse->jc[sparse->njc - 1] = sparse->nir;
477
0
                        } else {
478
0
                            free(sparse->jc);
479
0
                            free(sparse->ir);
480
0
                            free(matvar->data);
481
0
                            matvar->data = NULL;
482
0
                            Mat_Critical("Couldn't allocate memory for the sparse index array");
483
0
                            return MATIO_E_OUT_OF_MEMORY;
484
0
                        }
485
0
                    } else {
486
0
                        free(sparse->ir);
487
0
                        free(matvar->data);
488
0
                        matvar->data = NULL;
489
0
                        Mat_Critical("Couldn't allocate memory for the sparse index array");
490
0
                        return MATIO_E_OUT_OF_MEMORY;
491
0
                    }
492
0
                } else {
493
0
                    sparse->jc = (mat_uint32_t *)calloc(nBytes, 1);
494
0
                }
495
0
                err = ReadDoubleData(mat, &tmp, data_type, 1);
496
0
                if ( err ) {
497
0
                    free(sparse->jc);
498
0
                    free(sparse->ir);
499
0
                    free(matvar->data);
500
0
                    matvar->data = NULL;
501
0
                    return MATIO_E_FILE_FORMAT_VIOLATION;
502
0
                }
503
0
                sparse->ndata = sparse->nir;
504
0
                data_type = matvar->data_type;
505
#if !defined(EXTENDED_SPARSE)
506
                /* Without extended sparse support the values are always read as
507
                   double, so the destination buffer must be sized for double
508
                   regardless of the type declared in the file. */
509
                matvar->data_type = MAT_T_DOUBLE;
510
#endif
511
0
                if ( matvar->isComplex ) {
512
0
                    mat_complex_split_t *complex_data;
513
0
                    err = Mul(&nBytes, sparse->ndata, Mat_SizeOf(matvar->data_type));
514
0
                    if ( err ) {
515
0
                        free(sparse->jc);
516
0
                        free(sparse->ir);
517
0
                        free(matvar->data);
518
0
                        matvar->data = NULL;
519
0
                        Mat_Critical("Integer multiplication overflow");
520
0
                        return err;
521
0
                    }
522
0
                    complex_data = ComplexCalloc(nBytes);
523
0
                    if ( NULL != complex_data ) {
524
0
                        sparse->data = complex_data;
525
0
#if defined(EXTENDED_SPARSE)
526
0
                        switch ( data_type ) {
527
0
                            case MAT_T_DOUBLE:
528
0
                                err = ReadDoubleData(mat, (double *)complex_data->Re, data_type,
529
0
                                                     sparse->ndata);
530
0
                                if ( !err ) {
531
0
                                    err = ReadDoubleData(mat, &tmp, data_type, 1);
532
0
                                }
533
0
                                if ( !err ) {
534
0
                                    err = ReadDoubleData(mat, (double *)complex_data->Im, data_type,
535
0
                                                         sparse->ndata);
536
0
                                }
537
0
                                if ( !err ) {
538
0
                                    err = ReadDoubleData(mat, &tmp, data_type, 1);
539
0
                                }
540
0
                                break;
541
0
                            case MAT_T_SINGLE: {
542
0
                                float tmp2;
543
0
                                err = ReadSingleData(mat, (float *)complex_data->Re, data_type,
544
0
                                                     sparse->ndata);
545
0
                                if ( !err ) {
546
0
                                    err = ReadSingleData(mat, &tmp2, data_type, 1);
547
0
                                }
548
0
                                if ( !err ) {
549
0
                                    err = ReadSingleData(mat, (float *)complex_data->Im, data_type,
550
0
                                                         sparse->ndata);
551
0
                                }
552
0
                                if ( !err ) {
553
0
                                    err = ReadSingleData(mat, &tmp2, data_type, 1);
554
0
                                }
555
0
                                break;
556
0
                            }
557
0
                            case MAT_T_INT32: {
558
0
                                mat_int32_t tmp2;
559
0
                                err = ReadInt32Data(mat, (mat_int32_t *)complex_data->Re, data_type,
560
0
                                                    sparse->ndata);
561
0
                                if ( !err ) {
562
0
                                    err = ReadInt32Data(mat, &tmp2, data_type, 1);
563
0
                                }
564
0
                                if ( !err ) {
565
0
                                    err = ReadInt32Data(mat, (mat_int32_t *)complex_data->Im,
566
0
                                                        data_type, sparse->ndata);
567
0
                                }
568
0
                                if ( !err ) {
569
0
                                    err = ReadInt32Data(mat, &tmp2, data_type, 1);
570
0
                                }
571
0
                                break;
572
0
                            }
573
0
                            case MAT_T_INT16: {
574
0
                                mat_int16_t tmp2;
575
0
                                err = ReadInt16Data(mat, (mat_int16_t *)complex_data->Re, data_type,
576
0
                                                    sparse->ndata);
577
0
                                if ( !err ) {
578
0
                                    err = ReadInt16Data(mat, &tmp2, data_type, 1);
579
0
                                }
580
0
                                if ( !err ) {
581
0
                                    err = ReadInt16Data(mat, (mat_int16_t *)complex_data->Im,
582
0
                                                        data_type, sparse->ndata);
583
0
                                }
584
0
                                if ( !err ) {
585
0
                                    err = ReadInt16Data(mat, &tmp2, data_type, 1);
586
0
                                }
587
0
                                break;
588
0
                            }
589
0
                            case MAT_T_UINT16: {
590
0
                                mat_uint16_t tmp2;
591
0
                                err = ReadUInt16Data(mat, (mat_uint16_t *)complex_data->Re,
592
0
                                                     data_type, sparse->ndata);
593
0
                                if ( !err ) {
594
0
                                    err = ReadUInt16Data(mat, &tmp2, data_type, 1);
595
0
                                }
596
0
                                if ( !err ) {
597
0
                                    err = ReadUInt16Data(mat, (mat_uint16_t *)complex_data->Im,
598
0
                                                         data_type, sparse->ndata);
599
0
                                }
600
0
                                if ( !err ) {
601
0
                                    err = ReadUInt16Data(mat, &tmp2, data_type, 1);
602
0
                                }
603
0
                                break;
604
0
                            }
605
0
                            case MAT_T_UINT8: {
606
0
                                mat_uint8_t tmp2;
607
0
                                err = ReadUInt8Data(mat, (mat_uint8_t *)complex_data->Re, data_type,
608
0
                                                    sparse->ndata);
609
0
                                if ( !err ) {
610
0
                                    err = ReadUInt8Data(mat, &tmp2, data_type, 1);
611
0
                                }
612
0
                                if ( !err ) {
613
0
                                    err = ReadUInt8Data(mat, (mat_uint8_t *)complex_data->Im,
614
0
                                                        data_type, sparse->ndata);
615
0
                                }
616
0
                                if ( !err ) {
617
0
                                    err = ReadUInt8Data(mat, &tmp2, data_type, 1);
618
0
                                }
619
0
                                break;
620
0
                            }
621
0
                            default:
622
0
                                ComplexFree(complex_data);
623
0
                                free(sparse->jc);
624
0
                                free(sparse->ir);
625
0
                                free(matvar->data);
626
0
                                matvar->data = NULL;
627
0
                                Mat_Critical(
628
0
                                    "Mat_VarRead4: %d is not a supported data type for "
629
0
                                    "extended sparse",
630
0
                                    data_type);
631
0
                                return MATIO_E_FILE_FORMAT_VIOLATION;
632
0
                        }
633
#else
634
                        err = ReadDoubleData(mat, (double *)complex_data->Re, data_type,
635
                                             sparse->ndata);
636
                        if ( !err ) {
637
                            err = ReadDoubleData(mat, &tmp, data_type, 1);
638
                        }
639
                        if ( !err ) {
640
                            err = ReadDoubleData(mat, (double *)complex_data->Im, data_type,
641
                                                 sparse->ndata);
642
                        }
643
                        if ( !err ) {
644
                            err = ReadDoubleData(mat, &tmp, data_type, 1);
645
                        }
646
#endif
647
0
                        if ( err ) {
648
0
                            ComplexFree(complex_data);
649
0
                            free(sparse->jc);
650
0
                            free(sparse->ir);
651
0
                            free(matvar->data);
652
0
                            matvar->data = NULL;
653
0
                            return MATIO_E_FILE_FORMAT_VIOLATION;
654
0
                        }
655
0
                    } else {
656
0
                        free(sparse->jc);
657
0
                        free(sparse->ir);
658
0
                        free(matvar->data);
659
0
                        matvar->data = NULL;
660
0
                        Mat_Critical("Couldn't allocate memory for the complex sparse data");
661
0
                        return MATIO_E_OUT_OF_MEMORY;
662
0
                    }
663
0
                } else if ( sparse->ndata > 0 ) {
664
0
                    err = Mul(&nBytes, sparse->ndata, Mat_SizeOf(matvar->data_type));
665
0
                    if ( err ) {
666
0
                        free(sparse->jc);
667
0
                        free(sparse->ir);
668
0
                        free(matvar->data);
669
0
                        matvar->data = NULL;
670
0
                        Mat_Critical("Integer multiplication overflow");
671
0
                        return err;
672
0
                    }
673
0
                    sparse->data = malloc(nBytes);
674
0
                    if ( sparse->data != NULL ) {
675
0
#if defined(EXTENDED_SPARSE)
676
0
                        switch ( data_type ) {
677
0
                            case MAT_T_DOUBLE:
678
0
                                err = ReadDoubleData(mat, (double *)sparse->data, data_type,
679
0
                                                     sparse->ndata);
680
0
                                if ( !err ) {
681
0
                                    err = ReadDoubleData(mat, &tmp, data_type, 1);
682
0
                                }
683
0
                                break;
684
0
                            case MAT_T_SINGLE: {
685
0
                                float tmp2;
686
0
                                err = ReadSingleData(mat, (float *)sparse->data, data_type,
687
0
                                                     sparse->ndata);
688
0
                                if ( !err ) {
689
0
                                    err = ReadSingleData(mat, &tmp2, data_type, 1);
690
0
                                }
691
0
                                break;
692
0
                            }
693
0
                            case MAT_T_INT32: {
694
0
                                mat_int32_t tmp2;
695
0
                                err = ReadInt32Data(mat, (mat_int32_t *)sparse->data, data_type,
696
0
                                                    sparse->ndata);
697
0
                                if ( !err ) {
698
0
                                    err = ReadInt32Data(mat, &tmp2, data_type, 1);
699
0
                                }
700
0
                                break;
701
0
                            }
702
0
                            case MAT_T_INT16: {
703
0
                                mat_int16_t tmp2;
704
0
                                err = ReadInt16Data(mat, (mat_int16_t *)sparse->data, data_type,
705
0
                                                    sparse->ndata);
706
0
                                if ( !err ) {
707
0
                                    err = ReadInt16Data(mat, &tmp2, data_type, 1);
708
0
                                }
709
0
                                break;
710
0
                            }
711
0
                            case MAT_T_UINT16: {
712
0
                                mat_uint16_t tmp2;
713
0
                                err = ReadUInt16Data(mat, (mat_uint16_t *)sparse->data, data_type,
714
0
                                                     sparse->ndata);
715
0
                                if ( !err ) {
716
0
                                    err = ReadUInt16Data(mat, &tmp2, data_type, 1);
717
0
                                }
718
0
                                break;
719
0
                            }
720
0
                            case MAT_T_UINT8: {
721
0
                                mat_uint8_t tmp2;
722
0
                                err = ReadUInt8Data(mat, (mat_uint8_t *)sparse->data, data_type,
723
0
                                                    sparse->ndata);
724
0
                                if ( !err ) {
725
0
                                    err = ReadUInt8Data(mat, &tmp2, data_type, 1);
726
0
                                }
727
0
                                break;
728
0
                            }
729
0
                            default:
730
0
                                free(sparse->data);
731
0
                                free(sparse->jc);
732
0
                                free(sparse->ir);
733
0
                                free(matvar->data);
734
0
                                matvar->data = NULL;
735
0
                                Mat_Critical(
736
0
                                    "Mat_VarRead4: %d is not a supported data type for "
737
0
                                    "extended sparse",
738
0
                                    data_type);
739
0
                                return MATIO_E_FILE_FORMAT_VIOLATION;
740
0
                        }
741
#else
742
                        err = ReadDoubleData(mat, (double *)sparse->data, data_type, sparse->ndata);
743
                        if ( !err ) {
744
                            err = ReadDoubleData(mat, &tmp, data_type, 1);
745
                        }
746
#endif
747
0
                        if ( err ) {
748
0
                            free(sparse->data);
749
0
                            free(sparse->jc);
750
0
                            free(sparse->ir);
751
0
                            free(matvar->data);
752
0
                            matvar->data = NULL;
753
0
                            return MATIO_E_FILE_FORMAT_VIOLATION;
754
0
                        }
755
0
                    } else {
756
0
                        free(sparse->jc);
757
0
                        free(sparse->ir);
758
0
                        free(matvar->data);
759
0
                        matvar->data = NULL;
760
0
                        Mat_Critical("Couldn't allocate memory for the sparse data");
761
0
                        return MATIO_E_OUT_OF_MEMORY;
762
0
                    }
763
0
                } else {
764
0
                    err = ReadDoubleData(mat, &tmp, data_type, 1);
765
0
                    if ( err ) {
766
0
                        free(sparse->data);
767
0
                        free(sparse->jc);
768
0
                        free(sparse->ir);
769
0
                        free(matvar->data);
770
0
                        matvar->data = NULL;
771
0
                        return MATIO_E_FILE_FORMAT_VIOLATION;
772
0
                    }
773
0
                }
774
0
                break;
775
0
            } else {
776
0
                Mat_Critical("Couldn't allocate memory for the data");
777
0
                return MATIO_E_OUT_OF_MEMORY;
778
0
            }
779
0
        default:
780
0
            Mat_Critical("MAT V4 data type error");
781
0
            return MATIO_E_FILE_FORMAT_VIOLATION;
782
124
    }
783
784
26
    return MATIO_E_NO_ERROR;
785
124
}
786
787
/** @if mat_devman
788
 * @brief Reads a slab of data from a version 4 MAT file for the @c matvar variable
789
 *
790
 * @ingroup mat_internal
791
 * @param mat Version 4 MAT file pointer
792
 * @param matvar pointer to the mat variable
793
 * @param data pointer to store the read data in (must be of size
794
 *             edge[0]*...edge[rank-1]*Mat_SizeOfClass(matvar->class_type))
795
 * @param start index to start reading data in each dimension
796
 * @param stride write data every @c stride elements in each dimension
797
 * @param edge number of elements to read in each dimension
798
 * @retval 0 on success
799
 * @endif
800
 */
801
int
802
Mat_VarReadData4(mat_t *mat, const matvar_t *matvar, void *data, const int *start,
803
                 const int *stride, const int *edge)
804
39
{
805
39
    int err = MATIO_E_NO_ERROR;
806
807
39
    (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
808
809
39
    switch ( matvar->data_type ) {
810
14
        case MAT_T_DOUBLE:
811
19
        case MAT_T_SINGLE:
812
24
        case MAT_T_INT32:
813
26
        case MAT_T_INT16:
814
37
        case MAT_T_UINT16:
815
39
        case MAT_T_UINT8:
816
39
            break;
817
0
        default:
818
0
            return MATIO_E_FILE_FORMAT_VIOLATION;
819
39
    }
820
821
39
    if ( matvar->rank == 2 ) {
822
39
        if ( (size_t)stride[0] * (edge[0] - 1) + start[0] + 1 > matvar->dims[0] )
823
0
            err = MATIO_E_BAD_ARGUMENT;
824
39
        else if ( (size_t)stride[1] * (edge[1] - 1) + start[1] + 1 > matvar->dims[1] )
825
3
            err = MATIO_E_BAD_ARGUMENT;
826
39
        if ( matvar->isComplex ) {
827
15
            mat_complex_split_t *cdata = (mat_complex_split_t *)data;
828
15
            size_t nbytes = Mat_SizeOf(matvar->data_type);
829
15
            err = Mat_MulDims(matvar, &nbytes);
830
15
            if ( err ) {
831
0
                Mat_Critical("Integer multiplication overflow");
832
0
                return err;
833
0
            }
834
835
15
            ReadDataSlab2(mat, cdata->Re, matvar->class_type, matvar->data_type, matvar->dims,
836
15
                          start, stride, edge);
837
15
            (void)MatSeek(mat, matvar->internal->datapos + nbytes, SEEK_SET);
838
15
            ReadDataSlab2(mat, cdata->Im, matvar->class_type, matvar->data_type, matvar->dims,
839
15
                          start, stride, edge);
840
24
        } else {
841
24
            ReadDataSlab2(mat, data, matvar->class_type, matvar->data_type, matvar->dims, start,
842
24
                          stride, edge);
843
24
        }
844
39
    } else if ( matvar->isComplex ) {
845
0
        mat_complex_split_t *cdata = (mat_complex_split_t *)data;
846
0
        size_t nbytes = Mat_SizeOf(matvar->data_type);
847
0
        err = Mat_MulDims(matvar, &nbytes);
848
0
        if ( err ) {
849
0
            Mat_Critical("Integer multiplication overflow");
850
0
            return err;
851
0
        }
852
853
0
        ReadDataSlabN(mat, cdata->Re, matvar->class_type, matvar->data_type, matvar->rank,
854
0
                      matvar->dims, start, stride, edge);
855
0
        (void)MatSeek(mat, matvar->internal->datapos + nbytes, SEEK_SET);
856
0
        ReadDataSlabN(mat, cdata->Im, matvar->class_type, matvar->data_type, matvar->rank,
857
0
                      matvar->dims, start, stride, edge);
858
0
    } else {
859
0
        ReadDataSlabN(mat, data, matvar->class_type, matvar->data_type, matvar->rank, matvar->dims,
860
0
                      start, stride, edge);
861
0
    }
862
863
39
    return err;
864
39
}
865
866
/** @brief Reads a subset of a MAT variable using a 1-D indexing
867
 *
868
 * Reads data from a MAT variable using a linear (1-D) indexing mode. The
869
 * variable must have been read by Mat_VarReadInfo.
870
 * @ingroup MAT
871
 * @param mat MAT file to read data from
872
 * @param matvar MAT variable information
873
 * @param data pointer to store data in (must be pre-allocated)
874
 * @param start starting index
875
 * @param stride stride of data
876
 * @param edge number of elements to read
877
 * @retval 0 on success
878
 */
879
int
880
Mat_VarReadDataLinear4(mat_t *mat, matvar_t *matvar, void *data, int start, int stride, int edge)
881
10
{
882
10
    int err;
883
10
    size_t nelems = 1;
884
885
10
    err = Mat_MulDims(matvar, &nelems);
886
10
    if ( err ) {
887
0
        Mat_Critical("Integer multiplication overflow");
888
0
        return err;
889
0
    }
890
891
10
    (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
892
893
10
    matvar->data_size = (int)Mat_SizeOf(matvar->data_type);
894
895
10
    if ( (size_t)stride * (edge - 1) + start + 1 > nelems ) {
896
2
        return MATIO_E_BAD_ARGUMENT;
897
2
    }
898
8
    if ( matvar->isComplex ) {
899
4
        mat_complex_split_t *complex_data = (mat_complex_split_t *)data;
900
4
        err = Mul(&nelems, nelems, matvar->data_size);
901
4
        if ( err ) {
902
0
            Mat_Critical("Integer multiplication overflow");
903
0
            return err;
904
0
        }
905
906
4
        ReadDataSlab1(mat, complex_data->Re, matvar->class_type, matvar->data_type, start, stride,
907
4
                      edge);
908
4
        (void)MatSeek(mat, matvar->internal->datapos + nelems, SEEK_SET);
909
4
        ReadDataSlab1(mat, complex_data->Im, matvar->class_type, matvar->data_type, start, stride,
910
4
                      edge);
911
4
    } else {
912
4
        ReadDataSlab1(mat, data, matvar->class_type, matvar->data_type, start, stride, edge);
913
4
    }
914
915
8
    return err;
916
8
}
917
918
/** @if mat_devman
919
 * @brief Reads the header information for the next MAT variable in a version 4 MAT file
920
 *
921
 * @ingroup mat_internal
922
 * @param mat MAT file pointer
923
 * @return pointer to the MAT variable or NULL
924
 * @endif
925
 */
926
matvar_t *
927
Mat_VarReadNextInfo4(mat_t *mat)
928
450
{
929
450
    int M, O, data_type, class_type;
930
450
    mat_int32_t tmp;
931
450
    mat_off_t nBytes, fpos;
932
450
    matvar_t *matvar = NULL;
933
450
    union {
934
450
        mat_uint32_t u;
935
450
        mat_uint8_t c[4];
936
450
    } endian;
937
938
450
    if ( mat == NULL || mat->fp == NULL )
939
0
        return NULL;
940
941
450
    if ( IsEndOfFile(mat, &fpos) )
942
10
        return NULL;
943
944
440
    if ( fpos == -1L )
945
0
        return NULL;
946
947
440
    {
948
440
        size_t nbytes = 0;
949
440
        int err = Read(&tmp, sizeof(mat_int32_t), 1, mat, &nbytes);
950
440
        if ( err || 0 == nbytes )
951
52
            return NULL;
952
440
    }
953
954
388
    endian.u = 0x01020304;
955
956
    /* See if MOPT may need byteswapping */
957
388
    if ( tmp < 0 || tmp > 4052 ) {
958
65
        if ( Mat_int32Swap(&tmp) > 4052 ) {
959
13
            return NULL;
960
13
        }
961
65
    }
962
963
375
    M = (int)floor(tmp / 1000.0);
964
375
    switch ( M ) {
965
327
        case 0:
966
            /* IEEE little endian */
967
327
            mat->byteswap = endian.c[0] != 4;
968
327
            break;
969
41
        case 1:
970
            /* IEEE big endian */
971
41
            mat->byteswap = endian.c[0] != 1;
972
41
            break;
973
7
        default:
974
            /* VAX, Cray, or bogus */
975
7
            return NULL;
976
375
    }
977
978
368
    tmp -= M * 1000;
979
368
    O = (int)floor(tmp / 100.0);
980
    /* O must be zero */
981
368
    if ( 0 != O ) {
982
2
        return NULL;
983
2
    }
984
985
366
    if ( NULL == (matvar = Mat_VarCalloc()) )
986
0
        return NULL;
987
988
366
    tmp -= O * 100;
989
366
    data_type = (int)floor(tmp / 10.0);
990
    /* Convert the V4 data type */
991
366
    switch ( data_type ) {
992
108
        case 0:
993
108
            matvar->data_type = MAT_T_DOUBLE;
994
108
            break;
995
62
        case 1:
996
62
            matvar->data_type = MAT_T_SINGLE;
997
62
            break;
998
52
        case 2:
999
52
            matvar->data_type = MAT_T_INT32;
1000
52
            break;
1001
53
        case 3:
1002
53
            matvar->data_type = MAT_T_INT16;
1003
53
            break;
1004
82
        case 4:
1005
82
            matvar->data_type = MAT_T_UINT16;
1006
82
            break;
1007
9
        case 5:
1008
9
            matvar->data_type = MAT_T_UINT8;
1009
9
            break;
1010
0
        default:
1011
0
            Mat_VarFree(matvar);
1012
0
            return NULL;
1013
366
    }
1014
1015
366
    tmp -= data_type * 10;
1016
366
    class_type = (int)floor(tmp / 1.0);
1017
366
    switch ( class_type ) {
1018
222
        case 0:
1019
222
            matvar->class_type = MAT_C_DOUBLE;
1020
222
            break;
1021
90
        case 1:
1022
90
            matvar->class_type = MAT_C_CHAR;
1023
90
            break;
1024
54
        case 2:
1025
54
            matvar->class_type = MAT_C_SPARSE;
1026
54
            break;
1027
0
        default:
1028
0
            Mat_VarFree(matvar);
1029
0
            return NULL;
1030
366
    }
1031
1032
366
    matvar->rank = 2;
1033
366
    matvar->dims = (size_t *)calloc(2, sizeof(*matvar->dims));
1034
366
    if ( NULL == matvar->dims ) {
1035
0
        Mat_VarFree(matvar);
1036
0
        return NULL;
1037
0
    }
1038
366
    if ( 0 != Read(&tmp, sizeof(int), 1, mat, NULL) ) {
1039
0
        Mat_VarFree(matvar);
1040
0
        return NULL;
1041
0
    }
1042
366
    if ( mat->byteswap )
1043
40
        Mat_int32Swap(&tmp);
1044
366
    matvar->dims[0] = tmp;
1045
1046
366
    if ( 0 != Read(&tmp, sizeof(int), 1, mat, NULL) ) {
1047
0
        Mat_VarFree(matvar);
1048
0
        return NULL;
1049
0
    }
1050
366
    if ( mat->byteswap )
1051
40
        Mat_int32Swap(&tmp);
1052
366
    matvar->dims[1] = tmp;
1053
1054
366
    if ( 0 != Read(&(matvar->isComplex), sizeof(int), 1, mat, NULL) ) {
1055
0
        Mat_VarFree(matvar);
1056
0
        return NULL;
1057
0
    }
1058
366
    if ( matvar->isComplex && MAT_C_CHAR == matvar->class_type ) {
1059
1
        Mat_VarFree(matvar);
1060
1
        return NULL;
1061
1
    }
1062
365
    if ( 0 != Read(&tmp, sizeof(int), 1, mat, NULL) ) {
1063
0
        Mat_VarFree(matvar);
1064
0
        return NULL;
1065
0
    }
1066
365
    if ( mat->byteswap )
1067
40
        Mat_int32Swap(&tmp);
1068
    /* Check that the length of the variable name is at least 1 */
1069
365
    if ( tmp < 1 ) {
1070
22
        Mat_VarFree(matvar);
1071
22
        return NULL;
1072
22
    }
1073
343
    matvar->name = (char *)malloc(tmp);
1074
343
    if ( NULL == matvar->name ) {
1075
0
        Mat_VarFree(matvar);
1076
0
        return NULL;
1077
0
    }
1078
343
    if ( 0 != Read(matvar->name, sizeof(char), tmp, mat, NULL) ) {
1079
3
        Mat_VarFree(matvar);
1080
3
        return NULL;
1081
340
    } else {
1082
340
        matvar->name[tmp - 1] = '\0';
1083
340
    }
1084
1085
340
    matvar->internal->datapos = MatTell(mat);
1086
340
    if ( matvar->internal->datapos == -1L ) {
1087
0
        Mat_VarFree(matvar);
1088
0
        Mat_Critical("Couldn't determine file position");
1089
0
        return NULL;
1090
0
    }
1091
340
    {
1092
340
        int err;
1093
340
        size_t tmp2 = Mat_SizeOf(matvar->data_type);
1094
340
        if ( matvar->isComplex )
1095
116
            tmp2 *= 2;
1096
340
        err = Mat_MulDims(matvar, &tmp2);
1097
340
        if ( err ) {
1098
1
            Mat_VarFree(matvar);
1099
1
            Mat_Critical("Integer multiplication overflow");
1100
1
            return NULL;
1101
1
        }
1102
1103
339
        nBytes = (mat_off_t)tmp2;
1104
339
    }
1105
339
    (void)MatSeek(mat, nBytes, SEEK_CUR);
1106
1107
339
    return matvar;
1108
340
}