Coverage Report

Created: 2026-10-28 18:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/matio/src/mat5.c
Line
Count
Source
1
/** @file mat5.c
2
 * Matlab MAT version 5 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
/* FIXME: Implement Unicode support */
14
#include "matio_private.h"
15
#include "mat5.h"
16
#include "mcos.h"
17
#include <stddef.h>
18
#include <stdlib.h>
19
#include <string.h>
20
#include <stdio.h>
21
#include <math.h>
22
#include <time.h>
23
#if defined(_MSC_VER) || defined(__MINGW32__)
24
#define strdup _strdup
25
#endif
26
27
/* clang-format off */
28
/** Get type from tag */
29
#define TYPE_FROM_TAG(a) \
30
40.5k
    (((a)&0x000000ff) <= MAT_T_FUNCTION) ? (enum matio_types)((a)&0x000000ff) : MAT_T_UNKNOWN
31
/** Get class from array flag */
32
#define CLASS_FROM_ARRAY_FLAGS(a) \
33
71.6k
    (((a)&0x000000ff) <= MAT_C_OPAQUE) ? ((enum matio_classes)((a)&0x000000ff)) : MAT_C_EMPTY
34
/** Class type mask */
35
0
#define CLASS_TYPE_MASK 0x000000ff
36
/* clang-format on */
37
38
#if !defined(MAX_READ_SIZE_WITHOUT_EOF_CHECK)
39
/* Maximal number of bytes to read without EOF check */
40
5.69k
#define MAX_READ_SIZE_WITHOUT_EOF_CHECK (3)
41
#endif
42
43
static mat_complex_split_t null_complex_data = {NULL, NULL};
44
45
/*===========================================================================
46
 *  Private functions
47
 *===========================================================================
48
 */
49
static int GetTypeBufSize(matvar_t *matvar, size_t *size);
50
static int GetStructFieldBufSize(matvar_t *matvar, size_t *size);
51
static int GetCellArrayFieldBufSize(matvar_t *matvar, size_t *size);
52
static void SetFieldNames(matvar_t *matvar, const char *buf, size_t nfields,
53
                          mat_uint32_t fieldname_length);
54
static int ReadSparse(mat_t *mat, const matvar_t *matvar, mat_uint32_t *n, mat_uint32_t **v);
55
#if HAVE_ZLIB
56
static int GetMatrixMaxBufSize(matvar_t *matvar, size_t *size);
57
#endif
58
static int GetEmptyMatrixMaxBufSize(const char *name, int rank, size_t *size);
59
static size_t WriteCharData(mat_t *mat, void *data, size_t N, enum matio_types data_type);
60
static size_t ReadNextCell(mat_t *mat, matvar_t *matvar);
61
static size_t ReadNextStructField(mat_t *mat, matvar_t *matvar);
62
static size_t ReadNextFunctionHandle(mat_t *mat, matvar_t *matvar);
63
static int ReadRankDims(mat_t *mat, matvar_t *matvar, enum matio_types data_type,
64
                        mat_uint32_t nbytes, size_t *read_bytes);
65
static int WriteType(mat_t *mat, matvar_t *matvar);
66
static int WriteCellArrayField(mat_t *mat, matvar_t *matvar);
67
static int WriteStructField(mat_t *mat, matvar_t *matvar);
68
static int WriteData(mat_t *mat, const void *data, size_t N, enum matio_types data_type);
69
static size_t Mat_WriteEmptyVariable5(mat_t *mat, const char *name, int rank, const size_t *dims);
70
static int Mat_VarReadNumeric5(mat_t *mat, matvar_t *matvar, void *data, size_t N);
71
#if HAVE_ZLIB
72
static size_t WriteCompressedCharData(mat_t *mat, z_streamp z, void *data, size_t N,
73
                                      enum matio_types data_type);
74
static size_t WriteCompressedData(mat_t *mat, z_streamp z, void *data, int N,
75
                                  enum matio_types data_type);
76
static size_t WriteCompressedTypeArrayFlags(mat_t *mat, matvar_t *matvar, z_streamp z);
77
static size_t WriteCompressedType(mat_t *mat, matvar_t *matvar, z_streamp z);
78
static size_t WriteCompressedCellArrayField(mat_t *mat, matvar_t *matvar, z_streamp z);
79
static size_t WriteCompressedStructField(mat_t *mat, matvar_t *matvar, z_streamp z);
80
static size_t Mat_WriteCompressedEmptyVariable5(mat_t *mat, const char *name, int rank,
81
                                                const size_t *dims, z_streamp z);
82
#endif
83
84
/** @brief Reads a tagged INT8 string subelement from the file
85
 *
86
 * Handles both small element format (packed in tag) and normal format.
87
 *
88
 * @param mat      MAT file pointer
89
 * @param str      Output: newly allocated string (caller must free)
90
 * @param pre_buf  Optional pre-read tag buffer (2 uint32s), or NULL to read from file
91
 * @return 0 on success
92
 */
93
static int ReadTaggedString(mat_t *mat, char **str, const mat_uint32_t *pre_buf);
94
95
/** @brief Reads opaque subelements (name, type_name, class_name, metadata) from file
96
 *
97
 * For an uncompressed MAT_C_OPAQUE variable, reads the subelements that follow
98
 * the array flags: array name, type system name, class name, object metadata.
99
 *
100
 * @param mat      MAT file pointer
101
 * @param matvar   The opaque matvar to populate
102
 * @param name_tag Pre-read tag buffer for the array name (2 uint32s)
103
 * @return 0 on success
104
 */
105
static int ReadOpaqueInfo5(mat_t *mat, matvar_t *matvar, const mat_uint32_t *name_tag);
106
107
#if HAVE_ZLIB
108
/** @brief Reads opaque subelements from a compressed stream
109
 *
110
 * @param mat      MAT file pointer
111
 * @param matvar   The opaque matvar to populate
112
 * @param bytesread Running count of bytes inflated
113
 * @return 0 on success
114
 */
115
static int ReadCompressedOpaqueInfo5(mat_t *mat, matvar_t *matvar, size_t *bytesread);
116
#endif
117
118
/** @brief determines the number of bytes for a given class type
119
 *
120
 * @ingroup mat_internal
121
 * @param matvar MAT variable
122
 * @param size the number of bytes needed to store the MAT variable
123
 * @retval 0 on success
124
 */
125
static int
126
GetTypeBufSize(matvar_t *matvar, size_t *size)
127
0
{
128
0
    int err;
129
0
    size_t nBytes, data_bytes;
130
0
    size_t tag_size = 8;
131
0
    size_t nelems = 1;
132
0
    size_t rank_size;
133
134
0
    *size = 0;
135
136
0
    err = Mat_MulDims(matvar, &nelems);
137
0
    if ( err )
138
0
        return err;
139
140
    /* Add rank and dimensions, padded to an 8 byte block */
141
0
    err = Mul(&rank_size, matvar->rank, 4);
142
0
    if ( err )
143
0
        return err;
144
145
0
    if ( matvar->rank % 2 )
146
0
        nBytes = tag_size + 4;
147
0
    else
148
0
        nBytes = tag_size;
149
150
0
    err = Add(&nBytes, nBytes, rank_size);
151
0
    if ( err )
152
0
        return err;
153
154
0
    switch ( matvar->class_type ) {
155
0
        case MAT_C_STRUCT: {
156
0
            matvar_t **fields = (matvar_t **)matvar->data;
157
0
            size_t nfields = matvar->internal->num_fields;
158
0
            size_t maxlen = 0, i, field_buf_size;
159
160
0
            for ( i = 0; i < nfields; i++ ) {
161
0
                const char *fieldname = matvar->internal->fieldnames[i];
162
0
                if ( NULL != fieldname && strlen(fieldname) > maxlen )
163
0
                    maxlen = strlen(fieldname);
164
0
            }
165
0
            maxlen++;
166
0
            while ( nfields * maxlen % 8 != 0 )
167
0
                maxlen++;
168
169
0
            err = Mul(&field_buf_size, maxlen, nfields);
170
0
            if ( err )
171
0
                return err;
172
0
            err = Add(&nBytes, nBytes, tag_size + tag_size);
173
0
            if ( err )
174
0
                return err;
175
0
            err = Add(&nBytes, nBytes, field_buf_size);
176
0
            if ( err )
177
0
                return err;
178
179
0
            if ( NULL != fields && nfields > 0 ) {
180
0
                size_t nelems_x_nfields = 1;
181
0
                err = Mul(&nelems_x_nfields, nelems, nfields);
182
0
                if ( err )
183
0
                    return err;
184
185
0
                for ( i = 0; i < nelems_x_nfields; i++ ) {
186
0
                    err = GetStructFieldBufSize(fields[i], &field_buf_size);
187
0
                    if ( err )
188
0
                        return err;
189
0
                    err = Add(&nBytes, nBytes, tag_size);
190
0
                    if ( err )
191
0
                        return err;
192
0
                    err = Add(&nBytes, nBytes, field_buf_size);
193
0
                    if ( err )
194
0
                        return err;
195
0
                }
196
0
            }
197
0
            break;
198
0
        }
199
0
        case MAT_C_CELL: {
200
0
            matvar_t **cells = (matvar_t **)matvar->data;
201
202
0
            if ( matvar->nbytes == 0 || matvar->data_size == 0 )
203
0
                break;
204
205
0
            nelems = matvar->nbytes / matvar->data_size;
206
0
            if ( NULL != cells && nelems > 0 ) {
207
0
                size_t i, field_buf_size;
208
0
                for ( i = 0; i < nelems; i++ ) {
209
0
                    err = GetCellArrayFieldBufSize(cells[i], &field_buf_size);
210
0
                    if ( err )
211
0
                        return err;
212
0
                    err = Add(&nBytes, nBytes, tag_size);
213
0
                    if ( err )
214
0
                        return err;
215
0
                    err = Add(&nBytes, nBytes, field_buf_size);
216
0
                    if ( err )
217
0
                        return err;
218
0
                }
219
0
            }
220
0
            break;
221
0
        }
222
0
        case MAT_C_SPARSE: {
223
0
            const mat_sparse_t *sparse = (const mat_sparse_t *)matvar->data;
224
225
0
            if ( NULL == sparse )
226
0
                break;
227
228
0
            err = Mul(&data_bytes, sparse->nir, sizeof(mat_uint32_t));
229
0
            if ( err )
230
0
                return err;
231
0
            if ( data_bytes % 8 ) {
232
0
                err = Add(&data_bytes, data_bytes, 8 - data_bytes % 8);
233
0
                if ( err )
234
0
                    return err;
235
0
            }
236
0
            err = Add(&nBytes, nBytes, tag_size);
237
0
            if ( err )
238
0
                return err;
239
0
            err = Add(&nBytes, nBytes, data_bytes);
240
0
            if ( err )
241
0
                return err;
242
243
0
            err = Mul(&data_bytes, sparse->njc, sizeof(mat_uint32_t));
244
0
            if ( err )
245
0
                return err;
246
0
            if ( data_bytes % 8 ) {
247
0
                err = Add(&data_bytes, data_bytes, 8 - data_bytes % 8);
248
0
                if ( err )
249
0
                    return err;
250
0
            }
251
0
            err = Add(&nBytes, nBytes, tag_size);
252
0
            if ( err )
253
0
                return err;
254
0
            err = Add(&nBytes, nBytes, data_bytes);
255
0
            if ( err )
256
0
                return err;
257
258
0
            err = Mul(&data_bytes, sparse->ndata, Mat_SizeOf(matvar->data_type));
259
0
            if ( err )
260
0
                return err;
261
0
            if ( data_bytes % 8 ) {
262
0
                err = Add(&data_bytes, data_bytes, 8 - data_bytes % 8);
263
0
                if ( err )
264
0
                    return err;
265
0
            }
266
0
            err = Add(&nBytes, nBytes, tag_size);
267
0
            if ( err )
268
0
                return err;
269
0
            err = Add(&nBytes, nBytes, data_bytes);
270
0
            if ( err )
271
0
                return err;
272
273
0
            if ( matvar->isComplex && NULL != sparse->data ) {
274
0
                err = Add(&nBytes, nBytes, tag_size);
275
0
                if ( err )
276
0
                    return err;
277
0
                err = Add(&nBytes, nBytes, data_bytes);
278
0
                if ( err )
279
0
                    return err;
280
0
            }
281
282
0
            break;
283
0
        }
284
0
        case MAT_C_CHAR:
285
0
            if ( MAT_T_INT8 == matvar->data_type )
286
0
                err = Mul(&data_bytes, nelems, Mat_SizeOf(MAT_T_UINT16));
287
0
            else
288
0
                err = Mul(&data_bytes, nelems, Mat_SizeOf(matvar->data_type));
289
0
            if ( err )
290
0
                return err;
291
0
            if ( data_bytes % 8 ) {
292
0
                err = Add(&data_bytes, data_bytes, 8 - data_bytes % 8);
293
0
                if ( err )
294
0
                    return err;
295
0
            }
296
297
0
            err = Add(&nBytes, nBytes, tag_size);
298
0
            if ( err )
299
0
                return err;
300
0
            err = Add(&nBytes, nBytes, data_bytes);
301
0
            if ( err )
302
0
                return err;
303
304
0
            if ( matvar->isComplex ) {
305
0
                err = Add(&nBytes, nBytes, tag_size);
306
0
                if ( err )
307
0
                    return err;
308
0
                err = Add(&nBytes, nBytes, data_bytes);
309
0
                if ( err )
310
0
                    return err;
311
0
            }
312
313
0
            break;
314
0
        default:
315
0
            err = Mul(&data_bytes, nelems, Mat_SizeOf(matvar->data_type));
316
0
            if ( err )
317
0
                return err;
318
0
            if ( data_bytes % 8 ) {
319
0
                err = Add(&data_bytes, data_bytes, 8 - data_bytes % 8);
320
0
                if ( err )
321
0
                    return err;
322
0
            }
323
324
0
            err = Add(&nBytes, nBytes, tag_size);
325
0
            if ( err )
326
0
                return err;
327
0
            err = Add(&nBytes, nBytes, data_bytes);
328
0
            if ( err )
329
0
                return err;
330
331
0
            if ( matvar->isComplex ) {
332
0
                err = Add(&nBytes, nBytes, tag_size);
333
0
                if ( err )
334
0
                    return err;
335
0
                err = Add(&nBytes, nBytes, data_bytes);
336
0
                if ( err )
337
0
                    return err;
338
0
            }
339
0
    } /* switch ( matvar->class_type ) */
340
341
0
    *size = nBytes;
342
0
    return MATIO_E_NO_ERROR;
343
0
}
344
345
/** @brief determines the number of bytes needed to store the given struct field
346
 *
347
 * @ingroup mat_internal
348
 * @param matvar field of a structure
349
 * @param size the number of bytes needed to store the struct field
350
 * @retval 0 on success
351
 */
352
static int
353
GetStructFieldBufSize(matvar_t *matvar, size_t *size)
354
0
{
355
0
    int err;
356
0
    size_t nBytes = 0, type_buf_size;
357
0
    size_t tag_size = 8, array_flags_size = 8;
358
359
0
    *size = 0;
360
361
0
    if ( matvar == NULL )
362
0
        return GetEmptyMatrixMaxBufSize(NULL, 2, size);
363
364
    /* Add the Array Flags tag and space to the number of bytes */
365
0
    nBytes += tag_size + array_flags_size;
366
367
    /* In a struct field, the name is just a tag with 0 bytes */
368
0
    nBytes += tag_size;
369
370
0
    err = GetTypeBufSize(matvar, &type_buf_size);
371
0
    if ( err )
372
0
        return err;
373
0
    err = Add(&nBytes, nBytes, type_buf_size);
374
0
    if ( err )
375
0
        return err;
376
377
0
    *size = nBytes;
378
0
    return MATIO_E_NO_ERROR;
379
0
}
380
381
/** @brief determines the number of bytes needed to store the cell array element
382
 *
383
 * @ingroup mat_internal
384
 * @param matvar MAT variable
385
 * @param size the number of bytes needed to store the variable
386
 * @retval 0 on success
387
 */
388
static int
389
GetCellArrayFieldBufSize(matvar_t *matvar, size_t *size)
390
0
{
391
0
    int err;
392
0
    size_t nBytes = 0, type_buf_size;
393
0
    size_t tag_size = 8, array_flags_size = 8;
394
395
0
    *size = 0;
396
397
0
    if ( matvar == NULL )
398
0
        return MATIO_E_BAD_ARGUMENT;
399
400
    /* Add the Array Flags tag and space to the number of bytes */
401
0
    nBytes += tag_size + array_flags_size;
402
403
    /* In an element of a cell array, the name is just a tag with 0 bytes */
404
0
    nBytes += tag_size;
405
406
0
    err = GetTypeBufSize(matvar, &type_buf_size);
407
0
    if ( err )
408
0
        return err;
409
0
    err = Add(&nBytes, nBytes, type_buf_size);
410
0
    if ( err )
411
0
        return err;
412
413
0
    *size = nBytes;
414
0
    return MATIO_E_NO_ERROR;
415
0
}
416
417
/** @brief determines the number of bytes needed to store the given variable
418
 *
419
 * @ingroup mat_internal
420
 * @param name MAT variable
421
 * @param rank rank of the variable
422
 * @param size the number of bytes needed to store the variable
423
 * @retval 0 on success
424
 */
425
static int
426
GetEmptyMatrixMaxBufSize(const char *name, int rank, size_t *size)
427
0
{
428
0
    int err = 0;
429
0
    size_t nBytes = 0, len, rank_size;
430
0
    size_t tag_size = 8, array_flags_size = 8;
431
432
    /* Add the Array Flags tag and space to the number of bytes */
433
0
    nBytes += tag_size + array_flags_size;
434
435
    /* Get size of variable name, pad it to an 8 byte block, and add it to nBytes */
436
0
    if ( NULL != name )
437
0
        len = strlen(name);
438
0
    else
439
0
        len = 4;
440
441
0
    if ( len <= 4 ) {
442
0
        nBytes += tag_size;
443
0
    } else {
444
0
        nBytes += tag_size;
445
0
        if ( len % 8 ) {
446
0
            err = Add(&len, len, 8 - len % 8);
447
0
            if ( err )
448
0
                return err;
449
0
        }
450
451
0
        err = Add(&nBytes, nBytes, len);
452
0
        if ( err )
453
0
            return err;
454
0
    }
455
456
    /* Add rank and dimensions, padded to an 8 byte block */
457
0
    err = Mul(&rank_size, rank, 4);
458
0
    if ( err )
459
0
        return err;
460
0
    if ( rank % 2 )
461
0
        err = Add(&nBytes, nBytes, tag_size + 4);
462
0
    else
463
0
        err = Add(&nBytes, nBytes, tag_size);
464
0
    if ( err )
465
0
        return err;
466
467
0
    err = Add(&nBytes, nBytes, rank_size);
468
0
    if ( err )
469
0
        return err;
470
    /* Data tag */
471
0
    err = Add(&nBytes, nBytes, tag_size);
472
0
    if ( err )
473
0
        return err;
474
475
0
    *size = nBytes;
476
0
    return MATIO_E_NO_ERROR;
477
0
}
478
479
static void
480
SetFieldNames(matvar_t *matvar, const char *buf, size_t nfields, mat_uint32_t fieldname_length)
481
5.73k
{
482
5.73k
    size_t i;
483
484
5.73k
    matvar->internal->num_fields = 0;
485
5.73k
    if ( nfields == 0 || fieldname_length == 0 )
486
0
        return;
487
488
5.73k
    matvar->internal->fieldnames = (char **)calloc(nfields, sizeof(*matvar->internal->fieldnames));
489
5.73k
    if ( NULL == matvar->internal->fieldnames )
490
0
        return;
491
492
1.02M
    for ( i = 0; i < nfields; i++ ) {
493
1.02M
        matvar->internal->fieldnames[i] = (char *)malloc(fieldname_length);
494
1.02M
        if ( NULL == matvar->internal->fieldnames[i] ) {
495
0
            size_t j;
496
0
            for ( j = 0; j < i; j++ )
497
0
                free(matvar->internal->fieldnames[j]);
498
0
            free(matvar->internal->fieldnames);
499
0
            matvar->internal->fieldnames = NULL;
500
0
            return;
501
0
        }
502
1.02M
        memcpy(matvar->internal->fieldnames[i], buf + i * fieldname_length, fieldname_length);
503
1.02M
        matvar->internal->fieldnames[i][fieldname_length - 1] = '\0';
504
1.02M
    }
505
5.73k
    matvar->internal->num_fields = nfields;
506
5.73k
}
507
508
static int
509
ReadSparse(mat_t *mat, const matvar_t *matvar, mat_uint32_t *n, mat_uint32_t **v)
510
9.68k
{
511
9.68k
    int err;
512
9.68k
    int data_in_tag = 0;
513
9.68k
    enum matio_types packed_type;
514
9.68k
    mat_uint32_t N = 0;
515
516
9.68k
    if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
517
1.08k
#if HAVE_ZLIB
518
1.08k
        size_t readBytes;
519
1.08k
        mat_uint32_t tag[2] = {0, 0};
520
1.08k
        matvar->internal->z->avail_in = 0;
521
1.08k
        err = Inflate(mat, matvar->internal->z, tag, 4, &readBytes);
522
1.08k
        if ( err ) {
523
0
            return err;
524
0
        }
525
1.08k
        if ( mat->byteswap )
526
1.03k
            (void)Mat_uint32Swap(tag);
527
1.08k
        packed_type = TYPE_FROM_TAG(tag[0]);
528
1.08k
        if ( tag[0] & 0xffff0000 ) { /* Data is in the tag */
529
115
            data_in_tag = 1;
530
115
            N = (tag[0] & 0xffff0000) >> 16;
531
967
        } else {
532
967
            data_in_tag = 0;
533
967
            err = ReadCompressedUInt32Data(mat, matvar->internal->z, &N, MAT_T_UINT32, 1);
534
967
        }
535
1.08k
#endif
536
8.60k
    } else {
537
8.60k
        mat_uint32_t tag[2] = {0, 0};
538
8.60k
        err = Read(tag, 4, 1, mat, NULL);
539
8.60k
        if ( err ) {
540
1
            return err;
541
1
        }
542
8.60k
        if ( mat->byteswap )
543
2.60k
            (void)Mat_uint32Swap(tag);
544
8.60k
        packed_type = TYPE_FROM_TAG(tag[0]);
545
8.60k
        if ( tag[0] & 0xffff0000 ) { /* Data is in the tag */
546
6.54k
            data_in_tag = 1;
547
6.54k
            N = (tag[0] & 0xffff0000) >> 16;
548
6.54k
        } else {
549
2.05k
            data_in_tag = 0;
550
2.05k
            err = Read(&N, 4, 1, mat, NULL);
551
2.05k
            if ( err ) {
552
0
                return err;
553
0
            }
554
2.05k
            if ( mat->byteswap )
555
564
                (void)Mat_uint32Swap(&N);
556
2.05k
        }
557
8.60k
    }
558
9.68k
    if ( 0 == N )
559
96
        return MATIO_E_NO_ERROR;
560
9.58k
    *n = N / 4;
561
9.58k
    *v = (mat_uint32_t *)calloc(N, 1);
562
9.58k
    if ( NULL == *v ) {
563
0
        return MATIO_E_OUT_OF_MEMORY;
564
0
    }
565
9.58k
    if ( matvar->compression == MAT_COMPRESSION_NONE ) {
566
8.51k
        size_t nBytes;
567
8.51k
        err = ReadUInt32Data(mat, *v, packed_type, *n);
568
8.51k
        if ( err ) {
569
534
            return err;
570
534
        }
571
7.98k
        err = Mul(&nBytes, (size_t)*n, Mat_SizeOf(packed_type));
572
7.98k
        if ( err ) {
573
0
            return err;
574
0
        }
575
        /*
576
            * If the data was in the tag we started on a 4-byte
577
            * boundary so add 4 to make it an 8-byte
578
            */
579
7.98k
        if ( data_in_tag )
580
6.31k
            nBytes += 4;
581
7.98k
        if ( (nBytes % 8) != 0 )
582
7.49k
            (void)MatSeek(mat, 8 - (nBytes % 8), SEEK_CUR);
583
7.98k
#if HAVE_ZLIB
584
7.98k
    } else if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
585
1.07k
        size_t nBytes;
586
1.07k
        err = ReadCompressedUInt32Data(mat, matvar->internal->z, *v, packed_type, *n);
587
1.07k
        if ( err ) {
588
32
            return err;
589
32
        }
590
1.03k
        err = Mul(&nBytes, (size_t)*n, Mat_SizeOf(packed_type));
591
1.03k
        if ( err ) {
592
0
            return err;
593
0
        }
594
        /*
595
            * If the data was in the tag we started on a 4-byte
596
            * boundary so add 4 to make it an 8-byte
597
            */
598
1.03k
        if ( data_in_tag )
599
102
            nBytes += 4;
600
1.03k
        if ( (nBytes % 8) != 0 )
601
971
            err = InflateSkip(mat, matvar->internal->z, 8 - (nBytes % 8), NULL);
602
1.03k
#endif
603
1.03k
    }
604
605
9.02k
    return err;
606
9.58k
}
607
608
#if HAVE_ZLIB
609
/** @brief determines the number of bytes needed to store the given variable
610
 *
611
 * @ingroup mat_internal
612
 * @param matvar MAT variable
613
 * @param size the number of bytes needed to store the variable
614
 * @retval 0 on success
615
 */
616
static int
617
GetMatrixMaxBufSize(matvar_t *matvar, size_t *size)
618
0
{
619
0
    int err = MATIO_E_NO_ERROR;
620
0
    size_t nBytes = 0, len, type_buf_size;
621
0
    size_t tag_size = 8, array_flags_size = 8;
622
623
0
    if ( matvar == NULL )
624
0
        return MATIO_E_BAD_ARGUMENT;
625
626
    /* Add the Array Flags tag and space to the number of bytes */
627
0
    nBytes += tag_size + array_flags_size;
628
629
    /* Get size of variable name, pad it to an 8 byte block, and add it to nBytes */
630
0
    if ( NULL != matvar->name )
631
0
        len = strlen(matvar->name);
632
0
    else
633
0
        len = 4;
634
635
0
    if ( len <= 4 ) {
636
0
        nBytes += tag_size;
637
0
    } else {
638
0
        nBytes += tag_size;
639
0
        if ( len % 8 ) {
640
0
            err = Add(&len, len, 8 - len % 8);
641
0
            if ( err )
642
0
                return err;
643
0
        }
644
645
0
        err = Add(&nBytes, nBytes, len);
646
0
        if ( err )
647
0
            return err;
648
0
    }
649
650
0
    err = GetTypeBufSize(matvar, &type_buf_size);
651
0
    if ( err )
652
0
        return err;
653
0
    err = Add(&nBytes, nBytes, type_buf_size);
654
0
    if ( err )
655
0
        return err;
656
657
0
    *size = nBytes;
658
0
    return MATIO_E_NO_ERROR;
659
0
}
660
#endif
661
662
/** @if mat_devman
663
 * @brief Creates a new Matlab MAT version 5 file
664
 *
665
 * Tries to create a new Matlab MAT file with the given name and optional
666
 * header string.  If no header string is given, the default string
667
 * is used containing the software, version, and date in it.  If a header
668
 * string is given, at most the first 116 characters is written to the file.
669
 * The given header string need not be the full 116 characters, but MUST be
670
 * NULL terminated.
671
 * @ingroup MAT
672
 * @param matname Name of MAT file to create
673
 * @param hdr_str Optional header string, NULL to use default
674
 * @return A pointer to the MAT file or NULL if it failed.  This is not a
675
 * simple FILE * and should not be used as one.
676
 * @endif
677
 */
678
mat_t *
679
Mat_Create5(const char *matname, const char *hdr_str)
680
0
{
681
0
    FILE *fp;
682
0
    mat_int16_t endian = 0, version;
683
0
    mat_t *mat = NULL;
684
0
    size_t err;
685
0
    time_t t;
686
687
#if defined(_WIN32)
688
    wchar_t *wname = utf82u(matname);
689
    if ( NULL != wname ) {
690
        fp = _wfopen(wname, L"w+b");
691
        free(wname);
692
    } else {
693
        fp = NULL;
694
    }
695
#else
696
0
    fp = fopen(matname, "w+b");
697
0
#endif
698
0
    if ( !fp )
699
0
        return NULL;
700
701
0
    mat = (mat_t *)malloc(sizeof(*mat));
702
0
    if ( mat == NULL ) {
703
0
        fclose(fp);
704
0
        return NULL;
705
0
    }
706
707
0
    mat->memfile = NULL;
708
0
    mat->fp = NULL;
709
0
    mat->header = NULL;
710
0
    mat->subsys_offset = NULL;
711
0
    mat->filename = NULL;
712
0
    mat->version = 0;
713
0
    mat->byteswap = 0;
714
0
    mat->mode = 0;
715
0
    mat->bof = 128;
716
0
    mat->next_index = 0;
717
0
    mat->num_datasets = 0;
718
0
#if defined(MAT73) && MAT73
719
0
    mat->refs_id = -1;
720
0
#endif
721
0
    mat->dir = NULL;
722
0
#if defined(MCOS) && MCOS
723
0
    mat->mcos = NULL;
724
0
#endif
725
726
0
    t = time(NULL);
727
0
    mat->fp = fp;
728
0
    mat->filename = strdup(matname);
729
0
    mat->mode = MAT_ACC_RDWR;
730
0
    mat->byteswap = 0;
731
0
    mat->header = (char *)malloc(128 * sizeof(char));
732
0
    mat->subsys_offset = (char *)malloc(8 * sizeof(char));
733
0
    if ( NULL == mat->filename || NULL == mat->header || NULL == mat->subsys_offset ) {
734
0
        Mat_Close(mat);
735
0
        return NULL;
736
0
    }
737
0
    memset(mat->header, ' ', 128);
738
0
    if ( hdr_str == NULL ) {
739
0
        err = mat_snprintf(mat->header, 116,
740
0
                           "MATLAB 5.0 MAT-file, Platform: %s, "
741
0
                           "Created by: libmatio v%d.%d.%d on %s",
742
0
                           MATIO_PLATFORM, MATIO_MAJOR_VERSION, MATIO_MINOR_VERSION,
743
0
                           MATIO_RELEASE_LEVEL, ctime(&t));
744
0
    } else {
745
0
        err = mat_snprintf(mat->header, 116, "%s", hdr_str);
746
0
    }
747
0
    if ( err >= 116 )
748
0
        mat->header[115] = '\0'; /* Just to make sure it's NULL terminated */
749
0
    memset(mat->subsys_offset, ' ', 8);
750
0
    mat->version = 0x0100;
751
0
    endian = 0x4d49;
752
753
0
    version = 0x0100;
754
755
0
    fwrite(mat->header, 1, 116, (FILE *)mat->fp);
756
0
    fwrite(mat->subsys_offset, 1, 8, (FILE *)mat->fp);
757
0
    fwrite(&version, 2, 1, (FILE *)mat->fp);
758
0
    fwrite(&endian, 2, 1, (FILE *)mat->fp);
759
760
0
    return mat;
761
0
}
762
763
/** @if mat_devman
764
 * @brief Writes @c data as character data
765
 *
766
 * This function uses the knowledge that the data is part of a character class
767
 * to avoid some pitfalls with Matlab listed below.
768
 *   @li Matlab character data cannot be unsigned 8-bit integers, it needs at
769
 *       least unsigned 16-bit integers
770
 *
771
 * @ingroup mat_internal
772
 * @param mat MAT file pointer
773
 * @param data character data to write
774
 * @param N Number of elements to write
775
 * @param data_type character data type (enum matio_types)
776
 * @return number of bytes written
777
 * @endif
778
 */
779
static size_t
780
WriteCharData(mat_t *mat, void *data, size_t N, enum matio_types data_type)
781
0
{
782
0
    mat_uint32_t nBytes = 0;
783
0
    size_t nbytes = 0, i;
784
0
    size_t byteswritten = 0;
785
0
    const mat_uint8_t pad1 = 0;
786
0
    int err;
787
788
0
    switch ( data_type ) {
789
0
        case MAT_T_UINT8:
790
0
        case MAT_T_UINT16:
791
0
        case MAT_T_UTF8:
792
0
        case MAT_T_UTF16: {
793
0
            data_type = MAT_T_UINT8 == data_type ? MAT_T_UTF8 : data_type;
794
0
            err = Mul(&nbytes, N, Mat_SizeOf(data_type));
795
0
            if ( err ) {
796
0
                return 0;
797
0
            }
798
0
            nBytes = (mat_uint32_t)nbytes;
799
0
            fwrite(&data_type, 4, 1, (FILE *)mat->fp);
800
0
            fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
801
0
            if ( NULL != data && N > 0 )
802
0
                fwrite(data, 1, nbytes, (FILE *)mat->fp);
803
0
            if ( nBytes % 8 ) {
804
0
                for ( i = nbytes % 8; i < 8; i++ )
805
0
                    fwrite(&pad1, 1, 1, (FILE *)mat->fp);
806
0
            }
807
0
            break;
808
0
        }
809
0
        case MAT_T_INT8: {
810
0
            mat_int8_t *ptr;
811
0
            mat_uint16_t c;
812
813
            /* Matlab can't read MAT_C_CHAR as int8, needs uint16 */
814
0
            data_type = MAT_T_UINT16;
815
0
            err = Mul(&nbytes, N, Mat_SizeOf(data_type));
816
0
            if ( err ) {
817
0
                return 0;
818
0
            }
819
0
            nBytes = (mat_uint32_t)nbytes;
820
0
            fwrite(&data_type, 4, 1, (FILE *)mat->fp);
821
0
            fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
822
0
            ptr = (mat_int8_t *)data;
823
0
            if ( NULL == data )
824
0
                break;
825
0
            for ( i = 0; i < N; i++ ) {
826
0
                c = (mat_uint16_t) * (char *)ptr;
827
0
                fwrite(&c, 2, 1, (FILE *)mat->fp);
828
0
                ptr++;
829
0
            }
830
0
            if ( nbytes % 8 )
831
0
                for ( i = nbytes % 8; i < 8; i++ )
832
0
                    fwrite(&pad1, 1, 1, (FILE *)mat->fp);
833
0
            break;
834
0
        }
835
0
        case MAT_T_UNKNOWN: {
836
            /* Sometimes empty char data will have MAT_T_UNKNOWN, so just write
837
             * a data tag
838
             */
839
0
            data_type = MAT_T_UINT16;
840
0
            err = Mul(&nbytes, N, Mat_SizeOf(data_type));
841
0
            if ( err ) {
842
0
                return 0;
843
0
            }
844
0
            nBytes = (mat_uint32_t)nbytes;
845
0
            fwrite(&data_type, 4, 1, (FILE *)mat->fp);
846
0
            fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
847
0
            break;
848
0
        }
849
0
        default:
850
0
            nbytes = 0;
851
0
            break;
852
0
    }
853
0
    byteswritten += nbytes;
854
0
    return byteswritten;
855
0
}
856
857
#if HAVE_ZLIB
858
/** @brief Writes @c data as compressed character data
859
 *
860
 * This function uses the knowledge that the data is part of a character class
861
 * to avoid some pitfalls with Matlab listed below.
862
 *   @li Matlab character data cannot be unsigned 8-bit integers, it needs at
863
 *       least unsigned 16-bit integers
864
 *
865
 * @ingroup mat_internal
866
 * @param mat MAT file pointer
867
 * @param z pointer to the zlib compression stream
868
 * @param data character data to write
869
 * @param N Number of elements to write
870
 * @param data_type character data type (enum matio_types)
871
 * @return number of bytes written
872
 */
873
static size_t
874
WriteCompressedCharData(mat_t *mat, z_streamp z, void *data, size_t N, enum matio_types data_type)
875
0
{
876
0
    size_t data_size, byteswritten = 0, nbytes = 0;
877
0
    mat_uint32_t data_tag[2] = {0, 0};
878
0
    int buf_size = 1024;
879
0
    int err;
880
0
    mat_uint8_t buf[1024] = {0}, pad[8] = {0, 0, 0, 0, 0, 0, 0, 0};
881
882
0
    if ( mat == NULL || mat->fp == NULL )
883
0
        return 0;
884
885
0
    if ( data_type == MAT_T_UNKNOWN ) {
886
0
        data_size = Mat_SizeOf(MAT_T_UINT16);
887
0
    } else {
888
0
        data_size = Mat_SizeOf(data_type);
889
0
    }
890
891
0
    err = Mul(&nbytes, N, data_size);
892
0
    if ( err ) {
893
0
        return byteswritten;
894
0
    }
895
896
0
    switch ( data_type ) {
897
0
        case MAT_T_UINT8:
898
0
        case MAT_T_UINT16:
899
0
        case MAT_T_UTF8:
900
0
        case MAT_T_UTF16:
901
0
            data_tag[0] = MAT_T_UINT8 == data_type ? MAT_T_UTF8 : data_type;
902
0
            data_tag[1] = (mat_uint32_t)nbytes;
903
0
            z->next_in = ZLIB_BYTE_PTR(data_tag);
904
0
            z->avail_in = 8;
905
0
            do {
906
0
                z->next_out = buf;
907
0
                z->avail_out = buf_size;
908
0
                deflate(z, Z_NO_FLUSH);
909
0
                byteswritten += fwrite(buf, 1, buf_size - z->avail_out, (FILE *)mat->fp);
910
0
            } while ( z->avail_out == 0 );
911
912
            /* exit early if this is an empty data */
913
0
            if ( NULL == data || N < 1 )
914
0
                break;
915
916
0
            z->next_in = (Bytef *)data;
917
0
            z->avail_in = (mat_uint32_t)nbytes;
918
0
            do {
919
0
                z->next_out = buf;
920
0
                z->avail_out = buf_size;
921
0
                deflate(z, Z_NO_FLUSH);
922
0
                byteswritten += fwrite(buf, 1, buf_size - z->avail_out, (FILE *)mat->fp);
923
0
            } while ( z->avail_out == 0 );
924
            /* Add/Compress padding to pad to 8-byte boundary */
925
0
            if ( nbytes % 8 ) {
926
0
                z->next_in = pad;
927
0
                z->avail_in = 8 - (nbytes % 8);
928
0
                do {
929
0
                    z->next_out = buf;
930
0
                    z->avail_out = buf_size;
931
0
                    deflate(z, Z_NO_FLUSH);
932
0
                    byteswritten += fwrite(buf, 1, buf_size - z->avail_out, (FILE *)mat->fp);
933
0
                } while ( z->avail_out == 0 );
934
0
            }
935
0
            break;
936
0
        case MAT_T_INT8: {
937
0
            mat_uint8_t *ptr;
938
0
            mat_uint16_t c;
939
0
            size_t i;
940
941
            /* Matlab can't read MAT_C_CHAR as uint8, needs uint16 */
942
0
            data_size = 2;
943
0
            data_tag[0] = MAT_T_UINT16;
944
0
            data_tag[1] = N * data_size;
945
0
            z->next_in = ZLIB_BYTE_PTR(data_tag);
946
0
            z->avail_in = 8;
947
0
            do {
948
0
                z->next_out = buf;
949
0
                z->avail_out = buf_size;
950
0
                deflate(z, Z_NO_FLUSH);
951
0
                byteswritten += fwrite(buf, 1, buf_size - z->avail_out, (FILE *)mat->fp);
952
0
            } while ( z->avail_out == 0 );
953
954
            /* exit early if this is an empty data */
955
0
            if ( NULL == data || N < 1 )
956
0
                break;
957
958
0
            z->next_in = (Bytef *)data;
959
0
            z->avail_in = data_size * N;
960
0
            ptr = (mat_uint8_t *)data;
961
0
            for ( i = 0; i < N; i++ ) {
962
0
                c = (mat_uint16_t) * (char *)ptr;
963
0
                z->next_in = ZLIB_BYTE_PTR(&c);
964
0
                z->avail_in = 2;
965
0
                do {
966
0
                    z->next_out = buf;
967
0
                    z->avail_out = buf_size;
968
0
                    deflate(z, Z_NO_FLUSH);
969
0
                    byteswritten += fwrite(buf, 1, buf_size - z->avail_out, (FILE *)mat->fp);
970
0
                } while ( z->avail_out == 0 );
971
0
                ptr++;
972
0
            }
973
            /* Add/Compress padding to pad to 8-byte boundary */
974
0
            if ( N * data_size % 8 ) {
975
0
                z->next_in = pad;
976
0
                z->avail_in = 8 - (N * data_size % 8);
977
0
                do {
978
0
                    z->next_out = buf;
979
0
                    z->avail_out = buf_size;
980
0
                    deflate(z, Z_NO_FLUSH);
981
0
                    byteswritten += fwrite(buf, 1, buf_size - z->avail_out, (FILE *)mat->fp);
982
0
                } while ( z->avail_out == 0 );
983
0
            }
984
0
            break;
985
0
        }
986
0
        case MAT_T_UNKNOWN:
987
            /* Sometimes empty char data will have MAT_T_UNKNOWN, so just write a data tag */
988
0
            data_tag[0] = MAT_T_UINT16;
989
0
            data_tag[1] = (mat_uint32_t)nbytes;
990
0
            z->next_in = ZLIB_BYTE_PTR(data_tag);
991
0
            z->avail_in = 8;
992
0
            do {
993
0
                z->next_out = buf;
994
0
                z->avail_out = buf_size;
995
0
                deflate(z, Z_NO_FLUSH);
996
0
                byteswritten += fwrite(buf, 1, buf_size - z->avail_out, (FILE *)mat->fp);
997
0
            } while ( z->avail_out == 0 );
998
0
            break;
999
0
        default:
1000
0
            break;
1001
0
    }
1002
1003
0
    return byteswritten;
1004
0
}
1005
#endif
1006
1007
/** @brief Writes the data buffer to the file
1008
 *
1009
 * @param mat MAT file pointer
1010
 * @param data pointer to the data to write
1011
 * @param N number of elements to write
1012
 * @param data_type data type of the data
1013
 * @return number of bytes written
1014
 */
1015
static int
1016
WriteData(mat_t *mat, const void *data, size_t N, enum matio_types data_type)
1017
0
{
1018
0
    int nBytes = 0, data_size;
1019
1020
0
    if ( mat == NULL || mat->fp == NULL )
1021
0
        return 0;
1022
1023
0
    data_size = Mat_SizeOf(data_type);
1024
0
    nBytes = N * data_size;
1025
0
    fwrite(&data_type, 4, 1, (FILE *)mat->fp);
1026
0
    fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
1027
1028
0
    if ( data != NULL && N > 0 )
1029
0
        fwrite(data, data_size, N, (FILE *)mat->fp);
1030
1031
0
    return nBytes;
1032
0
}
1033
1034
#if HAVE_ZLIB
1035
/* Compresses the data buffer and writes it to the file */
1036
static size_t
1037
WriteCompressedData(mat_t *mat, z_streamp z, void *data, int N, enum matio_types data_type)
1038
0
{
1039
0
    int nBytes = 0, data_size, data_tag[2], byteswritten = 0;
1040
0
    int buf_size = 1024;
1041
0
    mat_uint8_t buf[1024] = {0}, pad[8] = {0, 0, 0, 0, 0, 0, 0, 0};
1042
1043
0
    if ( mat == NULL || mat->fp == NULL )
1044
0
        return 0;
1045
1046
0
    data_size = Mat_SizeOf(data_type);
1047
0
    data_tag[0] = data_type;
1048
0
    data_tag[1] = data_size * N;
1049
0
    z->next_in = ZLIB_BYTE_PTR(data_tag);
1050
0
    z->avail_in = 8;
1051
0
    do {
1052
0
        z->next_out = buf;
1053
0
        z->avail_out = buf_size;
1054
0
        deflate(z, Z_NO_FLUSH);
1055
0
        byteswritten += fwrite(buf, 1, buf_size - z->avail_out, (FILE *)mat->fp);
1056
0
    } while ( z->avail_out == 0 );
1057
1058
    /* exit early if this is an empty data */
1059
0
    if ( NULL == data || N < 1 )
1060
0
        return byteswritten;
1061
1062
0
    z->next_in = (Bytef *)data;
1063
0
    z->avail_in = N * data_size;
1064
0
    do {
1065
0
        z->next_out = buf;
1066
0
        z->avail_out = buf_size;
1067
0
        deflate(z, Z_NO_FLUSH);
1068
0
        byteswritten += fwrite(buf, 1, buf_size - z->avail_out, (FILE *)mat->fp);
1069
0
    } while ( z->avail_out == 0 );
1070
    /* Add/Compress padding to pad to 8-byte boundary */
1071
0
    if ( N * data_size % 8 ) {
1072
0
        z->next_in = pad;
1073
0
        z->avail_in = 8 - (N * data_size % 8);
1074
0
        do {
1075
0
            z->next_out = buf;
1076
0
            z->avail_out = buf_size;
1077
0
            deflate(z, Z_NO_FLUSH);
1078
0
            byteswritten += fwrite(buf, 1, buf_size - z->avail_out, (FILE *)mat->fp);
1079
0
        } while ( z->avail_out == 0 );
1080
0
    }
1081
0
    nBytes = byteswritten;
1082
0
    return nBytes;
1083
0
}
1084
#endif
1085
1086
/** @brief Reads the next cell of the cell array in @c matvar
1087
 *
1088
 * @ingroup mat_internal
1089
 * @param mat MAT file pointer
1090
 * @param matvar MAT variable pointer
1091
 * @return Number of bytes read
1092
 */
1093
static size_t
1094
ReadNextCell(mat_t *mat, matvar_t *matvar)
1095
10.8k
{
1096
10.8k
    size_t bytesread = 0;
1097
10.8k
    int err;
1098
10.8k
    matvar_t **cells = NULL;
1099
10.8k
    size_t nelems = 1;
1100
1101
10.8k
    err = Mat_MulDims(matvar, &nelems);
1102
10.8k
    if ( err ) {
1103
60
        Mat_Critical("Integer multiplication overflow");
1104
60
        return bytesread;
1105
60
    }
1106
10.7k
    matvar->data_size = sizeof(matvar_t *);
1107
10.7k
    err = Mul(&matvar->nbytes, nelems, matvar->data_size);
1108
10.7k
    if ( err ) {
1109
0
        Mat_Critical("Integer multiplication overflow");
1110
0
        return bytesread;
1111
0
    }
1112
1113
10.7k
    if ( nelems > 0 ) {
1114
10.4k
        matvar->data = calloc(nelems, matvar->data_size);
1115
10.4k
        if ( NULL == matvar->data ) {
1116
450
            matvar->nbytes = 0;
1117
450
            if ( NULL != matvar->name )
1118
2
                Mat_Critical("Couldn't allocate memory for %s->data", matvar->name);
1119
450
            return bytesread;
1120
450
        }
1121
10.4k
    }
1122
10.3k
    cells = (matvar_t **)matvar->data;
1123
1124
10.3k
    if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
1125
27
#if HAVE_ZLIB
1126
27
        size_t i;
1127
27
        mat_uint32_t uncomp_buf[16];
1128
27
        mat_uint32_t nBytes;
1129
27
        mat_uint32_t array_flags;
1130
1131
27
        memset(uncomp_buf, 0, sizeof(uncomp_buf));
1132
111
        for ( i = 0; i < nelems; i++ ) {
1133
107
            cells[i] = Mat_VarCalloc();
1134
107
            if ( NULL == cells[i] ) {
1135
0
                Mat_Critical("Couldn't allocate memory for cell %zu", i);
1136
0
                continue;
1137
0
            }
1138
1139
            /* Read variable tag for cell */
1140
107
            uncomp_buf[0] = 0;
1141
107
            uncomp_buf[1] = 0;
1142
107
            err = Inflate(mat, matvar->internal->z, uncomp_buf, 8, &bytesread);
1143
107
            if ( err ) {
1144
1
                Mat_VarFree(cells[i]);
1145
1
                cells[i] = NULL;
1146
1
                break;
1147
1
            }
1148
106
            if ( mat->byteswap ) {
1149
18
                (void)Mat_uint32Swap(uncomp_buf);
1150
18
                (void)Mat_uint32Swap(uncomp_buf + 1);
1151
18
            }
1152
106
            nBytes = uncomp_buf[1];
1153
106
            if ( 0 == nBytes ) {
1154
                /* Empty cell: Memory optimization */
1155
24
                free(cells[i]->internal);
1156
24
                cells[i]->internal = NULL;
1157
24
                continue;
1158
82
            } else if ( uncomp_buf[0] != MAT_T_MATRIX ) {
1159
21
                Mat_VarFree(cells[i]);
1160
21
                cells[i] = NULL;
1161
21
                Mat_Critical("cells[%zu], Uncompressed type not MAT_T_MATRIX", i);
1162
21
                break;
1163
21
            }
1164
61
            cells[i]->compression = MAT_COMPRESSION_ZLIB;
1165
61
            err = Inflate(mat, matvar->internal->z, uncomp_buf, 16, &bytesread);
1166
61
            if ( err ) {
1167
0
                Mat_VarFree(cells[i]);
1168
0
                cells[i] = NULL;
1169
0
                break;
1170
0
            }
1171
61
            nBytes -= 16;
1172
61
            if ( mat->byteswap ) {
1173
6
                (void)Mat_uint32Swap(uncomp_buf);
1174
6
                (void)Mat_uint32Swap(uncomp_buf + 1);
1175
6
                (void)Mat_uint32Swap(uncomp_buf + 2);
1176
6
                (void)Mat_uint32Swap(uncomp_buf + 3);
1177
6
            }
1178
            /* Array Flags */
1179
61
            if ( uncomp_buf[0] == MAT_T_UINT32 ) {
1180
61
                array_flags = uncomp_buf[2];
1181
61
                cells[i]->class_type = CLASS_FROM_ARRAY_FLAGS(array_flags);
1182
61
                cells[i]->isComplex = (array_flags & MAT_F_COMPLEX);
1183
61
                cells[i]->isGlobal = (array_flags & MAT_F_GLOBAL);
1184
61
                cells[i]->isLogical = (array_flags & MAT_F_LOGICAL);
1185
61
                if ( cells[i]->class_type == MAT_C_SPARSE ) {
1186
                    /* Need to find a more appropriate place to store nzmax */
1187
16
                    cells[i]->nbytes = uncomp_buf[3];
1188
16
                }
1189
61
            } else {
1190
0
                Mat_Critical("Expected MAT_T_UINT32 for array tags, got %d", uncomp_buf[0]);
1191
0
                InflateSkip(mat, matvar->internal->z, nBytes, &bytesread);
1192
0
            }
1193
61
            if ( cells[i]->class_type != MAT_C_OPAQUE ) {
1194
61
                mat_uint32_t *dims = NULL;
1195
61
                int do_clean = 0;
1196
61
                err = InflateRankDims(mat, matvar->internal->z, uncomp_buf, sizeof(uncomp_buf),
1197
61
                                      &dims, &bytesread);
1198
61
                if ( NULL == dims ) {
1199
56
                    dims = uncomp_buf + 2;
1200
56
                } else {
1201
5
                    do_clean = 1;
1202
5
                }
1203
61
                if ( err ) {
1204
1
                    if ( do_clean ) {
1205
0
                        free(dims);
1206
0
                    }
1207
1
                    Mat_VarFree(cells[i]);
1208
1
                    cells[i] = NULL;
1209
1
                    break;
1210
1
                }
1211
60
                nBytes -= 8;
1212
60
                if ( mat->byteswap ) {
1213
6
                    (void)Mat_uint32Swap(uncomp_buf);
1214
6
                    (void)Mat_uint32Swap(uncomp_buf + 1);
1215
6
                }
1216
                /* Rank and Dimension */
1217
60
                if ( uncomp_buf[0] == MAT_T_INT32 ) {
1218
60
                    int j;
1219
60
                    size_t size;
1220
60
                    cells[i]->rank = uncomp_buf[1];
1221
60
                    nBytes -= cells[i]->rank;
1222
60
                    cells[i]->rank /= 4;
1223
60
                    if ( 0 == do_clean && cells[i]->rank > 13 ) {
1224
0
                        int rank = cells[i]->rank;
1225
0
                        cells[i]->rank = 0;
1226
0
                        Mat_Critical("%d is not a valid rank", rank);
1227
0
                        continue;
1228
0
                    }
1229
60
                    err = Mul(&size, cells[i]->rank, sizeof(*cells[i]->dims));
1230
60
                    if ( err ) {
1231
0
                        if ( do_clean ) {
1232
0
                            free(dims);
1233
0
                        }
1234
0
                        Mat_VarFree(cells[i]);
1235
0
                        cells[i] = NULL;
1236
0
                        Mat_Critical("Integer multiplication overflow");
1237
0
                        continue;
1238
0
                    }
1239
60
                    cells[i]->dims = (size_t *)malloc(size);
1240
60
                    if ( NULL == cells[i]->dims ) {
1241
0
                        if ( do_clean ) {
1242
0
                            free(dims);
1243
0
                        }
1244
0
                        Mat_VarFree(cells[i]);
1245
0
                        cells[i] = NULL;
1246
0
                        Mat_Critical("Couldn't allocate memory for dims");
1247
0
                        continue;
1248
0
                    }
1249
60
                    if ( mat->byteswap ) {
1250
18
                        for ( j = 0; j < cells[i]->rank; j++ )
1251
12
                            cells[i]->dims[j] = Mat_uint32Swap(dims + j);
1252
54
                    } else {
1253
137k
                        for ( j = 0; j < cells[i]->rank; j++ )
1254
137k
                            cells[i]->dims[j] = dims[j];
1255
54
                    }
1256
60
                    if ( cells[i]->rank % 2 != 0 )
1257
0
                        nBytes -= 4;
1258
60
                }
1259
60
                if ( do_clean ) {
1260
5
                    free(dims);
1261
5
                }
1262
                /* Variable name tag */
1263
60
                err = Inflate(mat, matvar->internal->z, uncomp_buf, 8, &bytesread);
1264
60
                if ( err ) {
1265
0
                    Mat_VarFree(cells[i]);
1266
0
                    cells[i] = NULL;
1267
0
                    break;
1268
0
                }
1269
60
                nBytes -= 8;
1270
60
                if ( mat->byteswap ) {
1271
6
                    (void)Mat_uint32Swap(uncomp_buf);
1272
6
                    (void)Mat_uint32Swap(uncomp_buf + 1);
1273
6
                }
1274
                /* Handle cell elements written with a variable name */
1275
60
                if ( uncomp_buf[1] > 0 ) {
1276
                    /* Name of variable */
1277
9
                    if ( uncomp_buf[0] == MAT_T_INT8 ) { /* Name not in tag */
1278
0
                        mat_uint32_t len = uncomp_buf[1];
1279
1280
0
                        if ( len % 8 > 0 ) {
1281
0
                            if ( len < UINT32_MAX - 8 + (len % 8) )
1282
0
                                len = len + 8 - (len % 8);
1283
0
                            else {
1284
0
                                Mat_VarFree(cells[i]);
1285
0
                                cells[i] = NULL;
1286
0
                                break;
1287
0
                            }
1288
0
                        }
1289
0
                        cells[i]->name = (char *)malloc(len + 1);
1290
0
                        nBytes -= len;
1291
0
                        if ( NULL != cells[i]->name ) {
1292
                            /* Variable name */
1293
0
                            err =
1294
0
                                Inflate(mat, matvar->internal->z, cells[i]->name, len, &bytesread);
1295
0
                            if ( err ) {
1296
0
                                Mat_VarFree(cells[i]);
1297
0
                                cells[i] = NULL;
1298
0
                                break;
1299
0
                            }
1300
0
                            cells[i]->name[len] = '\0';
1301
0
                        }
1302
9
                    } else {
1303
9
                        mat_uint32_t len = (uncomp_buf[0] & 0xffff0000) >> 16;
1304
9
                        if ( ((uncomp_buf[0] & 0x0000ffff) == MAT_T_INT8) && len > 0 && len <= 4 ) {
1305
                            /* Name packed in tag */
1306
0
                            cells[i]->name = (char *)malloc(len + 1);
1307
0
                            if ( NULL != cells[i]->name ) {
1308
0
                                memcpy(cells[i]->name, uncomp_buf + 1, len);
1309
0
                                cells[i]->name[len] = '\0';
1310
0
                            }
1311
0
                        }
1312
9
                    }
1313
9
                }
1314
60
                cells[i]->internal->z = (z_streamp)calloc(1, sizeof(z_stream));
1315
60
                if ( cells[i]->internal->z != NULL ) {
1316
60
                    err = inflateCopy(cells[i]->internal->z, matvar->internal->z);
1317
60
                    if ( err == Z_OK ) {
1318
60
                        cells[i]->internal->datapos = MatTell(mat);
1319
60
                        if ( cells[i]->internal->datapos != -1L ) {
1320
60
                            cells[i]->internal->datapos -= matvar->internal->z->avail_in;
1321
60
                            if ( cells[i]->class_type == MAT_C_STRUCT )
1322
0
                                bytesread += ReadNextStructField(mat, cells[i]);
1323
60
                            else if ( cells[i]->class_type == MAT_C_CELL )
1324
0
                                bytesread += ReadNextCell(mat, cells[i]);
1325
60
                            else if ( nBytes <= (1 << MAX_WBITS) ) {
1326
                                /* Memory optimization: Read data if less in size
1327
                                   than the zlib inflate state (approximately) */
1328
51
                                err = Mat_VarRead5(mat, cells[i]);
1329
51
                                cells[i]->internal->data = cells[i]->data;
1330
51
                                cells[i]->data = NULL;
1331
51
                            }
1332
60
                            (void)MatSeek(mat, cells[i]->internal->datapos, SEEK_SET);
1333
60
                        } else {
1334
0
                            Mat_Critical("Couldn't determine file position");
1335
0
                        }
1336
60
                        if ( cells[i]->internal->data != NULL ||
1337
23
                             cells[i]->class_type == MAT_C_STRUCT ||
1338
51
                             cells[i]->class_type == MAT_C_CELL || nBytes <= (1 << MAX_WBITS) ) {
1339
                            /* Memory optimization: Free inflate state */
1340
51
                            inflateEnd(cells[i]->internal->z);
1341
51
                            free(cells[i]->internal->z);
1342
51
                            cells[i]->internal->z = NULL;
1343
51
                        }
1344
60
                    } else {
1345
0
                        Mat_Critical("inflateCopy returned error %s", zError(err));
1346
0
                    }
1347
60
                } else {
1348
0
                    Mat_Critical("Couldn't allocate memory");
1349
0
                }
1350
60
            } else {
1351
0
                size_t opaque_bytes = 0;
1352
0
                cells[i]->internal->z = (z_streamp)calloc(1, sizeof(z_stream));
1353
0
                if ( NULL != cells[i]->internal->z ) {
1354
0
                    err = inflateCopy(cells[i]->internal->z, matvar->internal->z);
1355
0
                    if ( err == Z_OK ) {
1356
0
                        cells[i]->internal->datapos = MatTell(mat);
1357
0
                        if ( cells[i]->internal->datapos != -1L ) {
1358
0
                            cells[i]->internal->datapos -= matvar->internal->z->avail_in;
1359
0
                            err = ReadCompressedOpaqueInfo5(mat, cells[i], &opaque_bytes);
1360
0
                            if ( err == Z_OK ) {
1361
0
                                inflateEnd(cells[i]->internal->z);
1362
0
                                free(cells[i]->internal->z);
1363
0
                                cells[i]->internal->z = NULL;
1364
0
                                bytesread += opaque_bytes;
1365
0
                                (void)MatSeek(mat, cells[i]->internal->datapos, SEEK_SET);
1366
0
                            } else {
1367
0
                                inflateEnd(cells[i]->internal->z);
1368
0
                                free(cells[i]->internal->z);
1369
0
                                cells[i]->internal->z = NULL;
1370
0
                                Mat_Critical("Couldn't read compressed opaque info");
1371
0
                            }
1372
0
                        } else {
1373
0
                            inflateEnd(cells[i]->internal->z);
1374
0
                            free(cells[i]->internal->z);
1375
0
                            cells[i]->internal->z = NULL;
1376
0
                            Mat_Critical("Couldn't determine file position");
1377
0
                        }
1378
0
                    } else {
1379
0
                        free(cells[i]->internal->z);
1380
0
                        cells[i]->internal->z = NULL;
1381
0
                        Mat_Critical("inflateCopy returned error %s", zError(err));
1382
0
                    }
1383
0
                } else {
1384
0
                    Mat_Critical("Couldn't allocate memory");
1385
0
                }
1386
0
            }
1387
1388
60
            InflateSkip(mat, matvar->internal->z, nBytes, &bytesread);
1389
60
        }
1390
#else
1391
        Mat_Critical("Not compiled with zlib support");
1392
#endif
1393
1394
10.2k
    } else {
1395
10.2k
        size_t i;
1396
10.2k
        mat_uint32_t buf[6] = {0, 0, 0, 0, 0, 0};
1397
10.2k
        mat_uint32_t nBytes;
1398
10.2k
        mat_uint32_t array_flags;
1399
1400
37.9k
        for ( i = 0; i < nelems; i++ ) {
1401
37.6k
            size_t nbytes = 0;
1402
37.6k
            cells[i] = Mat_VarCalloc();
1403
37.6k
            if ( NULL == cells[i] ) {
1404
0
                Mat_Critical("Couldn't allocate memory for cell %zu", i);
1405
0
                continue;
1406
0
            }
1407
1408
            /* Read variable tag for cell */
1409
37.6k
            err = Read(buf, 4, 2, mat, &nbytes);
1410
1411
            /* Empty cells at the end of a file may cause an EOF */
1412
37.6k
            if ( 0 == err && 0 == nbytes )
1413
0
                continue;
1414
37.6k
            bytesread += nbytes;
1415
37.6k
            if ( err ) {
1416
363
                Mat_VarFree(cells[i]);
1417
363
                cells[i] = NULL;
1418
363
                break;
1419
363
            }
1420
37.2k
            if ( mat->byteswap ) {
1421
7
                (void)Mat_uint32Swap(buf);
1422
7
                (void)Mat_uint32Swap(buf + 1);
1423
7
            }
1424
37.2k
            nBytes = buf[1];
1425
37.2k
            if ( 0 == nBytes ) {
1426
                /* Empty cell: Memory optimization */
1427
61
                free(cells[i]->internal);
1428
61
                cells[i]->internal = NULL;
1429
61
                continue;
1430
37.1k
            } else if ( buf[0] != MAT_T_MATRIX ) {
1431
9.60k
                Mat_VarFree(cells[i]);
1432
9.60k
                cells[i] = NULL;
1433
9.60k
#if HAVE_LONG_LONG_INT
1434
9.60k
                Mat_Critical("cells[%zu] not MAT_T_MATRIX, fpos = %lld", i,
1435
9.60k
                             (long long)MatTell(mat));
1436
#else
1437
                Mat_Critical("cells[%zu] not MAT_T_MATRIX", i);
1438
#endif
1439
9.60k
                break;
1440
9.60k
            }
1441
1442
            /* Read array flags and the dimensions tag */
1443
27.5k
            err = Read(buf, 4, 6, mat, &bytesread);
1444
27.5k
            if ( err ) {
1445
0
                Mat_VarFree(cells[i]);
1446
0
                cells[i] = NULL;
1447
0
                break;
1448
0
            }
1449
27.5k
            if ( mat->byteswap ) {
1450
0
                (void)Mat_uint32Swap(buf);
1451
0
                (void)Mat_uint32Swap(buf + 1);
1452
0
                (void)Mat_uint32Swap(buf + 2);
1453
0
                (void)Mat_uint32Swap(buf + 3);
1454
0
                (void)Mat_uint32Swap(buf + 4);
1455
0
                (void)Mat_uint32Swap(buf + 5);
1456
0
            }
1457
27.5k
            nBytes -= 24;
1458
            /* Array flags */
1459
27.5k
            if ( buf[0] == MAT_T_UINT32 ) {
1460
26.4k
                array_flags = buf[2];
1461
26.4k
                cells[i]->class_type = CLASS_FROM_ARRAY_FLAGS(array_flags);
1462
26.4k
                cells[i]->isComplex = (array_flags & MAT_F_COMPLEX);
1463
26.4k
                cells[i]->isGlobal = (array_flags & MAT_F_GLOBAL);
1464
26.4k
                cells[i]->isLogical = (array_flags & MAT_F_LOGICAL);
1465
26.4k
                if ( cells[i]->class_type == MAT_C_SPARSE ) {
1466
                    /* Need to find a more appropriate place to store nzmax */
1467
6.58k
                    cells[i]->nbytes = buf[3];
1468
6.58k
                }
1469
26.4k
            }
1470
1471
27.5k
            if ( cells[i]->class_type == MAT_C_OPAQUE && NULL != mat->filename ) {
1472
                /* Do NOT go here while processing GetSubsystem5 (mat->filename==NULL) */
1473
0
                mat_uint32_t name_tag[2];
1474
0
                mat_off_t opaque_data_start = MatTell(mat);
1475
0
                name_tag[0] = buf[4];
1476
0
                name_tag[1] = buf[5];
1477
0
                err = ReadOpaqueInfo5(mat, cells[i], name_tag);
1478
0
                if ( err ) {
1479
0
                    Mat_VarFree(cells[i]);
1480
0
                    cells[i] = NULL;
1481
0
                    break;
1482
0
                }
1483
                /* Seek to the end of the cell data */
1484
0
                if ( -1L != opaque_data_start )
1485
0
                    (void)MatSeek(mat, opaque_data_start + nBytes, SEEK_SET);
1486
0
                continue;
1487
0
            }
1488
1489
            /* Rank and dimension */
1490
27.5k
            nbytes = 0;
1491
27.5k
            err = ReadRankDims(mat, cells[i], (enum matio_types)buf[4], buf[5], &nbytes);
1492
27.5k
            bytesread += nbytes;
1493
27.5k
            nBytes -= nbytes;
1494
27.5k
            if ( err ) {
1495
0
                Mat_VarFree(cells[i]);
1496
0
                cells[i] = NULL;
1497
0
                break;
1498
0
            }
1499
            /* Variable name tag */
1500
27.5k
            if ( 0 != Read(buf, 1, 8, mat, &bytesread) ) {
1501
0
                Mat_VarFree(cells[i]);
1502
0
                cells[i] = NULL;
1503
0
                break;
1504
0
            }
1505
27.5k
            nBytes -= 8;
1506
27.5k
            if ( mat->byteswap ) {
1507
0
                (void)Mat_uint32Swap(buf);
1508
0
                (void)Mat_uint32Swap(buf + 1);
1509
0
            }
1510
27.5k
            if ( buf[1] > 0 ) {
1511
                /* Name of variable */
1512
27.5k
                if ( buf[0] == MAT_T_INT8 ) { /* Name not in tag */
1513
2.71k
                    mat_uint32_t name_len = buf[1];
1514
2.71k
                    if ( name_len % 8 > 0 ) {
1515
2.71k
                        if ( name_len < UINT32_MAX - 8 + (name_len % 8) ) {
1516
2.71k
                            name_len = name_len + 8 - (name_len % 8);
1517
2.71k
                        } else {
1518
0
                            Mat_VarFree(cells[i]);
1519
0
                            cells[i] = NULL;
1520
0
                            break;
1521
0
                        }
1522
2.71k
                    }
1523
2.71k
                    nBytes -= name_len;
1524
2.71k
                    (void)MatSeek(mat, name_len, SEEK_CUR);
1525
2.71k
                }
1526
27.5k
            }
1527
27.5k
            cells[i]->internal->datapos = MatTell(mat);
1528
27.5k
            if ( cells[i]->internal->datapos != -1L ) {
1529
27.5k
                if ( cells[i]->class_type == MAT_C_STRUCT )
1530
575
                    bytesread += ReadNextStructField(mat, cells[i]);
1531
27.5k
                if ( cells[i]->class_type == MAT_C_CELL )
1532
9.97k
                    bytesread += ReadNextCell(mat, cells[i]);
1533
27.5k
                (void)MatSeek(mat, cells[i]->internal->datapos + nBytes, SEEK_SET);
1534
27.5k
            } else {
1535
0
                Mat_Critical("Couldn't determine file position");
1536
0
            }
1537
27.5k
        }
1538
10.2k
    }
1539
1540
10.3k
    return bytesread;
1541
10.7k
}
1542
1543
/** @brief Allocates struct fields data for the given variable
1544
 *
1545
 * @ingroup mat_internal
1546
 * @param matvar MAT variable pointer
1547
 * @param nelems Number of elements
1548
 * @param nfields Number of fields
1549
 * @param[out] nelems_x_nfields Product of nelems and nfields
1550
 * @param[out] fields Pointer to allocated fields array
1551
 * @retval 0 on success
1552
 */
1553
static int
1554
AllocateStructFields(matvar_t *matvar, size_t nelems, size_t nfields, size_t *nelems_x_nfields,
1555
                     matvar_t ***fields)
1556
5.89k
{
1557
5.89k
    int err;
1558
1559
5.89k
    matvar->data_size = sizeof(matvar_t *);
1560
5.89k
    err = Mul(nelems_x_nfields, nelems, nfields);
1561
5.89k
    if ( err ) {
1562
0
        Mat_Critical("Integer multiplication overflow");
1563
0
        return err;
1564
0
    }
1565
5.89k
    err = Mul(&matvar->nbytes, *nelems_x_nfields, matvar->data_size);
1566
5.89k
    if ( err ) {
1567
0
        Mat_Critical("Integer multiplication overflow");
1568
0
        return err;
1569
0
    }
1570
5.89k
    if ( !matvar->nbytes )
1571
168
        return MATIO_E_NO_ERROR;
1572
1573
5.72k
    matvar->data = calloc(*nelems_x_nfields, matvar->data_size);
1574
5.72k
    if ( NULL == matvar->data ) {
1575
1
        matvar->nbytes = 0;
1576
1
        Mat_Critical("Couldn't allocate memory for the data");
1577
1
        return MATIO_E_OUT_OF_MEMORY;
1578
1
    }
1579
1580
5.72k
    *fields = (matvar_t **)matvar->data;
1581
5.72k
    return MATIO_E_NO_ERROR;
1582
5.72k
}
1583
1584
/** @brief Reads the next struct field of the structure in @c matvar
1585
 *
1586
 * Reads the next struct fields (fieldname length,names,data headers for all
1587
 * the fields
1588
 * @ingroup mat_internal
1589
 * @param mat MAT file pointer
1590
 * @param matvar MAT variable pointer
1591
 * @return Number of bytes read
1592
 */
1593
static size_t
1594
ReadNextStructField(mat_t *mat, matvar_t *matvar)
1595
8.02k
{
1596
8.02k
    int err;
1597
8.02k
    size_t bytesread = 0;
1598
8.02k
    matvar_t **fields = NULL;
1599
8.02k
    size_t nelems = 1, nelems_x_nfields;
1600
1601
8.02k
    err = Mat_MulDims(matvar, &nelems);
1602
8.02k
    if ( err ) {
1603
0
        Mat_Critical("Integer multiplication overflow");
1604
0
        return bytesread;
1605
0
    }
1606
8.02k
    if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
1607
4.13k
#if HAVE_ZLIB
1608
4.13k
        size_t nfields, i;
1609
4.13k
        mat_uint32_t uncomp_buf[16];
1610
4.13k
        mat_uint32_t array_flags, len, fieldname_size;
1611
1612
4.13k
        memset(uncomp_buf, 0, sizeof(uncomp_buf));
1613
        /* Field name length */
1614
4.13k
        err = Inflate(mat, matvar->internal->z, uncomp_buf, 8, &bytesread);
1615
4.13k
        if ( err ) {
1616
40
            return bytesread;
1617
40
        }
1618
4.09k
        if ( mat->byteswap ) {
1619
2.24k
            (void)Mat_uint32Swap(uncomp_buf);
1620
2.24k
            (void)Mat_uint32Swap(uncomp_buf + 1);
1621
2.24k
        }
1622
4.09k
        if ( (uncomp_buf[0] & 0x0000ffff) == MAT_T_INT32 && uncomp_buf[1] > 0 ) {
1623
4.03k
            fieldname_size = uncomp_buf[1];
1624
4.03k
        } else {
1625
57
            Mat_Critical("Error getting fieldname size");
1626
57
            return bytesread;
1627
57
        }
1628
1629
        /* Field name tag */
1630
4.03k
        err = Inflate(mat, matvar->internal->z, uncomp_buf, 8, &bytesread);
1631
4.03k
        if ( err ) {
1632
5
            return bytesread;
1633
5
        }
1634
4.03k
        if ( mat->byteswap )
1635
2.21k
            (void)Mat_uint32Swap(uncomp_buf);
1636
        /* Name of field */
1637
4.03k
        if ( uncomp_buf[0] == MAT_T_INT8 ) { /* Name not in tag */
1638
3.96k
            if ( mat->byteswap )
1639
2.15k
                len = Mat_uint32Swap(uncomp_buf + 1);
1640
1.81k
            else
1641
1.81k
                len = uncomp_buf[1];
1642
3.96k
            nfields = len / fieldname_size;
1643
3.96k
            if ( nfields * fieldname_size % 8 != 0 )
1644
1.86k
                i = 8 - (nfields * fieldname_size % 8);
1645
2.09k
            else
1646
2.09k
                i = 0;
1647
3.96k
            if ( nfields ) {
1648
3.96k
                char *ptr = (char *)malloc(nfields * fieldname_size + i);
1649
3.96k
                if ( NULL != ptr ) {
1650
3.96k
                    err = Inflate(mat, matvar->internal->z, ptr,
1651
3.96k
                                  (unsigned int)(nfields * fieldname_size + i), &bytesread);
1652
3.96k
                    if ( !err ) {
1653
3.89k
                        SetFieldNames(matvar, ptr, nfields, fieldname_size);
1654
3.89k
                    }
1655
3.96k
                    free(ptr);
1656
3.96k
                }
1657
3.96k
            } else {
1658
0
                matvar->internal->num_fields = 0;
1659
0
                matvar->internal->fieldnames = NULL;
1660
0
            }
1661
3.96k
        } else {
1662
66
            len = (uncomp_buf[0] & 0xffff0000) >> 16;
1663
66
            if ( ((uncomp_buf[0] & 0x0000ffff) == MAT_T_INT8) && len > 0 && len <= 4 ) {
1664
                /* Name packed in tag */
1665
15
                nfields = len / fieldname_size;
1666
15
                if ( nfields ) {
1667
15
                    SetFieldNames(matvar, (char *)(uncomp_buf + 1), nfields, fieldname_size);
1668
15
                } else {
1669
0
                    matvar->internal->num_fields = 0;
1670
0
                    matvar->internal->fieldnames = NULL;
1671
0
                }
1672
51
            } else {
1673
51
                nfields = 0;
1674
51
            }
1675
66
        }
1676
1677
4.03k
        if ( NULL == matvar->internal->fieldnames )
1678
116
            nfields = 0;
1679
1680
4.03k
        err = AllocateStructFields(matvar, nelems, nfields, &nelems_x_nfields, &fields);
1681
4.03k
        if ( err || !matvar->nbytes )
1682
116
            return bytesread;
1683
1684
8.03k
        for ( i = 0; i < nelems; i++ ) {
1685
4.12k
            size_t k;
1686
973k
            for ( k = 0; k < nfields; k++ ) {
1687
968k
                fields[i * nfields + k] = Mat_VarCalloc();
1688
968k
            }
1689
4.12k
        }
1690
3.91k
        if ( NULL != matvar->internal->fieldnames ) {
1691
8.03k
            for ( i = 0; i < nelems; i++ ) {
1692
4.12k
                size_t k;
1693
973k
                for ( k = 0; k < nfields; k++ ) {
1694
968k
                    if ( NULL != matvar->internal->fieldnames[k] ) {
1695
968k
                        fields[i * nfields + k]->name = strdup(matvar->internal->fieldnames[k]);
1696
968k
                        if ( NULL == fields[i * nfields + k]->name ) {
1697
0
                            err = MATIO_E_OUT_OF_MEMORY;
1698
0
                            break;
1699
0
                        }
1700
968k
                    }
1701
968k
                }
1702
4.12k
                if ( err )
1703
0
                    break;
1704
4.12k
            }
1705
3.91k
        }
1706
1707
18.3k
        for ( i = 0; i < nelems_x_nfields; i++ ) {
1708
18.0k
            mat_uint32_t nBytes;
1709
            /* Read variable tag for struct field */
1710
18.0k
            err = Inflate(mat, matvar->internal->z, uncomp_buf, 8, &bytesread);
1711
18.0k
            if ( err ) {
1712
770
                Mat_VarFree(fields[i]);
1713
770
                fields[i] = NULL;
1714
770
                break;
1715
770
            }
1716
17.2k
            if ( mat->byteswap ) {
1717
13.1k
                (void)Mat_uint32Swap(uncomp_buf);
1718
13.1k
                (void)Mat_uint32Swap(uncomp_buf + 1);
1719
13.1k
            }
1720
17.2k
            nBytes = uncomp_buf[1];
1721
17.2k
            if ( uncomp_buf[0] != MAT_T_MATRIX ) {
1722
2.47k
                Mat_VarFree(fields[i]);
1723
2.47k
                fields[i] = NULL;
1724
2.47k
                Mat_Critical("fields[%zu], Uncompressed type not MAT_T_MATRIX", i);
1725
2.47k
                break;
1726
14.7k
            } else if ( 0 == nBytes ) {
1727
                /* Empty field: Memory optimization */
1728
0
                free(fields[i]->internal);
1729
0
                fields[i]->internal = NULL;
1730
0
                continue;
1731
0
            }
1732
14.7k
            fields[i]->compression = MAT_COMPRESSION_ZLIB;
1733
14.7k
            err = Inflate(mat, matvar->internal->z, uncomp_buf, 16, &bytesread);
1734
14.7k
            if ( err ) {
1735
34
                Mat_VarFree(fields[i]);
1736
34
                fields[i] = NULL;
1737
34
                break;
1738
34
            }
1739
14.7k
            if ( mat->byteswap ) {
1740
11.5k
                (void)Mat_uint32Swap(uncomp_buf);
1741
11.5k
                (void)Mat_uint32Swap(uncomp_buf + 1);
1742
11.5k
                (void)Mat_uint32Swap(uncomp_buf + 2);
1743
11.5k
                (void)Mat_uint32Swap(uncomp_buf + 3);
1744
11.5k
            }
1745
14.7k
            nBytes -= 16;
1746
            /* Array flags */
1747
14.7k
            if ( uncomp_buf[0] == MAT_T_UINT32 ) {
1748
14.6k
                array_flags = uncomp_buf[2];
1749
14.6k
                fields[i]->class_type = CLASS_FROM_ARRAY_FLAGS(array_flags);
1750
14.6k
                fields[i]->isComplex = (array_flags & MAT_F_COMPLEX);
1751
14.6k
                fields[i]->isGlobal = (array_flags & MAT_F_GLOBAL);
1752
14.6k
                fields[i]->isLogical = (array_flags & MAT_F_LOGICAL);
1753
14.6k
                if ( fields[i]->class_type == MAT_C_SPARSE ) {
1754
                    /* Need to find a more appropriate place to store nzmax */
1755
553
                    fields[i]->nbytes = uncomp_buf[3];
1756
553
                }
1757
14.6k
            } else {
1758
97
                Mat_Critical("Expected MAT_T_UINT32 for array tags, got %d", uncomp_buf[0]);
1759
97
                InflateSkip(mat, matvar->internal->z, nBytes, &bytesread);
1760
97
            }
1761
14.7k
            if ( fields[i]->class_type != MAT_C_OPAQUE ) {
1762
14.7k
                mat_uint32_t *dims = NULL;
1763
14.7k
                int do_clean = 0;
1764
14.7k
                err = InflateRankDims(mat, matvar->internal->z, uncomp_buf, sizeof(uncomp_buf),
1765
14.7k
                                      &dims, &bytesread);
1766
14.7k
                if ( NULL == dims ) {
1767
14.7k
                    dims = uncomp_buf + 2;
1768
14.7k
                } else {
1769
61
                    do_clean = 1;
1770
61
                }
1771
14.7k
                if ( err ) {
1772
328
                    if ( do_clean ) {
1773
11
                        free(dims);
1774
11
                    }
1775
328
                    Mat_VarFree(fields[i]);
1776
328
                    fields[i] = NULL;
1777
328
                    break;
1778
328
                }
1779
14.4k
                nBytes -= 8;
1780
14.4k
                if ( mat->byteswap ) {
1781
11.4k
                    (void)Mat_uint32Swap(uncomp_buf);
1782
11.4k
                    (void)Mat_uint32Swap(uncomp_buf + 1);
1783
11.4k
                }
1784
                /* Rank and dimension */
1785
14.4k
                if ( uncomp_buf[0] == MAT_T_INT32 ) {
1786
14.4k
                    int j;
1787
14.4k
                    size_t size;
1788
14.4k
                    fields[i]->rank = uncomp_buf[1];
1789
14.4k
                    nBytes -= fields[i]->rank;
1790
14.4k
                    fields[i]->rank /= 4;
1791
14.4k
                    if ( 0 == do_clean && fields[i]->rank > 13 ) {
1792
0
                        int rank = fields[i]->rank;
1793
0
                        fields[i]->rank = 0;
1794
0
                        Mat_Critical("%d is not a valid rank", rank);
1795
0
                        continue;
1796
0
                    }
1797
14.4k
                    err = Mul(&size, fields[i]->rank, sizeof(*fields[i]->dims));
1798
14.4k
                    if ( err ) {
1799
0
                        if ( do_clean ) {
1800
0
                            free(dims);
1801
0
                        }
1802
0
                        Mat_VarFree(fields[i]);
1803
0
                        fields[i] = NULL;
1804
0
                        Mat_Critical("Integer multiplication overflow");
1805
0
                        continue;
1806
0
                    }
1807
14.4k
                    fields[i]->dims = (size_t *)malloc(size);
1808
14.4k
                    if ( NULL == fields[i]->dims ) {
1809
0
                        if ( do_clean ) {
1810
0
                            free(dims);
1811
0
                        }
1812
0
                        Mat_VarFree(fields[i]);
1813
0
                        fields[i] = NULL;
1814
0
                        Mat_Critical("Couldn't allocate memory for dims");
1815
0
                        continue;
1816
0
                    }
1817
14.4k
                    if ( mat->byteswap ) {
1818
822k
                        for ( j = 0; j < fields[i]->rank; j++ )
1819
811k
                            fields[i]->dims[j] = Mat_uint32Swap(dims + j);
1820
11.4k
                    } else {
1821
3.54M
                        for ( j = 0; j < fields[i]->rank; j++ )
1822
3.54M
                            fields[i]->dims[j] = dims[j];
1823
2.95k
                    }
1824
14.4k
                    if ( fields[i]->rank % 2 != 0 )
1825
7
                        nBytes -= 4;
1826
14.4k
                }
1827
14.4k
                if ( do_clean ) {
1828
50
                    free(dims);
1829
50
                }
1830
                /* Variable name tag */
1831
14.4k
                err = Inflate(mat, matvar->internal->z, uncomp_buf, 8, &bytesread);
1832
14.4k
                if ( err ) {
1833
0
                    Mat_VarFree(fields[i]);
1834
0
                    fields[i] = NULL;
1835
0
                    break;
1836
0
                }
1837
14.4k
                nBytes -= 8;
1838
14.4k
                fields[i]->internal->z = (z_streamp)calloc(1, sizeof(z_stream));
1839
14.4k
                if ( fields[i]->internal->z != NULL ) {
1840
14.4k
                    err = inflateCopy(fields[i]->internal->z, matvar->internal->z);
1841
14.4k
                    if ( err == Z_OK ) {
1842
14.4k
                        fields[i]->internal->datapos = MatTell(mat);
1843
14.4k
                        if ( fields[i]->internal->datapos != -1L ) {
1844
14.4k
                            fields[i]->internal->datapos -= matvar->internal->z->avail_in;
1845
14.4k
                            if ( fields[i]->class_type == MAT_C_STRUCT )
1846
1.19k
                                bytesread += ReadNextStructField(mat, fields[i]);
1847
13.2k
                            else if ( fields[i]->class_type == MAT_C_CELL )
1848
0
                                bytesread += ReadNextCell(mat, fields[i]);
1849
13.2k
                            else if ( nBytes <= (1 << MAX_WBITS) ) {
1850
                                /* Memory optimization: Read data if less in size
1851
                                   than the zlib inflate state (approximately) */
1852
12.9k
                                /* err = */ Mat_VarRead5(mat, fields[i]);
1853
12.9k
                                fields[i]->internal->data = fields[i]->data;
1854
12.9k
                                fields[i]->data = NULL;
1855
12.9k
                            }
1856
14.4k
                            (void)MatSeek(mat, fields[i]->internal->datapos, SEEK_SET);
1857
14.4k
                        } else {
1858
0
                            Mat_Critical("Couldn't determine file position");
1859
0
                        }
1860
14.4k
                        if ( fields[i]->internal->data != NULL ||
1861
3.64k
                             fields[i]->class_type == MAT_C_STRUCT ||
1862
14.1k
                             fields[i]->class_type == MAT_C_CELL || nBytes <= (1 << MAX_WBITS) ) {
1863
                            /* Memory optimization: Free inflate state */
1864
14.1k
                            inflateEnd(fields[i]->internal->z);
1865
14.1k
                            free(fields[i]->internal->z);
1866
14.1k
                            fields[i]->internal->z = NULL;
1867
14.1k
                        }
1868
14.4k
                    } else {
1869
0
                        Mat_Critical("inflateCopy returned error %s", zError(err));
1870
0
                    }
1871
14.4k
                } else {
1872
0
                    Mat_Critical("Couldn't allocate memory");
1873
0
                }
1874
14.4k
            } else {
1875
0
                size_t opaque_bytes = 0;
1876
                /* Save the field name since ReadCompressedOpaqueInfo5 overwrites
1877
                 * fields[i]->name with the array name of the opaque subelement.
1878
                 */
1879
0
                char *name = fields[i]->name;
1880
0
                fields[i]->name = NULL;
1881
0
                fields[i]->internal->z = (z_streamp)calloc(1, sizeof(z_stream));
1882
0
                if ( NULL != fields[i]->internal->z ) {
1883
0
                    err = inflateCopy(fields[i]->internal->z, matvar->internal->z);
1884
0
                    if ( err == Z_OK ) {
1885
0
                        fields[i]->internal->datapos = MatTell(mat);
1886
0
                        if ( fields[i]->internal->datapos != -1L ) {
1887
0
                            err = ReadCompressedOpaqueInfo5(mat, fields[i], &opaque_bytes);
1888
0
                            if ( err == Z_OK ) {
1889
0
                                inflateEnd(fields[i]->internal->z);
1890
0
                                free(fields[i]->internal->z);
1891
0
                                fields[i]->internal->z = NULL;
1892
0
                                free(fields[i]->name);
1893
0
                                fields[i]->name = name;
1894
0
                                bytesread += opaque_bytes;
1895
0
                                (void)MatSeek(mat, fields[i]->internal->datapos, SEEK_SET);
1896
0
                            } else {
1897
0
                                inflateEnd(fields[i]->internal->z);
1898
0
                                free(fields[i]->internal->z);
1899
0
                                fields[i]->internal->z = NULL;
1900
0
                                free(fields[i]->name);
1901
0
                                fields[i]->name = name;
1902
0
                                Mat_Critical("Couldn't read compressed opaque info");
1903
0
                            }
1904
0
                        } else {
1905
0
                            inflateEnd(fields[i]->internal->z);
1906
0
                            free(fields[i]->internal->z);
1907
0
                            fields[i]->internal->z = NULL;
1908
0
                            free(fields[i]->name);
1909
0
                            fields[i]->name = name;
1910
0
                            Mat_Critical("Couldn't determine file position");
1911
0
                        }
1912
0
                    } else {
1913
0
                        free(fields[i]->internal->z);
1914
0
                        fields[i]->internal->z = NULL;
1915
0
                        free(fields[i]->name);
1916
0
                        fields[i]->name = name;
1917
0
                        Mat_Critical("inflateCopy returned error %s", zError(err));
1918
0
                    }
1919
0
                } else {
1920
0
                    free(fields[i]->name);
1921
0
                    fields[i]->name = name;
1922
0
                    Mat_Critical("Couldn't allocate memory");
1923
0
                }
1924
0
            }
1925
14.4k
            InflateSkip(mat, matvar->internal->z, nBytes, &bytesread);
1926
14.4k
        }
1927
#else
1928
        Mat_Critical("Not compiled with zlib support");
1929
#endif
1930
3.91k
    } else {
1931
3.89k
        size_t nfields, i;
1932
3.89k
        mat_uint32_t buf[6] = {0, 0, 0, 0, 0, 0};
1933
3.89k
        mat_uint32_t array_flags, len, fieldname_size;
1934
1935
3.89k
        err = Read(buf, 4, 2, mat, &bytesread);
1936
3.89k
        if ( err ) {
1937
0
            return bytesread;
1938
0
        }
1939
3.89k
        if ( mat->byteswap ) {
1940
3.11k
            (void)Mat_uint32Swap(buf);
1941
3.11k
            (void)Mat_uint32Swap(buf + 1);
1942
3.11k
        }
1943
3.89k
        if ( (buf[0] & 0x0000ffff) == MAT_T_INT32 && buf[1] > 0 ) {
1944
1.86k
            fieldname_size = buf[1];
1945
2.02k
        } else {
1946
2.02k
            Mat_Critical("Error getting fieldname size");
1947
2.02k
            return bytesread;
1948
2.02k
        }
1949
1950
        /* Field name tag */
1951
1.86k
        err = Read(buf, 4, 2, mat, &bytesread);
1952
1.86k
        if ( err ) {
1953
0
            return bytesread;
1954
0
        }
1955
1.86k
        if ( mat->byteswap )
1956
1.66k
            (void)Mat_uint32Swap(buf);
1957
        /* Name of field */
1958
1.86k
        if ( buf[0] == MAT_T_INT8 ) { /* Name not in tag */
1959
1.83k
            if ( mat->byteswap )
1960
1.64k
                len = Mat_uint32Swap(buf + 1);
1961
186
            else
1962
186
                len = buf[1];
1963
1.83k
            nfields = len / fieldname_size;
1964
1.83k
            if ( nfields ) {
1965
1.82k
                char *ptr = (char *)malloc(nfields * fieldname_size);
1966
1.82k
                if ( NULL != ptr ) {
1967
1.82k
                    err = Read(ptr, 1, nfields * fieldname_size, mat, &bytesread);
1968
1.82k
                    if ( 0 == err ) {
1969
1.82k
                        SetFieldNames(matvar, ptr, nfields, fieldname_size);
1970
1.82k
                    } else {
1971
3
                        matvar->internal->num_fields = 0;
1972
3
                        matvar->internal->fieldnames = NULL;
1973
3
                    }
1974
1.82k
                    free(ptr);
1975
1.82k
                }
1976
1.82k
                if ( (nfields * fieldname_size) % 8 ) {
1977
148
                    (void)MatSeek(mat, 8 - ((nfields * fieldname_size) % 8), SEEK_CUR);
1978
148
                    bytesread += 8 - ((nfields * fieldname_size) % 8);
1979
148
                }
1980
1.82k
            } else {
1981
6
                matvar->internal->num_fields = 0;
1982
6
                matvar->internal->fieldnames = NULL;
1983
6
            }
1984
1.83k
        } else {
1985
30
            len = (buf[0] & 0xffff0000) >> 16;
1986
30
            if ( ((buf[0] & 0x0000ffff) == MAT_T_INT8) && len > 0 && len <= 4 ) {
1987
                /* Name packed in tag */
1988
11
                nfields = len / fieldname_size;
1989
11
                if ( nfields ) {
1990
0
                    SetFieldNames(matvar, (char *)(buf + 1), nfields, fieldname_size);
1991
11
                } else {
1992
11
                    matvar->internal->num_fields = 0;
1993
11
                    matvar->internal->fieldnames = NULL;
1994
11
                }
1995
19
            } else {
1996
19
                nfields = 0;
1997
19
            }
1998
30
        }
1999
2000
1.86k
        if ( NULL == matvar->internal->fieldnames )
2001
39
            nfields = 0;
2002
2003
1.86k
        err = AllocateStructFields(matvar, nelems, nfields, &nelems_x_nfields, &fields);
2004
1.86k
        if ( err || !matvar->nbytes )
2005
53
            return bytesread;
2006
2007
15.1k
        for ( i = 0; i < nelems_x_nfields; i++ ) {
2008
14.9k
            mat_uint32_t nBytes;
2009
2010
14.9k
            fields[i] = Mat_VarCalloc();
2011
14.9k
            if ( NULL == fields[i] ) {
2012
0
                Mat_Critical("Couldn't allocate memory for field %zu", i);
2013
0
                continue;
2014
0
            }
2015
2016
            /* Read variable tag for struct field */
2017
14.9k
            err = Read(buf, 4, 2, mat, &bytesread);
2018
14.9k
            if ( err ) {
2019
117
                Mat_VarFree(fields[i]);
2020
117
                fields[i] = NULL;
2021
117
                break;
2022
117
            }
2023
14.8k
            if ( mat->byteswap ) {
2024
13.9k
                (void)Mat_uint32Swap(buf);
2025
13.9k
                (void)Mat_uint32Swap(buf + 1);
2026
13.9k
            }
2027
14.8k
            nBytes = buf[1];
2028
14.8k
            if ( buf[0] != MAT_T_MATRIX ) {
2029
1.41k
                Mat_VarFree(fields[i]);
2030
1.41k
                fields[i] = NULL;
2031
1.41k
#if HAVE_LONG_LONG_INT
2032
1.41k
                Mat_Critical("fields[%zu] not MAT_T_MATRIX, fpos = %lld", i,
2033
1.41k
                             (long long)MatTell(mat));
2034
#else
2035
                Mat_Critical("fields[%zu] not MAT_T_MATRIX", i);
2036
#endif
2037
1.41k
                break;
2038
13.4k
            } else if ( 0 == nBytes ) {
2039
                /* Empty field: Memory optimization */
2040
12
                free(fields[i]->internal);
2041
12
                fields[i]->internal = NULL;
2042
12
                continue;
2043
12
            }
2044
13.4k
            {
2045
                /* Save position after the field tag for seeking past opaque fields */
2046
13.4k
                mat_off_t field_data_start = MatTell(mat);
2047
13.4k
                mat_uint32_t field_data_nBytes = nBytes;
2048
2049
                /* Read array flags and the dimensions tag */
2050
13.4k
                err = Read(buf, 4, 6, mat, &bytesread);
2051
13.4k
                if ( err ) {
2052
0
                    Mat_VarFree(fields[i]);
2053
0
                    fields[i] = NULL;
2054
0
                    break;
2055
0
                }
2056
13.4k
                if ( mat->byteswap ) {
2057
12.6k
                    (void)Mat_uint32Swap(buf);
2058
12.6k
                    (void)Mat_uint32Swap(buf + 1);
2059
12.6k
                    (void)Mat_uint32Swap(buf + 2);
2060
12.6k
                    (void)Mat_uint32Swap(buf + 3);
2061
12.6k
                    (void)Mat_uint32Swap(buf + 4);
2062
12.6k
                    (void)Mat_uint32Swap(buf + 5);
2063
12.6k
                }
2064
13.4k
                nBytes -= 24;
2065
                /* Array flags */
2066
13.4k
                if ( buf[0] == MAT_T_UINT32 ) {
2067
12.7k
                    array_flags = buf[2];
2068
12.7k
                    fields[i]->class_type = CLASS_FROM_ARRAY_FLAGS(array_flags);
2069
12.7k
                    fields[i]->isComplex = (array_flags & MAT_F_COMPLEX);
2070
12.7k
                    fields[i]->isGlobal = (array_flags & MAT_F_GLOBAL);
2071
12.7k
                    fields[i]->isLogical = (array_flags & MAT_F_LOGICAL);
2072
12.7k
                    if ( fields[i]->class_type == MAT_C_SPARSE ) {
2073
                        /* Need to find a more appropriate place to store nzmax */
2074
295
                        fields[i]->nbytes = buf[3];
2075
295
                    }
2076
12.7k
                }
2077
13.4k
                if ( fields[i]->class_type == MAT_C_OPAQUE && NULL != mat->filename ) {
2078
                    /* Do NOT go here while processing GetSubsystem5 (mat->filename==NULL) */
2079
57
                    mat_uint32_t name_tag[2];
2080
57
                    name_tag[0] = buf[4];
2081
57
                    name_tag[1] = buf[5];
2082
57
                    err = ReadOpaqueInfo5(mat, fields[i], name_tag);
2083
57
                    if ( err ) {
2084
44
                        Mat_VarFree(fields[i]);
2085
44
                        fields[i] = NULL;
2086
44
                        break;
2087
44
                    }
2088
                    /* Seek to the end of the field data regardless */
2089
13
                    (void)MatSeek(mat, field_data_start + field_data_nBytes, SEEK_SET);
2090
13.3k
                } else if ( fields[i]->class_type == MAT_C_OPAQUE ) {
2091
                    /* For opaque fields, buf[4..5] is the array name tag,
2092
                 * not the rank/dims tag. Read the opaque subelements.
2093
                 */
2094
0
                    mat_uint32_t name_tag2[2];
2095
0
                    char *tn = NULL, *cn = NULL;
2096
0
                    name_tag2[0] = buf[4];
2097
0
                    name_tag2[1] = buf[5];
2098
2099
0
                    err = ReadTaggedString(mat, &fields[i]->name, name_tag2);
2100
0
                    if ( !err )
2101
0
                        err = ReadTaggedString(mat, &tn, NULL);
2102
0
                    if ( !err ) {
2103
0
#if defined(MCOS) && MCOS
2104
0
                        fields[i]->internal->type_name = tn;
2105
#else
2106
                        free(tn);
2107
#endif
2108
0
                        err = ReadTaggedString(mat, &cn, NULL);
2109
0
                    }
2110
0
                    if ( !err ) {
2111
0
#if defined(MCOS) && MCOS
2112
0
                        fields[i]->internal->class_name = cn;
2113
#else
2114
                        free(cn);
2115
#endif
2116
0
                        { /* Check the next subelement: if it's a MAT_T_MATRIX
2117
                     * containing a cell array, convert the field.
2118
                     */
2119
0
                            mat_uint32_t ptag[2];
2120
0
                            err = Read(ptag, 4, 2, mat, &bytesread);
2121
0
                            if ( !err ) {
2122
0
                                if ( mat->byteswap ) {
2123
0
                                    (void)Mat_uint32Swap(&ptag[0]);
2124
0
                                    (void)Mat_uint32Swap(&ptag[1]);
2125
0
                                }
2126
0
                                if ( ptag[0] == MAT_T_MATRIX && ptag[1] > 0 ) {
2127
                                    /* Read inner array flags */
2128
0
                                    mat_uint32_t inner[6];
2129
0
                                    err = Read(inner, 4, 6, mat, &bytesread);
2130
0
                                    if ( !err ) {
2131
0
                                        if ( mat->byteswap ) {
2132
0
                                            (void)Mat_uint32Swap(&inner[0]);
2133
0
                                            (void)Mat_uint32Swap(&inner[2]);
2134
0
                                            (void)Mat_uint32Swap(&inner[4]);
2135
0
                                            (void)Mat_uint32Swap(&inner[5]);
2136
0
                                        }
2137
0
                                        if ( inner[0] == MAT_T_UINT32 ) {
2138
0
                                            enum matio_classes ic =
2139
0
                                                CLASS_FROM_ARRAY_FLAGS(inner[2]);
2140
0
                                            if ( ic == MAT_C_CELL ) {
2141
                                                /* Convert to cell and read */
2142
0
                                                size_t nbytes2 = 0;
2143
0
                                                fields[i]->class_type = MAT_C_CELL;
2144
0
                                                err = ReadRankDims(mat, fields[i],
2145
0
                                                                   (enum matio_types)inner[4],
2146
0
                                                                   inner[5], &nbytes2);
2147
0
                                                bytesread += nbytes2;
2148
                                                /* Skip inner name tag */
2149
0
                                                {
2150
0
                                                    mat_uint32_t skip_buf[2];
2151
0
                                                    Read(skip_buf, 4, 2, mat, &bytesread);
2152
0
                                                }
2153
0
                                                fields[i]->internal->datapos = MatTell(mat);
2154
0
                                                if ( fields[i]->internal->datapos != -1L ) {
2155
0
                                                    bytesread += ReadNextCell(mat, fields[i]);
2156
0
                                                }
2157
0
                                            }
2158
0
                                        }
2159
0
                                    }
2160
0
                                }
2161
0
                            }
2162
0
                        }
2163
0
                    }
2164
                    /* Seek to the end of the field data regardless */
2165
0
                    (void)MatSeek(mat, field_data_start + field_data_nBytes, SEEK_SET);
2166
13.3k
                } else {
2167
                    /* Rank and dimension */
2168
13.3k
                    {
2169
13.3k
                        size_t nbytes = 0;
2170
13.3k
                        err =
2171
13.3k
                            ReadRankDims(mat, fields[i], (enum matio_types)buf[4], buf[5], &nbytes);
2172
13.3k
                        bytesread += nbytes;
2173
13.3k
                        nBytes -= nbytes;
2174
13.3k
                        if ( err ) {
2175
8
                            Mat_VarFree(fields[i]);
2176
8
                            fields[i] = NULL;
2177
8
                            break;
2178
8
                        }
2179
13.3k
                    }
2180
                    /* Variable name tag */
2181
13.3k
                    err = Read(buf, 1, 8, mat, &bytesread);
2182
13.3k
                    if ( err ) {
2183
0
                        Mat_VarFree(fields[i]);
2184
0
                        fields[i] = NULL;
2185
0
                        break;
2186
0
                    }
2187
13.3k
                    nBytes -= 8;
2188
13.3k
                    fields[i]->internal->datapos = MatTell(mat);
2189
13.3k
                    if ( fields[i]->internal->datapos != -1L ) {
2190
13.3k
                        if ( fields[i]->class_type == MAT_C_STRUCT )
2191
185
                            bytesread += ReadNextStructField(mat, fields[i]);
2192
13.1k
                        else if ( fields[i]->class_type == MAT_C_CELL )
2193
14
                            bytesread += ReadNextCell(mat, fields[i]);
2194
13.3k
                        (void)MatSeek(mat, fields[i]->internal->datapos + nBytes, SEEK_SET);
2195
13.3k
                    } else {
2196
0
                        Mat_Critical("Couldn't determine file position");
2197
0
                    }
2198
13.3k
                } /* end non-opaque */
2199
13.4k
            } /* end field_data_start scope */
2200
13.4k
        }
2201
2202
1.81k
        if ( NULL != matvar->internal->fieldnames ) {
2203
38.3k
            for ( i = 0; i < nelems; i++ ) {
2204
36.5k
                size_t k;
2205
17.0M
                for ( k = 0; k < nfields; k++ ) {
2206
17.0M
                    if ( NULL != matvar->internal->fieldnames[k] &&
2207
17.0M
                         NULL != fields[i * nfields + k] ) {
2208
13.3k
                        free(fields[i * nfields + k]->name);
2209
13.3k
                        fields[i * nfields + k]->name = strdup(matvar->internal->fieldnames[k]);
2210
13.3k
                        if ( NULL == fields[i * nfields + k]->name )
2211
0
                            return bytesread;
2212
13.3k
                    }
2213
17.0M
                }
2214
36.5k
            }
2215
1.81k
        }
2216
1.81k
    }
2217
2218
5.72k
    return bytesread;
2219
8.02k
}
2220
2221
/** @brief Reads the function handle data of the function handle in @c matvar
2222
 *
2223
 * @ingroup mat_internal
2224
 * @param mat MAT file pointer
2225
 * @param matvar MAT variable pointer
2226
 * @return Number of bytes read
2227
 */
2228
static size_t
2229
ReadNextFunctionHandle(mat_t *mat, matvar_t *matvar)
2230
27
{
2231
27
    int err;
2232
27
    size_t nelems = 1;
2233
2234
27
    err = Mat_MulDims(matvar, &nelems);
2235
27
    matvar->data_size = sizeof(matvar_t *);
2236
27
    err |= Mul(&matvar->nbytes, nelems, matvar->data_size);
2237
27
    if ( err )
2238
0
        return 0;
2239
2240
27
    matvar->data = malloc(matvar->nbytes);
2241
27
    if ( matvar->data != NULL ) {
2242
26
        size_t i;
2243
26
        matvar_t **functions = (matvar_t **)matvar->data;
2244
31
        for ( i = 0; i < nelems; i++ ) {
2245
18
            functions[i] = Mat_VarReadNextInfo(mat);
2246
18
            err = NULL == functions[i];
2247
18
            if ( err )
2248
13
                break;
2249
18
        }
2250
26
        if ( err ) {
2251
13
            size_t j;
2252
31
            for ( j = 0; j <= i; j++ ) {
2253
18
                Mat_VarFree(functions[j]);
2254
18
            }
2255
13
            free(matvar->data);
2256
13
            matvar->data = NULL;
2257
13
            matvar->data_size = 0;
2258
13
            matvar->nbytes = 0;
2259
13
        }
2260
26
    } else {
2261
1
        matvar->data_size = 0;
2262
1
        matvar->nbytes = 0;
2263
1
    }
2264
2265
27
    return 0;
2266
27
}
2267
2268
/** @brief Reads the rank and dimensions in @c matvar
2269
 *
2270
 * @ingroup mat_internal
2271
 * @param mat MAT file pointer
2272
 * @param matvar MAT variable pointer
2273
 * @param data_type data type of dimension array
2274
 * @param nbytes len of dimension array in bytes
2275
 * @param[out] read_bytes Read bytes
2276
 * @retval 0 on success
2277
 */
2278
static int
2279
ReadRankDims(mat_t *mat, matvar_t *matvar, enum matio_types data_type, mat_uint32_t nbytes,
2280
             size_t *read_bytes)
2281
55.6k
{
2282
55.6k
    int err = MATIO_E_NO_ERROR;
2283
    /* Rank and dimension */
2284
55.6k
    if ( data_type == MAT_T_INT32 ) {
2285
47.0k
        matvar->rank = nbytes / sizeof(mat_uint32_t);
2286
47.0k
        matvar->dims = (size_t *)malloc(matvar->rank * sizeof(*matvar->dims));
2287
47.0k
        if ( NULL != matvar->dims ) {
2288
47.0k
            int i;
2289
47.0k
            mat_uint32_t buf;
2290
2291
791k
            for ( i = 0; i < matvar->rank; i++ ) {
2292
744k
                err = Read(&buf, sizeof(mat_uint32_t), 1, mat, read_bytes);
2293
744k
                if ( !err ) {
2294
744k
                    if ( mat->byteswap ) {
2295
558k
                        matvar->dims[i] = Mat_uint32Swap(&buf);
2296
558k
                    } else {
2297
186k
                        matvar->dims[i] = buf;
2298
186k
                    }
2299
744k
                } else {
2300
22
                    free(matvar->dims);
2301
22
                    matvar->dims = NULL;
2302
22
                    matvar->rank = 0;
2303
22
                    return err;
2304
22
                }
2305
744k
            }
2306
2307
47.0k
            if ( matvar->rank % 2 != 0 ) {
2308
2.24k
                err = Read(&buf, sizeof(mat_uint32_t), 1, mat, read_bytes);
2309
2.24k
                if ( err ) {
2310
0
                    free(matvar->dims);
2311
0
                    matvar->dims = NULL;
2312
0
                    matvar->rank = 0;
2313
0
                    return err;
2314
0
                }
2315
2.24k
            }
2316
47.0k
        } else {
2317
0
            matvar->rank = 0;
2318
0
            err = MATIO_E_OUT_OF_MEMORY;
2319
0
            Mat_Critical("Error allocating memory for dims");
2320
0
        }
2321
47.0k
    }
2322
55.6k
    return err;
2323
55.6k
}
2324
2325
/** @brief Writes the header and data for a given type
2326
 *
2327
 * @ingroup mat_internal
2328
 * @param mat MAT file pointer
2329
 * @param matvar pointer to the mat variable
2330
 * @retval 0 on success
2331
 */
2332
static int
2333
WriteType(mat_t *mat, matvar_t *matvar)
2334
0
{
2335
0
    int err;
2336
0
    const mat_uint8_t pad1 = 0;
2337
0
    int nBytes, j;
2338
0
    size_t nelems = 1;
2339
2340
0
    err = Mat_MulDims(matvar, &nelems);
2341
0
    if ( err )
2342
0
        return err;
2343
2344
0
    switch ( matvar->class_type ) {
2345
0
        case MAT_C_DOUBLE:
2346
0
        case MAT_C_SINGLE:
2347
0
        case MAT_C_INT64:
2348
0
        case MAT_C_UINT64:
2349
0
        case MAT_C_INT32:
2350
0
        case MAT_C_UINT32:
2351
0
        case MAT_C_INT16:
2352
0
        case MAT_C_UINT16:
2353
0
        case MAT_C_INT8:
2354
0
        case MAT_C_UINT8: {
2355
0
            if ( matvar->isComplex ) {
2356
0
                const mat_complex_split_t *complex_data = (mat_complex_split_t *)matvar->data;
2357
2358
0
                if ( NULL == matvar->data )
2359
0
                    complex_data = &null_complex_data;
2360
2361
0
                nBytes = WriteData(mat, complex_data->Re, nelems, matvar->data_type);
2362
0
                if ( nBytes % 8 )
2363
0
                    for ( j = nBytes % 8; j < 8; j++ )
2364
0
                        fwrite(&pad1, 1, 1, (FILE *)mat->fp);
2365
0
                nBytes = WriteData(mat, complex_data->Im, nelems, matvar->data_type);
2366
0
                if ( nBytes % 8 )
2367
0
                    for ( j = nBytes % 8; j < 8; j++ )
2368
0
                        fwrite(&pad1, 1, 1, (FILE *)mat->fp);
2369
0
            } else {
2370
0
                nBytes = WriteData(mat, matvar->data, nelems, matvar->data_type);
2371
0
                if ( nBytes % 8 )
2372
0
                    for ( j = nBytes % 8; j < 8; j++ )
2373
0
                        fwrite(&pad1, 1, 1, (FILE *)mat->fp);
2374
0
            }
2375
0
            break;
2376
0
        }
2377
0
        case MAT_C_CHAR:
2378
0
            if ( matvar->data_type == MAT_T_UTF8 ) {
2379
0
                nelems = matvar->nbytes;
2380
0
            }
2381
0
            /* nBytes = */ WriteCharData(mat, matvar->data, nelems, matvar->data_type);
2382
0
            break;
2383
0
        case MAT_C_CELL: {
2384
0
            size_t i;
2385
0
            matvar_t **cells = (matvar_t **)matvar->data;
2386
2387
            /* Check for an empty cell array */
2388
0
            if ( matvar->nbytes == 0 || matvar->data_size == 0 || matvar->data == NULL )
2389
0
                break;
2390
0
            nelems = matvar->nbytes / matvar->data_size;
2391
0
            for ( i = 0; i < nelems; i++ ) {
2392
0
                err = WriteCellArrayField(mat, cells[i]);
2393
0
                if ( err )
2394
0
                    break;
2395
0
            }
2396
0
            break;
2397
0
        }
2398
0
        case MAT_C_STRUCT: {
2399
0
            const mat_uint32_t array_name_type = MAT_T_INT8;
2400
0
            const mat_uint32_t fieldname_type = MAT_T_INT32;
2401
0
            const mat_uint32_t fieldname_data_size = 4;
2402
0
            char *padzero;
2403
0
            mat_uint32_t fieldname_size;
2404
0
            size_t maxlen = 0, nfields, i, nelems_x_nfields;
2405
0
            matvar_t **fields = (matvar_t **)matvar->data;
2406
0
            mat_uint32_t fieldname;
2407
2408
            /* nelems*matvar->data_size can be zero when saving a struct that
2409
             * contains an empty struct in one of its fields
2410
             * (e.g. x.y = struct('z', {})). If it's zero, we would divide
2411
             * by zero.
2412
             */
2413
0
            nfields = matvar->internal->num_fields;
2414
            /* Check for a structure with no fields */
2415
0
            if ( nfields < 1 ) {
2416
0
                fieldname = (fieldname_data_size << 16) | fieldname_type;
2417
0
                fwrite(&fieldname, 4, 1, (FILE *)mat->fp);
2418
0
                fieldname_size = 1;
2419
0
                fwrite(&fieldname_size, 4, 1, (FILE *)mat->fp);
2420
0
                fwrite(&array_name_type, 4, 1, (FILE *)mat->fp);
2421
0
                nBytes = 0;
2422
0
                fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
2423
0
                break;
2424
0
            }
2425
2426
0
            for ( i = 0; i < nfields; i++ ) {
2427
0
                size_t len = strlen(matvar->internal->fieldnames[i]);
2428
0
                if ( len > maxlen )
2429
0
                    maxlen = len;
2430
0
            }
2431
0
            maxlen++;
2432
0
            fieldname_size = maxlen;
2433
0
            while ( nfields * fieldname_size % 8 != 0 )
2434
0
                fieldname_size++;
2435
0
            fieldname = (fieldname_data_size << 16) | fieldname_type;
2436
0
            fwrite(&fieldname, 4, 1, (FILE *)mat->fp);
2437
0
            fwrite(&fieldname_size, 4, 1, (FILE *)mat->fp);
2438
0
            fwrite(&array_name_type, 4, 1, (FILE *)mat->fp);
2439
0
            nBytes = nfields * fieldname_size;
2440
0
            fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
2441
0
            padzero = (char *)calloc(fieldname_size, 1);
2442
0
            if ( padzero == NULL ) {
2443
0
                err = MATIO_E_OUT_OF_MEMORY;
2444
0
                break;
2445
0
            }
2446
0
            for ( i = 0; i < nfields; i++ ) {
2447
0
                size_t len = strlen(matvar->internal->fieldnames[i]);
2448
0
                fwrite(matvar->internal->fieldnames[i], 1, len, (FILE *)mat->fp);
2449
0
                fwrite(padzero, 1, fieldname_size - len, (FILE *)mat->fp);
2450
0
            }
2451
0
            free(padzero);
2452
0
            err = Mul(&nelems_x_nfields, nelems, nfields);
2453
0
            if ( err )
2454
0
                break;
2455
0
            if ( NULL != fields ) {
2456
0
                for ( i = 0; i < nelems_x_nfields; i++ ) {
2457
0
                    err = WriteStructField(mat, fields[i]);
2458
0
                    if ( err )
2459
0
                        break;
2460
0
                }
2461
0
            }
2462
0
            break;
2463
0
        }
2464
0
        case MAT_C_SPARSE: {
2465
0
            mat_sparse_t *sparse = (mat_sparse_t *)matvar->data;
2466
2467
0
            if ( NULL == sparse )
2468
0
                break;
2469
2470
0
            nBytes = WriteData(mat, sparse->ir, sparse->nir, MAT_T_UINT32);
2471
0
            if ( nBytes % 8 )
2472
0
                for ( j = nBytes % 8; j < 8; j++ )
2473
0
                    fwrite(&pad1, 1, 1, (FILE *)mat->fp);
2474
0
            nBytes = WriteData(mat, sparse->jc, sparse->njc, MAT_T_UINT32);
2475
0
            if ( nBytes % 8 )
2476
0
                for ( j = nBytes % 8; j < 8; j++ )
2477
0
                    fwrite(&pad1, 1, 1, (FILE *)mat->fp);
2478
0
            if ( matvar->isComplex && NULL != sparse->data ) {
2479
0
                const mat_complex_split_t *complex_data = (const mat_complex_split_t *)sparse->data;
2480
0
                nBytes = WriteData(mat, complex_data->Re, sparse->ndata, matvar->data_type);
2481
0
                if ( nBytes % 8 )
2482
0
                    for ( j = nBytes % 8; j < 8; j++ )
2483
0
                        fwrite(&pad1, 1, 1, (FILE *)mat->fp);
2484
0
                nBytes = WriteData(mat, complex_data->Im, sparse->ndata, matvar->data_type);
2485
0
                if ( nBytes % 8 )
2486
0
                    for ( j = nBytes % 8; j < 8; j++ )
2487
0
                        fwrite(&pad1, 1, 1, (FILE *)mat->fp);
2488
0
            } else {
2489
0
                nBytes = WriteData(mat, sparse->data, sparse->ndata, matvar->data_type);
2490
0
                if ( nBytes % 8 )
2491
0
                    for ( j = nBytes % 8; j < 8; j++ )
2492
0
                        fwrite(&pad1, 1, 1, (FILE *)mat->fp);
2493
0
            }
2494
0
            break;
2495
0
        }
2496
0
        case MAT_C_FUNCTION:
2497
0
        case MAT_C_OBJECT:
2498
0
        case MAT_C_EMPTY:
2499
0
        case MAT_C_OPAQUE:
2500
0
            break;
2501
0
        default:
2502
0
            err = MATIO_E_OUTPUT_BAD_DATA;
2503
0
            break;
2504
0
    }
2505
2506
0
    return err;
2507
0
}
2508
2509
/** @brief Writes the header and data for an element of a cell array
2510
 *
2511
 * @ingroup mat_internal
2512
 * @param mat MAT file pointer
2513
 * @param matvar pointer to the mat variable
2514
 * @retval 0 on success
2515
 */
2516
static int
2517
WriteCellArrayField(mat_t *mat, matvar_t *matvar)
2518
0
{
2519
0
    mat_uint32_t array_flags, nzmax = 0;
2520
0
    int array_flags_type = MAT_T_UINT32, dims_array_type = MAT_T_INT32;
2521
0
    int array_flags_size = 8, matrix_type = MAT_T_MATRIX;
2522
0
    const mat_uint32_t pad4 = 0;
2523
0
    const mat_uint8_t pad1 = 0;
2524
0
    int nBytes, i;
2525
0
    mat_off_t start = 0, end = 0;
2526
2527
0
    if ( matvar == NULL || mat == NULL )
2528
0
        return MATIO_E_BAD_ARGUMENT;
2529
2530
    /* A sparse variable requires its data; normalize broken variables
2531
     * (e.g. read from a corrupt file) to an empty matrix. */
2532
0
    if ( matvar->class_type == MAT_C_SPARSE && NULL == matvar->data )
2533
0
        matvar->class_type = MAT_C_EMPTY;
2534
2535
0
    fwrite(&matrix_type, 4, 1, (FILE *)mat->fp);
2536
0
    fwrite(&pad4, 4, 1, (FILE *)mat->fp);
2537
0
    if ( MAT_C_EMPTY == matvar->class_type ) {
2538
        /* exit early if this is an empty data */
2539
0
        return MATIO_E_NO_ERROR;
2540
0
    }
2541
0
    start = MatTell(mat);
2542
2543
    /* Array Flags */
2544
0
    array_flags = matvar->class_type & CLASS_TYPE_MASK;
2545
0
    if ( matvar->isComplex )
2546
0
        array_flags |= MAT_F_COMPLEX;
2547
0
    if ( matvar->isGlobal )
2548
0
        array_flags |= MAT_F_GLOBAL;
2549
0
    if ( matvar->isLogical )
2550
0
        array_flags |= MAT_F_LOGICAL;
2551
0
    if ( matvar->class_type == MAT_C_SPARSE && NULL != matvar->data )
2552
0
        nzmax = ((mat_sparse_t *)matvar->data)->nzmax;
2553
2554
0
    if ( mat->byteswap )
2555
0
        array_flags = Mat_int32Swap((mat_int32_t *)&array_flags);
2556
0
    fwrite(&array_flags_type, 4, 1, (FILE *)mat->fp);
2557
0
    fwrite(&array_flags_size, 4, 1, (FILE *)mat->fp);
2558
0
    fwrite(&array_flags, 4, 1, (FILE *)mat->fp);
2559
0
    fwrite(&nzmax, 4, 1, (FILE *)mat->fp);
2560
    /* Rank and Dimension */
2561
0
    nBytes = matvar->rank * 4;
2562
0
    fwrite(&dims_array_type, 4, 1, (FILE *)mat->fp);
2563
0
    fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
2564
0
    for ( i = 0; i < matvar->rank; i++ ) {
2565
0
        mat_int32_t dim;
2566
0
        dim = matvar->dims[i];
2567
0
        fwrite(&dim, 4, 1, (FILE *)mat->fp);
2568
0
    }
2569
0
    if ( matvar->rank % 2 != 0 )
2570
0
        fwrite(&pad4, 4, 1, (FILE *)mat->fp);
2571
    /* Name of variable */
2572
0
    if ( !matvar->name ) {
2573
0
        const mat_uint32_t array_name_type = MAT_T_INT8;
2574
0
        fwrite(&array_name_type, 4, 1, (FILE *)mat->fp);
2575
0
        fwrite(&pad4, 4, 1, (FILE *)mat->fp);
2576
0
    } else if ( strlen(matvar->name) <= 4 ) {
2577
0
        mat_uint32_t array_name_type = MAT_T_INT8;
2578
0
        const mat_uint32_t array_name_len = (mat_uint32_t)strlen(matvar->name);
2579
0
        array_name_type |= array_name_len << 16;
2580
0
        fwrite(&array_name_type, 4, 1, (FILE *)mat->fp);
2581
0
        fwrite(matvar->name, 1, array_name_len, (FILE *)mat->fp);
2582
0
        for ( i = array_name_len; i < 4; i++ )
2583
0
            fwrite(&pad1, 1, 1, (FILE *)mat->fp);
2584
0
    } else {
2585
0
        const mat_uint32_t array_name_type = MAT_T_INT8;
2586
0
        const mat_uint32_t array_name_len = (mat_uint32_t)strlen(matvar->name);
2587
0
        fwrite(&array_name_type, 4, 1, (FILE *)mat->fp);
2588
0
        fwrite(&array_name_len, 4, 1, (FILE *)mat->fp);
2589
0
        fwrite(matvar->name, 1, array_name_len, (FILE *)mat->fp);
2590
0
        if ( array_name_len % 8 )
2591
0
            for ( i = array_name_len % 8; i < 8; i++ )
2592
0
                fwrite(&pad1, 1, 1, (FILE *)mat->fp);
2593
0
    }
2594
2595
0
    {
2596
0
        int err = WriteType(mat, matvar);
2597
0
        if ( err )
2598
0
            return err;
2599
0
    }
2600
0
    end = MatTell(mat);
2601
0
    if ( start != -1L && end != -1L ) {
2602
0
        nBytes = (int)(end - start);
2603
0
        (void)MatSeek(mat, (mat_off_t) - (nBytes + 4), SEEK_CUR);
2604
0
        fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
2605
0
        (void)MatSeek(mat, end, SEEK_SET);
2606
0
    } else {
2607
0
        Mat_Critical("Couldn't determine file position");
2608
0
    }
2609
2610
0
    return MATIO_E_NO_ERROR;
2611
0
}
2612
2613
#if HAVE_ZLIB
2614
/** @brief Writes the header and data for a given class type
2615
 *
2616
 * @ingroup mat_internal
2617
 * @param mat MAT file pointer
2618
 * @param matvar pointer to the mat variable
2619
 * @return number of bytes written to the MAT file
2620
 */
2621
static size_t
2622
WriteCompressedTypeArrayFlags(mat_t *mat, matvar_t *matvar, z_streamp z)
2623
0
{
2624
0
    mat_uint32_t array_flags;
2625
0
    const mat_uint32_t array_name_type = MAT_T_INT8;
2626
0
    int array_flags_type = MAT_T_UINT32, dims_array_type = MAT_T_INT32;
2627
0
    int array_flags_size = 8;
2628
0
    int nBytes, i, nzmax = 0;
2629
2630
0
    mat_uint32_t comp_buf[512] = {0};
2631
0
    mat_uint32_t uncomp_buf[512];
2632
0
    int buf_size = 512;
2633
0
    size_t byteswritten = 0;
2634
2635
0
    if ( MAT_C_EMPTY == matvar->class_type ) {
2636
        /* exit early if this is an empty data */
2637
0
        return byteswritten;
2638
0
    }
2639
2640
    /* The rank/dimensions subelement is packed into the fixed-size
2641
     * uncomp_buf[512]: 6 header words followed by one word per dimension plus
2642
     * an optional padding word. Reject a rank that would not fit before it
2643
     * overflows the stack buffer. */
2644
0
    if ( matvar->rank < 0 || matvar->rank > 512 - 7 )
2645
0
        return byteswritten;
2646
2647
0
    memset(uncomp_buf, 0, sizeof(uncomp_buf));
2648
    /* Array Flags */
2649
0
    array_flags = matvar->class_type & CLASS_TYPE_MASK;
2650
0
    if ( matvar->isComplex )
2651
0
        array_flags |= MAT_F_COMPLEX;
2652
0
    if ( matvar->isGlobal )
2653
0
        array_flags |= MAT_F_GLOBAL;
2654
0
    if ( matvar->isLogical )
2655
0
        array_flags |= MAT_F_LOGICAL;
2656
0
    if ( matvar->class_type == MAT_C_SPARSE && NULL != matvar->data )
2657
0
        nzmax = ((mat_sparse_t *)matvar->data)->nzmax;
2658
0
    uncomp_buf[0] = array_flags_type;
2659
0
    uncomp_buf[1] = array_flags_size;
2660
0
    uncomp_buf[2] = array_flags;
2661
0
    uncomp_buf[3] = nzmax;
2662
    /* Rank and Dimension */
2663
0
    nBytes = matvar->rank * 4;
2664
0
    uncomp_buf[4] = dims_array_type;
2665
0
    uncomp_buf[5] = nBytes;
2666
0
    for ( i = 0; i < matvar->rank; i++ ) {
2667
0
        mat_int32_t dim;
2668
0
        dim = matvar->dims[i];
2669
0
        uncomp_buf[6 + i] = dim;
2670
0
    }
2671
0
    if ( matvar->rank % 2 != 0 ) {
2672
0
        const mat_uint32_t pad4 = 0;
2673
0
        uncomp_buf[6 + i] = pad4;
2674
0
        i++;
2675
0
    }
2676
2677
0
    z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
2678
0
    z->avail_in = (6 + i) * sizeof(*uncomp_buf);
2679
0
    do {
2680
0
        z->next_out = ZLIB_BYTE_PTR(comp_buf);
2681
0
        z->avail_out = buf_size * sizeof(*comp_buf);
2682
0
        deflate(z, Z_NO_FLUSH);
2683
0
        byteswritten +=
2684
0
            fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out, (FILE *)mat->fp);
2685
0
    } while ( z->avail_out == 0 );
2686
    /* Name of variable */
2687
0
    uncomp_buf[0] = array_name_type;
2688
0
    uncomp_buf[1] = 0;
2689
0
    z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
2690
0
    z->avail_in = 8;
2691
0
    do {
2692
0
        z->next_out = ZLIB_BYTE_PTR(comp_buf);
2693
0
        z->avail_out = buf_size * sizeof(*comp_buf);
2694
0
        deflate(z, Z_NO_FLUSH);
2695
0
        byteswritten +=
2696
0
            fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out, (FILE *)mat->fp);
2697
0
    } while ( z->avail_out == 0 );
2698
2699
0
    matvar->internal->datapos = MatTell(mat);
2700
0
    if ( matvar->internal->datapos == -1L ) {
2701
0
        Mat_Critical("Couldn't determine file position");
2702
0
    }
2703
2704
0
    byteswritten += WriteCompressedType(mat, matvar, z);
2705
0
    return byteswritten;
2706
0
}
2707
2708
/** @brief Writes the header and data for a given class type
2709
 *
2710
 * @ingroup mat_internal
2711
 * @param mat MAT file pointer
2712
 * @param matvar pointer to the mat variable
2713
 * @return number of bytes written to the MAT file
2714
 */
2715
static size_t
2716
WriteCompressedType(mat_t *mat, matvar_t *matvar, z_streamp z)
2717
0
{
2718
0
    int err;
2719
0
    mat_uint32_t comp_buf[512] = {0};
2720
0
    mat_uint32_t uncomp_buf[512];
2721
0
    size_t byteswritten = 0, nelems = 1;
2722
2723
0
    if ( MAT_C_EMPTY == matvar->class_type ) {
2724
        /* exit early if this is an empty data */
2725
0
        return byteswritten;
2726
0
    }
2727
2728
0
    memset(uncomp_buf, 0, sizeof(uncomp_buf));
2729
0
    err = Mat_MulDims(matvar, &nelems);
2730
0
    if ( err ) {
2731
0
        Mat_Critical("Integer multiplication overflow");
2732
0
        return byteswritten;
2733
0
    }
2734
2735
0
    switch ( matvar->class_type ) {
2736
0
        case MAT_C_DOUBLE:
2737
0
        case MAT_C_SINGLE:
2738
0
        case MAT_C_INT64:
2739
0
        case MAT_C_UINT64:
2740
0
        case MAT_C_INT32:
2741
0
        case MAT_C_UINT32:
2742
0
        case MAT_C_INT16:
2743
0
        case MAT_C_UINT16:
2744
0
        case MAT_C_INT8:
2745
0
        case MAT_C_UINT8: {
2746
            /* WriteCompressedData makes sure uncompressed data is aligned
2747
             * on an 8-byte boundary */
2748
0
            if ( matvar->isComplex ) {
2749
0
                mat_complex_split_t *complex_data = (mat_complex_split_t *)matvar->data;
2750
2751
0
                if ( NULL == matvar->data )
2752
0
                    complex_data = &null_complex_data;
2753
2754
0
                byteswritten +=
2755
0
                    WriteCompressedData(mat, z, complex_data->Re, nelems, matvar->data_type);
2756
0
                byteswritten +=
2757
0
                    WriteCompressedData(mat, z, complex_data->Im, nelems, matvar->data_type);
2758
0
            } else {
2759
0
                byteswritten +=
2760
0
                    WriteCompressedData(mat, z, matvar->data, nelems, matvar->data_type);
2761
0
            }
2762
0
            break;
2763
0
        }
2764
0
        case MAT_C_CHAR: {
2765
0
            if ( matvar->data_type == MAT_T_UTF8 ) {
2766
0
                nelems = matvar->nbytes;
2767
0
            }
2768
0
            byteswritten +=
2769
0
                WriteCompressedCharData(mat, z, matvar->data, nelems, matvar->data_type);
2770
0
            break;
2771
0
        }
2772
0
        case MAT_C_CELL: {
2773
0
            size_t i;
2774
0
            matvar_t **cells = (matvar_t **)matvar->data;
2775
2776
            /* Check for an empty cell array */
2777
0
            if ( matvar->nbytes == 0 || matvar->data_size == 0 || matvar->data == NULL )
2778
0
                break;
2779
0
            nelems = matvar->nbytes / matvar->data_size;
2780
0
            for ( i = 0; i < nelems; i++ )
2781
0
                WriteCompressedCellArrayField(mat, cells[i], z);
2782
0
            break;
2783
0
        }
2784
0
        case MAT_C_STRUCT: {
2785
0
            int buf_size = 512;
2786
0
            const mat_uint32_t fieldname_type = MAT_T_INT32;
2787
0
            const mat_uint32_t fieldname_data_size = 4;
2788
0
            unsigned char *padzero;
2789
0
            int fieldname_size;
2790
0
            size_t maxlen = 0, nfields, i, nelems_x_nfields;
2791
0
            const mat_uint32_t array_name_type = MAT_T_INT8;
2792
0
            matvar_t **fields = (matvar_t **)matvar->data;
2793
2794
0
            nfields = matvar->internal->num_fields;
2795
            /* Check for a structure with no fields */
2796
0
            if ( nfields < 1 ) {
2797
0
                fieldname_size = 1;
2798
0
                uncomp_buf[0] = (fieldname_data_size << 16) | fieldname_type;
2799
0
                uncomp_buf[1] = fieldname_size;
2800
0
                uncomp_buf[2] = array_name_type;
2801
0
                uncomp_buf[3] = 0;
2802
0
                z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
2803
0
                z->avail_in = 16;
2804
0
                do {
2805
0
                    z->next_out = ZLIB_BYTE_PTR(comp_buf);
2806
0
                    z->avail_out = buf_size * sizeof(*comp_buf);
2807
0
                    deflate(z, Z_NO_FLUSH);
2808
0
                    byteswritten += fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out,
2809
0
                                           (FILE *)mat->fp);
2810
0
                } while ( z->avail_out == 0 );
2811
0
                break;
2812
0
            }
2813
2814
0
            for ( i = 0; i < nfields; i++ ) {
2815
0
                size_t len = strlen(matvar->internal->fieldnames[i]);
2816
0
                if ( len > maxlen )
2817
0
                    maxlen = len;
2818
0
            }
2819
0
            maxlen++;
2820
0
            fieldname_size = maxlen;
2821
0
            while ( nfields * fieldname_size % 8 != 0 )
2822
0
                fieldname_size++;
2823
0
            uncomp_buf[0] = (fieldname_data_size << 16) | fieldname_type;
2824
0
            uncomp_buf[1] = fieldname_size;
2825
0
            uncomp_buf[2] = array_name_type;
2826
0
            uncomp_buf[3] = nfields * fieldname_size;
2827
2828
0
            padzero = (unsigned char *)calloc(fieldname_size, 1);
2829
0
            if ( padzero == NULL ) {
2830
0
                err = MATIO_E_OUT_OF_MEMORY;
2831
0
                break;
2832
0
            }
2833
0
            z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
2834
0
            z->avail_in = 16;
2835
0
            do {
2836
0
                z->next_out = ZLIB_BYTE_PTR(comp_buf);
2837
0
                z->avail_out = buf_size * sizeof(*comp_buf);
2838
0
                deflate(z, Z_NO_FLUSH);
2839
0
                byteswritten += fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out,
2840
0
                                       (FILE *)mat->fp);
2841
0
            } while ( z->avail_out == 0 );
2842
0
            for ( i = 0; i < nfields; i++ ) {
2843
0
                size_t len = strlen(matvar->internal->fieldnames[i]);
2844
0
                memset(padzero, '\0', fieldname_size);
2845
0
                memcpy(padzero, matvar->internal->fieldnames[i], len);
2846
0
                z->next_in = ZLIB_BYTE_PTR(padzero);
2847
0
                z->avail_in = fieldname_size;
2848
0
                do {
2849
0
                    z->next_out = ZLIB_BYTE_PTR(comp_buf);
2850
0
                    z->avail_out = buf_size * sizeof(*comp_buf);
2851
0
                    deflate(z, Z_NO_FLUSH);
2852
0
                    byteswritten += fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out,
2853
0
                                           (FILE *)mat->fp);
2854
0
                } while ( z->avail_out == 0 );
2855
0
            }
2856
0
            free(padzero);
2857
0
            err = Mul(&nelems_x_nfields, nelems, nfields);
2858
0
            if ( err ) {
2859
0
                Mat_Critical("Integer multiplication overflow");
2860
0
                return byteswritten;
2861
0
            }
2862
0
            if ( NULL != fields ) {
2863
0
                for ( i = 0; i < nelems_x_nfields; i++ )
2864
0
                    byteswritten += WriteCompressedStructField(mat, fields[i], z);
2865
0
            }
2866
0
            break;
2867
0
        }
2868
0
        case MAT_C_SPARSE: {
2869
0
            mat_sparse_t *sparse = (mat_sparse_t *)matvar->data;
2870
2871
0
            if ( NULL == sparse )
2872
0
                break;
2873
2874
0
            byteswritten += WriteCompressedData(mat, z, sparse->ir, sparse->nir, MAT_T_UINT32);
2875
0
            byteswritten += WriteCompressedData(mat, z, sparse->jc, sparse->njc, MAT_T_UINT32);
2876
0
            if ( matvar->isComplex && NULL != sparse->data ) {
2877
0
                mat_complex_split_t *complex_data = (mat_complex_split_t *)sparse->data;
2878
0
                byteswritten +=
2879
0
                    WriteCompressedData(mat, z, complex_data->Re, sparse->ndata, matvar->data_type);
2880
0
                byteswritten +=
2881
0
                    WriteCompressedData(mat, z, complex_data->Im, sparse->ndata, matvar->data_type);
2882
0
            } else {
2883
0
                byteswritten +=
2884
0
                    WriteCompressedData(mat, z, sparse->data, sparse->ndata, matvar->data_type);
2885
0
            }
2886
0
            break;
2887
0
        }
2888
0
        case MAT_C_FUNCTION:
2889
0
        case MAT_C_OBJECT:
2890
0
        case MAT_C_EMPTY:
2891
0
        case MAT_C_OPAQUE:
2892
0
            break;
2893
0
    }
2894
2895
0
    return byteswritten;
2896
0
}
2897
2898
/** @brief Writes the header and data for a field of a compressed cell array
2899
 *
2900
 * @ingroup mat_internal
2901
 * @param mat MAT file pointer
2902
 * @param matvar pointer to the mat variable
2903
 * @return number of bytes written to the MAT file
2904
 */
2905
static size_t
2906
WriteCompressedCellArrayField(mat_t *mat, matvar_t *matvar, z_streamp z)
2907
0
{
2908
0
    mat_uint32_t comp_buf[512] = {0};
2909
0
    mat_uint32_t uncomp_buf[512];
2910
0
    int buf_size = 512;
2911
0
    size_t byteswritten = 0, field_buf_size;
2912
2913
0
    if ( NULL == matvar || NULL == mat || NULL == z )
2914
0
        return 0;
2915
2916
    /* A sparse variable requires its data; normalize broken variables
2917
     * (e.g. read from a corrupt file) to an empty matrix. */
2918
0
    if ( matvar->class_type == MAT_C_SPARSE && NULL == matvar->data )
2919
0
        matvar->class_type = MAT_C_EMPTY;
2920
2921
0
    memset(uncomp_buf, 0, sizeof(uncomp_buf));
2922
0
    uncomp_buf[0] = MAT_T_MATRIX;
2923
0
    if ( MAT_C_EMPTY != matvar->class_type ) {
2924
0
        int err = GetCellArrayFieldBufSize(matvar, &field_buf_size);
2925
0
        if ( err || field_buf_size > UINT32_MAX )
2926
0
            return 0;
2927
2928
0
        uncomp_buf[1] = field_buf_size;
2929
0
    } else {
2930
0
        uncomp_buf[1] = 0;
2931
0
    }
2932
0
    z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
2933
0
    z->avail_in = 8;
2934
0
    do {
2935
0
        z->next_out = ZLIB_BYTE_PTR(comp_buf);
2936
0
        z->avail_out = buf_size * sizeof(*comp_buf);
2937
0
        deflate(z, Z_NO_FLUSH);
2938
0
        byteswritten +=
2939
0
            fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out, (FILE *)mat->fp);
2940
0
    } while ( z->avail_out == 0 );
2941
2942
0
    byteswritten += WriteCompressedTypeArrayFlags(mat, matvar, z);
2943
0
    return byteswritten;
2944
0
}
2945
#endif
2946
2947
/** @brief Writes the header and data for a field of a struct array
2948
 *
2949
 * @ingroup mat_internal
2950
 * @param mat MAT file pointer
2951
 * @param matvar pointer to the mat variable
2952
 * @retval 0 on success
2953
 */
2954
static int
2955
WriteStructField(mat_t *mat, matvar_t *matvar)
2956
0
{
2957
0
    mat_uint32_t array_flags;
2958
0
    const mat_uint32_t array_name_type = MAT_T_INT8;
2959
0
    int array_flags_type = MAT_T_UINT32, dims_array_type = MAT_T_INT32;
2960
0
    int array_flags_size = 8, matrix_type = MAT_T_MATRIX;
2961
0
    const mat_uint32_t pad4 = 0;
2962
0
    int nBytes, i, nzmax = 0;
2963
0
    mat_off_t start = 0, end = 0;
2964
2965
0
    if ( mat == NULL )
2966
0
        return MATIO_E_BAD_ARGUMENT;
2967
2968
0
    if ( NULL == matvar ) {
2969
0
        const size_t dims[2] = {0, 0};
2970
0
        Mat_WriteEmptyVariable5(mat, NULL, 2, dims);
2971
0
        return MATIO_E_NO_ERROR;
2972
0
    }
2973
2974
    /* A sparse variable requires its data; normalize broken variables
2975
     * (e.g. read from a corrupt file) to an empty matrix. */
2976
0
    if ( matvar->class_type == MAT_C_SPARSE && NULL == matvar->data )
2977
0
        matvar->class_type = MAT_C_EMPTY;
2978
2979
0
    fwrite(&matrix_type, 4, 1, (FILE *)mat->fp);
2980
0
    fwrite(&pad4, 4, 1, (FILE *)mat->fp);
2981
0
    if ( MAT_C_EMPTY == matvar->class_type ) {
2982
        /* exit early if this is an empty data */
2983
0
        return MATIO_E_NO_ERROR;
2984
0
    }
2985
0
    start = MatTell(mat);
2986
2987
    /* Array Flags */
2988
0
    array_flags = matvar->class_type & CLASS_TYPE_MASK;
2989
0
    if ( matvar->isComplex )
2990
0
        array_flags |= MAT_F_COMPLEX;
2991
0
    if ( matvar->isGlobal )
2992
0
        array_flags |= MAT_F_GLOBAL;
2993
0
    if ( matvar->isLogical )
2994
0
        array_flags |= MAT_F_LOGICAL;
2995
0
    if ( matvar->class_type == MAT_C_SPARSE && NULL != matvar->data )
2996
0
        nzmax = ((mat_sparse_t *)matvar->data)->nzmax;
2997
2998
0
    if ( mat->byteswap )
2999
0
        array_flags = Mat_int32Swap((mat_int32_t *)&array_flags);
3000
0
    fwrite(&array_flags_type, 4, 1, (FILE *)mat->fp);
3001
0
    fwrite(&array_flags_size, 4, 1, (FILE *)mat->fp);
3002
0
    fwrite(&array_flags, 4, 1, (FILE *)mat->fp);
3003
0
    fwrite(&nzmax, 4, 1, (FILE *)mat->fp);
3004
    /* Rank and Dimension */
3005
0
    nBytes = matvar->rank * 4;
3006
0
    fwrite(&dims_array_type, 4, 1, (FILE *)mat->fp);
3007
0
    fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
3008
0
    for ( i = 0; i < matvar->rank; i++ ) {
3009
0
        mat_int32_t dim;
3010
0
        dim = matvar->dims[i];
3011
0
        fwrite(&dim, 4, 1, (FILE *)mat->fp);
3012
0
    }
3013
0
    if ( matvar->rank % 2 != 0 )
3014
0
        fwrite(&pad4, 4, 1, (FILE *)mat->fp);
3015
3016
    /* Name of variable */
3017
0
    fwrite(&array_name_type, 4, 1, (FILE *)mat->fp);
3018
0
    fwrite(&pad4, 4, 1, (FILE *)mat->fp);
3019
3020
0
    {
3021
0
        int err = WriteType(mat, matvar);
3022
0
        if ( err )
3023
0
            return err;
3024
0
    }
3025
0
    end = MatTell(mat);
3026
0
    if ( start != -1L && end != -1L ) {
3027
0
        nBytes = (int)(end - start);
3028
0
        (void)MatSeek(mat, (mat_off_t) - (nBytes + 4), SEEK_CUR);
3029
0
        fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
3030
0
        (void)MatSeek(mat, end, SEEK_SET);
3031
0
    } else {
3032
0
        Mat_Critical("Couldn't determine file position");
3033
0
    }
3034
3035
0
    return MATIO_E_NO_ERROR;
3036
0
}
3037
3038
#if HAVE_ZLIB
3039
/** @brief Writes the header and data for a field of a compressed struct array
3040
 *
3041
 * @ingroup mat_internal
3042
 * @fixme Currently does not work for cell arrays or sparse data
3043
 * @param mat MAT file pointer
3044
 * @param matvar pointer to the mat variable
3045
 * @return number of bytes written to the MAT file
3046
 */
3047
static size_t
3048
WriteCompressedStructField(mat_t *mat, matvar_t *matvar, z_streamp z)
3049
0
{
3050
0
    mat_uint32_t comp_buf[512] = {0};
3051
0
    mat_uint32_t uncomp_buf[512];
3052
0
    int buf_size = 512;
3053
0
    size_t byteswritten = 0, field_buf_size;
3054
3055
0
    if ( NULL == mat || NULL == z )
3056
0
        return 0;
3057
3058
0
    if ( NULL == matvar ) {
3059
0
        const size_t dims[2] = {0, 0};
3060
0
        byteswritten = Mat_WriteCompressedEmptyVariable5(mat, NULL, 2, dims, z);
3061
0
        return byteswritten;
3062
0
    }
3063
3064
    /* A sparse variable requires its data; normalize broken variables
3065
     * (e.g. read from a corrupt file) to an empty matrix. */
3066
0
    if ( matvar->class_type == MAT_C_SPARSE && NULL == matvar->data )
3067
0
        matvar->class_type = MAT_C_EMPTY;
3068
3069
0
    memset(uncomp_buf, 0, sizeof(uncomp_buf));
3070
0
    uncomp_buf[0] = MAT_T_MATRIX;
3071
0
    if ( MAT_C_EMPTY != matvar->class_type ) {
3072
0
        int err = GetStructFieldBufSize(matvar, &field_buf_size);
3073
0
        if ( err || field_buf_size > UINT32_MAX )
3074
0
            return 0;
3075
0
        uncomp_buf[1] = field_buf_size;
3076
0
    } else {
3077
0
        uncomp_buf[1] = 0;
3078
0
    }
3079
0
    z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
3080
0
    z->avail_in = 8;
3081
0
    do {
3082
0
        z->next_out = ZLIB_BYTE_PTR(comp_buf);
3083
0
        z->avail_out = buf_size * sizeof(*comp_buf);
3084
0
        deflate(z, Z_NO_FLUSH);
3085
0
        byteswritten +=
3086
0
            fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out, (FILE *)mat->fp);
3087
0
    } while ( z->avail_out == 0 );
3088
3089
0
    byteswritten += WriteCompressedTypeArrayFlags(mat, matvar, z);
3090
0
    return byteswritten;
3091
0
}
3092
#endif
3093
3094
static size_t
3095
Mat_WriteEmptyVariable5(mat_t *mat, const char *name, int rank, const size_t *dims)
3096
0
{
3097
0
    mat_uint32_t array_flags;
3098
0
    mat_uint32_t array_name_type = MAT_T_INT8;
3099
0
    const mat_uint32_t matrix_type = MAT_T_MATRIX;
3100
0
    int array_flags_type = MAT_T_UINT32, dims_array_type = MAT_T_INT32;
3101
0
    int array_flags_size = 8, nBytes, i;
3102
0
    const mat_uint32_t pad4 = 0;
3103
0
    const mat_uint8_t pad1 = 0;
3104
0
    size_t byteswritten = 0;
3105
0
    mat_off_t start = 0, end = 0;
3106
3107
0
    fwrite(&matrix_type, 4, 1, (FILE *)mat->fp);
3108
0
    fwrite(&pad4, 4, 1, (FILE *)mat->fp);
3109
0
    start = MatTell(mat);
3110
3111
    /* Array Flags */
3112
0
    array_flags = MAT_C_DOUBLE;
3113
3114
0
    if ( mat->byteswap )
3115
0
        array_flags = Mat_int32Swap((mat_int32_t *)&array_flags);
3116
0
    byteswritten += fwrite(&array_flags_type, 4, 1, (FILE *)mat->fp);
3117
0
    byteswritten += fwrite(&array_flags_size, 4, 1, (FILE *)mat->fp);
3118
0
    byteswritten += fwrite(&array_flags, 4, 1, (FILE *)mat->fp);
3119
0
    byteswritten += fwrite(&pad4, 4, 1, (FILE *)mat->fp);
3120
    /* Rank and Dimension */
3121
0
    nBytes = rank * 4;
3122
0
    byteswritten += fwrite(&dims_array_type, 4, 1, (FILE *)mat->fp);
3123
0
    byteswritten += fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
3124
0
    for ( i = 0; i < rank; i++ ) {
3125
0
        mat_int32_t dim;
3126
0
        dim = dims[i];
3127
0
        byteswritten += fwrite(&dim, 4, 1, (FILE *)mat->fp);
3128
0
    }
3129
0
    if ( rank % 2 != 0 )
3130
0
        byteswritten += fwrite(&pad4, 4, 1, (FILE *)mat->fp);
3131
3132
0
    if ( NULL == name ) {
3133
        /* Name of variable */
3134
0
        byteswritten += fwrite(&array_name_type, 4, 1, (FILE *)mat->fp);
3135
0
        byteswritten += fwrite(&pad4, 4, 1, (FILE *)mat->fp);
3136
0
    } else {
3137
0
        mat_int32_t array_name_len = (mat_int32_t)strlen(name);
3138
        /* Name of variable */
3139
0
        if ( array_name_len <= 4 ) {
3140
0
            array_name_type |= array_name_len << 16;
3141
0
            byteswritten += fwrite(&array_name_type, 4, 1, (FILE *)mat->fp);
3142
0
            byteswritten += fwrite(name, 1, array_name_len, (FILE *)mat->fp);
3143
0
            for ( i = array_name_len; i < 4; i++ )
3144
0
                byteswritten += fwrite(&pad1, 1, 1, (FILE *)mat->fp);
3145
0
        } else {
3146
0
            byteswritten += fwrite(&array_name_type, 4, 1, (FILE *)mat->fp);
3147
0
            byteswritten += fwrite(&array_name_len, 4, 1, (FILE *)mat->fp);
3148
0
            byteswritten += fwrite(name, 1, array_name_len, (FILE *)mat->fp);
3149
0
            if ( array_name_len % 8 )
3150
0
                for ( i = array_name_len % 8; i < 8; i++ )
3151
0
                    byteswritten += fwrite(&pad1, 1, 1, (FILE *)mat->fp);
3152
0
        }
3153
0
    }
3154
3155
0
    nBytes = WriteData(mat, NULL, 0, MAT_T_DOUBLE);
3156
0
    byteswritten += nBytes;
3157
0
    if ( nBytes % 8 )
3158
0
        for ( i = nBytes % 8; i < 8; i++ )
3159
0
            byteswritten += fwrite(&pad1, 1, 1, (FILE *)mat->fp);
3160
3161
0
    end = MatTell(mat);
3162
0
    if ( start != -1L && end != -1L ) {
3163
0
        nBytes = (int)(end - start);
3164
0
        (void)MatSeek(mat, (mat_off_t) - (nBytes + 4), SEEK_CUR);
3165
0
        fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
3166
0
        (void)MatSeek(mat, end, SEEK_SET);
3167
0
    } else {
3168
0
        Mat_Critical("Couldn't determine file position");
3169
0
    }
3170
3171
0
    return byteswritten;
3172
0
}
3173
3174
#if HAVE_ZLIB
3175
static size_t
3176
Mat_WriteCompressedEmptyVariable5(mat_t *mat, const char *name, int rank, const size_t *dims,
3177
                                  z_streamp z)
3178
0
{
3179
0
    mat_uint32_t array_flags;
3180
0
    int array_flags_type = MAT_T_UINT32, dims_array_type = MAT_T_INT32;
3181
0
    int array_flags_size = 8;
3182
0
    int i, err;
3183
0
    size_t nBytes, empty_matrix_max_buf_size;
3184
3185
0
    mat_uint32_t comp_buf[512] = {0};
3186
0
    mat_uint32_t uncomp_buf[512];
3187
0
    int buf_size = 512;
3188
0
    size_t byteswritten = 0, buf_size_bytes;
3189
3190
0
    if ( NULL == mat || NULL == z )
3191
0
        return byteswritten;
3192
3193
0
    buf_size_bytes = buf_size * sizeof(*comp_buf);
3194
3195
    /* Array Flags */
3196
0
    array_flags = MAT_C_DOUBLE;
3197
3198
0
    memset(uncomp_buf, 0, sizeof(uncomp_buf));
3199
0
    uncomp_buf[0] = MAT_T_MATRIX;
3200
0
    err = GetEmptyMatrixMaxBufSize(name, rank, &empty_matrix_max_buf_size);
3201
0
    if ( err || empty_matrix_max_buf_size > UINT32_MAX )
3202
0
        return byteswritten;
3203
0
    uncomp_buf[1] = empty_matrix_max_buf_size;
3204
0
    z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
3205
0
    z->avail_in = 8;
3206
0
    do {
3207
0
        z->next_out = ZLIB_BYTE_PTR(comp_buf);
3208
0
        z->avail_out = buf_size_bytes;
3209
0
        deflate(z, Z_NO_FLUSH);
3210
0
        byteswritten += fwrite(comp_buf, 1, buf_size_bytes - z->avail_out, (FILE *)mat->fp);
3211
0
    } while ( z->avail_out == 0 );
3212
0
    uncomp_buf[0] = array_flags_type;
3213
0
    uncomp_buf[1] = array_flags_size;
3214
0
    uncomp_buf[2] = array_flags;
3215
0
    uncomp_buf[3] = 0;
3216
    /* Rank and Dimension */
3217
0
    nBytes = rank * 4;
3218
0
    uncomp_buf[4] = dims_array_type;
3219
0
    uncomp_buf[5] = nBytes;
3220
0
    for ( i = 0; i < rank; i++ ) {
3221
0
        mat_int32_t dim;
3222
0
        dim = dims[i];
3223
0
        uncomp_buf[6 + i] = dim;
3224
0
    }
3225
0
    if ( rank % 2 != 0 ) {
3226
0
        const mat_uint32_t pad4 = 0;
3227
0
        uncomp_buf[6 + i] = pad4;
3228
0
        i++;
3229
0
    }
3230
3231
0
    z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
3232
0
    z->avail_in = (6 + i) * sizeof(*uncomp_buf);
3233
0
    do {
3234
0
        z->next_out = ZLIB_BYTE_PTR(comp_buf);
3235
0
        z->avail_out = buf_size_bytes;
3236
0
        deflate(z, Z_NO_FLUSH);
3237
0
        byteswritten += fwrite(comp_buf, 1, buf_size_bytes - z->avail_out, (FILE *)mat->fp);
3238
0
    } while ( z->avail_out == 0 );
3239
    /* Name of variable */
3240
0
    if ( NULL == name ) {
3241
0
        const mat_uint32_t array_name_type = MAT_T_INT8;
3242
0
        uncomp_buf[0] = array_name_type;
3243
0
        uncomp_buf[1] = 0;
3244
0
        z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
3245
0
        z->avail_in = 8;
3246
0
        do {
3247
0
            z->next_out = ZLIB_BYTE_PTR(comp_buf);
3248
0
            z->avail_out = buf_size_bytes;
3249
0
            deflate(z, Z_NO_FLUSH);
3250
0
            byteswritten += fwrite(comp_buf, 1, buf_size_bytes - z->avail_out, (FILE *)mat->fp);
3251
0
        } while ( z->avail_out == 0 );
3252
0
    } else if ( strlen(name) <= 4 ) {
3253
0
        mat_uint32_t array_name_len = (mat_uint32_t)strlen(name);
3254
0
        const mat_uint32_t array_name_type = MAT_T_INT8;
3255
3256
0
        memset(uncomp_buf, 0, 8);
3257
0
        uncomp_buf[0] = (array_name_len << 16) | array_name_type;
3258
0
        memcpy(uncomp_buf + 1, name, array_name_len);
3259
        /* if ( array_name_len % 4 ) */
3260
        /*    array_name_len += 4 - (array_name_len % 4); */
3261
3262
0
        z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
3263
0
        z->avail_in = 8;
3264
0
        do {
3265
0
            z->next_out = ZLIB_BYTE_PTR(comp_buf);
3266
0
            z->avail_out = buf_size_bytes;
3267
0
            deflate(z, Z_NO_FLUSH);
3268
0
            byteswritten += fwrite(comp_buf, 1, buf_size_bytes - z->avail_out, (FILE *)mat->fp);
3269
0
        } while ( z->avail_out == 0 );
3270
0
    } else {
3271
0
        mat_uint32_t array_name_len = (mat_uint32_t)strlen(name);
3272
0
        const mat_uint32_t array_name_type = MAT_T_INT8;
3273
3274
0
        memset(uncomp_buf, 0, buf_size * sizeof(*uncomp_buf));
3275
0
        uncomp_buf[0] = array_name_type;
3276
0
        uncomp_buf[1] = array_name_len;
3277
0
        memcpy(uncomp_buf + 2, name, array_name_len);
3278
0
        if ( array_name_len % 8 )
3279
0
            array_name_len += 8 - (array_name_len % 8);
3280
0
        z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
3281
0
        z->avail_in = 8 + array_name_len;
3282
0
        do {
3283
0
            z->next_out = ZLIB_BYTE_PTR(comp_buf);
3284
0
            z->avail_out = buf_size_bytes;
3285
0
            deflate(z, Z_NO_FLUSH);
3286
0
            byteswritten += fwrite(comp_buf, 1, buf_size_bytes - z->avail_out, (FILE *)mat->fp);
3287
0
        } while ( z->avail_out == 0 );
3288
0
    }
3289
3290
0
    byteswritten += WriteCompressedData(mat, z, NULL, 0, MAT_T_DOUBLE);
3291
0
    return byteswritten;
3292
0
}
3293
#endif
3294
3295
/** @if mat_devman
3296
 * @brief Reads a data element including tag and data
3297
 *
3298
 * @ingroup mat_internal
3299
 * @param mat MAT file pointer
3300
 * @param matvar MAT variable pointer
3301
 * @param data Pointer to store the data
3302
 * @param N number of data elements allocated for the pointer
3303
 * @retval 0 on success
3304
 * @endif
3305
 */
3306
static int
3307
Mat_VarReadNumeric5(mat_t *mat, matvar_t *matvar, void *data, size_t N)
3308
18.9k
{
3309
18.9k
    int data_in_tag = 0, err = MATIO_E_NO_ERROR;
3310
18.9k
    size_t nBytes = 0;
3311
18.9k
    enum matio_types packed_type = MAT_T_UNKNOWN;
3312
18.9k
    mat_uint32_t tag[2] = {0, 0};
3313
3314
18.9k
    if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
3315
11.6k
#if HAVE_ZLIB
3316
11.6k
        matvar->internal->z->avail_in = 0;
3317
11.6k
        err = Inflate(mat, matvar->internal->z, tag, 4, NULL);
3318
11.6k
        if ( err ) {
3319
0
            return err;
3320
0
        }
3321
11.6k
        if ( mat->byteswap )
3322
9.05k
            (void)Mat_uint32Swap(tag);
3323
3324
11.6k
        packed_type = TYPE_FROM_TAG(tag[0]);
3325
11.6k
        if ( tag[0] & 0xffff0000 ) { /* Data is in the tag */
3326
1.41k
            data_in_tag = 1;
3327
1.41k
            nBytes = (tag[0] & 0xffff0000) >> 16;
3328
10.2k
        } else {
3329
10.2k
            data_in_tag = 0;
3330
10.2k
            err = Inflate(mat, matvar->internal->z, tag + 1, 4, NULL);
3331
10.2k
            if ( err ) {
3332
0
                return err;
3333
0
            }
3334
10.2k
            if ( mat->byteswap )
3335
8.08k
                (void)Mat_uint32Swap(tag + 1);
3336
10.2k
            nBytes = tag[1];
3337
10.2k
        }
3338
11.6k
#endif
3339
11.6k
    } else {
3340
7.29k
        err = Read(tag, 4, 1, mat, NULL);
3341
7.29k
        if ( err ) {
3342
0
            return err;
3343
0
        }
3344
7.29k
        if ( mat->byteswap )
3345
4.81k
            (void)Mat_uint32Swap(tag);
3346
7.29k
        packed_type = TYPE_FROM_TAG(tag[0]);
3347
7.29k
        if ( tag[0] & 0xffff0000 ) { /* Data is in the tag */
3348
2.48k
            data_in_tag = 1;
3349
2.48k
            nBytes = (tag[0] & 0xffff0000) >> 16;
3350
4.81k
        } else {
3351
4.81k
            data_in_tag = 0;
3352
4.81k
            err = Read(tag + 1, 4, 1, mat, NULL);
3353
4.81k
            if ( err ) {
3354
0
                return err;
3355
0
            }
3356
4.81k
            if ( mat->byteswap )
3357
3.58k
                (void)Mat_uint32Swap(tag + 1);
3358
4.81k
            nBytes = tag[1];
3359
4.81k
        }
3360
7.29k
    }
3361
18.9k
    if ( nBytes == 0 ) {
3362
397
        matvar->nbytes = 0;
3363
397
        if ( N > 0 )
3364
396
            return MATIO_E_FILE_FORMAT_VIOLATION;
3365
1
        return err;
3366
18.5k
    } else {
3367
18.5k
        size_t data_bytes = 0;
3368
18.5k
        err = Mul(&data_bytes, N, Mat_SizeOf(packed_type));
3369
18.5k
        if ( err )
3370
0
            return err;
3371
18.5k
        if ( nBytes < data_bytes ) {
3372
2.13k
            matvar->nbytes = 0;
3373
2.13k
            return MATIO_E_FILE_FORMAT_VIOLATION;
3374
2.13k
        }
3375
18.5k
    }
3376
3377
16.4k
    if ( matvar->compression == MAT_COMPRESSION_NONE ) {
3378
6.10k
        switch ( matvar->class_type ) {
3379
1.45k
            case MAT_C_DOUBLE:
3380
1.45k
                err = ReadDoubleData(mat, (double *)data, packed_type, N);
3381
1.45k
                break;
3382
1.45k
            case MAT_C_SINGLE:
3383
1.45k
                err = ReadSingleData(mat, (float *)data, packed_type, N);
3384
1.45k
                break;
3385
362
            case MAT_C_INT64:
3386
362
#ifdef HAVE_MAT_INT64_T
3387
362
                err = ReadInt64Data(mat, (mat_int64_t *)data, packed_type, N);
3388
362
#endif
3389
362
                break;
3390
338
            case MAT_C_UINT64:
3391
338
#ifdef HAVE_MAT_UINT64_T
3392
338
                err = ReadUInt64Data(mat, (mat_uint64_t *)data, packed_type, N);
3393
338
#endif
3394
338
                break;
3395
999
            case MAT_C_INT32:
3396
999
                err = ReadInt32Data(mat, (mat_int32_t *)data, packed_type, N);
3397
999
                break;
3398
62
            case MAT_C_UINT32:
3399
62
                err = ReadUInt32Data(mat, (mat_uint32_t *)data, packed_type, N);
3400
62
                break;
3401
585
            case MAT_C_INT16:
3402
585
                err = ReadInt16Data(mat, (mat_int16_t *)data, packed_type, N);
3403
585
                break;
3404
153
            case MAT_C_UINT16:
3405
153
                err = ReadUInt16Data(mat, (mat_uint16_t *)data, packed_type, N);
3406
153
                break;
3407
525
            case MAT_C_INT8:
3408
525
                err = ReadInt8Data(mat, (mat_int8_t *)data, packed_type, N);
3409
525
                break;
3410
183
            case MAT_C_UINT8:
3411
183
                err = ReadUInt8Data(mat, (mat_uint8_t *)data, packed_type, N);
3412
183
                break;
3413
0
            default:
3414
0
                err = MATIO_E_FILE_FORMAT_VIOLATION;
3415
0
                break;
3416
6.10k
        }
3417
6.10k
        if ( err ) {
3418
1.53k
            return err;
3419
1.53k
        }
3420
4.57k
        err = Mul(&nBytes, N, Mat_SizeOf(packed_type));
3421
4.57k
        if ( err ) {
3422
0
            return err;
3423
0
        }
3424
        /*
3425
         * If the data was in the tag we started on a 4-byte
3426
         * boundary so add 4 to make it an 8-byte
3427
         */
3428
4.57k
        if ( data_in_tag )
3429
1.05k
            nBytes += 4;
3430
4.57k
        if ( (nBytes % 8) != 0 )
3431
1.78k
            (void)MatSeek(mat, 8 - (nBytes % 8), SEEK_CUR);
3432
4.57k
#if HAVE_ZLIB
3433
10.2k
    } else if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
3434
10.2k
        switch ( matvar->class_type ) {
3435
2.84k
            case MAT_C_DOUBLE:
3436
2.84k
                err = ReadCompressedDoubleData(mat, matvar->internal->z, (double *)data,
3437
2.84k
                                               packed_type, N);
3438
2.84k
                break;
3439
3.13k
            case MAT_C_SINGLE:
3440
3.13k
                err = ReadCompressedSingleData(mat, matvar->internal->z, (float *)data, packed_type,
3441
3.13k
                                               N);
3442
3.13k
                break;
3443
48
            case MAT_C_INT64:
3444
48
#ifdef HAVE_MAT_INT64_T
3445
48
                err = ReadCompressedInt64Data(mat, matvar->internal->z, (mat_int64_t *)data,
3446
48
                                              packed_type, N);
3447
48
#endif
3448
48
                break;
3449
2
            case MAT_C_UINT64:
3450
2
#ifdef HAVE_MAT_UINT64_T
3451
2
                err = ReadCompressedUInt64Data(mat, matvar->internal->z, (mat_uint64_t *)data,
3452
2
                                               packed_type, N);
3453
2
#endif
3454
2
                break;
3455
1.30k
            case MAT_C_INT32:
3456
1.30k
                err = ReadCompressedInt32Data(mat, matvar->internal->z, (mat_int32_t *)data,
3457
1.30k
                                              packed_type, N);
3458
1.30k
                break;
3459
4
            case MAT_C_UINT32:
3460
4
                err = ReadCompressedUInt32Data(mat, matvar->internal->z, (mat_uint32_t *)data,
3461
4
                                               packed_type, N);
3462
4
                break;
3463
1.41k
            case MAT_C_INT16:
3464
1.41k
                err = ReadCompressedInt16Data(mat, matvar->internal->z, (mat_int16_t *)data,
3465
1.41k
                                              packed_type, N);
3466
1.41k
                break;
3467
15
            case MAT_C_UINT16:
3468
15
                err = ReadCompressedUInt16Data(mat, matvar->internal->z, (mat_uint16_t *)data,
3469
15
                                               packed_type, N);
3470
15
                break;
3471
1.49k
            case MAT_C_INT8:
3472
1.49k
                err = ReadCompressedInt8Data(mat, matvar->internal->z, (mat_int8_t *)data,
3473
1.49k
                                             packed_type, N);
3474
1.49k
                break;
3475
42
            case MAT_C_UINT8:
3476
42
                err = ReadCompressedUInt8Data(mat, matvar->internal->z, (mat_uint8_t *)data,
3477
42
                                              packed_type, N);
3478
42
                break;
3479
0
            default:
3480
0
                err = MATIO_E_FILE_FORMAT_VIOLATION;
3481
0
                break;
3482
10.2k
        }
3483
10.2k
        if ( err ) {
3484
693
            return err;
3485
693
        }
3486
9.60k
        err = Mul(&nBytes, N, Mat_SizeOf(packed_type));
3487
9.60k
        if ( err ) {
3488
0
            return err;
3489
0
        }
3490
        /*
3491
         * If the data was in the tag we started on a 4-byte
3492
         * boundary so add 4 to make it an 8-byte
3493
         */
3494
9.60k
        if ( data_in_tag )
3495
629
            nBytes += 4;
3496
9.60k
        if ( (nBytes % 8) != 0 )
3497
4.89k
            err = InflateSkip(mat, matvar->internal->z, 8 - (nBytes % 8), NULL);
3498
9.60k
#endif
3499
9.60k
    }
3500
14.1k
    return err;
3501
16.4k
}
3502
3503
/** @brief Validates a UTF-8 character data element
3504
 *
3505
 * Walks @c nbytes bytes of UTF-8 data, verifying that every multi-byte
3506
 * sequence is complete and that the total number of decoded characters
3507
 * equals @c expected. Used by the reader to reject malformed character data
3508
 * before it is handed back to the caller, which may re-wrap the buffer with
3509
 * Mat_VarCreate (which trusts the buffer bounds while recomputing @c nbytes).
3510
 *
3511
 * @ingroup mat_internal
3512
 * @param data pointer to the UTF-8 data
3513
 * @param nbytes number of bytes in @c data
3514
 * @param expected expected number of characters
3515
 * @retval MATIO_E_NO_ERROR if the data is valid, MATIO_E_FILE_FORMAT_VIOLATION otherwise
3516
 */
3517
static int
3518
ValidateUtf8CharData(const mat_uint8_t *data, size_t nbytes, size_t expected)
3519
1.22k
{
3520
1.22k
    size_t i = 0;
3521
1.22k
    size_t nchars = 0;
3522
3523
84.1M
    while ( i < nbytes ) {
3524
84.1M
        const size_t len = Mat_Utf8SeqLen(data[i]);
3525
84.1M
        if ( len == 0 || i + len > nbytes )
3526
0
            return MATIO_E_FILE_FORMAT_VIOLATION;
3527
84.1M
        i += len;
3528
84.1M
        nchars++;
3529
84.1M
    }
3530
3531
1.22k
    if ( nchars != expected )
3532
39
        return MATIO_E_FILE_FORMAT_VIOLATION;
3533
3534
1.19k
    return MATIO_E_NO_ERROR;
3535
1.22k
}
3536
3537
/** @if mat_devman
3538
 * @brief Reads the data of a version 5 MAT variable
3539
 *
3540
 * @ingroup mat_internal
3541
 * @param mat MAT file pointer
3542
 * @param matvar MAT variable pointer to read the data
3543
 * @retval 0 on success
3544
 * @endif
3545
 */
3546
int
3547
Mat_VarRead5(mat_t *mat, matvar_t *matvar)
3548
966k
{
3549
966k
    int byteswap, data_in_tag = 0, err;
3550
966k
    size_t nelems = 1;
3551
966k
    enum matio_types packed_type = MAT_T_UNKNOWN;
3552
966k
    mat_off_t fpos;
3553
966k
    mat_uint32_t tag[2] = {0, 0};
3554
966k
    size_t bytesread = 0;
3555
3556
966k
    if ( matvar == NULL )
3557
0
        return MATIO_E_BAD_ARGUMENT;
3558
966k
    if ( matvar->rank == 0 && matvar->class_type != MAT_C_OPAQUE ) { /* An empty data set */
3559
        /* No data was read for this variable, so it must not claim a
3560
         * data-bearing class.  Discard any empty data container allocated
3561
         * while reading the variable information and normalize the class
3562
         * to keep the variable self-consistent (see issue #341). */
3563
928k
        if ( NULL != matvar->data ) {
3564
13
            free(matvar->data);
3565
13
            matvar->data = NULL;
3566
13
        }
3567
928k
        matvar->class_type = MAT_C_EMPTY;
3568
928k
        return MATIO_E_NO_ERROR;
3569
928k
    }
3570
37.7k
#if HAVE_ZLIB
3571
37.7k
    if ( NULL != matvar->internal->data ) {
3572
        /* Data already read in ReadNextStructField or ReadNextCell */
3573
4.35k
        matvar->data = matvar->internal->data;
3574
4.35k
        matvar->internal->data = NULL;
3575
4.35k
        return MATIO_E_NO_ERROR;
3576
4.35k
    }
3577
33.4k
    if ( matvar->compression == MAT_COMPRESSION_ZLIB && NULL == matvar->internal->z &&
3578
999
         matvar->class_type != MAT_C_STRUCT && matvar->class_type != MAT_C_CELL &&
3579
508
         matvar->class_type != MAT_C_OPAQUE ) {
3580
        /* Element was already consumed while reading the parent (empty data)
3581
         * and its inflate state was released: there is no data to read */
3582
508
        matvar->nbytes = 0;
3583
508
        return MATIO_E_NO_ERROR;
3584
508
    }
3585
32.9k
#endif
3586
32.9k
    fpos = MatTell(mat);
3587
32.9k
    if ( fpos == -1L ) {
3588
0
        Mat_Critical("Couldn't determine file position");
3589
0
        return MATIO_E_GENERIC_READ_ERROR;
3590
0
    }
3591
32.9k
    err = Mat_MulDims(matvar, &nelems);
3592
32.9k
    if ( err ) {
3593
63
        Mat_Critical("Integer multiplication overflow");
3594
63
        return err;
3595
63
    }
3596
32.8k
    byteswap = mat->byteswap;
3597
32.8k
    switch ( matvar->class_type ) {
3598
1.10k
        case MAT_C_EMPTY:
3599
1.10k
            matvar->nbytes = 0;
3600
1.10k
            matvar->data_size = sizeof(double);
3601
1.10k
            matvar->data_type = MAT_T_DOUBLE;
3602
1.10k
            matvar->rank = 2;
3603
1.10k
            if ( NULL != matvar->dims ) {
3604
1.10k
                free(matvar->dims);
3605
1.10k
            }
3606
1.10k
            matvar->dims = (size_t *)calloc(matvar->rank, sizeof(*(matvar->dims)));
3607
1.10k
            break;
3608
4.68k
        case MAT_C_DOUBLE:
3609
4.68k
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3610
4.68k
            matvar->data_size = sizeof(double);
3611
4.68k
            matvar->data_type = MAT_T_DOUBLE;
3612
4.68k
            break;
3613
4.71k
        case MAT_C_SINGLE:
3614
4.71k
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3615
4.71k
            matvar->data_size = sizeof(float);
3616
4.71k
            matvar->data_type = MAT_T_SINGLE;
3617
4.71k
            break;
3618
497
        case MAT_C_INT64:
3619
497
#ifdef HAVE_MAT_INT64_T
3620
497
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3621
497
            matvar->data_size = sizeof(mat_int64_t);
3622
497
            matvar->data_type = MAT_T_INT64;
3623
497
#endif
3624
497
            break;
3625
367
        case MAT_C_UINT64:
3626
367
#ifdef HAVE_MAT_UINT64_T
3627
367
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3628
367
            matvar->data_size = sizeof(mat_uint64_t);
3629
367
            matvar->data_type = MAT_T_UINT64;
3630
367
#endif
3631
367
            break;
3632
2.94k
        case MAT_C_INT32:
3633
2.94k
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3634
2.94k
            matvar->data_size = sizeof(mat_int32_t);
3635
2.94k
            matvar->data_type = MAT_T_INT32;
3636
2.94k
            break;
3637
201
        case MAT_C_UINT32:
3638
201
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3639
201
            matvar->data_size = sizeof(mat_uint32_t);
3640
201
            matvar->data_type = MAT_T_UINT32;
3641
201
            break;
3642
2.04k
        case MAT_C_INT16:
3643
2.04k
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3644
2.04k
            matvar->data_size = sizeof(mat_int16_t);
3645
2.04k
            matvar->data_type = MAT_T_INT16;
3646
2.04k
            break;
3647
137
        case MAT_C_UINT16:
3648
137
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3649
137
            matvar->data_size = sizeof(mat_uint16_t);
3650
137
            matvar->data_type = MAT_T_UINT16;
3651
137
            break;
3652
2.08k
        case MAT_C_INT8:
3653
2.08k
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3654
2.08k
            matvar->data_size = sizeof(mat_int8_t);
3655
2.08k
            matvar->data_type = MAT_T_INT8;
3656
2.08k
            break;
3657
229
        case MAT_C_UINT8:
3658
229
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3659
229
            matvar->data_size = sizeof(mat_uint8_t);
3660
229
            matvar->data_type = MAT_T_UINT8;
3661
229
            break;
3662
1.99k
        case MAT_C_CHAR:
3663
1.99k
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3664
1.99k
            if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
3665
1.28k
#if HAVE_ZLIB
3666
1.28k
                if ( matvar->internal->z == NULL ) {
3667
0
                    break;
3668
0
                }
3669
1.28k
                matvar->internal->z->avail_in = 0;
3670
1.28k
                err = Inflate(mat, matvar->internal->z, tag, 4, &bytesread);
3671
1.28k
                if ( err ) {
3672
0
                    break;
3673
0
                }
3674
1.28k
                if ( byteswap )
3675
1.24k
                    (void)Mat_uint32Swap(tag);
3676
1.28k
                packed_type = TYPE_FROM_TAG(tag[0]);
3677
1.28k
                if ( tag[0] & 0xffff0000 ) { /* Data is in the tag */
3678
478
                    data_in_tag = 1;
3679
478
                    matvar->nbytes = (tag[0] & 0xffff0000) >> 16;
3680
806
                } else {
3681
806
                    data_in_tag = 0;
3682
806
                    err = Inflate(mat, matvar->internal->z, tag + 1, 4, &bytesread);
3683
806
                    if ( err ) {
3684
0
                        break;
3685
0
                    }
3686
806
                    if ( byteswap )
3687
764
                        (void)Mat_uint32Swap(tag + 1);
3688
806
                    matvar->nbytes = tag[1];
3689
806
                }
3690
#else
3691
                matvar->nbytes = 0;
3692
#endif
3693
1.28k
                matvar->data_type = packed_type;
3694
1.28k
                matvar->data_size = Mat_SizeOf(matvar->data_type);
3695
1.28k
            } else {
3696
713
                err = Read(tag, 4, 1, mat, &bytesread);
3697
713
                if ( err ) {
3698
0
                    break;
3699
0
                }
3700
713
                if ( byteswap )
3701
669
                    (void)Mat_uint32Swap(tag);
3702
713
                packed_type = TYPE_FROM_TAG(tag[0]);
3703
713
                if ( tag[0] & 0xffff0000 ) { /* Data is in the tag */
3704
9
                    data_in_tag = 1;
3705
9
                    matvar->nbytes = (tag[0] & 0xffff0000) >> 16;
3706
704
                } else {
3707
704
                    data_in_tag = 0;
3708
704
                    err = Read(tag + 1, 4, 1, mat, &bytesread);
3709
704
                    if ( err ) {
3710
0
                        break;
3711
0
                    }
3712
704
                    if ( byteswap )
3713
660
                        (void)Mat_uint32Swap(tag + 1);
3714
704
                    matvar->nbytes = tag[1];
3715
704
                }
3716
713
                matvar->data_type = packed_type;
3717
713
                matvar->data_size = Mat_SizeOf(matvar->data_type);
3718
713
            }
3719
1.99k
            if ( matvar->isComplex ) {
3720
8
                break;
3721
8
            }
3722
1.98k
            if ( 0 == matvar->nbytes ) {
3723
0
                break;
3724
0
            }
3725
1.98k
            matvar->data = calloc(matvar->nbytes, 1);
3726
1.98k
            if ( NULL == matvar->data ) {
3727
0
                err = MATIO_E_OUT_OF_MEMORY;
3728
0
                Mat_Critical("Couldn't allocate memory for the data");
3729
0
                break;
3730
0
            }
3731
1.98k
            {
3732
1.98k
                size_t nbytes = 0;
3733
1.98k
                err = Mul(&nbytes, nelems, matvar->data_size);
3734
1.98k
                if ( err || nbytes > matvar->nbytes ) {
3735
18
                    free(matvar->data);
3736
18
                    matvar->data = NULL;
3737
18
                    matvar->nbytes = 0;
3738
18
                    break;
3739
18
                }
3740
1.98k
            }
3741
1.97k
            if ( matvar->data_type == MAT_T_UTF8 ) {
3742
1.25k
                nelems = matvar->nbytes;
3743
1.25k
            }
3744
1.97k
            if ( matvar->compression == MAT_COMPRESSION_NONE ) {
3745
693
                size_t nBytes;
3746
693
                err = ReadCharData(mat, matvar->data, matvar->data_type, nelems);
3747
693
                if ( err ) {
3748
23
                    free(matvar->data);
3749
23
                    matvar->data = NULL;
3750
23
                    matvar->nbytes = 0;
3751
23
                    break;
3752
23
                }
3753
670
                err = Mul(&nBytes, nelems, Mat_SizeOf(matvar->data_type));
3754
670
                if ( err ) {
3755
0
                    free(matvar->data);
3756
0
                    matvar->data = NULL;
3757
0
                    matvar->nbytes = 0;
3758
0
                    break;
3759
0
                }
3760
                /*
3761
                 * If the data was in the tag we started on a 4-byte
3762
                 * boundary so add 4 to make it an 8-byte
3763
                 */
3764
670
                if ( data_in_tag )
3765
0
                    nBytes += 4;
3766
670
                if ( (nBytes % 8) != 0 )
3767
652
                    (void)MatSeek(mat, 8 - (nBytes % 8), SEEK_CUR);
3768
670
#if HAVE_ZLIB
3769
1.27k
            } else if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
3770
1.27k
                size_t nBytes;
3771
1.27k
                err = ReadCompressedCharData(mat, matvar->internal->z, matvar->data,
3772
1.27k
                                             matvar->data_type, nelems);
3773
1.27k
                if ( err ) {
3774
49
                    free(matvar->data);
3775
49
                    matvar->data = NULL;
3776
49
                    matvar->nbytes = 0;
3777
49
                    break;
3778
49
                }
3779
1.22k
                err = Mul(&nBytes, nelems, Mat_SizeOf(matvar->data_type));
3780
1.22k
                if ( err ) {
3781
0
                    free(matvar->data);
3782
0
                    matvar->data = NULL;
3783
0
                    matvar->nbytes = 0;
3784
0
                    break;
3785
0
                }
3786
                /*
3787
                 * If the data was in the tag we started on a 4-byte
3788
                 * boundary so add 4 to make it an 8-byte
3789
                 */
3790
1.22k
                if ( data_in_tag )
3791
454
                    nBytes += 4;
3792
1.22k
                if ( (nBytes % 8) != 0 )
3793
1.18k
                    err = InflateSkip(mat, matvar->internal->z, 8 - (nBytes % 8), NULL);
3794
1.22k
                if ( err ) {
3795
0
                    free(matvar->data);
3796
0
                    matvar->data = NULL;
3797
0
                    matvar->nbytes = 0;
3798
0
                    break;
3799
0
                }
3800
1.22k
#endif
3801
1.22k
            }
3802
1.89k
            if ( matvar->data_type == MAT_T_UTF8 ) {
3803
1.22k
                size_t nchars = 1;
3804
1.22k
                err = Mat_MulDims(matvar, &nchars);
3805
1.22k
                if ( !err )
3806
1.22k
                    err = ValidateUtf8CharData((const mat_uint8_t *)matvar->data, matvar->nbytes,
3807
1.22k
                                               nchars);
3808
1.22k
                if ( err ) {
3809
39
                    free(matvar->data);
3810
39
                    matvar->data = NULL;
3811
39
                    matvar->nbytes = 0;
3812
39
                }
3813
1.22k
            }
3814
1.89k
            break;
3815
2.31k
        case MAT_C_STRUCT: {
3816
2.31k
            matvar_t **fields;
3817
2.31k
            size_t i, nelems_x_nfields;
3818
3819
2.31k
            matvar->data_type = MAT_T_STRUCT;
3820
2.31k
            err = Mul(&nelems_x_nfields, nelems, matvar->internal->num_fields);
3821
2.31k
            if ( err )
3822
0
                break;
3823
2.31k
            if ( !matvar->nbytes || !matvar->data_size || NULL == matvar->data ) {
3824
169
                if ( nelems_x_nfields > 0 ) {
3825
1
                    Mat_Critical("Data is NULL for struct %s", matvar->name);
3826
1
                    err = MATIO_E_FILE_FORMAT_VIOLATION;
3827
1
                }
3828
169
                break;
3829
169
            }
3830
2.14k
            fields = (matvar_t **)matvar->data;
3831
17.7M
            for ( i = 0; i < nelems_x_nfields; i++ ) {
3832
17.7M
                if ( NULL != fields[i] ) {
3833
934k
                    err = Mat_VarRead5(mat, fields[i]);
3834
934k
                    if ( err )
3835
623
                        break;
3836
934k
                }
3837
17.7M
            }
3838
2.14k
            break;
3839
2.31k
        }
3840
4.49k
        case MAT_C_CELL: {
3841
4.49k
            matvar_t **cells;
3842
4.49k
            size_t i;
3843
3844
4.49k
            matvar->data_type = MAT_T_CELL;
3845
4.49k
            if ( NULL == matvar->data ) {
3846
57
                if ( nelems > 0 ) {
3847
4
                    Mat_Critical("Data is NULL for cell array %s", matvar->name);
3848
4
                    err = MATIO_E_FILE_FORMAT_VIOLATION;
3849
4
                }
3850
57
                break;
3851
57
            }
3852
4.43k
            cells = (matvar_t **)matvar->data;
3853
2.72M
            for ( i = 0; i < nelems; i++ ) {
3854
2.72M
                if ( NULL != cells[i] ) {
3855
10.4k
                    err = Mat_VarRead5(mat, cells[i]);
3856
10.4k
                    if ( err )
3857
1.31k
                        break;
3858
10.4k
                }
3859
2.72M
            }
3860
4.43k
            matvar->data_type = MAT_T_CELL;
3861
4.43k
            break;
3862
4.49k
        }
3863
4.92k
        case MAT_C_SPARSE: {
3864
4.92k
            mat_uint32_t N = 0;
3865
4.92k
            mat_sparse_t *sparse;
3866
3867
4.92k
            matvar->data_size = sizeof(mat_sparse_t);
3868
4.92k
            matvar->data = calloc(1, matvar->data_size);
3869
4.92k
            if ( matvar->data == NULL ) {
3870
0
                err = MATIO_E_OUT_OF_MEMORY;
3871
0
                Mat_Critical("Mat_VarRead5: Allocation of data pointer failed");
3872
0
                break;
3873
0
            }
3874
4.92k
            sparse = (mat_sparse_t *)matvar->data;
3875
4.92k
            sparse->nzmax = matvar->nbytes;
3876
4.92k
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
3877
            /*  Read ir    */
3878
4.92k
            err = ReadSparse(mat, matvar, &sparse->nir, &sparse->ir);
3879
4.92k
            if ( err ) {
3880
164
                free(sparse->ir);
3881
164
                free(matvar->data);
3882
164
                matvar->data = NULL;
3883
164
                break;
3884
164
            }
3885
            /*  Read jc    */
3886
4.76k
            err = ReadSparse(mat, matvar, &sparse->njc, &sparse->jc);
3887
4.76k
            if ( err ) {
3888
403
                free(sparse->jc);
3889
403
                free(sparse->ir);
3890
403
                free(matvar->data);
3891
403
                matvar->data = NULL;
3892
403
                break;
3893
403
            }
3894
            /*  Read data  */
3895
4.35k
            if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
3896
513
#if HAVE_ZLIB
3897
513
                matvar->internal->z->avail_in = 0;
3898
513
                err = Inflate(mat, matvar->internal->z, tag, 4, &bytesread);
3899
513
                if ( err ) {
3900
0
                    free(sparse->jc);
3901
0
                    free(sparse->ir);
3902
0
                    free(matvar->data);
3903
0
                    matvar->data = NULL;
3904
0
                    break;
3905
0
                }
3906
513
                if ( mat->byteswap )
3907
501
                    (void)Mat_uint32Swap(tag);
3908
513
                packed_type = TYPE_FROM_TAG(tag[0]);
3909
513
                if ( tag[0] & 0xffff0000 ) { /* Data is in the tag */
3910
419
                    data_in_tag = 1;
3911
419
                    N = (tag[0] & 0xffff0000) >> 16;
3912
419
                } else {
3913
94
                    data_in_tag = 0;
3914
94
                    err = ReadCompressedUInt32Data(mat, matvar->internal->z, &N, MAT_T_UINT32, 1);
3915
94
                }
3916
513
#endif
3917
3.84k
            } else {
3918
3.84k
                err = Read(tag, 4, 1, mat, &bytesread);
3919
3.84k
                if ( err ) {
3920
0
                    free(sparse->jc);
3921
0
                    free(sparse->ir);
3922
0
                    free(matvar->data);
3923
0
                    matvar->data = NULL;
3924
0
                    break;
3925
0
                }
3926
3.84k
                if ( mat->byteswap )
3927
996
                    (void)Mat_uint32Swap(tag);
3928
3.84k
                packed_type = TYPE_FROM_TAG(tag[0]);
3929
3.84k
                if ( tag[0] & 0xffff0000 ) { /* Data is in the tag */
3930
3.28k
                    data_in_tag = 1;
3931
3.28k
                    N = (tag[0] & 0xffff0000) >> 16;
3932
3.28k
                } else {
3933
556
                    data_in_tag = 0;
3934
556
                    err = Read(&N, 4, 1, mat, &bytesread);
3935
556
                    if ( err ) {
3936
0
                        free(sparse->jc);
3937
0
                        free(sparse->ir);
3938
0
                        free(matvar->data);
3939
0
                        matvar->data = NULL;
3940
0
                        break;
3941
0
                    }
3942
556
                    if ( mat->byteswap )
3943
392
                        (void)Mat_uint32Swap(&N);
3944
556
                }
3945
3.84k
            }
3946
4.35k
            if ( matvar->isLogical && packed_type == MAT_T_DOUBLE ) {
3947
                /* For some reason, MAT says the data type is a double,
3948
                 * but it appears to be written as 8-bit unsigned integer.
3949
                 */
3950
614
                packed_type = MAT_T_UINT8;
3951
614
            }
3952
4.35k
#if defined(EXTENDED_SPARSE)
3953
4.35k
            matvar->data_type = packed_type;
3954
#else
3955
            matvar->data_type = MAT_T_DOUBLE;
3956
#endif
3957
4.35k
            {
3958
4.35k
                size_t s_type = Mat_SizeOf(packed_type);
3959
4.35k
                if ( s_type == 0 ) {
3960
202
                    err = MATIO_E_FILE_FORMAT_VIOLATION;
3961
202
                    break;
3962
202
                }
3963
4.15k
                sparse->ndata = N / s_type;
3964
4.15k
            }
3965
4.15k
            if ( matvar->isComplex ) {
3966
4.09k
                mat_complex_split_t *complex_data;
3967
4.09k
                size_t nBytes = 0;
3968
4.09k
                err = Mul(&nBytes, sparse->ndata, Mat_SizeOf(matvar->data_type));
3969
4.09k
                if ( err ) {
3970
0
                    Mat_Critical("Integer multiplication overflow");
3971
0
                    break;
3972
0
                }
3973
4.09k
                complex_data = ComplexCalloc(nBytes);
3974
4.09k
                if ( NULL == complex_data ) {
3975
0
                    err = MATIO_E_OUT_OF_MEMORY;
3976
0
                    Mat_Critical("Couldn't allocate memory for the complex sparse data");
3977
0
                    break;
3978
0
                }
3979
4.09k
                if ( matvar->compression == MAT_COMPRESSION_NONE ) {
3980
3.62k
#if defined(EXTENDED_SPARSE)
3981
3.62k
                    switch ( matvar->data_type ) {
3982
3
                        case MAT_T_DOUBLE:
3983
3
                            err = ReadDoubleData(mat, (double *)complex_data->Re, packed_type,
3984
3
                                                 sparse->ndata);
3985
3
                            break;
3986
486
                        case MAT_T_SINGLE:
3987
486
                            err = ReadSingleData(mat, (float *)complex_data->Re, packed_type,
3988
486
                                                 sparse->ndata);
3989
486
                            break;
3990
293
                        case MAT_T_INT64:
3991
293
#ifdef HAVE_MAT_INT64_T
3992
293
                            err = ReadInt64Data(mat, (mat_int64_t *)complex_data->Re, packed_type,
3993
293
                                                sparse->ndata);
3994
293
#endif
3995
293
                            break;
3996
749
                        case MAT_T_UINT64:
3997
749
#ifdef HAVE_MAT_UINT64_T
3998
749
                            err = ReadUInt64Data(mat, (mat_uint64_t *)complex_data->Re, packed_type,
3999
749
                                                 sparse->ndata);
4000
749
#endif
4001
749
                            break;
4002
270
                        case MAT_T_INT32:
4003
270
                            err = ReadInt32Data(mat, (mat_int32_t *)complex_data->Re, packed_type,
4004
270
                                                sparse->ndata);
4005
270
                            break;
4006
27
                        case MAT_T_UINT32:
4007
27
                            err = ReadUInt32Data(mat, (mat_uint32_t *)complex_data->Re, packed_type,
4008
27
                                                 sparse->ndata);
4009
27
                            break;
4010
132
                        case MAT_T_INT16:
4011
132
                            err = ReadInt16Data(mat, (mat_int16_t *)complex_data->Re, packed_type,
4012
132
                                                sparse->ndata);
4013
132
                            break;
4014
415
                        case MAT_T_UINT16:
4015
415
                            err = ReadUInt16Data(mat, (mat_uint16_t *)complex_data->Re, packed_type,
4016
415
                                                 sparse->ndata);
4017
415
                            break;
4018
358
                        case MAT_T_INT8:
4019
358
                            err = ReadInt8Data(mat, (mat_int8_t *)complex_data->Re, packed_type,
4020
358
                                               sparse->ndata);
4021
358
                            break;
4022
879
                        case MAT_T_UINT8:
4023
879
                            err = ReadUInt8Data(mat, (mat_uint8_t *)complex_data->Re, packed_type,
4024
879
                                                sparse->ndata);
4025
879
                            break;
4026
8
                        default:
4027
8
                            err = MATIO_E_FILE_FORMAT_VIOLATION;
4028
8
                            break;
4029
3.62k
                    }
4030
#else
4031
                    err =
4032
                        ReadDoubleData(mat, (double *)complex_data->Re, packed_type, sparse->ndata);
4033
#endif
4034
3.62k
                    if ( err ) {
4035
51
                        ComplexFree(complex_data);
4036
51
                        break;
4037
51
                    }
4038
3.56k
                    err = Mul(&nBytes, sparse->ndata, Mat_SizeOf(packed_type));
4039
3.56k
                    if ( err ) {
4040
0
                        ComplexFree(complex_data);
4041
0
                        break;
4042
0
                    }
4043
3.56k
                    if ( data_in_tag )
4044
3.14k
                        nBytes += 4;
4045
3.56k
                    if ( (nBytes % 8) != 0 )
4046
2.89k
                        (void)MatSeek(mat, 8 - (nBytes % 8), SEEK_CUR);
4047
                    /* Complex Data Tag */
4048
3.56k
                    err = Read(tag, 4, 1, mat, &bytesread);
4049
3.56k
                    if ( err ) {
4050
0
                        ComplexFree(complex_data);
4051
0
                        break;
4052
0
                    }
4053
3.56k
                    if ( byteswap )
4054
795
                        (void)Mat_uint32Swap(tag);
4055
3.56k
                    packed_type = TYPE_FROM_TAG(tag[0]);
4056
3.56k
                    if ( tag[0] & 0xffff0000 ) { /* Data is in the tag */
4057
3.12k
                        data_in_tag = 1;
4058
3.12k
                    } else {
4059
446
                        data_in_tag = 0;
4060
446
                        err = Read(tag + 1, 4, 1, mat, &bytesread);
4061
446
                        if ( err ) {
4062
11
                            ComplexFree(complex_data);
4063
11
                            break;
4064
11
                        }
4065
435
                        if ( byteswap )
4066
264
                            (void)Mat_uint32Swap(tag + 1);
4067
435
                    }
4068
3.55k
#if defined(EXTENDED_SPARSE)
4069
3.55k
                    switch ( matvar->data_type ) {
4070
3
                        case MAT_T_DOUBLE:
4071
3
                            err = ReadDoubleData(mat, (double *)complex_data->Im, packed_type,
4072
3
                                                 sparse->ndata);
4073
3
                            break;
4074
486
                        case MAT_T_SINGLE:
4075
486
                            err = ReadSingleData(mat, (float *)complex_data->Im, packed_type,
4076
486
                                                 sparse->ndata);
4077
486
                            break;
4078
285
                        case MAT_T_INT64:
4079
285
#ifdef HAVE_MAT_INT64_T
4080
285
                            err = ReadInt64Data(mat, (mat_int64_t *)complex_data->Im, packed_type,
4081
285
                                                sparse->ndata);
4082
285
#endif
4083
285
                            break;
4084
749
                        case MAT_T_UINT64:
4085
749
#ifdef HAVE_MAT_UINT64_T
4086
749
                            err = ReadUInt64Data(mat, (mat_uint64_t *)complex_data->Im, packed_type,
4087
749
                                                 sparse->ndata);
4088
749
#endif
4089
749
                            break;
4090
270
                        case MAT_T_INT32:
4091
270
                            err = ReadInt32Data(mat, (mat_int32_t *)complex_data->Im, packed_type,
4092
270
                                                sparse->ndata);
4093
270
                            break;
4094
27
                        case MAT_T_UINT32:
4095
27
                            err = ReadUInt32Data(mat, (mat_uint32_t *)complex_data->Im, packed_type,
4096
27
                                                 sparse->ndata);
4097
27
                            break;
4098
124
                        case MAT_T_INT16:
4099
124
                            err = ReadInt16Data(mat, (mat_int16_t *)complex_data->Im, packed_type,
4100
124
                                                sparse->ndata);
4101
124
                            break;
4102
415
                        case MAT_T_UINT16:
4103
415
                            err = ReadUInt16Data(mat, (mat_uint16_t *)complex_data->Im, packed_type,
4104
415
                                                 sparse->ndata);
4105
415
                            break;
4106
333
                        case MAT_T_INT8:
4107
333
                            err = ReadInt8Data(mat, (mat_int8_t *)complex_data->Im, packed_type,
4108
333
                                               sparse->ndata);
4109
333
                            break;
4110
866
                        case MAT_T_UINT8:
4111
866
                            err = ReadUInt8Data(mat, (mat_uint8_t *)complex_data->Im, packed_type,
4112
866
                                                sparse->ndata);
4113
866
                            break;
4114
0
                        default:
4115
0
                            err = MATIO_E_FILE_FORMAT_VIOLATION;
4116
0
                            break;
4117
3.55k
                    }
4118
#else  /* EXTENDED_SPARSE */
4119
                    err =
4120
                        ReadDoubleData(mat, (double *)complex_data->Im, packed_type, sparse->ndata);
4121
#endif /* EXTENDED_SPARSE */
4122
3.55k
                    if ( err ) {
4123
701
                        ComplexFree(complex_data);
4124
701
                        break;
4125
701
                    }
4126
2.85k
                    err = Mul(&nBytes, sparse->ndata, Mat_SizeOf(packed_type));
4127
2.85k
                    if ( err ) {
4128
0
                        ComplexFree(complex_data);
4129
0
                        break;
4130
0
                    }
4131
2.85k
                    if ( data_in_tag )
4132
2.52k
                        nBytes += 4;
4133
2.85k
                    if ( (nBytes % 8) != 0 )
4134
2.05k
                        (void)MatSeek(mat, 8 - (nBytes % 8), SEEK_CUR);
4135
2.85k
#if HAVE_ZLIB
4136
2.85k
                } else if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
4137
470
#if defined(EXTENDED_SPARSE)
4138
470
                    switch ( matvar->data_type ) {
4139
0
                        case MAT_T_DOUBLE:
4140
0
                            err = ReadCompressedDoubleData(mat, matvar->internal->z,
4141
0
                                                           (double *)complex_data->Re, packed_type,
4142
0
                                                           sparse->ndata);
4143
0
                            break;
4144
74
                        case MAT_T_SINGLE:
4145
74
                            err = ReadCompressedSingleData(mat, matvar->internal->z,
4146
74
                                                           (float *)complex_data->Re, packed_type,
4147
74
                                                           sparse->ndata);
4148
74
                            break;
4149
44
                        case MAT_T_INT64:
4150
44
#ifdef HAVE_MAT_INT64_T
4151
44
                            err = ReadCompressedInt64Data(mat, matvar->internal->z,
4152
44
                                                          (mat_int64_t *)complex_data->Re,
4153
44
                                                          packed_type, sparse->ndata);
4154
44
#endif
4155
44
                            break;
4156
36
                        case MAT_T_UINT64:
4157
36
#ifdef HAVE_MAT_UINT64_T
4158
36
                            err = ReadCompressedUInt64Data(mat, matvar->internal->z,
4159
36
                                                           (mat_uint64_t *)complex_data->Re,
4160
36
                                                           packed_type, sparse->ndata);
4161
36
#endif
4162
36
                            break;
4163
28
                        case MAT_T_INT32:
4164
28
                            err = ReadCompressedInt32Data(mat, matvar->internal->z,
4165
28
                                                          (mat_int32_t *)complex_data->Re,
4166
28
                                                          packed_type, sparse->ndata);
4167
28
                            break;
4168
6
                        case MAT_T_UINT32:
4169
6
                            err = ReadCompressedUInt32Data(mat, matvar->internal->z,
4170
6
                                                           (mat_uint32_t *)complex_data->Re,
4171
6
                                                           packed_type, sparse->ndata);
4172
6
                            break;
4173
64
                        case MAT_T_INT16:
4174
64
                            err = ReadCompressedInt16Data(mat, matvar->internal->z,
4175
64
                                                          (mat_int16_t *)complex_data->Re,
4176
64
                                                          packed_type, sparse->ndata);
4177
64
                            break;
4178
94
                        case MAT_T_UINT16:
4179
94
                            err = ReadCompressedUInt16Data(mat, matvar->internal->z,
4180
94
                                                           (mat_uint16_t *)complex_data->Re,
4181
94
                                                           packed_type, sparse->ndata);
4182
94
                            break;
4183
57
                        case MAT_T_INT8:
4184
57
                            err = ReadCompressedInt8Data(mat, matvar->internal->z,
4185
57
                                                         (mat_int8_t *)complex_data->Re,
4186
57
                                                         packed_type, sparse->ndata);
4187
57
                            break;
4188
66
                        case MAT_T_UINT8:
4189
66
                            err = ReadCompressedUInt8Data(mat, matvar->internal->z,
4190
66
                                                          (mat_uint8_t *)complex_data->Re,
4191
66
                                                          packed_type, sparse->ndata);
4192
66
                            break;
4193
1
                        default:
4194
1
                            err = MATIO_E_FILE_FORMAT_VIOLATION;
4195
1
                            break;
4196
470
                    }
4197
#else  /* EXTENDED_SPARSE */
4198
                    err = ReadCompressedDoubleData(mat, matvar->internal->z,
4199
                                                   (double *)complex_data->Re, packed_type,
4200
                                                   sparse->ndata);
4201
#endif /* EXTENDED_SPARSE */
4202
470
                    if ( err ) {
4203
7
                        ComplexFree(complex_data);
4204
7
                        break;
4205
7
                    }
4206
463
                    err = Mul(&nBytes, sparse->ndata, Mat_SizeOf(packed_type));
4207
463
                    if ( err ) {
4208
0
                        ComplexFree(complex_data);
4209
0
                        break;
4210
0
                    }
4211
463
                    if ( data_in_tag )
4212
402
                        nBytes += 4;
4213
463
                    if ( (nBytes % 8) != 0 )
4214
358
                        err = InflateSkip(mat, matvar->internal->z, 8 - (nBytes % 8), NULL);
4215
463
                    if ( err ) {
4216
0
                        ComplexFree(complex_data);
4217
0
                        break;
4218
0
                    }
4219
4220
                    /* Complex Data Tag */
4221
463
                    err = Inflate(mat, matvar->internal->z, tag, 4, NULL);
4222
463
                    if ( err ) {
4223
2
                        ComplexFree(complex_data);
4224
2
                        break;
4225
2
                    }
4226
461
                    if ( byteswap )
4227
453
                        (void)Mat_uint32Swap(tag);
4228
4229
461
                    packed_type = TYPE_FROM_TAG(tag[0]);
4230
461
                    if ( tag[0] & 0xffff0000 ) { /* Data is in the tag */
4231
420
                        data_in_tag = 1;
4232
420
                    } else {
4233
41
                        data_in_tag = 0;
4234
41
                        err = Inflate(mat, matvar->internal->z, tag + 1, 4, NULL);
4235
41
                        if ( err ) {
4236
0
                            ComplexFree(complex_data);
4237
0
                            break;
4238
0
                        }
4239
41
                        if ( byteswap )
4240
41
                            (void)Mat_uint32Swap(tag + 1);
4241
41
                    }
4242
461
#if defined(EXTENDED_SPARSE)
4243
461
                    switch ( matvar->data_type ) {
4244
0
                        case MAT_T_DOUBLE:
4245
0
                            err = ReadCompressedDoubleData(mat, matvar->internal->z,
4246
0
                                                           (double *)complex_data->Im, packed_type,
4247
0
                                                           sparse->ndata);
4248
0
                            break;
4249
74
                        case MAT_T_SINGLE:
4250
74
                            err = ReadCompressedSingleData(mat, matvar->internal->z,
4251
74
                                                           (float *)complex_data->Im, packed_type,
4252
74
                                                           sparse->ndata);
4253
74
                            break;
4254
44
                        case MAT_T_INT64:
4255
44
#ifdef HAVE_MAT_INT64_T
4256
44
                            err = ReadCompressedInt64Data(mat, matvar->internal->z,
4257
44
                                                          (mat_int64_t *)complex_data->Im,
4258
44
                                                          packed_type, sparse->ndata);
4259
44
#endif
4260
44
                            break;
4261
36
                        case MAT_T_UINT64:
4262
36
#ifdef HAVE_MAT_UINT64_T
4263
36
                            err = ReadCompressedUInt64Data(mat, matvar->internal->z,
4264
36
                                                           (mat_uint64_t *)complex_data->Im,
4265
36
                                                           packed_type, sparse->ndata);
4266
36
#endif
4267
36
                            break;
4268
28
                        case MAT_T_INT32:
4269
28
                            err = ReadCompressedInt32Data(mat, matvar->internal->z,
4270
28
                                                          (mat_int32_t *)complex_data->Im,
4271
28
                                                          packed_type, sparse->ndata);
4272
28
                            break;
4273
6
                        case MAT_T_UINT32:
4274
6
                            err = ReadCompressedUInt32Data(mat, matvar->internal->z,
4275
6
                                                           (mat_uint32_t *)complex_data->Im,
4276
6
                                                           packed_type, sparse->ndata);
4277
6
                            break;
4278
64
                        case MAT_T_INT16:
4279
64
                            err = ReadCompressedInt16Data(mat, matvar->internal->z,
4280
64
                                                          (mat_int16_t *)complex_data->Im,
4281
64
                                                          packed_type, sparse->ndata);
4282
64
                            break;
4283
90
                        case MAT_T_UINT16:
4284
90
                            err = ReadCompressedUInt16Data(mat, matvar->internal->z,
4285
90
                                                           (mat_uint16_t *)complex_data->Im,
4286
90
                                                           packed_type, sparse->ndata);
4287
90
                            break;
4288
55
                        case MAT_T_INT8:
4289
55
                            err = ReadCompressedInt8Data(mat, matvar->internal->z,
4290
55
                                                         (mat_int8_t *)complex_data->Im,
4291
55
                                                         packed_type, sparse->ndata);
4292
55
                            break;
4293
64
                        case MAT_T_UINT8:
4294
64
                            err = ReadCompressedUInt8Data(mat, matvar->internal->z,
4295
64
                                                          (mat_uint8_t *)complex_data->Im,
4296
64
                                                          packed_type, sparse->ndata);
4297
64
                            break;
4298
0
                        default:
4299
0
                            err = MATIO_E_FILE_FORMAT_VIOLATION;
4300
0
                            break;
4301
461
                    }
4302
#else  /* EXTENDED_SPARSE */
4303
                    err = ReadCompressedDoubleData(mat, matvar->internal->z,
4304
                                                   (double *)complex_data->Im, packed_type,
4305
                                                   sparse->ndata);
4306
#endif /* EXTENDED_SPARSE */
4307
461
                    if ( err ) {
4308
156
                        ComplexFree(complex_data);
4309
156
                        break;
4310
156
                    }
4311
305
                    err = Mul(&nBytes, sparse->ndata, Mat_SizeOf(packed_type));
4312
305
                    if ( err ) {
4313
0
                        ComplexFree(complex_data);
4314
0
                        break;
4315
0
                    }
4316
305
                    if ( data_in_tag )
4317
291
                        nBytes += 4;
4318
305
                    if ( (nBytes % 8) != 0 )
4319
250
                        err = InflateSkip(mat, matvar->internal->z, 8 - (nBytes % 8), NULL);
4320
305
                    if ( err ) {
4321
2
                        ComplexFree(complex_data);
4322
2
                        break;
4323
2
                    }
4324
305
#endif /* HAVE_ZLIB */
4325
305
                }
4326
3.16k
                sparse->data = complex_data;
4327
3.16k
            } else { /* isComplex */
4328
65
                size_t nBytes = 0;
4329
65
                err = Mul(&nBytes, sparse->ndata, Mat_SizeOf(matvar->data_type));
4330
65
                if ( err ) {
4331
0
                    Mat_Critical("Integer multiplication overflow");
4332
0
                    break;
4333
0
                }
4334
65
                if ( nBytes > 0 ) {
4335
64
                    sparse->data = malloc(nBytes);
4336
64
                    if ( sparse->data == NULL ) {
4337
0
                        err = MATIO_E_OUT_OF_MEMORY;
4338
0
                        Mat_Critical("Couldn't allocate memory for the sparse data");
4339
0
                        break;
4340
0
                    }
4341
64
                }
4342
65
                if ( matvar->compression == MAT_COMPRESSION_NONE && nBytes > 0 ) {
4343
42
#if defined(EXTENDED_SPARSE)
4344
42
                    switch ( matvar->data_type ) {
4345
8
                        case MAT_T_DOUBLE:
4346
8
                            err = ReadDoubleData(mat, (double *)sparse->data, packed_type,
4347
8
                                                 sparse->ndata);
4348
8
                            break;
4349
0
                        case MAT_T_SINGLE:
4350
0
                            err = ReadSingleData(mat, (float *)sparse->data, packed_type,
4351
0
                                                 sparse->ndata);
4352
0
                            break;
4353
8
                        case MAT_T_INT64:
4354
8
#ifdef HAVE_MAT_INT64_T
4355
8
                            err = ReadInt64Data(mat, (mat_int64_t *)sparse->data, packed_type,
4356
8
                                                sparse->ndata);
4357
8
#endif
4358
8
                            break;
4359
6
                        case MAT_T_UINT64:
4360
6
#ifdef HAVE_MAT_UINT64_T
4361
6
                            err = ReadUInt64Data(mat, (mat_uint64_t *)sparse->data, packed_type,
4362
6
                                                 sparse->ndata);
4363
6
#endif
4364
6
                            break;
4365
0
                        case MAT_T_INT32:
4366
0
                            err = ReadInt32Data(mat, (mat_int32_t *)sparse->data, packed_type,
4367
0
                                                sparse->ndata);
4368
0
                            break;
4369
9
                        case MAT_T_UINT32:
4370
9
                            err = ReadUInt32Data(mat, (mat_uint32_t *)sparse->data, packed_type,
4371
9
                                                 sparse->ndata);
4372
9
                            break;
4373
3
                        case MAT_T_INT16:
4374
3
                            err = ReadInt16Data(mat, (mat_int16_t *)sparse->data, packed_type,
4375
3
                                                sparse->ndata);
4376
3
                            break;
4377
0
                        case MAT_T_UINT16:
4378
0
                            err = ReadUInt16Data(mat, (mat_uint16_t *)sparse->data, packed_type,
4379
0
                                                 sparse->ndata);
4380
0
                            break;
4381
2
                        case MAT_T_INT8:
4382
2
                            err = ReadInt8Data(mat, (mat_int8_t *)sparse->data, packed_type,
4383
2
                                               sparse->ndata);
4384
2
                            break;
4385
6
                        case MAT_T_UINT8:
4386
6
                            err = ReadUInt8Data(mat, (mat_uint8_t *)sparse->data, packed_type,
4387
6
                                                sparse->ndata);
4388
6
                            break;
4389
0
                        default:
4390
0
                            err = MATIO_E_FILE_FORMAT_VIOLATION;
4391
0
                            break;
4392
42
                    }
4393
#else
4394
                    err = ReadDoubleData(mat, (double *)sparse->data, packed_type, sparse->ndata);
4395
#endif
4396
42
                    if ( err ) {
4397
8
                        free(sparse->data);
4398
8
                        sparse->data = NULL;
4399
8
                        break;
4400
8
                    }
4401
34
                    err = Mul(&nBytes, sparse->ndata, Mat_SizeOf(packed_type));
4402
34
                    if ( err ) {
4403
0
                        free(sparse->data);
4404
0
                        sparse->data = NULL;
4405
0
                        break;
4406
0
                    }
4407
34
                    if ( data_in_tag )
4408
17
                        nBytes += 4;
4409
34
                    if ( (nBytes % 8) != 0 )
4410
25
                        (void)MatSeek(mat, 8 - (nBytes % 8), SEEK_CUR);
4411
34
#if HAVE_ZLIB
4412
34
                } else if ( matvar->compression == MAT_COMPRESSION_ZLIB && nBytes > 0 ) {
4413
22
#if defined(EXTENDED_SPARSE)
4414
22
                    switch ( matvar->data_type ) {
4415
17
                        case MAT_T_DOUBLE:
4416
17
                            err = ReadCompressedDoubleData(mat, matvar->internal->z,
4417
17
                                                           (double *)sparse->data, packed_type,
4418
17
                                                           sparse->ndata);
4419
17
                            break;
4420
2
                        case MAT_T_SINGLE:
4421
2
                            err = ReadCompressedSingleData(mat, matvar->internal->z,
4422
2
                                                           (float *)sparse->data, packed_type,
4423
2
                                                           sparse->ndata);
4424
2
                            break;
4425
0
                        case MAT_T_INT64:
4426
0
#ifdef HAVE_MAT_INT64_T
4427
0
                            err = ReadCompressedInt64Data(mat, matvar->internal->z,
4428
0
                                                          (mat_int64_t *)sparse->data, packed_type,
4429
0
                                                          sparse->ndata);
4430
0
#endif
4431
0
                            break;
4432
0
                        case MAT_T_UINT64:
4433
0
#ifdef HAVE_MAT_UINT64_T
4434
0
                            err = ReadCompressedUInt64Data(mat, matvar->internal->z,
4435
0
                                                           (mat_uint64_t *)sparse->data,
4436
0
                                                           packed_type, sparse->ndata);
4437
0
#endif
4438
0
                            break;
4439
0
                        case MAT_T_INT32:
4440
0
                            err = ReadCompressedInt32Data(mat, matvar->internal->z,
4441
0
                                                          (mat_int32_t *)sparse->data, packed_type,
4442
0
                                                          sparse->ndata);
4443
0
                            break;
4444
0
                        case MAT_T_UINT32:
4445
0
                            err = ReadCompressedUInt32Data(mat, matvar->internal->z,
4446
0
                                                           (mat_uint32_t *)sparse->data,
4447
0
                                                           packed_type, sparse->ndata);
4448
0
                            break;
4449
0
                        case MAT_T_INT16:
4450
0
                            err = ReadCompressedInt16Data(mat, matvar->internal->z,
4451
0
                                                          (mat_int16_t *)sparse->data, packed_type,
4452
0
                                                          sparse->ndata);
4453
0
                            break;
4454
0
                        case MAT_T_UINT16:
4455
0
                            err = ReadCompressedUInt16Data(mat, matvar->internal->z,
4456
0
                                                           (mat_uint16_t *)sparse->data,
4457
0
                                                           packed_type, sparse->ndata);
4458
0
                            break;
4459
0
                        case MAT_T_INT8:
4460
0
                            err = ReadCompressedInt8Data(mat, matvar->internal->z,
4461
0
                                                         (mat_int8_t *)sparse->data, packed_type,
4462
0
                                                         sparse->ndata);
4463
0
                            break;
4464
3
                        case MAT_T_UINT8:
4465
3
                            err = ReadCompressedUInt8Data(mat, matvar->internal->z,
4466
3
                                                          (mat_uint8_t *)sparse->data, packed_type,
4467
3
                                                          sparse->ndata);
4468
3
                            break;
4469
0
                        default:
4470
0
                            err = MATIO_E_FILE_FORMAT_VIOLATION;
4471
0
                            break;
4472
22
                    }
4473
#else  /* EXTENDED_SPARSE */
4474
                    err = ReadCompressedDoubleData(mat, matvar->internal->z, (double *)sparse->data,
4475
                                                   packed_type, sparse->ndata);
4476
#endif /* EXTENDED_SPARSE */
4477
22
                    if ( err ) {
4478
2
                        free(sparse->data);
4479
2
                        sparse->data = NULL;
4480
2
                        break;
4481
2
                    }
4482
20
                    err = Mul(&nBytes, sparse->ndata, Mat_SizeOf(packed_type));
4483
20
                    if ( err ) {
4484
0
                        free(sparse->data);
4485
0
                        sparse->data = NULL;
4486
0
                        break;
4487
0
                    }
4488
20
                    if ( data_in_tag )
4489
5
                        nBytes += 4;
4490
20
                    if ( (nBytes % 8) != 0 )
4491
5
                        err = InflateSkip(mat, matvar->internal->z, 8 - (nBytes % 8), NULL);
4492
20
                    if ( err ) {
4493
0
                        free(sparse->data);
4494
0
                        sparse->data = NULL;
4495
0
                        break;
4496
0
                    }
4497
20
                } else if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
4498
0
                    if ( data_in_tag )
4499
0
                        nBytes = 4;
4500
0
                    if ( (nBytes % 8) != 0 )
4501
0
                        err = InflateSkip(mat, matvar->internal->z, 8 - (nBytes % 8), NULL);
4502
0
                    if ( err ) {
4503
0
                        free(sparse->data);
4504
0
                        sparse->data = NULL;
4505
0
                        break;
4506
0
                    }
4507
0
#endif /* HAVE_ZLIB */
4508
0
                }
4509
65
            }
4510
3.21k
            break;
4511
4.15k
        }
4512
3.21k
        case MAT_C_FUNCTION: {
4513
13
            matvar_t **functions;
4514
13
            size_t nfunctions = 0;
4515
4516
13
            if ( !matvar->nbytes || !matvar->data_size )
4517
13
                break;
4518
0
            nfunctions = matvar->nbytes / matvar->data_size;
4519
0
            functions = (matvar_t **)matvar->data;
4520
0
            if ( NULL != functions ) {
4521
0
                size_t i;
4522
0
                for ( i = 0; i < nfunctions; i++ ) {
4523
0
                    err = Mat_VarRead5(mat, functions[i]);
4524
0
                    if ( err )
4525
0
                        break;
4526
0
                }
4527
0
            }
4528
0
            matvar->data_type = MAT_T_FUNCTION;
4529
0
            break;
4530
13
        }
4531
103
        case MAT_C_OBJECT:
4532
103
            Mat_Warning("Mat_VarRead5: %d is not a supported class", matvar->class_type);
4533
103
            break;
4534
1
        case MAT_C_OPAQUE:
4535
1
#if defined(MCOS) && MCOS
4536
1
            err = Mat_MCOS_Read5(mat, matvar);
4537
1
#endif
4538
1
            break;
4539
0
        default:
4540
0
            err = MATIO_E_OPERATION_NOT_SUPPORTED;
4541
0
            Mat_Critical("Mat_VarRead5: %d is not a supported class", matvar->class_type);
4542
0
            break;
4543
32.8k
    }
4544
32.8k
    switch ( matvar->class_type ) {
4545
4.68k
        case MAT_C_DOUBLE:
4546
9.39k
        case MAT_C_SINGLE:
4547
9.39k
#ifdef HAVE_MAT_INT64_T
4548
9.89k
        case MAT_C_INT64:
4549
9.89k
#endif
4550
9.89k
#ifdef HAVE_MAT_UINT64_T
4551
10.2k
        case MAT_C_UINT64:
4552
10.2k
#endif
4553
13.2k
        case MAT_C_INT32:
4554
13.4k
        case MAT_C_UINT32:
4555
15.4k
        case MAT_C_INT16:
4556
15.5k
        case MAT_C_UINT16:
4557
17.6k
        case MAT_C_INT8:
4558
17.9k
        case MAT_C_UINT8:
4559
17.9k
            if ( matvar->isComplex ) {
4560
2.36k
                mat_complex_split_t *complex_data;
4561
4562
2.36k
                err = Mul(&matvar->nbytes, nelems, matvar->data_size);
4563
2.36k
                if ( err ) {
4564
2
                    Mat_Critical("Integer multiplication overflow");
4565
2
                    break;
4566
2
                }
4567
2.36k
                complex_data = ComplexCalloc(matvar->nbytes);
4568
2.36k
                if ( NULL == complex_data ) {
4569
47
                    if ( matvar->nbytes > 0 ) {
4570
47
                        err = MATIO_E_OUT_OF_MEMORY;
4571
47
                        Mat_Critical("Couldn't allocate memory for the complex data");
4572
47
                    }
4573
47
                    break;
4574
47
                }
4575
4576
2.31k
                err = Mat_VarReadNumeric5(mat, matvar, complex_data->Re, nelems);
4577
2.31k
                if ( err ) {
4578
1.22k
                    ComplexFree(complex_data);
4579
1.22k
                    break;
4580
1.22k
                }
4581
1.09k
                err = Mat_VarReadNumeric5(mat, matvar, complex_data->Im, nelems);
4582
1.09k
                if ( err ) {
4583
855
                    ComplexFree(complex_data);
4584
855
                    break;
4585
855
                }
4586
235
                matvar->data = complex_data;
4587
15.5k
            } else {
4588
15.5k
                void *data;
4589
15.5k
                err = Mul(&matvar->nbytes, nelems, matvar->data_size);
4590
15.5k
                if ( err ) {
4591
0
                    Mat_Critical("Integer multiplication overflow");
4592
0
                    break;
4593
0
                }
4594
15.5k
                data = calloc(matvar->nbytes, 1);
4595
15.5k
                if ( NULL == data && matvar->nbytes > 0 ) {
4596
7
                    err = MATIO_E_OUT_OF_MEMORY;
4597
7
                    Mat_Critical("Couldn't allocate memory for the data");
4598
7
                    break;
4599
7
                }
4600
15.5k
                err = Mat_VarReadNumeric5(mat, matvar, data, nelems);
4601
15.5k
                if ( err ) {
4602
2.69k
                    free(data);
4603
2.69k
                    break;
4604
2.69k
                }
4605
12.8k
                matvar->data = data;
4606
12.8k
            }
4607
28.0k
        default:
4608
28.0k
            break;
4609
32.8k
    }
4610
32.8k
    (void)MatSeek(mat, fpos, SEEK_SET);
4611
4612
32.8k
    return err;
4613
32.8k
}
4614
4615
#if HAVE_ZLIB
4616
#define GET_DATA_SLAB2(T)                              \
4617
0
    do {                                               \
4618
0
        ptr_in += start[1] * dims[0] + start[0];       \
4619
0
        for ( i = 0; i < edge[1]; i++ ) {              \
4620
0
            for ( j = 0; j < edge[0]; j++ ) {          \
4621
0
                *ptr = (T)(*(ptr_in + j * stride[0])); \
4622
0
                ptr++;                                 \
4623
0
            }                                          \
4624
0
            ptr_in += stride[1] * dims[0];             \
4625
0
        }                                              \
4626
0
    } while ( 0 )
4627
4628
#define GET_DATA_SLABN(T)                                                                         \
4629
0
    do {                                                                                          \
4630
0
        for ( i = 0; i < N; i += (size_t)edge[0] ) {                                              \
4631
0
            int k;                                                                                \
4632
0
            size_t block = i / (size_t)edge[0];                                                   \
4633
0
            size_t input_index = (size_t)start[0];                                                \
4634
0
            for ( j = 1; j < rank; j++ ) {                                                        \
4635
0
                const size_t coordinate = block % (size_t)edge[j];                                \
4636
0
                input_index += ((size_t)start[j] + coordinate * (size_t)stride[j]) * dimp[j - 1]; \
4637
0
                block /= (size_t)edge[j];                                                         \
4638
0
            }                                                                                     \
4639
0
            for ( k = 0; k < edge[0]; k++ )                                                       \
4640
0
                *(ptr + i + (size_t)k) =                                                          \
4641
0
                    (T)(*(ptr_in + input_index + (size_t)k * (size_t)stride[0]));                 \
4642
0
        }                                                                                         \
4643
0
    } while ( 0 )
4644
4645
#ifdef HAVE_MAT_INT64_T
4646
#define GET_DATA_SLAB2_INT64(T)                           \
4647
0
    do {                                                  \
4648
0
        if ( MAT_T_INT64 == data_type ) {                 \
4649
0
            mat_int64_t *ptr_in = (mat_int64_t *)data_in; \
4650
0
            GET_DATA_SLAB2(T);                            \
4651
0
            err = MATIO_E_NO_ERROR;                       \
4652
0
        }                                                 \
4653
0
    } while ( 0 )
4654
#else
4655
#define GET_DATA_SLAB2_INT64(T)
4656
#endif /* HAVE_MAT_INT64_T */
4657
4658
#ifdef HAVE_MAT_UINT64_T
4659
#define GET_DATA_SLAB2_UINT64(T)                            \
4660
0
    do {                                                    \
4661
0
        if ( MAT_T_UINT64 == data_type ) {                  \
4662
0
            mat_uint64_t *ptr_in = (mat_uint64_t *)data_in; \
4663
0
            GET_DATA_SLAB2(T);                              \
4664
0
            err = MATIO_E_NO_ERROR;                         \
4665
0
        }                                                   \
4666
0
    } while ( 0 )
4667
#else
4668
#define GET_DATA_SLAB2_UINT64(T)
4669
#endif /* HAVE_MAT_UINT64_T */
4670
4671
#define GET_DATA_SLAB2_TYPE(T)                                  \
4672
0
    do {                                                        \
4673
0
        switch ( data_type ) {                                  \
4674
0
            case MAT_T_DOUBLE: {                                \
4675
0
                double *ptr_in = (double *)data_in;             \
4676
0
                GET_DATA_SLAB2(T);                              \
4677
0
                break;                                          \
4678
0
            }                                                   \
4679
0
            case MAT_T_SINGLE: {                                \
4680
0
                float *ptr_in = (float *)data_in;               \
4681
0
                GET_DATA_SLAB2(T);                              \
4682
0
                break;                                          \
4683
0
            }                                                   \
4684
0
            case MAT_T_INT32: {                                 \
4685
0
                mat_int32_t *ptr_in = (mat_int32_t *)data_in;   \
4686
0
                GET_DATA_SLAB2(T);                              \
4687
0
                break;                                          \
4688
0
            }                                                   \
4689
0
            case MAT_T_UINT32: {                                \
4690
0
                mat_uint32_t *ptr_in = (mat_uint32_t *)data_in; \
4691
0
                GET_DATA_SLAB2(T);                              \
4692
0
                break;                                          \
4693
0
            }                                                   \
4694
0
            case MAT_T_INT16: {                                 \
4695
0
                mat_int16_t *ptr_in = (mat_int16_t *)data_in;   \
4696
0
                GET_DATA_SLAB2(T);                              \
4697
0
                break;                                          \
4698
0
            }                                                   \
4699
0
            case MAT_T_UINT16: {                                \
4700
0
                mat_uint16_t *ptr_in = (mat_uint16_t *)data_in; \
4701
0
                GET_DATA_SLAB2(T);                              \
4702
0
                break;                                          \
4703
0
            }                                                   \
4704
0
            case MAT_T_INT8: {                                  \
4705
0
                mat_int8_t *ptr_in = (mat_int8_t *)data_in;     \
4706
0
                GET_DATA_SLAB2(T);                              \
4707
0
                break;                                          \
4708
0
            }                                                   \
4709
0
            case MAT_T_UINT8: {                                 \
4710
0
                mat_uint8_t *ptr_in = (mat_uint8_t *)data_in;   \
4711
0
                GET_DATA_SLAB2(T);                              \
4712
0
                break;                                          \
4713
0
            }                                                   \
4714
0
            default:                                            \
4715
0
                err = MATIO_E_OPERATION_NOT_SUPPORTED;          \
4716
0
                GET_DATA_SLAB2_INT64(T);                        \
4717
0
                GET_DATA_SLAB2_UINT64(T);                       \
4718
0
                break;                                          \
4719
0
        }                                                       \
4720
0
    } while ( 0 )
4721
4722
#ifdef HAVE_MAT_INT64_T
4723
#define GET_DATA_SLABN_INT64(T)                           \
4724
0
    do {                                                  \
4725
0
        if ( MAT_T_INT64 == data_type ) {                 \
4726
0
            mat_int64_t *ptr_in = (mat_int64_t *)data_in; \
4727
0
            GET_DATA_SLABN(T);                            \
4728
0
            err = MATIO_E_NO_ERROR;                       \
4729
0
        }                                                 \
4730
0
    } while ( 0 )
4731
#else
4732
#define GET_DATA_SLABN_INT64(T)
4733
#endif /* HAVE_MAT_INT64_T */
4734
4735
#ifdef HAVE_MAT_UINT64_T
4736
#define GET_DATA_SLABN_UINT64(T)                            \
4737
0
    do {                                                    \
4738
0
        if ( MAT_T_UINT64 == data_type ) {                  \
4739
0
            mat_uint64_t *ptr_in = (mat_uint64_t *)data_in; \
4740
0
            GET_DATA_SLABN(T);                              \
4741
0
            err = 0;                                        \
4742
0
        }                                                   \
4743
0
    } while ( 0 )
4744
#else
4745
#define GET_DATA_SLABN_UINT64(T)
4746
#endif /* HAVE_MAT_UINT64_T */
4747
4748
#define GET_DATA_SLABN_TYPE(T)                                  \
4749
0
    do {                                                        \
4750
0
        switch ( data_type ) {                                  \
4751
0
            case MAT_T_DOUBLE: {                                \
4752
0
                double *ptr_in = (double *)data_in;             \
4753
0
                GET_DATA_SLABN(T);                              \
4754
0
                break;                                          \
4755
0
            }                                                   \
4756
0
            case MAT_T_SINGLE: {                                \
4757
0
                float *ptr_in = (float *)data_in;               \
4758
0
                GET_DATA_SLABN(T);                              \
4759
0
                break;                                          \
4760
0
            }                                                   \
4761
0
            case MAT_T_INT32: {                                 \
4762
0
                mat_int32_t *ptr_in = (mat_int32_t *)data_in;   \
4763
0
                GET_DATA_SLABN(T);                              \
4764
0
                break;                                          \
4765
0
            }                                                   \
4766
0
            case MAT_T_UINT32: {                                \
4767
0
                mat_uint32_t *ptr_in = (mat_uint32_t *)data_in; \
4768
0
                GET_DATA_SLABN(T);                              \
4769
0
                break;                                          \
4770
0
            }                                                   \
4771
0
            case MAT_T_INT16: {                                 \
4772
0
                mat_int16_t *ptr_in = (mat_int16_t *)data_in;   \
4773
0
                GET_DATA_SLABN(T);                              \
4774
0
                break;                                          \
4775
0
            }                                                   \
4776
0
            case MAT_T_UINT16: {                                \
4777
0
                mat_uint16_t *ptr_in = (mat_uint16_t *)data_in; \
4778
0
                GET_DATA_SLABN(T);                              \
4779
0
                break;                                          \
4780
0
            }                                                   \
4781
0
            case MAT_T_INT8: {                                  \
4782
0
                mat_int8_t *ptr_in = (mat_int8_t *)data_in;     \
4783
0
                GET_DATA_SLABN(T);                              \
4784
0
                break;                                          \
4785
0
            }                                                   \
4786
0
            case MAT_T_UINT8: {                                 \
4787
0
                mat_uint8_t *ptr_in = (mat_uint8_t *)data_in;   \
4788
0
                GET_DATA_SLABN(T);                              \
4789
0
                break;                                          \
4790
0
            }                                                   \
4791
0
            default:                                            \
4792
0
                err = MATIO_E_OPERATION_NOT_SUPPORTED;          \
4793
0
                GET_DATA_SLABN_INT64(T);                        \
4794
0
                GET_DATA_SLABN_UINT64(T);                       \
4795
0
                break;                                          \
4796
0
        }                                                       \
4797
0
    } while ( 0 )
4798
4799
static int
4800
GetDataSlab(void *data_in, void *data_out, enum matio_classes class_type,
4801
            enum matio_types data_type, const size_t *dims, const int *start, const int *stride,
4802
            const int *edge, int rank, size_t nbytes)
4803
0
{
4804
0
    int err = MATIO_E_NO_ERROR, i;
4805
0
    int same_type = 0;
4806
0
    if ( (class_type == MAT_C_DOUBLE && data_type == MAT_T_DOUBLE) ||
4807
0
         (class_type == MAT_C_SINGLE && data_type == MAT_T_SINGLE) ||
4808
0
         (class_type == MAT_C_INT16 && data_type == MAT_T_INT16) ||
4809
0
         (class_type == MAT_C_INT32 && data_type == MAT_T_INT32) ||
4810
0
         (class_type == MAT_C_INT64 && data_type == MAT_T_INT64) ||
4811
0
         (class_type == MAT_C_INT8 && data_type == MAT_T_INT8) ||
4812
0
         (class_type == MAT_C_UINT16 && data_type == MAT_T_UINT16) ||
4813
0
         (class_type == MAT_C_UINT32 && data_type == MAT_T_UINT32) ||
4814
0
         (class_type == MAT_C_UINT64 && data_type == MAT_T_UINT64) ||
4815
0
         (class_type == MAT_C_UINT8 && data_type == MAT_T_UINT8) )
4816
0
        same_type = 1;
4817
4818
0
    if ( rank < 1 || rank > 10 )
4819
0
        return MATIO_E_BAD_ARGUMENT;
4820
0
    for ( i = 0; i < rank; i++ ) {
4821
0
        if ( start[i] < 0 || stride[i] < 1 || edge[i] < 1 || (size_t)start[i] >= dims[i] ||
4822
0
             (size_t)(edge[i] - 1) > (dims[i] - 1 - (size_t)start[i]) / (size_t)stride[i] )
4823
0
            return MATIO_E_BAD_ARGUMENT;
4824
0
    }
4825
4826
0
    if ( rank == 2 ) {
4827
0
        if ( (stride[0] == 1 && (size_t)edge[0] == dims[0]) &&
4828
0
             (stride[1] == 1 && (size_t)edge[1] == dims[1]) && (same_type == 1) )
4829
0
            memcpy(data_out, data_in, nbytes);
4830
0
        else {
4831
0
            int i, j;
4832
4833
0
            switch ( class_type ) {
4834
0
                case MAT_C_DOUBLE: {
4835
0
                    double *ptr = (double *)data_out;
4836
0
                    GET_DATA_SLAB2_TYPE(double);
4837
0
                    break;
4838
0
                }
4839
0
                case MAT_C_SINGLE: {
4840
0
                    float *ptr = (float *)data_out;
4841
0
                    GET_DATA_SLAB2_TYPE(float);
4842
0
                    break;
4843
0
                }
4844
0
#ifdef HAVE_MAT_INT64_T
4845
0
                case MAT_C_INT64: {
4846
0
                    mat_int64_t *ptr = (mat_int64_t *)data_out;
4847
0
                    GET_DATA_SLAB2_TYPE(mat_int64_t);
4848
0
                    break;
4849
0
                }
4850
0
#endif /* HAVE_MAT_INT64_T */
4851
0
#ifdef HAVE_MAT_UINT64_T
4852
0
                case MAT_C_UINT64: {
4853
0
                    mat_uint64_t *ptr = (mat_uint64_t *)data_out;
4854
0
                    GET_DATA_SLAB2_TYPE(mat_uint64_t);
4855
0
                    break;
4856
0
                }
4857
0
#endif /* HAVE_MAT_UINT64_T */
4858
0
                case MAT_C_INT32: {
4859
0
                    mat_int32_t *ptr = (mat_int32_t *)data_out;
4860
0
                    GET_DATA_SLAB2_TYPE(mat_int32_t);
4861
0
                    break;
4862
0
                }
4863
0
                case MAT_C_UINT32: {
4864
0
                    mat_uint32_t *ptr = (mat_uint32_t *)data_out;
4865
0
                    GET_DATA_SLAB2_TYPE(mat_uint32_t);
4866
0
                    break;
4867
0
                }
4868
0
                case MAT_C_INT16: {
4869
0
                    mat_int16_t *ptr = (mat_int16_t *)data_out;
4870
0
                    GET_DATA_SLAB2_TYPE(mat_int16_t);
4871
0
                    break;
4872
0
                }
4873
0
                case MAT_C_UINT16: {
4874
0
                    mat_uint16_t *ptr = (mat_uint16_t *)data_out;
4875
0
                    GET_DATA_SLAB2_TYPE(mat_uint16_t);
4876
0
                    break;
4877
0
                }
4878
0
                case MAT_C_INT8: {
4879
0
                    mat_int8_t *ptr = (mat_int8_t *)data_out;
4880
0
                    GET_DATA_SLAB2_TYPE(mat_int8_t);
4881
0
                    break;
4882
0
                }
4883
0
                case MAT_C_UINT8: {
4884
0
                    mat_uint8_t *ptr = (mat_uint8_t *)data_out;
4885
0
                    GET_DATA_SLAB2_TYPE(mat_uint8_t);
4886
0
                    break;
4887
0
                }
4888
0
                default:
4889
0
                    err = MATIO_E_OPERATION_NOT_SUPPORTED;
4890
0
                    break;
4891
0
            }
4892
0
        }
4893
0
    } else {
4894
0
        int j;
4895
0
        size_t N = (size_t)edge[0];
4896
0
        size_t dimp[10];
4897
0
        dimp[0] = dims[0];
4898
0
        for ( j = 1; j < 10; j++ )
4899
0
            dimp[j] = 0;
4900
4901
0
        for ( j = 1; j < rank; j++ ) {
4902
0
            err = Mul(&dimp[j], dimp[j - 1], dims[j]);
4903
0
            if ( !err )
4904
0
                err = Mul(&N, N, (size_t)edge[j]);
4905
0
            if ( err )
4906
0
                return err;
4907
0
        }
4908
4909
0
        switch ( class_type ) {
4910
0
            case MAT_C_DOUBLE: {
4911
0
                double *ptr = (double *)data_out;
4912
0
                GET_DATA_SLABN_TYPE(double);
4913
0
                break;
4914
0
            }
4915
0
            case MAT_C_SINGLE: {
4916
0
                float *ptr = (float *)data_out;
4917
0
                GET_DATA_SLABN_TYPE(float);
4918
0
                break;
4919
0
            }
4920
0
#ifdef HAVE_MAT_INT64_T
4921
0
            case MAT_C_INT64: {
4922
0
                mat_int64_t *ptr = (mat_int64_t *)data_out;
4923
0
                GET_DATA_SLABN_TYPE(mat_int64_t);
4924
0
                break;
4925
0
            }
4926
0
#endif /* HAVE_MAT_INT64_T */
4927
0
#ifdef HAVE_MAT_UINT64_T
4928
0
            case MAT_C_UINT64: {
4929
0
                mat_uint64_t *ptr = (mat_uint64_t *)data_out;
4930
0
                GET_DATA_SLABN_TYPE(mat_uint64_t);
4931
0
                break;
4932
0
            }
4933
0
#endif /* HAVE_MAT_UINT64_T */
4934
0
            case MAT_C_INT32: {
4935
0
                mat_int32_t *ptr = (mat_int32_t *)data_out;
4936
0
                GET_DATA_SLABN_TYPE(mat_int32_t);
4937
0
                break;
4938
0
            }
4939
0
            case MAT_C_UINT32: {
4940
0
                mat_uint32_t *ptr = (mat_uint32_t *)data_out;
4941
0
                GET_DATA_SLABN_TYPE(mat_uint32_t);
4942
0
                break;
4943
0
            }
4944
0
            case MAT_C_INT16: {
4945
0
                mat_int16_t *ptr = (mat_int16_t *)data_out;
4946
0
                GET_DATA_SLABN_TYPE(mat_int16_t);
4947
0
                break;
4948
0
            }
4949
0
            case MAT_C_UINT16: {
4950
0
                mat_uint16_t *ptr = (mat_uint16_t *)data_out;
4951
0
                GET_DATA_SLABN_TYPE(mat_uint16_t);
4952
0
                break;
4953
0
            }
4954
0
            case MAT_C_INT8: {
4955
0
                mat_int8_t *ptr = (mat_int8_t *)data_out;
4956
0
                GET_DATA_SLABN_TYPE(mat_int8_t);
4957
0
                break;
4958
0
            }
4959
0
            case MAT_C_UINT8: {
4960
0
                mat_uint8_t *ptr = (mat_uint8_t *)data_out;
4961
0
                GET_DATA_SLABN_TYPE(mat_uint8_t);
4962
0
                break;
4963
0
            }
4964
0
            default:
4965
0
                err = MATIO_E_OPERATION_NOT_SUPPORTED;
4966
0
                break;
4967
0
        }
4968
0
    }
4969
4970
0
    return err;
4971
0
}
4972
4973
#undef GET_DATA_SLAB2
4974
#undef GET_DATA_SLAB2_TYPE
4975
#undef GET_DATA_SLAB2_INT64
4976
#undef GET_DATA_SLAB2_UINT64
4977
#undef GET_DATA_SLABN
4978
#undef GET_DATA_SLABN_TYPE
4979
#undef GET_DATA_SLABN_INT64
4980
#undef GET_DATA_SLABN_UINT64
4981
4982
#define GET_DATA_LINEAR                                        \
4983
0
    do {                                                       \
4984
0
        ptr_in += start;                                       \
4985
0
        if ( !stride ) {                                       \
4986
0
            memcpy(ptr, ptr_in, (size_t)edge * data_size);     \
4987
0
        } else {                                               \
4988
0
            int i;                                             \
4989
0
            for ( i = 0; i < edge; i++ )                       \
4990
0
                memcpy(ptr++, ptr_in + i * stride, data_size); \
4991
0
        }                                                      \
4992
0
    } while ( 0 )
4993
4994
static int
4995
GetDataLinear(void *data_in, void *data_out, enum matio_classes class_type,
4996
              enum matio_types data_type, int start, int stride, int edge)
4997
0
{
4998
0
    int err = MATIO_E_NO_ERROR;
4999
0
    size_t data_size = Mat_SizeOf(data_type);
5000
5001
0
    switch ( class_type ) {
5002
0
        case MAT_C_DOUBLE: {
5003
0
            double *ptr = (double *)data_out;
5004
0
            double *ptr_in = (double *)data_in;
5005
0
            GET_DATA_LINEAR;
5006
0
            break;
5007
0
        }
5008
0
        case MAT_C_SINGLE: {
5009
0
            float *ptr = (float *)data_out;
5010
0
            float *ptr_in = (float *)data_in;
5011
0
            GET_DATA_LINEAR;
5012
0
            break;
5013
0
        }
5014
0
#ifdef HAVE_MAT_INT64_T
5015
0
        case MAT_C_INT64: {
5016
0
            mat_int64_t *ptr = (mat_int64_t *)data_out;
5017
0
            mat_int64_t *ptr_in = (mat_int64_t *)data_in;
5018
0
            GET_DATA_LINEAR;
5019
0
            break;
5020
0
        }
5021
0
#endif /* HAVE_MAT_INT64_T */
5022
0
#ifdef HAVE_MAT_UINT64_T
5023
0
        case MAT_C_UINT64: {
5024
0
            mat_uint64_t *ptr = (mat_uint64_t *)data_out;
5025
0
            mat_uint64_t *ptr_in = (mat_uint64_t *)data_in;
5026
0
            GET_DATA_LINEAR;
5027
0
            break;
5028
0
        }
5029
0
#endif /* HAVE_MAT_UINT64_T */
5030
0
        case MAT_C_INT32: {
5031
0
            mat_int32_t *ptr = (mat_int32_t *)data_out;
5032
0
            mat_int32_t *ptr_in = (mat_int32_t *)data_in;
5033
0
            GET_DATA_LINEAR;
5034
0
            break;
5035
0
        }
5036
0
        case MAT_C_UINT32: {
5037
0
            mat_uint32_t *ptr = (mat_uint32_t *)data_out;
5038
0
            mat_uint32_t *ptr_in = (mat_uint32_t *)data_in;
5039
0
            GET_DATA_LINEAR;
5040
0
            break;
5041
0
        }
5042
0
        case MAT_C_INT16: {
5043
0
            mat_int16_t *ptr = (mat_int16_t *)data_out;
5044
0
            mat_int16_t *ptr_in = (mat_int16_t *)data_in;
5045
0
            GET_DATA_LINEAR;
5046
0
            break;
5047
0
        }
5048
0
        case MAT_C_UINT16: {
5049
0
            mat_uint16_t *ptr = (mat_uint16_t *)data_out;
5050
0
            mat_uint16_t *ptr_in = (mat_uint16_t *)data_in;
5051
0
            GET_DATA_LINEAR;
5052
0
            break;
5053
0
        }
5054
0
        case MAT_C_INT8: {
5055
0
            mat_int8_t *ptr = (mat_int8_t *)data_out;
5056
0
            mat_int8_t *ptr_in = (mat_int8_t *)data_in;
5057
0
            GET_DATA_LINEAR;
5058
0
            break;
5059
0
        }
5060
0
        case MAT_C_UINT8: {
5061
0
            mat_uint8_t *ptr = (mat_uint8_t *)data_out;
5062
0
            mat_uint8_t *ptr_in = (mat_uint8_t *)data_in;
5063
0
            GET_DATA_LINEAR;
5064
0
            break;
5065
0
        }
5066
0
        default:
5067
0
            err = MATIO_E_OPERATION_NOT_SUPPORTED;
5068
0
            break;
5069
0
    }
5070
5071
0
    return err;
5072
0
}
5073
5074
#undef GET_DATA_LINEAR
5075
#endif
5076
5077
/** @if mat_devman
5078
 * @brief Reads a slab of data from the mat variable @c matvar
5079
 *
5080
 * @ingroup mat_internal
5081
 * @param mat MAT file pointer
5082
 * @param matvar pointer to the mat variable
5083
 * @param data pointer to store the read data in (must be of size
5084
 *             edge[0]*...edge[rank-1]*Mat_SizeOfClass(matvar->class_type))
5085
 * @param start index to start reading data in each dimension
5086
 * @param stride write data every @c stride elements in each dimension
5087
 * @param edge number of elements to read in each dimension
5088
 * @retval 0 on success
5089
 * @endif
5090
 */
5091
int
5092
Mat_VarReadData5(mat_t *mat, matvar_t *matvar, void *data, const int *start, const int *stride,
5093
                 const int *edge)
5094
1.35k
{
5095
1.35k
    int err = MATIO_E_NO_ERROR, real_bytes = 0;
5096
1.35k
    mat_uint32_t tag[2] = {0, 0};
5097
1.35k
#if HAVE_ZLIB
5098
1.35k
    z_stream z;
5099
1.35k
    int z_copy = 0;
5100
1.35k
#endif
5101
5102
1.35k
    (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
5103
1.35k
    if ( matvar->compression == MAT_COMPRESSION_NONE ) {
5104
1.05k
        err = Read(tag, 4, 2, mat, NULL);
5105
1.05k
        if ( err ) {
5106
0
            return err;
5107
0
        }
5108
1.05k
        if ( mat->byteswap ) {
5109
716
            (void)Mat_uint32Swap(tag);
5110
716
            (void)Mat_uint32Swap(tag + 1);
5111
716
        }
5112
1.05k
        matvar->data_type = TYPE_FROM_TAG(tag[0]);
5113
1.05k
        if ( tag[0] & 0xffff0000 ) { /* Data is packed in the tag */
5114
404
            (void)MatSeek(mat, -4, SEEK_CUR);
5115
404
            real_bytes = 4 + (tag[0] >> 16);
5116
649
        } else {
5117
649
            real_bytes = 8 + tag[1];
5118
649
        }
5119
1.05k
#if HAVE_ZLIB
5120
1.05k
    } else if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
5121
306
        if ( NULL != matvar->internal->data ) {
5122
            /* Data already read in ReadNextStructField or ReadNextCell */
5123
0
            if ( matvar->isComplex ) {
5124
0
                mat_complex_split_t *ci, *co;
5125
5126
0
                co = (mat_complex_split_t *)data;
5127
0
                ci = (mat_complex_split_t *)matvar->internal->data;
5128
0
                err = GetDataSlab(ci->Re, co->Re, matvar->class_type, matvar->data_type,
5129
0
                                  matvar->dims, start, stride, edge, matvar->rank, matvar->nbytes);
5130
0
                if ( !err )
5131
0
                    err = GetDataSlab(ci->Im, co->Im, matvar->class_type, matvar->data_type,
5132
0
                                      matvar->dims, start, stride, edge, matvar->rank,
5133
0
                                      matvar->nbytes);
5134
0
                return err;
5135
0
            } else {
5136
0
                return GetDataSlab(matvar->internal->data, data, matvar->class_type,
5137
0
                                   matvar->data_type, matvar->dims, start, stride, edge,
5138
0
                                   matvar->rank, matvar->nbytes);
5139
0
            }
5140
0
        }
5141
5142
306
        err = inflateCopy(&z, matvar->internal->z);
5143
306
        if ( err != Z_OK ) {
5144
0
            Mat_Critical("inflateCopy returned error %s", zError(err));
5145
0
            return MATIO_E_FILE_FORMAT_VIOLATION;
5146
0
        }
5147
306
        z_copy = 1;
5148
306
        z.avail_in = 0;
5149
306
        err = Inflate(mat, &z, tag, 4, NULL);
5150
306
        if ( err ) {
5151
0
            inflateEnd(&z);
5152
0
            return err;
5153
0
        }
5154
306
        if ( mat->byteswap ) {
5155
289
            (void)Mat_uint32Swap(tag);
5156
289
        }
5157
306
        matvar->data_type = TYPE_FROM_TAG(tag[0]);
5158
306
        if ( !(tag[0] & 0xffff0000) ) { /* Data is NOT packed in the tag */
5159
138
            err = Inflate(mat, &z, tag + 1, 4, NULL);
5160
138
            if ( err ) {
5161
0
                inflateEnd(&z);
5162
0
                return err;
5163
0
            }
5164
138
            if ( mat->byteswap ) {
5165
128
                (void)Mat_uint32Swap(tag + 1);
5166
128
            }
5167
138
            real_bytes = 8 + tag[1];
5168
168
        } else {
5169
168
            real_bytes = 4 + (tag[0] >> 16);
5170
168
        }
5171
306
#endif
5172
306
    }
5173
1.35k
    if ( real_bytes % 8 )
5174
633
        real_bytes += (8 - (real_bytes % 8));
5175
5176
1.35k
    if ( matvar->rank == 2 ) {
5177
1.26k
        if ( (size_t)stride[0] * (edge[0] - 1) + start[0] + 1 > matvar->dims[0] )
5178
162
            err = MATIO_E_BAD_ARGUMENT;
5179
1.10k
        else if ( (size_t)stride[1] * (edge[1] - 1) + start[1] + 1 > matvar->dims[1] )
5180
62
            err = MATIO_E_BAD_ARGUMENT;
5181
1.04k
        else if ( matvar->compression == MAT_COMPRESSION_NONE ) {
5182
803
            if ( matvar->isComplex ) {
5183
212
                mat_complex_split_t *complex_data = (mat_complex_split_t *)data;
5184
5185
212
                ReadDataSlab2(mat, complex_data->Re, matvar->class_type, matvar->data_type,
5186
212
                              matvar->dims, start, stride, edge);
5187
212
                (void)MatSeek(mat, matvar->internal->datapos + real_bytes, SEEK_SET);
5188
212
                err = Read(tag, 4, 2, mat, NULL);
5189
212
                if ( err ) {
5190
50
                    return err;
5191
50
                }
5192
162
                if ( mat->byteswap ) {
5193
153
                    (void)Mat_uint32Swap(tag);
5194
153
                    (void)Mat_uint32Swap(tag + 1);
5195
153
                }
5196
162
                matvar->data_type = TYPE_FROM_TAG(tag[0]);
5197
162
                if ( tag[0] & 0xffff0000 ) { /* Data is packed in the tag */
5198
86
                    (void)MatSeek(mat, -4, SEEK_CUR);
5199
86
                }
5200
162
                ReadDataSlab2(mat, complex_data->Im, matvar->class_type, matvar->data_type,
5201
162
                              matvar->dims, start, stride, edge);
5202
591
            } else {
5203
591
                ReadDataSlab2(mat, data, matvar->class_type, matvar->data_type, matvar->dims, start,
5204
591
                              stride, edge);
5205
591
            }
5206
803
        }
5207
240
#if HAVE_ZLIB
5208
240
        else if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
5209
240
            if ( matvar->isComplex ) {
5210
3
                mat_complex_split_t *complex_data = (mat_complex_split_t *)data;
5211
5212
3
                ReadCompressedDataSlab2(mat, &z, complex_data->Re, matvar->class_type,
5213
3
                                        matvar->data_type, matvar->dims, start, stride, edge);
5214
5215
3
                (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
5216
5217
                /* Reset zlib knowledge to before reading real tag */
5218
3
                inflateEnd(&z);
5219
3
                err = inflateCopy(&z, matvar->internal->z);
5220
3
                if ( err != Z_OK ) {
5221
0
                    Mat_Critical("inflateCopy returned error %s", zError(err));
5222
0
                    z_copy = 0;
5223
0
                    return MATIO_E_FILE_FORMAT_VIOLATION;
5224
0
                }
5225
3
                InflateSkip(mat, &z, real_bytes, NULL);
5226
3
                z.avail_in = 0;
5227
3
                err = Inflate(mat, &z, tag, 4, NULL);
5228
3
                if ( err ) {
5229
1
                    inflateEnd(&z);
5230
1
                    z_copy = 0;
5231
1
                    return err;
5232
1
                }
5233
2
                if ( mat->byteswap ) {
5234
0
                    (void)Mat_uint32Swap(tag);
5235
0
                }
5236
2
                matvar->data_type = TYPE_FROM_TAG(tag[0]);
5237
2
                if ( !(tag[0] & 0xffff0000) ) { /*Data is NOT packed in the tag*/
5238
0
                    InflateSkip(mat, &z, 4, NULL);
5239
0
                }
5240
2
                ReadCompressedDataSlab2(mat, &z, complex_data->Im, matvar->class_type,
5241
2
                                        matvar->data_type, matvar->dims, start, stride, edge);
5242
237
            } else {
5243
237
                ReadCompressedDataSlab2(mat, &z, data, matvar->class_type, matvar->data_type,
5244
237
                                        matvar->dims, start, stride, edge);
5245
237
            }
5246
239
            inflateEnd(&z);
5247
239
            z_copy = 0;
5248
239
        }
5249
1.26k
#endif
5250
1.26k
    } else {
5251
92
        if ( matvar->compression == MAT_COMPRESSION_NONE ) {
5252
53
            if ( matvar->isComplex ) {
5253
1
                mat_complex_split_t *complex_data = (mat_complex_split_t *)data;
5254
5255
1
                ReadDataSlabN(mat, complex_data->Re, matvar->class_type, matvar->data_type,
5256
1
                              matvar->rank, matvar->dims, start, stride, edge);
5257
5258
1
                (void)MatSeek(mat, matvar->internal->datapos + real_bytes, SEEK_SET);
5259
1
                err = Read(tag, 4, 2, mat, NULL);
5260
1
                if ( err ) {
5261
0
                    return err;
5262
0
                }
5263
1
                if ( mat->byteswap ) {
5264
1
                    (void)Mat_uint32Swap(tag);
5265
1
                    (void)Mat_uint32Swap(tag + 1);
5266
1
                }
5267
1
                matvar->data_type = TYPE_FROM_TAG(tag[0]);
5268
1
                if ( tag[0] & 0xffff0000 ) { /* Data is packed in the tag */
5269
0
                    (void)MatSeek(mat, -4, SEEK_CUR);
5270
0
                }
5271
1
                ReadDataSlabN(mat, complex_data->Im, matvar->class_type, matvar->data_type,
5272
1
                              matvar->rank, matvar->dims, start, stride, edge);
5273
52
            } else {
5274
52
                ReadDataSlabN(mat, data, matvar->class_type, matvar->data_type, matvar->rank,
5275
52
                              matvar->dims, start, stride, edge);
5276
52
            }
5277
53
        }
5278
39
#if HAVE_ZLIB
5279
39
        else if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
5280
39
            if ( matvar->isComplex ) {
5281
0
                mat_complex_split_t *complex_data = (mat_complex_split_t *)data;
5282
5283
0
                ReadCompressedDataSlabN(mat, &z, complex_data->Re, matvar->class_type,
5284
0
                                        matvar->data_type, matvar->rank, matvar->dims, start,
5285
0
                                        stride, edge);
5286
5287
0
                (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
5288
                /* Reset zlib knowledge to before reading real tag */
5289
0
                inflateEnd(&z);
5290
0
                err = inflateCopy(&z, matvar->internal->z);
5291
0
                if ( err != Z_OK ) {
5292
0
                    Mat_Critical("inflateCopy returned error %s", zError(err));
5293
0
                    z_copy = 0;
5294
0
                    return MATIO_E_FILE_FORMAT_VIOLATION;
5295
0
                }
5296
0
                InflateSkip(mat, &z, real_bytes, NULL);
5297
0
                z.avail_in = 0;
5298
0
                err = Inflate(mat, &z, tag, 4, NULL);
5299
0
                if ( err ) {
5300
0
                    inflateEnd(&z);
5301
0
                    z_copy = 0;
5302
0
                    return err;
5303
0
                }
5304
0
                if ( mat->byteswap ) {
5305
0
                    (void)Mat_uint32Swap(tag);
5306
0
                }
5307
0
                matvar->data_type = TYPE_FROM_TAG(tag[0]);
5308
0
                if ( !(tag[0] & 0xffff0000) ) { /*Data is NOT packed in the tag*/
5309
0
                    InflateSkip(mat, &z, 4, NULL);
5310
0
                }
5311
0
                ReadCompressedDataSlabN(mat, &z, complex_data->Im, matvar->class_type,
5312
0
                                        matvar->data_type, matvar->rank, matvar->dims, start,
5313
0
                                        stride, edge);
5314
39
            } else {
5315
39
                ReadCompressedDataSlabN(mat, &z, data, matvar->class_type, matvar->data_type,
5316
39
                                        matvar->rank, matvar->dims, start, stride, edge);
5317
39
            }
5318
39
            inflateEnd(&z);
5319
39
            z_copy = 0;
5320
39
        }
5321
92
#endif
5322
92
    }
5323
1.30k
#if HAVE_ZLIB
5324
1.30k
    if ( z_copy ) {
5325
27
        inflateEnd(&z);
5326
27
    }
5327
1.30k
#endif
5328
1.30k
    if ( !err ) {
5329
1.08k
        matvar->data_type = ClassType2DataType(matvar->class_type);
5330
1.08k
        matvar->data_size = Mat_SizeOfClass(matvar->class_type);
5331
1.08k
    }
5332
1.30k
    return err;
5333
1.35k
}
5334
5335
/** @brief Reads a subset of a MAT variable using a 1-D indexing
5336
 *
5337
 * Reads data from a MAT variable using a linear (1-D) indexing mode. The
5338
 * variable must have been read by Mat_VarReadInfo.
5339
 * @ingroup MAT
5340
 * @param mat MAT file to read data from
5341
 * @param matvar MAT variable information
5342
 * @param data pointer to store data in (must be pre-allocated)
5343
 * @param start starting index
5344
 * @param stride stride of data
5345
 * @param edge number of elements to read
5346
 * @retval 0 on success
5347
 */
5348
int
5349
Mat_VarReadDataLinear5(mat_t *mat, matvar_t *matvar, void *data, int start, int stride, int edge)
5350
761
{
5351
761
    int err = MATIO_E_NO_ERROR, real_bytes = 0;
5352
761
    mat_uint32_t tag[2] = {0, 0};
5353
761
#if HAVE_ZLIB
5354
761
    z_stream z;
5355
761
    int z_copy = 0;
5356
761
#endif
5357
761
    size_t nelems = 1;
5358
5359
761
    if ( mat->version == MAT_FT_MAT4 )
5360
0
        return -1;
5361
5362
761
    err = Mat_MulDims(matvar, &nelems);
5363
761
    if ( err ) {
5364
0
        Mat_Critical("Integer multiplication overflow");
5365
0
        return err;
5366
0
    }
5367
761
    if ( (size_t)stride * (edge - 1) + start + 1 > nelems )
5368
76
        return MATIO_E_BAD_ARGUMENT;
5369
5370
685
    (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
5371
685
    if ( matvar->compression == MAT_COMPRESSION_NONE ) {
5372
514
        err = Read(tag, 4, 2, mat, NULL);
5373
514
        if ( err ) {
5374
0
            return err;
5375
0
        }
5376
514
        if ( mat->byteswap ) {
5377
355
            (void)Mat_uint32Swap(tag);
5378
355
            (void)Mat_uint32Swap(tag + 1);
5379
355
        }
5380
514
        matvar->data_type = (enum matio_types)(tag[0] & 0x000000ff);
5381
514
        if ( tag[0] & 0xffff0000 ) { /* Data is packed in the tag */
5382
229
            (void)MatSeek(mat, -4, SEEK_CUR);
5383
229
            real_bytes = 4 + (tag[0] >> 16);
5384
285
        } else {
5385
285
            real_bytes = 8 + tag[1];
5386
285
        }
5387
514
#if HAVE_ZLIB
5388
514
    } else if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
5389
171
        if ( NULL != matvar->internal->data ) {
5390
            /* Data already read in ReadNextStructField or ReadNextCell */
5391
0
            if ( matvar->isComplex ) {
5392
0
                mat_complex_split_t *ci, *co;
5393
5394
0
                co = (mat_complex_split_t *)data;
5395
0
                ci = (mat_complex_split_t *)matvar->internal->data;
5396
0
                err = GetDataLinear(ci->Re, co->Re, matvar->class_type, matvar->data_type, start,
5397
0
                                    stride, edge);
5398
0
                if ( !err )
5399
0
                    err = GetDataLinear(ci->Im, co->Im, matvar->class_type, matvar->data_type,
5400
0
                                        start, stride, edge);
5401
0
                return err;
5402
0
            } else {
5403
0
                return GetDataLinear(matvar->internal->data, data, matvar->class_type,
5404
0
                                     matvar->data_type, start, stride, edge);
5405
0
            }
5406
0
        }
5407
5408
171
        matvar->internal->z->avail_in = 0;
5409
171
        err = inflateCopy(&z, matvar->internal->z);
5410
171
        if ( err != Z_OK ) {
5411
0
            Mat_Critical("inflateCopy returned error %s", zError(err));
5412
0
            return MATIO_E_FILE_FORMAT_VIOLATION;
5413
0
        }
5414
171
        z_copy = 1;
5415
171
        err = Inflate(mat, &z, tag, 4, NULL);
5416
171
        if ( err ) {
5417
0
            inflateEnd(&z);
5418
0
            return err;
5419
0
        }
5420
171
        if ( mat->byteswap ) {
5421
165
            (void)Mat_uint32Swap(tag);
5422
165
            (void)Mat_uint32Swap(tag + 1);
5423
165
        }
5424
171
        matvar->data_type = (enum matio_types)(tag[0] & 0x000000ff);
5425
171
        if ( !(tag[0] & 0xffff0000) ) { /* Data is NOT packed in the tag */
5426
93
            err = Inflate(mat, &z, tag + 1, 4, NULL);
5427
93
            if ( err ) {
5428
0
                inflateEnd(&z);
5429
0
                return err;
5430
0
            }
5431
93
            if ( mat->byteswap ) {
5432
90
                (void)Mat_uint32Swap(tag + 1);
5433
90
            }
5434
93
            real_bytes = 8 + tag[1];
5435
93
        } else {
5436
78
            real_bytes = 4 + (tag[0] >> 16);
5437
78
        }
5438
171
#endif
5439
171
    }
5440
685
    if ( real_bytes % 8 )
5441
325
        real_bytes += (8 - (real_bytes % 8));
5442
5443
685
    if ( matvar->compression == MAT_COMPRESSION_NONE ) {
5444
514
        if ( matvar->isComplex ) {
5445
185
            mat_complex_split_t *complex_data = (mat_complex_split_t *)data;
5446
5447
185
            ReadDataSlab1(mat, complex_data->Re, matvar->class_type, matvar->data_type, start,
5448
185
                          stride, edge);
5449
185
            (void)MatSeek(mat, matvar->internal->datapos + real_bytes, SEEK_SET);
5450
185
            err = Read(tag, 4, 2, mat, NULL);
5451
185
            if ( err ) {
5452
37
                return err;
5453
37
            }
5454
148
            if ( mat->byteswap ) {
5455
142
                (void)Mat_uint32Swap(tag);
5456
142
                (void)Mat_uint32Swap(tag + 1);
5457
142
            }
5458
148
            matvar->data_type = (enum matio_types)(tag[0] & 0x000000ff);
5459
148
            if ( tag[0] & 0xffff0000 ) { /* Data is packed in the tag */
5460
80
                (void)MatSeek(mat, -4, SEEK_CUR);
5461
80
            }
5462
148
            ReadDataSlab1(mat, complex_data->Im, matvar->class_type, matvar->data_type, start,
5463
148
                          stride, edge);
5464
329
        } else {
5465
329
            ReadDataSlab1(mat, data, matvar->class_type, matvar->data_type, start, stride, edge);
5466
329
        }
5467
514
#if HAVE_ZLIB
5468
514
    } else if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
5469
171
        if ( matvar->isComplex ) {
5470
2
            mat_complex_split_t *complex_data = (mat_complex_split_t *)data;
5471
5472
2
            ReadCompressedDataSlab1(mat, &z, complex_data->Re, matvar->class_type,
5473
2
                                    matvar->data_type, start, stride, edge);
5474
5475
2
            (void)MatSeek(mat, matvar->internal->datapos, SEEK_SET);
5476
5477
            /* Reset zlib knowledge to before reading real tag */
5478
2
            inflateEnd(&z);
5479
2
            err = inflateCopy(&z, matvar->internal->z);
5480
2
            if ( err != Z_OK ) {
5481
0
                Mat_Critical("inflateCopy returned error %s", zError(err));
5482
0
                z_copy = 0;
5483
0
                return MATIO_E_FILE_FORMAT_VIOLATION;
5484
0
            }
5485
2
            InflateSkip(mat, &z, real_bytes, NULL);
5486
2
            z.avail_in = 0;
5487
2
            err = Inflate(mat, &z, tag, 4, NULL);
5488
2
            if ( err ) {
5489
2
                inflateEnd(&z);
5490
2
                z_copy = 0;
5491
2
                return err;
5492
2
            }
5493
0
            if ( mat->byteswap ) {
5494
0
                (void)Mat_uint32Swap(tag);
5495
0
            }
5496
0
            matvar->data_type = (enum matio_types)(tag[0] & 0x000000ff);
5497
0
            if ( !(tag[0] & 0xffff0000) ) { /*Data is NOT packed in the tag*/
5498
0
                InflateSkip(mat, &z, 4, NULL);
5499
0
            }
5500
0
            ReadCompressedDataSlab1(mat, &z, complex_data->Im, matvar->class_type,
5501
0
                                    matvar->data_type, start, stride, edge);
5502
169
        } else {
5503
169
            ReadCompressedDataSlab1(mat, &z, data, matvar->class_type, matvar->data_type, start,
5504
169
                                    stride, edge);
5505
169
        }
5506
169
        inflateEnd(&z);
5507
169
        z_copy = 0;
5508
169
#endif
5509
169
    }
5510
5511
646
#if HAVE_ZLIB
5512
646
    if ( z_copy ) {
5513
0
        inflateEnd(&z);
5514
0
    }
5515
646
#endif
5516
646
    matvar->data_type = ClassType2DataType(matvar->class_type);
5517
646
    matvar->data_size = Mat_SizeOfClass(matvar->class_type);
5518
5519
646
    return err;
5520
685
}
5521
5522
/** @if mat_devman
5523
 * @brief Writes a matlab variable to a version 5 matlab file
5524
 *
5525
 * @ingroup mat_internal
5526
 * @param mat MAT file pointer
5527
 * @param matvar pointer to the mat variable
5528
 * @param compress option to compress the variable
5529
 *                 (only works for numeric types)
5530
 * @retval 0 on success
5531
 * @endif
5532
 */
5533
int
5534
Mat_VarWrite5(mat_t *mat, matvar_t *matvar, int compress)
5535
0
{
5536
0
    mat_uint32_t array_flags;
5537
0
    int array_flags_type = MAT_T_UINT32, dims_array_type = MAT_T_INT32;
5538
0
    int array_flags_size = 8, matrix_type = MAT_T_MATRIX;
5539
0
    const mat_uint32_t pad4 = 0;
5540
0
    int nBytes, nzmax = 0;
5541
0
    mat_off_t start = 0, end = 0;
5542
5543
0
    if ( NULL == mat || NULL == matvar )
5544
0
        return MATIO_E_BAD_ARGUMENT;
5545
5546
    /* A sparse variable requires its data; normalize broken variables
5547
     * (e.g. read from a corrupt file) to an empty matrix. */
5548
0
    if ( matvar->class_type == MAT_C_SPARSE && NULL == matvar->data )
5549
0
        matvar->class_type = MAT_C_EMPTY;
5550
5551
    /* FIXME: SEEK_END is not Guaranteed by the C standard */
5552
0
    (void)MatSeek(mat, 0, SEEK_END); /* Always write at end of file */
5553
5554
0
#if HAVE_ZLIB
5555
0
    if ( compress == MAT_COMPRESSION_NONE ) {
5556
#else
5557
    {
5558
#endif
5559
0
        int i;
5560
0
        fwrite(&matrix_type, 4, 1, (FILE *)mat->fp);
5561
0
        fwrite(&pad4, 4, 1, (FILE *)mat->fp);
5562
0
        start = MatTell(mat);
5563
5564
        /* Array Flags */
5565
0
        array_flags = matvar->class_type & CLASS_TYPE_MASK;
5566
0
        if ( matvar->isComplex )
5567
0
            array_flags |= MAT_F_COMPLEX;
5568
0
        if ( matvar->isGlobal )
5569
0
            array_flags |= MAT_F_GLOBAL;
5570
0
        if ( matvar->isLogical )
5571
0
            array_flags |= MAT_F_LOGICAL;
5572
0
        if ( matvar->class_type == MAT_C_SPARSE && NULL != matvar->data )
5573
0
            nzmax = ((mat_sparse_t *)matvar->data)->nzmax;
5574
5575
0
        fwrite(&array_flags_type, 4, 1, (FILE *)mat->fp);
5576
0
        fwrite(&array_flags_size, 4, 1, (FILE *)mat->fp);
5577
0
        fwrite(&array_flags, 4, 1, (FILE *)mat->fp);
5578
0
        fwrite(&nzmax, 4, 1, (FILE *)mat->fp);
5579
        /* Rank and Dimension */
5580
0
        nBytes = matvar->rank * 4;
5581
0
        fwrite(&dims_array_type, 4, 1, (FILE *)mat->fp);
5582
0
        fwrite(&nBytes, 4, 1, (FILE *)mat->fp);
5583
0
        for ( i = 0; i < matvar->rank; i++ ) {
5584
0
            mat_int32_t dim;
5585
0
            dim = matvar->dims[i];
5586
0
            fwrite(&dim, 4, 1, (FILE *)mat->fp);
5587
0
        }
5588
0
        if ( matvar->rank % 2 != 0 )
5589
0
            fwrite(&pad4, 4, 1, (FILE *)mat->fp);
5590
        /* Name of variable */
5591
0
        {
5592
0
            const char *name = matvar->name != NULL ? matvar->name : "";
5593
0
            if ( strlen(name) <= 4 ) {
5594
0
                mat_uint32_t array_name_type = MAT_T_INT8;
5595
0
                const mat_uint32_t array_name_len = (mat_uint32_t)strlen(name);
5596
0
                const mat_uint8_t pad1 = 0;
5597
0
                array_name_type |= array_name_len << 16;
5598
0
                fwrite(&array_name_type, 4, 1, (FILE *)mat->fp);
5599
0
                fwrite(name, 1, array_name_len, (FILE *)mat->fp);
5600
0
                for ( i = array_name_len; i < 4; i++ )
5601
0
                    fwrite(&pad1, 1, 1, (FILE *)mat->fp);
5602
0
            } else {
5603
0
                const mat_uint32_t array_name_type = MAT_T_INT8;
5604
0
                const mat_uint32_t array_name_len = (mat_uint32_t)strlen(name);
5605
0
                const mat_uint8_t pad1 = 0;
5606
5607
0
                fwrite(&array_name_type, 4, 1, (FILE *)mat->fp);
5608
0
                fwrite(&array_name_len, 4, 1, (FILE *)mat->fp);
5609
0
                fwrite(name, 1, array_name_len, (FILE *)mat->fp);
5610
0
                if ( array_name_len % 8 )
5611
0
                    for ( i = array_name_len % 8; i < 8; i++ )
5612
0
                        fwrite(&pad1, 1, 1, (FILE *)mat->fp);
5613
0
            }
5614
0
        }
5615
5616
0
        if ( NULL != matvar->internal ) {
5617
0
            matvar->internal->datapos = MatTell(mat);
5618
0
            if ( matvar->internal->datapos == -1L ) {
5619
0
                Mat_Critical("Couldn't determine file position");
5620
0
                return MATIO_E_GENERIC_READ_ERROR;
5621
0
            }
5622
0
        } else {
5623
            /* Must be empty */
5624
0
            matvar->class_type = MAT_C_EMPTY;
5625
0
        }
5626
0
        {
5627
0
            int err = WriteType(mat, matvar);
5628
0
            if ( err )
5629
0
                return err;
5630
0
        }
5631
0
#if HAVE_ZLIB
5632
0
    } else if ( compress == MAT_COMPRESSION_ZLIB ) {
5633
0
        mat_uint32_t comp_buf[512] = {0};
5634
0
        mat_uint32_t uncomp_buf[512];
5635
0
        int buf_size = 512, err, i;
5636
0
        size_t matrix_max_buf_size;
5637
0
        z_streamp z;
5638
5639
0
        z = (z_streamp)calloc(1, sizeof(*z));
5640
0
        if ( z == NULL )
5641
0
            return MATIO_E_OUT_OF_MEMORY;
5642
0
        err = deflateInit(z, Z_DEFAULT_COMPRESSION);
5643
0
        if ( err != Z_OK ) {
5644
0
            free(z);
5645
0
            Mat_Critical("deflateInit returned %s", zError(err));
5646
0
            return MATIO_E_FILE_FORMAT_VIOLATION;
5647
0
        }
5648
5649
0
        matrix_type = MAT_T_COMPRESSED;
5650
0
        fwrite(&matrix_type, 4, 1, (FILE *)mat->fp);
5651
0
        fwrite(&pad4, 4, 1, (FILE *)mat->fp);
5652
0
        start = MatTell(mat);
5653
5654
        /* Array Flags */
5655
0
        array_flags = matvar->class_type & CLASS_TYPE_MASK;
5656
0
        if ( matvar->isComplex )
5657
0
            array_flags |= MAT_F_COMPLEX;
5658
0
        if ( matvar->isGlobal )
5659
0
            array_flags |= MAT_F_GLOBAL;
5660
0
        if ( matvar->isLogical )
5661
0
            array_flags |= MAT_F_LOGICAL;
5662
0
        if ( matvar->class_type == MAT_C_SPARSE && NULL != matvar->data )
5663
0
            nzmax = ((mat_sparse_t *)matvar->data)->nzmax;
5664
5665
0
        memset(uncomp_buf, 0, sizeof(uncomp_buf));
5666
0
        uncomp_buf[0] = MAT_T_MATRIX;
5667
0
        err = GetMatrixMaxBufSize(matvar, &matrix_max_buf_size);
5668
0
        if ( err ) {
5669
0
            free(z);
5670
0
            return err;
5671
0
        }
5672
0
        if ( matrix_max_buf_size > UINT32_MAX ) {
5673
0
            free(z);
5674
0
            return MATIO_E_INDEX_TOO_BIG;
5675
0
        }
5676
        /* The rank/dimensions subelement is packed into the fixed-size
5677
         * uncomp_buf[512]: 6 header words followed by one word per dimension
5678
         * plus an optional padding word. Reject a rank that would not fit
5679
         * before it overflows the stack buffer. */
5680
0
        if ( matvar->rank < 0 || matvar->rank > 512 - 7 ) {
5681
0
            free(z);
5682
0
            return MATIO_E_INDEX_TOO_BIG;
5683
0
        }
5684
0
        uncomp_buf[1] = matrix_max_buf_size;
5685
0
        z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
5686
0
        z->avail_in = 8;
5687
0
        do {
5688
0
            z->next_out = ZLIB_BYTE_PTR(comp_buf);
5689
0
            z->avail_out = buf_size * sizeof(*comp_buf);
5690
0
            deflate(z, Z_NO_FLUSH);
5691
0
            fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out, (FILE *)mat->fp);
5692
0
        } while ( z->avail_out == 0 );
5693
0
        uncomp_buf[0] = array_flags_type;
5694
0
        uncomp_buf[1] = array_flags_size;
5695
0
        uncomp_buf[2] = array_flags;
5696
0
        uncomp_buf[3] = nzmax;
5697
        /* Rank and Dimension */
5698
0
        nBytes = matvar->rank * 4;
5699
0
        uncomp_buf[4] = dims_array_type;
5700
0
        uncomp_buf[5] = nBytes;
5701
0
        for ( i = 0; i < matvar->rank; i++ ) {
5702
0
            mat_int32_t dim;
5703
0
            dim = matvar->dims[i];
5704
0
            uncomp_buf[6 + i] = dim;
5705
0
        }
5706
0
        if ( matvar->rank % 2 != 0 ) {
5707
0
            uncomp_buf[6 + i] = pad4;
5708
0
            i++;
5709
0
        }
5710
5711
0
        z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
5712
0
        z->avail_in = (6 + i) * sizeof(*uncomp_buf);
5713
0
        do {
5714
0
            z->next_out = ZLIB_BYTE_PTR(comp_buf);
5715
0
            z->avail_out = buf_size * sizeof(*comp_buf);
5716
0
            deflate(z, Z_NO_FLUSH);
5717
0
            fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out, (FILE *)mat->fp);
5718
0
        } while ( z->avail_out == 0 );
5719
        /* Name of variable */
5720
0
        {
5721
0
            const char *name = matvar->name != NULL ? matvar->name : "";
5722
0
            if ( strlen(name) <= 4 ) {
5723
0
                mat_uint32_t array_name_len = (mat_uint32_t)strlen(name);
5724
0
                const mat_uint32_t array_name_type = MAT_T_INT8;
5725
5726
0
                memset(uncomp_buf, 0, 8);
5727
0
                uncomp_buf[0] = (array_name_len << 16) | array_name_type;
5728
0
                memcpy(uncomp_buf + 1, name, array_name_len);
5729
5730
0
                z->next_in = ZLIB_BYTE_PTR(uncomp_buf);
5731
0
                z->avail_in = 8;
5732
0
                do {
5733
0
                    z->next_out = ZLIB_BYTE_PTR(comp_buf);
5734
0
                    z->avail_out = buf_size * sizeof(*comp_buf);
5735
0
                    deflate(z, Z_NO_FLUSH);
5736
0
                    fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out,
5737
0
                           (FILE *)mat->fp);
5738
0
                } while ( z->avail_out == 0 );
5739
0
            } else {
5740
0
                const mat_uint32_t array_name_len = (mat_uint32_t)strlen(name);
5741
0
                const mat_uint32_t array_name_type = MAT_T_INT8;
5742
0
                const mat_uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0};
5743
0
                const Bytef *chunks[3];
5744
0
                uInt chunk_len[3];
5745
0
                int n_chunks = 2, c;
5746
5747
                /* Stream the name straight into the deflate stream instead of
5748
                 * copying it into the fixed uncomp_buf, so a name longer than
5749
                 * that buffer cannot overflow it. */
5750
0
                uncomp_buf[0] = array_name_type;
5751
0
                uncomp_buf[1] = array_name_len;
5752
0
                chunks[0] = ZLIB_BYTE_PTR(uncomp_buf);
5753
0
                chunk_len[0] = 8;
5754
0
                chunks[1] = ZLIB_BYTE_PTR(name);
5755
0
                chunk_len[1] = array_name_len;
5756
0
                if ( array_name_len % 8 ) {
5757
0
                    chunks[2] = ZLIB_BYTE_PTR(zeros);
5758
0
                    chunk_len[2] = 8 - (array_name_len % 8);
5759
0
                    n_chunks = 3;
5760
0
                }
5761
0
                for ( c = 0; c < n_chunks; c++ ) {
5762
0
                    z->next_in = (Bytef *)chunks[c];
5763
0
                    z->avail_in = chunk_len[c];
5764
0
                    do {
5765
0
                        z->next_out = ZLIB_BYTE_PTR(comp_buf);
5766
0
                        z->avail_out = buf_size * sizeof(*comp_buf);
5767
0
                        deflate(z, Z_NO_FLUSH);
5768
0
                        fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out,
5769
0
                               (FILE *)mat->fp);
5770
0
                    } while ( z->avail_out == 0 );
5771
0
                }
5772
0
            }
5773
0
        }
5774
0
        if ( NULL != matvar->internal ) {
5775
0
            matvar->internal->datapos = MatTell(mat);
5776
0
            if ( matvar->internal->datapos == -1L ) {
5777
0
                free(z);
5778
0
                Mat_Critical("Couldn't determine file position");
5779
0
                return MATIO_E_GENERIC_READ_ERROR;
5780
0
            }
5781
0
        } else {
5782
            /* Must be empty */
5783
0
            matvar->class_type = MAT_C_EMPTY;
5784
0
        }
5785
0
        WriteCompressedType(mat, matvar, z);
5786
0
        z->next_in = NULL;
5787
0
        z->avail_in = 0;
5788
0
        do {
5789
0
            z->next_out = ZLIB_BYTE_PTR(comp_buf);
5790
0
            z->avail_out = buf_size * sizeof(*comp_buf);
5791
0
            err = deflate(z, Z_FINISH);
5792
0
            fwrite(comp_buf, 1, buf_size * sizeof(*comp_buf) - z->avail_out, (FILE *)mat->fp);
5793
0
        } while ( err != Z_STREAM_END && z->avail_out == 0 );
5794
0
        (void)deflateEnd(z);
5795
0
        free(z);
5796
0
#endif
5797
0
    }
5798
0
    end = MatTell(mat);
5799
0
    if ( start != -1L && end != -1L ) {
5800
0
        const mat_uint32_t _nBytes = (mat_uint32_t)(end - start);
5801
0
        (void)MatSeek(mat, start - 4, SEEK_SET);
5802
0
        fwrite(&_nBytes, 4, 1, (FILE *)mat->fp);
5803
0
        (void)MatSeek(mat, end, SEEK_SET);
5804
0
    } else {
5805
0
        Mat_Critical("Couldn't determine file position");
5806
0
    }
5807
5808
0
    return MATIO_E_NO_ERROR;
5809
0
}
5810
5811
/** @brief Reads a tagged INT8 string from file (handles packed and normal format)
5812
 */
5813
static int
5814
ReadTaggedString(mat_t *mat, char **str, const mat_uint32_t *pre_buf)
5815
207
{
5816
207
    mat_uint32_t tag[2];
5817
207
    int err;
5818
5819
207
    *str = NULL;
5820
5821
207
    if ( pre_buf != NULL ) {
5822
69
        tag[0] = pre_buf[0];
5823
69
        tag[1] = pre_buf[1];
5824
138
    } else {
5825
138
        err = Read(tag, 4, 2, mat, NULL);
5826
138
        if ( err )
5827
0
            return err;
5828
138
        if ( mat->byteswap ) {
5829
124
            (void)Mat_uint32Swap(&tag[0]);
5830
124
        }
5831
138
    }
5832
5833
207
    if ( tag[0] == MAT_T_INT8 ) { /* Normal format: type in tag[0], length in tag[1] */
5834
63
        mat_uint32_t len, len_pad;
5835
63
        if ( pre_buf == NULL && mat->byteswap )
5836
62
            (void)Mat_uint32Swap(&tag[1]);
5837
63
        len = tag[1];
5838
63
        if ( len % 8 == 0 )
5839
1
            len_pad = len;
5840
62
        else if ( len < UINT32_MAX - 8 + (len % 8) )
5841
62
            len_pad = len + 8 - (len % 8);
5842
0
        else
5843
0
            return MATIO_E_FILE_FORMAT_VIOLATION;
5844
63
        *str = (char *)malloc(len_pad + 1);
5845
63
        if ( *str == NULL )
5846
0
            return MATIO_E_OUT_OF_MEMORY;
5847
63
        err = Read(*str, 1, len_pad, mat, NULL);
5848
63
        if ( err ) {
5849
0
            free(*str);
5850
0
            *str = NULL;
5851
0
            return err;
5852
0
        }
5853
63
        (*str)[len] = '\0';
5854
144
    } else {
5855
        /* Small element format: type in lower 16 bits, length in upper 16 bits */
5856
144
        mat_uint32_t len = (tag[0] & 0xffff0000) >> 16;
5857
144
        mat_uint32_t type = tag[0] & 0x0000ffff;
5858
144
        if ( type == MAT_T_INT8 && len > 0 && len <= 4 ) {
5859
6
            *str = (char *)malloc(len + 1);
5860
6
            if ( *str == NULL )
5861
0
                return MATIO_E_OUT_OF_MEMORY;
5862
6
            if ( pre_buf != NULL && mat->byteswap )
5863
0
                (void)Mat_uint32Swap(&tag[1]);
5864
6
            memcpy(*str, &tag[1], len);
5865
6
            (*str)[len] = '\0';
5866
6
        }
5867
144
    }
5868
5869
207
    return MATIO_E_NO_ERROR;
5870
207
}
5871
5872
/** @brief Processes opaque metadata after reading/inflating
5873
 *
5874
 * Byte-swaps metadata values if needed, then extracts rank/dims or
5875
 * delegates to ParseOpaqueMetadata.
5876
 *
5877
 * @param mat MAT file pointer
5878
 * @param matvar MAT variable pointer
5879
 * @param meta Metadata buffer (freed by this function)
5880
 * @param meta_nvals Number of uint32 values in meta
5881
 * @retval 0 on success
5882
 */
5883
static int
5884
ProcessOpaqueMetadata(mat_t *mat, matvar_t *matvar, mat_uint32_t *meta, mat_uint32_t meta_nvals)
5885
9
{
5886
9
    int err = MATIO_E_NO_ERROR;
5887
5888
9
    if ( mat->byteswap ) {
5889
9
        mat_uint32_t k;
5890
44.5k
        for ( k = 0; k < meta_nvals; k++ )
5891
44.4k
            (void)Mat_uint32Swap(&meta[k]);
5892
9
    }
5893
5894
9
    if ( meta_nvals >= 4 ) {
5895
9
#if defined(MCOS) && MCOS
5896
9
        err = ParseOpaqueMetadata(meta, meta_nvals, matvar);
5897
9
        if ( err ) {
5898
9
            free(meta);
5899
9
            return err;
5900
9
        }
5901
#else
5902
        mat_uint32_t ndims = meta[1];
5903
        mat_uint32_t dim_start = 2;
5904
5905
        if ( ndims < meta_nvals - dim_start ) {
5906
            mat_uint32_t d;
5907
            matvar->rank = (int)ndims;
5908
            matvar->dims = (size_t *)malloc(ndims * sizeof(size_t));
5909
            if ( matvar->dims != NULL ) {
5910
                for ( d = 0; d < ndims; d++ )
5911
                    matvar->dims[d] = meta[dim_start + d];
5912
            }
5913
        }
5914
#endif
5915
9
    }
5916
0
    free(meta);
5917
5918
0
    return err;
5919
9
}
5920
5921
/** @brief Reads opaque variable subelements from an uncompressed stream
5922
 *
5923
 * Reads: array name, type system name, class name, object metadata.
5924
 * The name_tag parameter provides the pre-read 2 uint32 tag for the name.
5925
 */
5926
static int
5927
ReadOpaqueInfo5(mat_t *mat, matvar_t *matvar, const mat_uint32_t *name_tag)
5928
69
{
5929
69
    int err;
5930
69
    mat_uint32_t tag[2];
5931
69
    char *type_name = NULL;
5932
69
    char *class_name = NULL;
5933
5934
    /* Array name - use pre-read tag */
5935
69
    err = ReadTaggedString(mat, &matvar->name, name_tag);
5936
69
    if ( err )
5937
0
        return err;
5938
5939
    /* Type system name (e.g. "MCOS") */
5940
69
    err = ReadTaggedString(mat, &type_name, NULL);
5941
69
    if ( err )
5942
0
        return err;
5943
69
#if defined(MCOS) && MCOS
5944
69
    matvar->internal->type_name = type_name;
5945
#else
5946
    free(type_name);
5947
#endif
5948
5949
    /* Class name (e.g. "table", "SimpleClass") */
5950
69
    err = ReadTaggedString(mat, &class_name, NULL);
5951
69
    if ( err )
5952
0
        return err;
5953
69
#if defined(MCOS) && MCOS
5954
69
    matvar->internal->class_name = class_name;
5955
#else
5956
    free(class_name);
5957
#endif
5958
5959
    /* Object metadata: miUINT32 array
5960
     * Contains: reference_value (0xDD000000), ndims, dim1, dim2, ..., obj_id(s), class_id
5961
     */
5962
69
    err = Read(tag, 4, 2, mat, NULL);
5963
69
    if ( err )
5964
0
        return err;
5965
69
    if ( mat->byteswap ) {
5966
62
        (void)Mat_uint32Swap(&tag[0]);
5967
62
        (void)Mat_uint32Swap(&tag[1]);
5968
62
    }
5969
5970
69
    {
5971
69
        mat_uint32_t meta_type = tag[0];
5972
69
        mat_uint32_t meta_nbytes = tag[1];
5973
69
        mat_uint32_t meta_nvals;
5974
69
        mat_uint32_t *meta = NULL;
5975
69
        mat_uint32_t meta_pad;
5976
69
        int is_small = 0;
5977
5978
        /* The 4th subelement may be wrapped in a MAT_T_MATRIX container.
5979
         * If so, read through the inner matrix structure (array_flags,
5980
         * rank/dims, name) to reach the actual UINT32 data.
5981
         * For enum instance arrays, the inner matrix is a struct instead.
5982
         */
5983
69
        if ( meta_type == MAT_T_MATRIX ) {
5984
51
            mat_uint32_t inner[4];
5985
51
            mat_uint32_t inner_dims_tag[2];
5986
51
            mat_uint32_t ndims_bytes, ndims_pad;
5987
51
            enum matio_classes inner_class;
5988
5989
            /* Array flags: 16 bytes (tag + data) */
5990
51
            err = Read(inner, 4, 4, mat, NULL);
5991
51
            if ( err )
5992
0
                return err;
5993
5994
51
            if ( mat->byteswap )
5995
51
                (void)Mat_uint32Swap(&inner[2]);
5996
51
            inner_class = CLASS_FROM_ARRAY_FLAGS(inner[2]);
5997
5998
            /* Rank/dims tag */
5999
51
            err = Read(inner_dims_tag, 4, 2, mat, NULL);
6000
51
            if ( err )
6001
0
                return err;
6002
51
            if ( mat->byteswap ) {
6003
51
                (void)Mat_uint32Swap(&inner_dims_tag[0]);
6004
51
                (void)Mat_uint32Swap(&inner_dims_tag[1]);
6005
51
            }
6006
51
            ndims_bytes = inner_dims_tag[1];
6007
51
            ndims_pad = (ndims_bytes % 8 == 0) ? ndims_bytes : ndims_bytes + 8 - (ndims_bytes % 8);
6008
6009
51
            if ( inner_class == MAT_C_STRUCT ) {
6010
                /* Enum instance: inner matrix is a struct.
6011
                 * Read dims, skip name, then use ReadNextStructField.
6012
                 */
6013
0
                mat_uint32_t rank_inner = ndims_bytes / sizeof(mat_uint32_t);
6014
0
                if ( ndims_pad > 0 ) {
6015
0
                    mat_uint32_t *dims_buf = (mat_uint32_t *)malloc(ndims_pad);
6016
0
                    if ( dims_buf == NULL )
6017
0
                        return MATIO_E_OUT_OF_MEMORY;
6018
0
                    err = Read(dims_buf, 1, ndims_pad, mat, NULL);
6019
0
                    if ( err ) {
6020
0
                        free(dims_buf);
6021
0
                        return err;
6022
0
                    }
6023
0
                    matvar->rank = (int)rank_inner;
6024
0
                    matvar->dims = (size_t *)calloc(rank_inner, sizeof(size_t));
6025
0
                    if ( matvar->dims != NULL ) {
6026
0
                        mat_uint32_t j_d;
6027
0
                        for ( j_d = 0; j_d < rank_inner; j_d++ ) {
6028
0
                            if ( mat->byteswap )
6029
0
                                matvar->dims[j_d] = Mat_uint32Swap(dims_buf + j_d);
6030
0
                            else
6031
0
                                matvar->dims[j_d] = dims_buf[j_d];
6032
0
                        }
6033
0
                    }
6034
0
                    free(dims_buf);
6035
0
                }
6036
6037
                /* Skip inner matrix name (empty) */
6038
0
                {
6039
0
                    mat_uint32_t name_tag2[2];
6040
0
                    err = Read(name_tag2, 4, 2, mat, NULL);
6041
0
                    if ( err )
6042
0
                        return err;
6043
0
                    if ( mat->byteswap )
6044
0
                        (void)Mat_uint32Swap(name_tag2);
6045
0
                    if ( name_tag2[0] == MAT_T_INT8 ) {
6046
0
                        mat_uint32_t name_len;
6047
0
                        if ( mat->byteswap )
6048
0
                            name_len = Mat_uint32Swap(name_tag2 + 1);
6049
0
                        else
6050
0
                            name_len = name_tag2[1];
6051
0
                        {
6052
0
                            mat_uint32_t name_pad =
6053
0
                                (name_len % 8 == 0) ? name_len : name_len + 8 - (name_len % 8);
6054
0
                            if ( name_pad > 0 )
6055
0
                                (void)MatSeek(mat, (mat_off_t)name_pad, SEEK_CUR);
6056
0
                        }
6057
0
                    }
6058
0
                }
6059
6060
                /* Read struct fields */
6061
0
                matvar->class_type = MAT_C_STRUCT;
6062
0
                matvar->data_type = MAT_T_STRUCT;
6063
0
                matvar->data_size = sizeof(matvar_t *);
6064
0
                (void)ReadNextStructField(mat, matvar);
6065
6066
0
                free(meta);
6067
0
                return MATIO_E_NO_ERROR;
6068
0
            }
6069
6070
            /* Non-struct inner matrix: skip dims and name, read UINT32 data tag */
6071
51
            if ( ndims_pad > 0 )
6072
51
                (void)MatSeek(mat, (mat_off_t)ndims_pad, SEEK_CUR);
6073
6074
            /* Name tag: skip name */
6075
51
            {
6076
51
                mat_uint32_t data_tag[2];
6077
51
                err = Read(data_tag, 4, 2, mat, NULL);
6078
51
                if ( err )
6079
36
                    return err;
6080
15
                if ( mat->byteswap )
6081
15
                    (void)Mat_uint32Swap(data_tag);
6082
15
                if ( data_tag[0] == MAT_T_INT8 ) {
6083
9
                    mat_uint32_t name_len;
6084
9
                    mat_uint32_t name_pad;
6085
9
                    if ( mat->byteswap )
6086
9
                        name_len = Mat_uint32Swap(data_tag + 1);
6087
0
                    else
6088
0
                        name_len = data_tag[1];
6089
9
                    name_pad = (name_len % 8 == 0) ? name_len : name_len + 8 - (name_len % 8);
6090
9
                    if ( name_pad > 0 )
6091
9
                        (void)MatSeek(mat, (mat_off_t)name_pad, SEEK_CUR);
6092
9
                }
6093
6094
                /* Data tag: should be our UINT32 data */
6095
15
                err = Read(data_tag, 4, 2, mat, NULL);
6096
15
                if ( err )
6097
0
                    return err;
6098
15
                if ( mat->byteswap ) {
6099
15
                    (void)Mat_uint32Swap(&data_tag[0]);
6100
15
                    (void)Mat_uint32Swap(&data_tag[1]);
6101
15
                }
6102
6103
                /* Use the data tag as the metadata tag */
6104
15
                meta_type = data_tag[0];
6105
15
                meta_nbytes = data_tag[1];
6106
15
            }
6107
15
        }
6108
6109
        /* Handle small element format */
6110
33
        if ( (meta_type & 0xffff0000) != 0 ) {
6111
11
            meta_nbytes = (meta_type & 0xffff0000) >> 16;
6112
11
            meta_type = meta_type & 0x0000ffff;
6113
11
            is_small = 1;
6114
11
        }
6115
6116
33
        if ( meta_type != MAT_T_UINT32 || meta_nbytes == 0 ) {
6117
24
            if ( !is_small && meta_nbytes > 0 ) {
6118
7
                meta_pad =
6119
7
                    (meta_nbytes % 8 == 0) ? meta_nbytes : meta_nbytes + 8 - (meta_nbytes % 8);
6120
7
                (void)MatSeek(mat, (mat_off_t)meta_pad, SEEK_CUR);
6121
7
            }
6122
24
            return MATIO_E_NO_ERROR;
6123
24
        }
6124
6125
9
        meta_nvals = meta_nbytes / sizeof(mat_uint32_t);
6126
9
        if ( is_small ) {
6127
            /* Data is in tag[1] */
6128
0
            if ( meta_nvals == 1 ) {
6129
0
                meta = (mat_uint32_t *)malloc(sizeof(mat_uint32_t));
6130
0
                if ( meta == NULL )
6131
0
                    return MATIO_E_OUT_OF_MEMORY;
6132
0
                meta[0] = tag[1];
6133
0
            }
6134
9
        } else {
6135
9
            if ( meta_nbytes > UINT32_MAX - 7 ) {
6136
0
                return MATIO_E_FILE_FORMAT_VIOLATION;
6137
0
            }
6138
9
            meta_pad = (meta_nbytes % 8 == 0) ? meta_nbytes : meta_nbytes + 8 - (meta_nbytes % 8);
6139
9
            meta = (mat_uint32_t *)malloc(meta_pad);
6140
9
            if ( meta == NULL )
6141
0
                return MATIO_E_OUT_OF_MEMORY;
6142
9
            err = Read(meta, 1, meta_pad, mat, NULL);
6143
9
            if ( err ) {
6144
0
                free(meta);
6145
0
                return err;
6146
0
            }
6147
9
        }
6148
6149
9
        if ( meta != NULL ) {
6150
9
            err = ProcessOpaqueMetadata(mat, matvar, meta, meta_nvals);
6151
9
            if ( err )
6152
9
                return err;
6153
9
        }
6154
9
    }
6155
6156
0
    return MATIO_E_NO_ERROR;
6157
9
}
6158
6159
#if HAVE_ZLIB
6160
/** @brief Reads opaque variable subelements from a compressed stream
6161
 *
6162
 * Reads: array name, type system name, class name, object metadata.
6163
 */
6164
static int
6165
ReadCompressedOpaqueInfo5(mat_t *mat, matvar_t *matvar, size_t *bytesread)
6166
0
{
6167
0
    mat_uint32_t buf[4];
6168
0
    int err;
6169
6170
    /* Inflate and parse a tagged string from z stream into out_str.
6171
     * Same logic as INFLATE_TAGGED_STRING but uses return (not break) on error,
6172
     * since ReadCompressedOpaqueInfo5 returns immediately on any failure.
6173
     */
6174
0
#define READ_COMPRESSED_STRING(z_strm, bytesread_ptr, out_str)                         \
6175
0
    do {                                                                               \
6176
0
        mat_uint32_t _tag[2];                                                          \
6177
0
        char *_s = NULL;                                                               \
6178
0
        err = Inflate(mat, z_strm, _tag, 8, bytesread_ptr);                            \
6179
0
        if ( err )                                                                     \
6180
0
            return err;                                                                \
6181
0
        if ( mat->byteswap )                                                           \
6182
0
            (void)Mat_uint32Swap(_tag);                                                \
6183
0
        if ( _tag[0] == MAT_T_INT8 ) {                                                 \
6184
0
            mat_uint32_t _len, _pad;                                                   \
6185
0
            if ( mat->byteswap )                                                       \
6186
0
                _len = Mat_uint32Swap(_tag + 1);                                       \
6187
0
            else                                                                       \
6188
0
                _len = _tag[1];                                                        \
6189
0
            if ( _len % 8 == 0 )                                                       \
6190
0
                _pad = _len;                                                           \
6191
0
            else if ( _len < UINT32_MAX - 8 + (_len % 8) )                             \
6192
0
                _pad = _len + 8 - (_len % 8);                                          \
6193
0
            else                                                                       \
6194
0
                return MATIO_E_FILE_FORMAT_VIOLATION;                                  \
6195
0
            _s = (char *)malloc(_pad + 1);                                             \
6196
0
            if ( _s == NULL )                                                          \
6197
0
                return MATIO_E_OUT_OF_MEMORY;                                          \
6198
0
            if ( _pad > 0 ) {                                                          \
6199
0
                err = Inflate(mat, z_strm, _s, _pad, bytesread_ptr);                   \
6200
0
                if ( err ) {                                                           \
6201
0
                    free(_s);                                                          \
6202
0
                    return err;                                                        \
6203
0
                }                                                                      \
6204
0
            }                                                                          \
6205
0
            _s[_len] = '\0';                                                           \
6206
0
        } else {                                                                       \
6207
0
            mat_uint32_t _slen = (_tag[0] & 0xffff0000) >> 16;                         \
6208
0
            if ( ((_tag[0] & 0x0000ffff) == MAT_T_INT8) && _slen > 0 && _slen <= 4 ) { \
6209
0
                _s = (char *)malloc(_slen + 1);                                        \
6210
0
                if ( _s == NULL )                                                      \
6211
0
                    return MATIO_E_OUT_OF_MEMORY;                                      \
6212
0
                memcpy(_s, _tag + 1, _slen);                                           \
6213
0
                _s[_slen] = '\0';                                                      \
6214
0
            }                                                                          \
6215
0
        }                                                                              \
6216
0
        (out_str) = _s;                                                                \
6217
0
    } while ( 0 )
6218
6219
    /* Array name */
6220
0
    READ_COMPRESSED_STRING(matvar->internal->z, bytesread, matvar->name);
6221
6222
    /* Type system name */
6223
0
    {
6224
0
        char *type_name_tmp = NULL;
6225
0
        READ_COMPRESSED_STRING(matvar->internal->z, bytesread, type_name_tmp);
6226
0
#if defined(MCOS) && MCOS
6227
0
        matvar->internal->type_name = type_name_tmp;
6228
#else
6229
        free(type_name_tmp);
6230
#endif
6231
0
    }
6232
6233
    /* Class name */
6234
0
    {
6235
0
        char *class_name_tmp = NULL;
6236
0
        READ_COMPRESSED_STRING(matvar->internal->z, bytesread, class_name_tmp);
6237
0
#if defined(MCOS) && MCOS
6238
0
        matvar->internal->class_name = class_name_tmp;
6239
#else
6240
        free(class_name_tmp);
6241
#endif
6242
0
    }
6243
6244
    /* Object metadata: miUINT32 array */
6245
0
    err = Inflate(mat, matvar->internal->z, buf, 8, bytesread);
6246
0
    if ( err )
6247
0
        return err;
6248
0
    if ( mat->byteswap ) {
6249
0
        (void)Mat_uint32Swap(buf);
6250
0
        (void)Mat_uint32Swap(buf + 1);
6251
0
    }
6252
6253
0
    {
6254
0
        mat_uint32_t meta_type = buf[0];
6255
0
        mat_uint32_t meta_nbytes = buf[1];
6256
0
        mat_uint32_t meta_nvals;
6257
0
        mat_uint32_t *meta = NULL;
6258
0
        mat_uint32_t meta_pad;
6259
0
        int is_small = 0;
6260
6261
        /* The 4th subelement may be wrapped in a MAT_T_MATRIX container.
6262
         * If so, read through the inner matrix structure (array_flags,
6263
         * rank/dims, name) to reach the actual UINT32 data.
6264
         * For enum instance arrays, the inner matrix is a struct instead.
6265
         */
6266
0
        if ( meta_type == MAT_T_MATRIX ) {
6267
0
            mat_uint32_t inner[4];
6268
0
            mat_uint32_t inner_dims_tag[2];
6269
0
            mat_uint32_t name_tag2[2];
6270
0
            mat_uint32_t ndims_bytes, ndims_pad;
6271
0
            enum matio_classes inner_class;
6272
6273
            /* Array flags: 16 bytes (tag + data) */
6274
0
            err = Inflate(mat, matvar->internal->z, inner, 16, bytesread);
6275
0
            if ( err )
6276
0
                return err;
6277
6278
0
            if ( mat->byteswap )
6279
0
                (void)Mat_uint32Swap(&inner[2]);
6280
0
            inner_class = CLASS_FROM_ARRAY_FLAGS(inner[2]);
6281
6282
            /* Rank/dims tag */
6283
0
            err = Inflate(mat, matvar->internal->z, inner_dims_tag, 8, bytesread);
6284
0
            if ( err )
6285
0
                return err;
6286
0
            if ( mat->byteswap ) {
6287
0
                (void)Mat_uint32Swap(&inner_dims_tag[0]);
6288
0
                (void)Mat_uint32Swap(&inner_dims_tag[1]);
6289
0
            }
6290
0
            ndims_bytes = inner_dims_tag[1];
6291
0
            ndims_pad = (ndims_bytes % 8 == 0) ? ndims_bytes : ndims_bytes + 8 - (ndims_bytes % 8);
6292
6293
0
            if ( inner_class == MAT_C_STRUCT ) {
6294
                /* Enum instance: inner matrix is a struct.
6295
                 * Read dims, skip name, then use ReadNextStructField to
6296
                 * read field names and values from the z stream.
6297
                 */
6298
0
                mat_uint32_t rank_inner = ndims_bytes / sizeof(mat_uint32_t);
6299
0
                mat_uint32_t *dims_buf = NULL;
6300
0
                if ( ndims_pad > 0 ) {
6301
0
                    dims_buf = (mat_uint32_t *)malloc(ndims_pad);
6302
0
                    if ( dims_buf == NULL )
6303
0
                        return MATIO_E_OUT_OF_MEMORY;
6304
0
                    err = Inflate(mat, matvar->internal->z, dims_buf, ndims_pad, bytesread);
6305
0
                    if ( err ) {
6306
0
                        free(dims_buf);
6307
0
                        return err;
6308
0
                    }
6309
0
                }
6310
0
                matvar->rank = (int)rank_inner;
6311
0
                matvar->dims = (size_t *)calloc(rank_inner, sizeof(size_t));
6312
0
                if ( matvar->dims != NULL && dims_buf != NULL ) {
6313
0
                    mat_uint32_t j_d;
6314
0
                    for ( j_d = 0; j_d < rank_inner; j_d++ ) {
6315
0
                        if ( mat->byteswap )
6316
0
                            matvar->dims[j_d] = Mat_uint32Swap(dims_buf + j_d);
6317
0
                        else
6318
0
                            matvar->dims[j_d] = dims_buf[j_d];
6319
0
                    }
6320
0
                }
6321
0
                free(dims_buf);
6322
6323
                /* Skip inner matrix name (empty) */
6324
0
                err = Inflate(mat, matvar->internal->z, name_tag2, 8, bytesread);
6325
0
                if ( err )
6326
0
                    return err;
6327
0
                if ( mat->byteswap )
6328
0
                    (void)Mat_uint32Swap(name_tag2);
6329
0
                if ( name_tag2[0] == MAT_T_INT8 ) {
6330
0
                    if ( mat->byteswap )
6331
0
                        (void)Mat_uint32Swap(name_tag2 + 1);
6332
0
                    {
6333
0
                        mat_uint32_t name_len = name_tag2[1];
6334
0
                        mat_uint32_t name_pad =
6335
0
                            (name_len % 8 == 0) ? name_len : name_len + 8 - (name_len % 8);
6336
0
                        if ( name_pad > 0 ) {
6337
0
                            char *skip_nm = (char *)malloc(name_pad);
6338
0
                            if ( skip_nm == NULL )
6339
0
                                return MATIO_E_OUT_OF_MEMORY;
6340
0
                            err = Inflate(mat, matvar->internal->z, skip_nm, name_pad, bytesread);
6341
0
                            free(skip_nm);
6342
0
                            if ( err )
6343
0
                                return err;
6344
0
                        }
6345
0
                    }
6346
0
                }
6347
6348
                /* Read struct fields (field_name_length, field_names, values) */
6349
0
                matvar->class_type = MAT_C_STRUCT;
6350
0
                matvar->data_type = MAT_T_STRUCT;
6351
0
                matvar->data_size = sizeof(matvar_t *);
6352
0
                (void)ReadNextStructField(mat, matvar);
6353
6354
0
                return MATIO_E_NO_ERROR;
6355
0
            }
6356
6357
            /* Non-struct inner matrix: skip dims and name, then read UINT32 data tag */
6358
0
            if ( ndims_pad > 0 ) {
6359
0
                mat_uint32_t *skip = (mat_uint32_t *)malloc(ndims_pad);
6360
0
                if ( skip == NULL )
6361
0
                    return MATIO_E_OUT_OF_MEMORY;
6362
0
                err = Inflate(mat, matvar->internal->z, skip, ndims_pad, bytesread);
6363
0
                free(skip);
6364
0
                if ( err )
6365
0
                    return err;
6366
0
            }
6367
6368
            /* Name tag: skip empty name */
6369
0
            err = Inflate(mat, matvar->internal->z, name_tag2, 8, bytesread);
6370
0
            if ( err )
6371
0
                return err;
6372
0
            if ( mat->byteswap )
6373
0
                (void)Mat_uint32Swap(name_tag2);
6374
0
            if ( name_tag2[0] == MAT_T_INT8 ) {
6375
0
                if ( mat->byteswap )
6376
0
                    (void)Mat_uint32Swap(name_tag2 + 1);
6377
0
                {
6378
0
                    mat_uint32_t name_len = name_tag2[1];
6379
0
                    mat_uint32_t name_pad =
6380
0
                        (name_len % 8 == 0) ? name_len : name_len + 8 - (name_len % 8);
6381
0
                    if ( name_pad > 0 ) {
6382
0
                        char *skip_nm = (char *)malloc(name_pad);
6383
0
                        if ( skip_nm == NULL )
6384
0
                            return MATIO_E_OUT_OF_MEMORY;
6385
0
                        err = Inflate(mat, matvar->internal->z, skip_nm, name_pad, bytesread);
6386
0
                        free(skip_nm);
6387
0
                        if ( err )
6388
0
                            return err;
6389
0
                    }
6390
0
                }
6391
0
            }
6392
6393
0
            {
6394
0
                mat_uint32_t data_tag[2];
6395
                /* Data tag: should be our UINT32 data */
6396
0
                err = Inflate(mat, matvar->internal->z, data_tag, 8, bytesread);
6397
0
                if ( err )
6398
0
                    return err;
6399
0
                if ( mat->byteswap ) {
6400
0
                    (void)Mat_uint32Swap(&data_tag[0]);
6401
0
                    (void)Mat_uint32Swap(&data_tag[1]);
6402
0
                }
6403
6404
                /* Use the data tag as the metadata tag */
6405
0
                meta_type = data_tag[0];
6406
0
                meta_nbytes = data_tag[1];
6407
0
            }
6408
0
        }
6409
6410
0
        is_small = 0;
6411
0
        if ( (meta_type & 0xffff0000) != 0 ) {
6412
0
            meta_nbytes = (meta_type & 0xffff0000) >> 16;
6413
0
            meta_type = meta_type & 0x0000ffff;
6414
0
            is_small = 1;
6415
0
        }
6416
6417
0
        if ( meta_type != MAT_T_UINT32 || meta_nbytes == 0 )
6418
0
            return MATIO_E_NO_ERROR;
6419
6420
0
        meta_nvals = meta_nbytes / sizeof(mat_uint32_t);
6421
6422
0
        if ( is_small ) {
6423
0
            if ( meta_nvals == 1 ) {
6424
0
                meta = (mat_uint32_t *)malloc(sizeof(mat_uint32_t));
6425
0
                if ( meta == NULL )
6426
0
                    return MATIO_E_OUT_OF_MEMORY;
6427
0
                meta[0] = buf[1];
6428
0
            }
6429
0
        } else {
6430
0
            if ( meta_nbytes > UINT32_MAX - 7 ) {
6431
0
                return MATIO_E_FILE_FORMAT_VIOLATION;
6432
0
            }
6433
0
            meta_pad = (meta_nbytes % 8 == 0) ? meta_nbytes : meta_nbytes + 8 - (meta_nbytes % 8);
6434
0
            meta = (mat_uint32_t *)malloc(meta_pad);
6435
0
            if ( meta == NULL )
6436
0
                return MATIO_E_OUT_OF_MEMORY;
6437
0
            err = Inflate(mat, matvar->internal->z, meta, meta_pad, bytesread);
6438
0
            if ( err ) {
6439
0
                free(meta);
6440
0
                return err;
6441
0
            }
6442
0
        }
6443
6444
0
        if ( meta != NULL ) {
6445
0
            err = ProcessOpaqueMetadata(mat, matvar, meta, meta_nvals);
6446
0
            if ( err )
6447
0
                return err;
6448
0
        }
6449
0
    }
6450
6451
0
#undef READ_COMPRESSED_STRING
6452
6453
0
    return MATIO_E_NO_ERROR;
6454
0
}
6455
#endif
6456
6457
/** @if mat_devman
6458
 * @brief Reads the header information for the next MAT variable
6459
 *
6460
 * @ingroup mat_internal
6461
 * @param mat MAT file pointer
6462
 * @return pointer to the MAT variable or NULL
6463
 * @endif
6464
 */
6465
matvar_t *
6466
Mat_VarReadNextInfo5(mat_t *mat)
6467
21.1k
{
6468
21.1k
    int err;
6469
21.1k
    mat_uint32_t data_type, nBytes;
6470
21.1k
    mat_off_t fpos;
6471
21.1k
    matvar_t *matvar = NULL;
6472
6473
21.1k
    if ( mat == NULL || mat->fp == NULL )
6474
0
        return NULL;
6475
6476
21.1k
    if ( IsEndOfFile(mat, &fpos) )
6477
65
        return NULL;
6478
6479
21.0k
    if ( fpos == -1L )
6480
0
        return NULL;
6481
6482
21.0k
    {
6483
21.0k
        size_t nbytes = 0;
6484
21.0k
        err = Read(&data_type, sizeof(mat_uint32_t), 1, mat, &nbytes);
6485
21.0k
        if ( err || 0 == nbytes )
6486
119
            return NULL;
6487
21.0k
    }
6488
20.9k
    err = Read(&nBytes, sizeof(mat_uint32_t), 1, mat, NULL);
6489
20.9k
    if ( err )
6490
0
        return NULL;
6491
20.9k
    if ( mat->byteswap ) {
6492
12.9k
        (void)Mat_uint32Swap(&data_type);
6493
12.9k
        (void)Mat_uint32Swap(&nBytes);
6494
12.9k
    }
6495
20.9k
    if ( nBytes > UINT32_MAX - 8 )
6496
83
        return NULL;
6497
20.8k
    switch ( data_type ) {
6498
3.70k
        case MAT_T_COMPRESSED: {
6499
3.70k
#if HAVE_ZLIB
6500
3.70k
            mat_uint32_t uncomp_buf[16];
6501
3.70k
            size_t bytesread = 0;
6502
6503
3.70k
            memset(uncomp_buf, 0, sizeof(uncomp_buf));
6504
3.70k
            matvar = Mat_VarCalloc();
6505
3.70k
            if ( NULL == matvar ) {
6506
0
                Mat_Critical("Couldn't allocate memory");
6507
0
                break;
6508
0
            }
6509
6510
3.70k
            matvar->compression = MAT_COMPRESSION_ZLIB;
6511
3.70k
            matvar->internal->z = (z_streamp)calloc(1, sizeof(z_stream));
6512
3.70k
            err = inflateInit(matvar->internal->z);
6513
3.70k
            if ( err != Z_OK ) {
6514
0
                Mat_VarFree(matvar);
6515
0
                matvar = NULL;
6516
0
                Mat_Critical("inflateInit returned %s", zError(err));
6517
0
                break;
6518
0
            }
6519
6520
            /* Read variable tag */
6521
3.70k
            err = Inflate(mat, matvar->internal->z, uncomp_buf, 8, &bytesread);
6522
3.70k
            if ( err ) {
6523
8
                Mat_VarFree(matvar);
6524
8
                matvar = NULL;
6525
8
                break;
6526
8
            }
6527
3.69k
            if ( mat->byteswap ) {
6528
2.06k
                (void)Mat_uint32Swap(uncomp_buf);
6529
2.06k
                (void)Mat_uint32Swap(uncomp_buf + 1);
6530
2.06k
            }
6531
3.69k
            if ( uncomp_buf[0] != MAT_T_MATRIX ) {
6532
1
                (void)MatSeek(mat, (mat_off_t)(nBytes - bytesread), SEEK_CUR);
6533
1
                Mat_VarFree(matvar);
6534
1
                matvar = NULL;
6535
1
                Mat_Critical("Uncompressed type not MAT_T_MATRIX");
6536
1
                break;
6537
1
            }
6538
            /* Array flags */
6539
3.69k
            err = Inflate(mat, matvar->internal->z, uncomp_buf, 16, &bytesread);
6540
3.69k
            if ( err ) {
6541
0
                Mat_VarFree(matvar);
6542
0
                matvar = NULL;
6543
0
                break;
6544
0
            }
6545
3.69k
            if ( mat->byteswap ) {
6546
2.06k
                (void)Mat_uint32Swap(uncomp_buf);
6547
2.06k
                (void)Mat_uint32Swap(uncomp_buf + 2);
6548
2.06k
                (void)Mat_uint32Swap(uncomp_buf + 3);
6549
2.06k
            }
6550
            /* Array flags */
6551
3.69k
            if ( uncomp_buf[0] == MAT_T_UINT32 ) {
6552
3.68k
                mat_uint32_t array_flags = uncomp_buf[2];
6553
3.68k
                matvar->class_type = CLASS_FROM_ARRAY_FLAGS(array_flags);
6554
3.68k
                matvar->isComplex = (array_flags & MAT_F_COMPLEX);
6555
3.68k
                matvar->isGlobal = (array_flags & MAT_F_GLOBAL);
6556
3.68k
                matvar->isLogical = (array_flags & MAT_F_LOGICAL);
6557
3.68k
                if ( matvar->class_type == MAT_C_SPARSE ) {
6558
                    /* Need to find a more appropriate place to store nzmax */
6559
2
                    matvar->nbytes = uncomp_buf[3];
6560
2
                }
6561
3.68k
            }
6562
3.69k
            if ( matvar->class_type != MAT_C_OPAQUE ) {
6563
3.69k
                mat_uint32_t *dims = NULL;
6564
3.69k
                int do_clean = 0;
6565
3.69k
                err = InflateRankDims(mat, matvar->internal->z, uncomp_buf, sizeof(uncomp_buf),
6566
3.69k
                                      &dims, &bytesread);
6567
3.69k
                if ( NULL == dims ) {
6568
3.68k
                    dims = uncomp_buf + 2;
6569
3.68k
                } else {
6570
9
                    do_clean = 1;
6571
9
                }
6572
3.69k
                if ( err ) {
6573
4
                    if ( do_clean ) {
6574
4
                        free(dims);
6575
4
                    }
6576
4
                    Mat_VarFree(matvar);
6577
4
                    matvar = NULL;
6578
4
                    break;
6579
4
                }
6580
3.69k
                if ( mat->byteswap ) {
6581
2.06k
                    (void)Mat_uint32Swap(uncomp_buf);
6582
2.06k
                    (void)Mat_uint32Swap(uncomp_buf + 1);
6583
2.06k
                }
6584
                /* Rank and dimension */
6585
3.69k
                if ( uncomp_buf[0] == MAT_T_INT32 ) {
6586
3.68k
                    int j;
6587
3.68k
                    size_t size;
6588
3.68k
                    int nbytes = uncomp_buf[1];
6589
3.68k
                    matvar->rank = nbytes / 4;
6590
3.68k
                    if ( 0 == do_clean && matvar->rank > 13 ) {
6591
0
                        int rank = matvar->rank;
6592
0
                        matvar->rank = 0;
6593
0
                        Mat_Critical("%d is not a valid rank", rank);
6594
0
                        break;
6595
0
                    }
6596
3.68k
                    err = Mul(&size, matvar->rank, sizeof(*matvar->dims));
6597
3.68k
                    if ( err ) {
6598
0
                        if ( do_clean ) {
6599
0
                            free(dims);
6600
0
                        }
6601
0
                        (void)MatSeek(mat, (mat_off_t)(nBytes - bytesread), SEEK_CUR);
6602
0
                        Mat_VarFree(matvar);
6603
0
                        matvar = NULL;
6604
0
                        Mat_Critical("Integer multiplication overflow");
6605
0
                        break;
6606
0
                    }
6607
3.68k
                    matvar->dims = (size_t *)malloc(size);
6608
3.68k
                    if ( NULL == matvar->dims ) {
6609
0
                        if ( do_clean )
6610
0
                            free(dims);
6611
0
                        (void)MatSeek(mat, (mat_off_t)(nBytes - bytesread), SEEK_CUR);
6612
0
                        Mat_VarFree(matvar);
6613
0
                        matvar = NULL;
6614
0
                        Mat_Critical("Couldn't allocate memory");
6615
0
                        break;
6616
0
                    }
6617
3.68k
                    if ( mat->byteswap ) {
6618
137k
                        for ( j = 0; j < matvar->rank; j++ )
6619
135k
                            matvar->dims[j] = Mat_uint32Swap(dims + j);
6620
2.06k
                    } else {
6621
4.86k
                        for ( j = 0; j < matvar->rank; j++ )
6622
3.23k
                            matvar->dims[j] = dims[j];
6623
1.62k
                    }
6624
3.68k
                }
6625
3.69k
                if ( do_clean ) {
6626
5
                    free(dims);
6627
5
                }
6628
                /* Variable name tag */
6629
3.69k
                err = Inflate(mat, matvar->internal->z, uncomp_buf, 8, &bytesread);
6630
3.69k
                if ( err ) {
6631
0
                    Mat_VarFree(matvar);
6632
0
                    matvar = NULL;
6633
0
                    break;
6634
0
                }
6635
3.69k
                if ( mat->byteswap )
6636
2.06k
                    (void)Mat_uint32Swap(uncomp_buf);
6637
                /* Name of variable */
6638
3.69k
                if ( uncomp_buf[0] == MAT_T_INT8 ) { /* Name not in tag */
6639
1.94k
                    mat_uint32_t len, len_pad;
6640
1.94k
                    if ( mat->byteswap )
6641
919
                        len = Mat_uint32Swap(uncomp_buf + 1);
6642
1.02k
                    else
6643
1.02k
                        len = uncomp_buf[1];
6644
6645
1.94k
                    if ( len % 8 == 0 )
6646
1.18k
                        len_pad = len;
6647
760
                    else if ( len < UINT32_MAX - 8 + (len % 8) )
6648
760
                        len_pad = len + 8 - (len % 8);
6649
0
                    else {
6650
0
                        Mat_VarFree(matvar);
6651
0
                        matvar = NULL;
6652
0
                        break;
6653
0
                    }
6654
1.94k
                    if ( len_pad > 0 ) {
6655
1.94k
                        matvar->name = (char *)malloc(len_pad + 1);
6656
1.94k
                        if ( NULL != matvar->name ) {
6657
                            /* Variable name */
6658
1.94k
                            err = Inflate(mat, matvar->internal->z, matvar->name, len_pad,
6659
1.94k
                                          &bytesread);
6660
1.94k
                            if ( err ) {
6661
0
                                Mat_VarFree(matvar);
6662
0
                                matvar = NULL;
6663
0
                                break;
6664
0
                            }
6665
1.94k
                            matvar->name[len] = '\0';
6666
1.94k
                        }
6667
1.94k
                    }
6668
1.94k
                } else {
6669
1.75k
                    mat_uint32_t len = (uncomp_buf[0] & 0xffff0000) >> 16;
6670
1.75k
                    if ( ((uncomp_buf[0] & 0x0000ffff) == MAT_T_INT8) && len > 0 && len <= 4 ) {
6671
                        /* Name packed in tag */
6672
1.58k
                        matvar->name = (char *)malloc(len + 1);
6673
1.58k
                        if ( NULL != matvar->name ) {
6674
1.58k
                            memcpy(matvar->name, uncomp_buf + 1, len);
6675
1.58k
                            matvar->name[len] = '\0';
6676
1.58k
                        }
6677
1.58k
                    }
6678
1.75k
                }
6679
3.69k
                if ( matvar->class_type == MAT_C_STRUCT )
6680
2.93k
                    (void)ReadNextStructField(mat, matvar);
6681
753
                else if ( matvar->class_type == MAT_C_CELL )
6682
27
                    (void)ReadNextCell(mat, matvar);
6683
3.69k
                (void)MatSeek(mat, -(mat_off_t)matvar->internal->z->avail_in, SEEK_CUR);
6684
3.69k
                matvar->internal->datapos = MatTell(mat);
6685
3.69k
                if ( matvar->internal->datapos == -1L ) {
6686
0
                    Mat_Critical("Couldn't determine file position");
6687
0
                }
6688
3.69k
            } else {
6689
                /* MAT_C_OPAQUE: read name, type system name, class name, metadata */
6690
0
                err = ReadCompressedOpaqueInfo5(mat, matvar, &bytesread);
6691
0
                if ( err ) {
6692
0
                    Mat_VarFree(matvar);
6693
0
                    matvar = NULL;
6694
0
                    break;
6695
0
                }
6696
0
                (void)MatSeek(mat, -(mat_off_t)matvar->internal->z->avail_in, SEEK_CUR);
6697
0
                matvar->internal->datapos = MatTell(mat);
6698
0
                if ( matvar->internal->datapos == -1L ) {
6699
0
                    Mat_Critical("Couldn't determine file position");
6700
0
                }
6701
0
            }
6702
3.69k
            (void)MatSeek(mat, nBytes + 8 + fpos, SEEK_SET);
6703
3.69k
            break;
6704
#else
6705
            Mat_Critical(
6706
                "Compressed variable found in \"%s\", but matio was "
6707
                "built without zlib support",
6708
                mat->filename);
6709
            (void)MatSeek(mat, nBytes + 8 + fpos, SEEK_SET);
6710
            return NULL;
6711
#endif
6712
3.69k
        }
6713
14.7k
        case MAT_T_MATRIX: {
6714
14.7k
            mat_uint32_t buf[6];
6715
6716
            /* Read array flags and the dimensions tag */
6717
14.7k
            err = Read(buf, 4, 6, mat, NULL);
6718
14.7k
            if ( err ) {
6719
0
                (void)MatSeek(mat, fpos, SEEK_SET);
6720
0
                break;
6721
0
            }
6722
14.7k
            if ( mat->byteswap ) {
6723
9.16k
                (void)Mat_uint32Swap(buf);
6724
9.16k
                (void)Mat_uint32Swap(buf + 1);
6725
9.16k
                (void)Mat_uint32Swap(buf + 2);
6726
9.16k
                (void)Mat_uint32Swap(buf + 3);
6727
9.16k
                (void)Mat_uint32Swap(buf + 4);
6728
9.16k
                (void)Mat_uint32Swap(buf + 5);
6729
9.16k
            }
6730
6731
14.7k
            matvar = Mat_VarCalloc();
6732
14.7k
            if ( NULL == matvar ) {
6733
0
                Mat_Critical("Couldn't allocate memory");
6734
0
                break;
6735
0
            }
6736
6737
            /* Array flags */
6738
14.7k
            if ( buf[0] == MAT_T_UINT32 || buf[0] == MAT_T_INT32 ) { /* Also allow INT32 for SWAN */
6739
13.9k
                mat_uint32_t array_flags = buf[2];
6740
13.9k
                matvar->class_type = CLASS_FROM_ARRAY_FLAGS(array_flags);
6741
13.9k
                matvar->isComplex = (array_flags & MAT_F_COMPLEX);
6742
13.9k
                matvar->isGlobal = (array_flags & MAT_F_GLOBAL);
6743
13.9k
                matvar->isLogical = (array_flags & MAT_F_LOGICAL);
6744
13.9k
                if ( matvar->class_type == MAT_C_SPARSE ) {
6745
                    /* Need to find a more appropriate place to store nzmax */
6746
2.04k
                    matvar->nbytes = buf[3];
6747
2.04k
                }
6748
13.9k
            }
6749
14.7k
            matvar->data_type = ClassType2DataType(matvar->class_type);
6750
14.7k
            if ( matvar->class_type == MAT_C_OPAQUE ) {
6751
                /* For opaque: buf[4..5] is the array name tag, not rank/dims.
6752
                 * Read: name (using buf[4..5] as pre-read tag), type_name, class_name, metadata
6753
                 */
6754
12
                mat_uint32_t name_tag[2];
6755
12
                name_tag[0] = buf[4];
6756
12
                name_tag[1] = buf[5];
6757
12
                err = ReadOpaqueInfo5(mat, matvar, name_tag);
6758
12
                if ( err ) {
6759
1
                    Mat_VarFree(matvar);
6760
1
                    matvar = NULL;
6761
1
                    (void)MatSeek(mat, fpos, SEEK_SET);
6762
1
                    break;
6763
1
                }
6764
11
                matvar->internal->datapos = MatTell(mat);
6765
11
                if ( matvar->internal->datapos == -1L ) {
6766
0
                    Mat_Critical("Couldn't determine file position");
6767
0
                }
6768
14.7k
            } else {
6769
                /* Rank and dimension */
6770
14.7k
                {
6771
14.7k
                    size_t nbytes = 0;
6772
14.7k
                    err = ReadRankDims(mat, matvar, (enum matio_types)buf[4], buf[5], &nbytes);
6773
14.7k
                    if ( err ) {
6774
14
                        Mat_VarFree(matvar);
6775
14
                        matvar = NULL;
6776
14
                        (void)MatSeek(mat, fpos, SEEK_SET);
6777
14
                        break;
6778
14
                    }
6779
14.7k
                }
6780
                /* Variable name tag */
6781
14.7k
                err = Read(buf, 4, 2, mat, NULL);
6782
14.7k
                if ( err ) {
6783
0
                    Mat_VarFree(matvar);
6784
0
                    matvar = NULL;
6785
0
                    (void)MatSeek(mat, fpos, SEEK_SET);
6786
0
                    break;
6787
0
                }
6788
14.7k
                if ( mat->byteswap )
6789
9.15k
                    (void)Mat_uint32Swap(buf);
6790
                /* Name of variable */
6791
14.7k
                if ( buf[0] == MAT_T_INT8 ) { /* Name not in tag */
6792
5.69k
                    mat_uint32_t len, len_pad;
6793
5.69k
                    if ( mat->byteswap )
6794
4.12k
                        len = Mat_uint32Swap(buf + 1);
6795
1.57k
                    else
6796
1.57k
                        len = buf[1];
6797
5.69k
                    if ( len % 8 == 0 )
6798
5.46k
                        len_pad = len;
6799
226
                    else if ( len < UINT32_MAX - 8 + (len % 8) )
6800
226
                        len_pad = len + 8 - (len % 8);
6801
0
                    else {
6802
0
                        Mat_VarFree(matvar);
6803
0
                        matvar = NULL;
6804
0
                        (void)MatSeek(mat, fpos, SEEK_SET);
6805
0
                        break;
6806
0
                    }
6807
5.69k
                    if ( len_pad > MAX_READ_SIZE_WITHOUT_EOF_CHECK ) {
6808
2.10k
                        err = CheckSeekFile(mat, (mat_off_t)len_pad);
6809
2.10k
                        if ( err ) {
6810
76
                            Mat_VarFree(matvar);
6811
76
                            matvar = NULL;
6812
76
                            (void)MatSeek(mat, fpos, SEEK_SET);
6813
76
                            break;
6814
76
                        }
6815
2.10k
                    }
6816
5.61k
                    matvar->name = (char *)malloc(len_pad + 1);
6817
5.61k
                    if ( NULL != matvar->name ) {
6818
5.61k
                        err = Read(matvar->name, 1, len_pad, mat, NULL);
6819
5.61k
                        if ( !err ) {
6820
5.61k
                            matvar->name[len] = '\0';
6821
5.61k
                        } else {
6822
0
                            Mat_VarFree(matvar);
6823
0
                            matvar = NULL;
6824
0
                            (void)MatSeek(mat, fpos, SEEK_SET);
6825
0
                            break;
6826
0
                        }
6827
5.61k
                    }
6828
9.05k
                } else {
6829
9.05k
                    mat_uint32_t len = (buf[0] & 0xffff0000) >> 16;
6830
9.05k
                    if ( ((buf[0] & 0x0000ffff) == MAT_T_INT8) && len > 0 && len <= 4 ) {
6831
                        /* Name packed in tag */
6832
4.02k
                        matvar->name = (char *)malloc(len + 1);
6833
4.02k
                        if ( NULL != matvar->name ) {
6834
4.02k
                            memcpy(matvar->name, buf + 1, len);
6835
4.02k
                            matvar->name[len] = '\0';
6836
4.02k
                        }
6837
4.02k
                    }
6838
9.05k
                }
6839
14.6k
                if ( matvar->class_type == MAT_C_STRUCT )
6840
3.13k
                    (void)ReadNextStructField(mat, matvar);
6841
11.5k
                else if ( matvar->class_type == MAT_C_CELL )
6842
799
                    (void)ReadNextCell(mat, matvar);
6843
10.7k
                else if ( matvar->class_type == MAT_C_FUNCTION )
6844
27
                    (void)ReadNextFunctionHandle(mat, matvar);
6845
14.6k
                matvar->internal->datapos = MatTell(mat);
6846
14.6k
                if ( matvar->internal->datapos == -1L ) {
6847
0
                    Mat_Critical("Couldn't determine file position");
6848
0
                }
6849
14.6k
            } /* end else (non-opaque) */
6850
14.6k
            (void)MatSeek(mat, nBytes + 8 + fpos, SEEK_SET);
6851
14.6k
            break;
6852
14.7k
        }
6853
2.37k
        default:
6854
2.37k
            Mat_Critical("%u is not valid (MAT_T_MATRIX or MAT_T_COMPRESSED)", data_type);
6855
2.37k
            return NULL;
6856
20.8k
    }
6857
6858
18.4k
    return matvar;
6859
20.8k
}