GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
ls-mat5.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-2026 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <cstring>
31
32#include <iomanip>
33#include <istream>
34#include <limits>
35#include <ostream>
36#include <sstream>
37#include <string>
38#include <vector>
39
40#include "byte-swap.h"
41#include "dMatrix.h"
42#include "data-conv.h"
43#include "file-ops.h"
44#include "file-stat.h"
45#include "glob-match.h"
46#include "mach-info.h"
47#include "mappers.h"
48#include "oct-env.h"
49#include "oct-locbuf.h"
50#include "oct-sysdep.h"
51#include "oct-time.h"
52#include "quit.h"
53#include "str-vec.h"
54#include "unistr-wrappers.h"
55
56#include "cdef-utils.h"
57#include "Cell.h"
58#include "defaults.h"
59#include "defun.h"
60#include "error.h"
61#include "errwarn.h"
62#include "interpreter-private.h"
63#include "interpreter.h"
64#include "load-path.h"
65#include "load-save.h"
66#include "ls-mat5.h"
67#include "ls-mat-subsys.h"
68#include "ls-utils.h"
69#include "oct-map.h"
70#include "ov-cell.h"
71#include "ov-class.h"
72#include "ov-classdef.h"
73#include "ov.h"
74#include "ovl.h"
75#include "pager.h"
76#include "parse.h"
77#include "pt-eval.h"
78#include "stack-frame.h"
79#include "sysdep.h"
80#include "unwind-prot.h"
81#include "utils.h"
82#include "variables.h"
83#include "version.h"
84
85#if defined (HAVE_ZLIB)
86# include <zlib.h>
87#endif
88
89#define READ_PAD(is_small_data_element, l) ((is_small_data_element) ? 4 : (((l)+7)/8)*8)
90#define PAD(l) (((l) > 0 && (l) <= 4) ? 4 : (((l)+7)/8)*8)
91#define INT8(l) ((l) == miINT8 || (l) == miUINT8 || (l) == miUTF8)
92
93// FIXME: the following enum values should be the same as the
94// mxClassID values in mexproto.h, but it seems they have also changed
95// over time. What is the correct way to handle this and maintain
96// backward compatibility with old MAT files? For now, use
97// "MAT_FILE_" instead of "mx" as the prefix for these names to avoid
98// conflict with the mxClassID enum in mexproto.h.
99
101{
102 MAT_FILE_CELL_CLASS=1, // cell array
105 MAT_FILE_CHAR_CLASS, // character array
106 MAT_FILE_SPARSE_CLASS, // sparse array
107 MAT_FILE_DOUBLE_CLASS, // double precision array
108 MAT_FILE_SINGLE_CLASS, // single precision floating point
109 MAT_FILE_INT8_CLASS, // 8 bit signed integer
110 MAT_FILE_UINT8_CLASS, // 8 bit unsigned integer
111 MAT_FILE_INT16_CLASS, // 16 bit signed integer
112 MAT_FILE_UINT16_CLASS, // 16 bit unsigned integer
113 MAT_FILE_INT32_CLASS, // 32 bit signed integer
114 MAT_FILE_UINT32_CLASS, // 32 bit unsigned integer
115 MAT_FILE_INT64_CLASS, // 64 bit signed integer
116 MAT_FILE_UINT64_CLASS, // 64 bit unsigned integer
117 MAT_FILE_FUNCTION_CLASS, // Function handle
118 MAT_FILE_WORKSPACE_CLASS // Workspace (undocumented)
120
121// Read COUNT elements of data from IS in the format specified by TYPE,
122// placing the result in DATA. If SWAP is TRUE, swap the bytes of
123// each element before copying to DATA. FLT_FMT specifies the format
124// of the data if we are reading floating point numbers.
125
126static void
127read_mat5_binary_data (std::istream& is, double *data,
128 octave_idx_type count, bool swap, mat5_data_type type,
129 octave::mach_info::float_format flt_fmt)
130{
131
132 switch (type)
133 {
134 case miINT8:
135 read_doubles (is, data, LS_CHAR, count, swap, flt_fmt);
136 break;
137
138 case miUTF8:
139 case miUINT8:
140 read_doubles (is, data, LS_U_CHAR, count, swap, flt_fmt);
141 break;
142
143 case miINT16:
144 read_doubles (is, data, LS_SHORT, count, swap, flt_fmt);
145 break;
146
147 case miUTF16:
148 case miUINT16:
149 read_doubles (is, data, LS_U_SHORT, count, swap, flt_fmt);
150 break;
151
152 case miINT32:
153 read_doubles (is, data, LS_INT, count, swap, flt_fmt);
154 break;
155
156 case miUTF32:
157 case miUINT32:
158 read_doubles (is, data, LS_U_INT, count, swap, flt_fmt);
159 break;
160
161 case miSINGLE:
162 read_doubles (is, data, LS_FLOAT, count, swap, flt_fmt);
163 break;
164
165 case miRESERVE1:
166 break;
167
168 case miDOUBLE:
169 read_doubles (is, data, LS_DOUBLE, count, swap, flt_fmt);
170 break;
171
172 case miRESERVE2:
173 case miRESERVE3:
174 break;
175
176 // FIXME: how are the 64-bit cases supposed to work here?
177 case miINT64:
178 read_doubles (is, data, LS_LONG, count, swap, flt_fmt);
179 break;
180
181 case miUINT64:
182 read_doubles (is, data, LS_U_LONG, count, swap, flt_fmt);
183 break;
184
185 case miMATRIX:
186 default:
187 break;
188 }
189}
190
191static void
192read_mat5_binary_data (std::istream& is, float *data,
193 octave_idx_type count, bool swap, mat5_data_type type,
194 octave::mach_info::float_format flt_fmt)
195{
196
197 switch (type)
198 {
199 case miINT8:
200 read_floats (is, data, LS_CHAR, count, swap, flt_fmt);
201 break;
202
203 case miUTF8:
204 case miUINT8:
205 read_floats (is, data, LS_U_CHAR, count, swap, flt_fmt);
206 break;
207
208 case miINT16:
209 read_floats (is, data, LS_SHORT, count, swap, flt_fmt);
210 break;
211
212 case miUTF16:
213 case miUINT16:
214 read_floats (is, data, LS_U_SHORT, count, swap, flt_fmt);
215 break;
216
217 case miINT32:
218 read_floats (is, data, LS_INT, count, swap, flt_fmt);
219 break;
220
221 case miUTF32:
222 case miUINT32:
223 read_floats (is, data, LS_U_INT, count, swap, flt_fmt);
224 break;
225
226 case miSINGLE:
227 read_floats (is, data, LS_FLOAT, count, swap, flt_fmt);
228 break;
229
230 case miRESERVE1:
231 break;
232
233 case miDOUBLE:
234 read_floats (is, data, LS_DOUBLE, count, swap, flt_fmt);
235 break;
236
237 case miRESERVE2:
238 case miRESERVE3:
239 break;
240
241 // FIXME: how are the 64-bit cases supposed to work here?
242 case miINT64:
243 read_floats (is, data, LS_LONG, count, swap, flt_fmt);
244 break;
245
246 case miUINT64:
247 read_floats (is, data, LS_U_LONG, count, swap, flt_fmt);
248 break;
249
250 case miMATRIX:
251 default:
252 break;
253 }
254}
255
256template <typename T>
257void
258read_mat5_integer_data (std::istream& is, T *m, octave_idx_type count,
259 bool swap, mat5_data_type type)
260{
261
262#define READ_INTEGER_DATA(TYPE, swap, data, size, len, stream) \
263 do \
264 { \
265 if (len > 0) \
266 { \
267 OCTAVE_LOCAL_BUFFER (TYPE, ptr, len); \
268 std::streamsize n_bytes = size * static_cast<std::streamsize> (len); \
269 stream.read (reinterpret_cast<char *> (ptr), n_bytes); \
270 if (swap) \
271 swap_bytes< size > (ptr, len); \
272 for (octave_idx_type i = 0; i < len; i++) \
273 data[i] = ptr[i]; \
274 } \
275 } \
276 while (0)
277
278 switch (type)
279 {
280 case miINT8:
281 READ_INTEGER_DATA (int8_t, swap, m, 1, count, is);
282 break;
283
284 case miUINT8:
285 READ_INTEGER_DATA (uint8_t, swap, m, 1, count, is);
286 break;
287
288 case miINT16:
289 READ_INTEGER_DATA (int16_t, swap, m, 2, count, is);
290 break;
291
292 case miUINT16:
293 READ_INTEGER_DATA (uint16_t, swap, m, 2, count, is);
294 break;
295
296 case miINT32:
297 READ_INTEGER_DATA (int32_t, swap, m, 4, count, is);
298 break;
299
300 case miUINT32:
301 READ_INTEGER_DATA (uint32_t, swap, m, 4, count, is);
302 break;
303
304 case miSINGLE:
305 case miRESERVE1:
306 case miDOUBLE:
307 case miRESERVE2:
308 case miRESERVE3:
309 break;
310
311 case miINT64:
312 READ_INTEGER_DATA (int64_t, swap, m, 8, count, is);
313 break;
314
315 case miUINT64:
316 READ_INTEGER_DATA (uint64_t, swap, m, 8, count, is);
317 break;
318
319 case miMATRIX:
320 default:
321 break;
322 }
323
324#undef READ_INTEGER_DATA
325
326}
327
328template void
330 octave_idx_type count, bool swap,
331 mat5_data_type type);
332
333template void
335 octave_idx_type count, bool swap,
336 mat5_data_type type);
337
338template void
340 octave_idx_type count, bool swap,
341 mat5_data_type type);
342
343template void
345 octave_idx_type count, bool swap,
346 mat5_data_type type);
347
348template void
350 octave_idx_type count, bool swap,
351 mat5_data_type type);
352
353template void
355 octave_idx_type count, bool swap,
356 mat5_data_type type);
357
358template void
360 octave_idx_type count, bool swap,
361 mat5_data_type type);
362
363template void
365 octave_idx_type count, bool swap,
366 mat5_data_type type);
367
368template void
369read_mat5_integer_data (std::istream& is, int *m,
370 octave_idx_type count, bool swap,
371 mat5_data_type type);
372
373#define OCTAVE_MAT5_INTEGER_READ(TYP) \
374 { \
375 TYP re (dims); \
376 \
377 std::streampos tmp_pos; \
378 \
379 if (read_mat5_tag (is, swap, type, len, is_small_data_element)) \
380 error ("load: reading matrix data for '%s'", retval.c_str ()); \
381 \
382 octave_idx_type n = re.numel (); \
383 tmp_pos = is.tellg (); \
384 read_mat5_integer_data (is, re.rwdata (), n, swap, \
385 static_cast<enum mat5_data_type> (type)); \
386 \
387 if (! is) \
388 error ("load: reading matrix data for '%s'", retval.c_str ()); \
389 \
390 is.seekg (tmp_pos + static_cast<std::streamoff> \
391 (READ_PAD (is_small_data_element, len))); \
392 \
393 if (imag) \
394 { \
395 /* We don't handle imag integer types, convert to an array */ \
396 NDArray im (dims); \
397 \
398 if (read_mat5_tag (is, swap, type, len, is_small_data_element)) \
399 error ("load: reading matrix data for '%s'", \
400 retval.c_str ()); \
401 \
402 n = im.numel (); \
403 read_mat5_binary_data (is, im.rwdata (), n, swap, \
404 static_cast<enum mat5_data_type> (type), flt_fmt); \
405 \
406 if (! is) \
407 error ("load: reading imaginary matrix data for '%s'", \
408 retval.c_str ()); \
409 \
410 ComplexNDArray ctmp (dims); \
411 \
412 for (octave_idx_type i = 0; i < n; i++) \
413 ctmp(i) = Complex (re(i).double_value (), im(i)); \
414 \
415 tc = ctmp; \
416 } \
417 else \
418 tc = re; \
419 }
420
421// Read one element tag from stream IS,
422// place the type code in TYPE, the byte count in BYTES and true (false) to
423// IS_SMALL_DATA_ELEMENT if the tag is 4 (8) bytes long.
424// return nonzero on error
425static int
426read_mat5_tag (std::istream& is, bool swap, int32_t& type, int32_t& bytes,
427 bool& is_small_data_element)
428{
429 unsigned int upper;
430 int32_t temp;
431
432 if (! is.read (reinterpret_cast<char *> (&temp), 4))
433 return 1;
434
435 if (swap)
436 swap_bytes<4> (&temp);
437
438 upper = (temp >> 16) & 0xffff;
439 type = temp & 0xffff;
440
441 if (upper)
442 {
443 // "compressed" format
444 bytes = upper;
445 is_small_data_element = true;
446 }
447 else
448 {
449 if (! is.read (reinterpret_cast<char *> (&temp), 4))
450 return 1;
451 if (swap)
452 swap_bytes<4> (&temp);
453 bytes = temp;
454 is_small_data_element = false;
455 }
456
457 return 0;
458}
459
460static void
461read_int (std::istream& is, bool swap, int32_t& val)
462{
463 is.read (reinterpret_cast<char *> (&val), 4);
464
465 if (swap)
466 swap_bytes<4> (&val);
467}
468
469// Extract one data element (scalar, matrix, string, etc.) from stream
470// IS and place it in TC, returning the name of the variable.
471//
472// The data is expected to be in Matlab's "Version 5" .mat format,
473// though not all the features of that format are supported.
474//
475// FILENAME is used for error messages.
476
477std::string
478read_mat5_binary_element (std::istream& is, const std::string& filename,
479 bool swap, bool& global, octave_value& tc)
480{
481 std::string retval;
482
483 global = false;
484
485 // NOTE: these are initialized here instead of closer to where they
486 // are first used to avoid errors from gcc about goto crossing
487 // initialization of variable.
488
489 bool imag;
490 bool isclass = false;
491 bool logicalvar;
492 dim_vector dims;
493 enum arrayclasstype arrayclass;
494 octave_idx_type nzmax;
495 std::string classname;
496
497 bool flt_fmt_is_big_endian
498 = (octave::mach_info::native_float_format ()
499 == octave::mach_info::flt_fmt_ieee_big_endian);
500
501 // MAT files always use IEEE floating point
502 octave::mach_info::float_format flt_fmt = octave::mach_info::flt_fmt_unknown;
503 if ((flt_fmt_is_big_endian && ! swap) || (! flt_fmt_is_big_endian && swap))
504 flt_fmt = octave::mach_info::flt_fmt_ieee_big_endian;
505 else
506 flt_fmt = octave::mach_info::flt_fmt_ieee_little_endian;
507
508 // element type, length and small data element flag
509 int32_t type = 0;
510 int32_t element_length;
511 bool is_small_data_element;
512 if (read_mat5_tag (is, swap, type, element_length, is_small_data_element))
513 return retval; // EOF
514
515 octave::interpreter& interp = octave::__get_interpreter__ ();
516
517 if (type == miCOMPRESSED)
518 {
519#if defined (HAVE_ZLIB)
520 // If C++ allowed us direct access to the file descriptor of an
521 // ifstream in a uniform way, the code below could be vastly
522 // simplified, and additional copies of the data in memory
523 // wouldn't be needed.
524
525 OCTAVE_LOCAL_BUFFER (char, inbuf, element_length);
526 is.read (inbuf, element_length);
527
528 // We uncompress the first 8 bytes of the header to get the buffer length
529 // This will fail with an error Z_MEM_ERROR
530 uLongf destLen = 8;
531 uLongf elt_len = element_length;
532 OCTAVE_LOCAL_BUFFER (unsigned int, tmp, 2);
533 if (uncompress2 (reinterpret_cast<Bytef *> (tmp), &destLen,
534 reinterpret_cast<Bytef *> (inbuf), &elt_len)
535 == Z_MEM_ERROR)
536 error ("load: error probing size of compressed data element");
537
538 // Why should I have to initialize outbuf as I'll just overwrite!!
539 if (swap)
540 swap_bytes<4> (tmp, 2);
541
542 destLen = tmp[1] + 8;
543 std::string outbuf (destLen, ' ');
544
545 // FIXME: find a way to avoid casting away const here!
546
547 elt_len = element_length;
548 int err = uncompress2 (reinterpret_cast<Bytef *>
549 (const_cast<char *> (outbuf.c_str ())),
550 &destLen, reinterpret_cast<Bytef *> (inbuf),
551 &elt_len);
552
553 // Ignore buffer error if we have consumed all the input buffer
554 // and uncompressing the data generated as many bytes of output as
555 // we were expecting given the data element size that was stored
556 // in the Matlab data element header.
557 if (err == Z_BUF_ERROR && destLen == tmp[1] + 8
558 && elt_len == static_cast<uLongf> (element_length))
559 err = Z_OK;
560
561 if (err != Z_OK)
562 {
563 std::string msg;
564 switch (err)
565 {
566 case Z_STREAM_END:
567 msg = "stream end";
568 break;
569
570 case Z_NEED_DICT:
571 msg = "need dict";
572 break;
573
574 case Z_ERRNO:
575 msg = "errno case";
576 break;
577
578 case Z_STREAM_ERROR:
579 msg = "stream error";
580 break;
581
582 case Z_DATA_ERROR:
583 msg = "data error";
584 break;
585
586 case Z_MEM_ERROR:
587 msg = "mem error";
588 break;
589
590 case Z_BUF_ERROR:
591 msg = "buf error";
592 break;
593
594 case Z_VERSION_ERROR:
595 msg = "version error";
596 break;
597 }
598
599 error ("load: error uncompressing data element (%s from zlib)",
600 msg.c_str ());
601 }
602 else
603 {
604 std::istringstream gz_is (outbuf);
605 retval = read_mat5_binary_element (gz_is, filename,
606 swap, global, tc);
607 }
608
609 return retval;
610
611#else
612 err_disabled_feature ("load", "compressed data elements (zlib)");
613#endif
614 }
615
616 std::streampos pos;
617
618 if (type != miMATRIX)
619 {
620 pos = is.tellg ();
621 error ("load: invalid element type = %d", type);
622 }
623
624 if (element_length == 0)
625 {
626 tc = Matrix ();
627 return retval;
628 }
629
630 pos = is.tellg ();
631
632 // array flags subelement
633 int32_t len;
634 if (read_mat5_tag (is, swap, type, len, is_small_data_element)
635 || type != miUINT32 || len != 8 || is_small_data_element)
636 error ("load: invalid array flags subelement");
637
638 int32_t flags;
639 read_int (is, swap, flags);
640
641 imag = (flags & 0x0800) != 0; // has an imaginary part?
642
643 global = (flags & 0x0400) != 0; // global variable?
644
645 logicalvar = (flags & 0x0200) != 0; // boolean ?
646
647 arrayclass = static_cast<arrayclasstype> (flags & 0xff);
648
649 int32_t tmp_nzmax;
650 read_int (is, swap, tmp_nzmax); // max number of nonzero in sparse
651 nzmax = tmp_nzmax;
652
653 // dimensions array subelement
654 if (arrayclass != MAT_FILE_WORKSPACE_CLASS)
655 {
656 int32_t dim_len;
657
658 if (read_mat5_tag (is, swap, type, dim_len, is_small_data_element)
659 || type != miINT32)
660 error ("load: invalid dimensions array subelement");
661
662 int ndims = dim_len / 4;
663 if (ndims == 1)
664 {
665 // R and Python can create a 1-D object which is really an Nx1 object
666 dims.resize (2);
667 dims(1) = 1;
668 }
669 else
670 dims.resize (ndims);
671
672 for (int i = 0; i < ndims; i++)
673 {
674 int32_t n;
675 read_int (is, swap, n);
676 dims(i) = n;
677 }
678
679 std::streampos tmp_pos = is.tellg ();
680 is.seekg (tmp_pos + static_cast<std::streamoff>
681 (READ_PAD (is_small_data_element, dim_len) - dim_len));
682 }
683
684 if (read_mat5_tag (is, swap, type, len, is_small_data_element)
685 || ! INT8 (type))
686 error ("load: invalid array name subelement");
687
688 {
689 OCTAVE_LOCAL_BUFFER (char, name, len+1);
690
691 // Structure field subelements have zero-length array name subelements.
692
693 std::streampos tmp_pos = is.tellg ();
694
695 if (len)
696 {
697 if (! is.read (name, len))
698 goto data_read_error;
699
700 is.seekg (tmp_pos + static_cast<std::streamoff>
701 (READ_PAD (is_small_data_element, len)));
702 }
703
704 name[len] = '\0';
705 retval = name;
706 }
707
708 switch (arrayclass)
709 {
711 {
712 Cell cell_array (dims);
713
714 octave_idx_type n = cell_array.numel ();
715
716 for (octave_idx_type i = 0; i < n; i++)
717 {
718 octave_value tc2;
719
720 std::string nm
721 = read_mat5_binary_element (is, filename, swap, global, tc2);
722
723 if (! is)
724 error ("load: reading cell data for '%s'", nm.c_str ());
725
726 cell_array(i) = tc2;
727 }
728
729 tc = cell_array;
730 }
731 break;
732
734 {
735 octave_idx_type nr = dims(0);
736 octave_idx_type nc = dims(1);
737 SparseMatrix sm;
739 octave_idx_type *ridx;
740 octave_idx_type *cidx;
741 double *data;
742
743 // Setup return value
744 if (imag)
745 {
746 scm = SparseComplexMatrix (nr, nc, nzmax);
747 ridx = scm.ridx ();
748 cidx = scm.cidx ();
749 data = nullptr;
750 }
751 else
752 {
753 sm = SparseMatrix (nr, nc, nzmax);
754 ridx = sm.ridx ();
755 cidx = sm.cidx ();
756 data = sm.data ();
757 }
758
759 // row indices
760 std::streampos tmp_pos;
761
762 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
763 error ("load: reading sparse row data for '%s'", retval.c_str ());
764
765 tmp_pos = is.tellg ();
766
767 read_mat5_integer_data (is, ridx, nzmax, swap,
768 static_cast<enum mat5_data_type> (type));
769
770 if (! is)
771 error ("load: reading sparse row data for '%s'", retval.c_str ());
772
773 is.seekg (tmp_pos + static_cast<std::streamoff>
774 (READ_PAD (is_small_data_element, len)));
775
776 // col indices
777 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
778 error ("load: reading sparse column data for '%s'",
779 retval.c_str ());
780
781 tmp_pos = is.tellg ();
782
783 read_mat5_integer_data (is, cidx, nc + 1, swap,
784 static_cast<enum mat5_data_type> (type));
785
786 if (! is)
787 error ("load: reading sparse column data for '%s'",
788 retval.c_str ());
789
790 is.seekg (tmp_pos + static_cast<std::streamoff>
791 (READ_PAD (is_small_data_element, len)));
792
793 // real data subelement
794 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
795 error ("load: reading sparse matrix data for '%s'",
796 retval.c_str ());
797
798 octave_idx_type nnz = cidx[nc];
799 NDArray re;
800 if (imag)
801 {
802 re = NDArray (dim_vector (nnz, 1));
803 data = re.rwdata ();
804 }
805
806 tmp_pos = is.tellg ();
807 read_mat5_binary_data (is, data, nnz, swap,
808 static_cast<enum mat5_data_type> (type),
809 flt_fmt);
810
811 if (! is)
812 error ("load: reading sparse matrix data for '%s'",
813 retval.c_str ());
814
815 is.seekg (tmp_pos + static_cast<std::streamoff>
816 (READ_PAD (is_small_data_element, len)));
817
818 // imaginary data subelement
819 if (imag)
820 {
821 NDArray im (dim_vector (static_cast<int> (nnz), 1));
822
823 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
824 error ("load: reading sparse matrix data for '%s'",
825 retval.c_str ());
826
827 read_mat5_binary_data (is, im.rwdata (), nnz, swap,
828 static_cast<enum mat5_data_type> (type),
829 flt_fmt);
830
831 if (! is)
832 error ("load: reading imaginary sparse matrix data for '%s'",
833 retval.c_str ());
834
835 for (octave_idx_type i = 0; i < nnz; i++)
836 scm.xdata (i) = Complex (re (i), im (i));
837
838 tc = scm;
839 }
840 else
841 tc = sm;
842 }
843 break;
844
846 {
847 octave_value tc2;
848 std::string nm
849 = read_mat5_binary_element (is, filename, swap, global, tc2);
850
851 if (! is)
852 goto data_read_error;
853
854 // Octave can handle both "/" and "\" as a directory separator
855 // and so can ignore the separator field of m0. I think the
856 // sentinel field is also save to ignore.
859 = m0.contents ("function_handle").scalar_map_value ();
860 std::string ftype = m1.contents ("type").string_value ();
861 std::string fname = m1.contents ("function").string_value ();
862 std::string fpath = m1.contents ("file").string_value ();
863
864 if (ftype == "simple" || ftype == "scopedfunction")
865 {
866 if (fpath.empty ())
867 {
868 octave::tree_evaluator& tw = interp.get_evaluator ();
869
870 // We have a builtin function
871 // XXX FCN_HANDLE: SIMPLE/SCOPED
872 tc = tw.make_fcn_handle (fname);
873 }
874 else
875 {
876 std::string mroot = m0.contents ("matlabroot").string_value ();
877
878 if ((fpath.length () >= mroot.length ())
879 && fpath.substr (0, mroot.length ()) == mroot
880 && octave::config::octave_exec_home () != mroot)
881 {
882 // If fpath starts with matlabroot, and matlabroot
883 // doesn't equal __octave_config_info__ ("exec_prefix")
884 // then the function points to a version of Octave
885 // or Matlab other than the running version. In that
886 // case we replace with the same function in the
887 // running version of Octave?
888
889 // First check if just replacing matlabroot is enough
890 std::string str
891 = (octave::config::octave_exec_home ()
892 + fpath.substr (mroot.length ()));
893
894 if (octave::sys::file_exists (str))
895 {
896 std::size_t xpos
897 = str.find_last_of (octave::sys::file_ops::dir_sep_chars ());
898
899 std::string dir_name = str.substr (0, xpos);
900
901 octave_value ov_fcn
902 = octave::load_fcn_from_file (str, dir_name,
903 "", "", fname);
904
905 if (ov_fcn.is_defined ())
906 // XXX FCN_HANDLE: SIMPLE/SCOPED
907 tc = octave_value (new octave_fcn_handle (ov_fcn,
908 fname));
909 }
910 else
911 {
912 // Next just search for it anywhere in the system path
913 std::list<std::string> names;
914 names.push_back (fname + ".oct");
915 names.push_back (fname + ".mex");
916 names.push_back (fname + ".m");
917
918 octave::load_path& lp = interp.get_load_path ();
919
920 octave::directory_path p (lp.system_path ());
921
922 str = octave::sys::env::make_absolute (p.find_first_of (names));
923
924 std::size_t xpos
925 = str.find_last_of (octave::sys::file_ops::dir_sep_chars ());
926
927 std::string dir_name = str.substr (0, xpos);
928
929 octave_value ov_fcn
930 = octave::load_fcn_from_file (str, dir_name,
931 "", "", fname);
932
933 if (ov_fcn.is_defined ())
934 // XXX FCN_HANDLE: SIMPLE/SCOPED
935 tc = octave_value (new octave_fcn_handle (ov_fcn,
936 fname));
937 else
938 {
939 warning_with_id ("Octave:load:file-not-found",
940 "load: can't find the file %s",
941 fpath.c_str ());
942 goto skip_ahead;
943 }
944 }
945 }
946 else
947 {
948 std::size_t xpos
949 = fpath.find_last_of (octave::sys::file_ops::dir_sep_chars ());
950
951 std::string dir_name = fpath.substr (0, xpos);
952
953 octave_value ov_fcn
954 = octave::load_fcn_from_file (fpath, dir_name,
955 "", "", fname);
956
957 if (ov_fcn.is_defined ())
958 // XXX FCN_HANDLE: SIMPLE/SCOPED
959 tc = octave_value (new octave_fcn_handle (ov_fcn, fname));
960 else
961 {
962 warning_with_id ("Octave:load:file-not-found",
963 "load: can't find the file %s",
964 fpath.c_str ());
965 goto skip_ahead;
966 }
967 }
968 }
969 }
970 else if (ftype == "nested")
971 {
972 warning_with_id ("Octave:load:unsupported-type",
973 "load: can't load nested function");
974 goto skip_ahead;
975 }
976 else if (ftype == "anonymous")
977 {
978 // get workspace context of anonymous function handle
979 tc2 = m1.contents ("workspace");
980
981 octave::stack_frame::local_vars_map local_vars;
982
983 if (! tc2.isempty ())
984 {
986
987 if (m2.nfields () > 0)
988 {
989 for (auto p0 = m2.begin (); p0 != m2.end (); p0++)
990 {
991 std::string key = m2.key (p0);
992 octave_value val = m2.contents (p0);
993
994 local_vars[key] = val;
995 }
996 }
997 }
998
999 // Set up temporary scope to use for evaluating the text
1000 // that defines the anonymous function so that we don't
1001 // pick up values of random variables that might be in the
1002 // current scope.
1003
1004 octave::tree_evaluator& tw = interp.get_evaluator ();
1005 tw.push_dummy_scope ("read_mat5_binary_element");
1006
1007 octave::unwind_action act ([&tw] () { tw.pop_scope (); });
1008
1009 // FIXME: If evaluation of the string gives us an anonymous
1010 // function handle object, then why extract the function and
1011 // create a new anonymous function object? Why not just
1012 // attach the workspace values to the object returned by
1013 // eval_string? This code is also is duplicated in
1014 // anon_fcn_handle::parse_anon_fcn_handle.
1015
1016 int parse_status;
1017 octave_value anon_fcn_handle
1018 = interp.eval_string (fname.substr (4), true, parse_status);
1019
1020 if (parse_status != 0)
1021 error ("load: failed to load anonymous function handle");
1022
1023 octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
1024
1025 if (! fh)
1026 error ("load: failed to load anonymous function handle");
1027
1028 // XXX FCN_HANDLE: ANONYMOUS
1029 tc = octave_value (new octave_fcn_handle (fh->fcn_val (),
1030 local_vars));
1031 }
1032 else
1033 error ("load: invalid function handle type");
1034 }
1035 break;
1036
1038 {
1039
1040 std::string type_system;
1041 if (read_mat5_tag (is, swap, type, len, is_small_data_element)
1042 || ! INT8 (type))
1043 error ("load: invalid type system");
1044
1045 {
1046 // Type System
1047 OCTAVE_LOCAL_BUFFER (char, name, len+1);
1048
1049 std::streampos tmp_pos = is.tellg ();
1050
1051 if (len)
1052 {
1053 if (! is.read (name, len))
1054 goto data_read_error;
1055
1056 is.seekg (tmp_pos + static_cast<std::streamoff>
1057 (READ_PAD (is_small_data_element, len)));
1058 }
1059
1060 name[len] = '\0';
1061 type_system = name;
1062 }
1063
1064
1065 if (read_mat5_tag (is, swap, type, len, is_small_data_element)
1066 || ! INT8 (type))
1067 error ("load: invalid class name");
1068
1069 {
1070 // Class Name
1071 OCTAVE_LOCAL_BUFFER (char, name, len+1);
1072
1073 std::streampos tmp_pos = is.tellg ();
1074
1075 if (len)
1076 {
1077 if (! is.read (name, len))
1078 goto data_read_error;
1079
1080 is.seekg (tmp_pos + static_cast<std::streamoff>
1081 (READ_PAD (is_small_data_element, len)));
1082 }
1083
1084 name[len] = '\0';
1085 classname = name;
1086 }
1087
1088 octave_value objmetadata;
1089 read_mat5_binary_element (is, filename, swap, global, objmetadata);
1090 if (! is)
1091 goto data_read_error;
1092
1093 if (type_system != "MCOS")
1094 {
1095 // Other type systems known are "java" and "handle"
1096 // java is used for java objects
1097 // handle is used for certain COM objects
1098 warning_with_id ("Octave:load:classdef-not-supported",
1099 "load: MATLAB class object with type system '%s' "
1100 "not supported. Loading as %s",
1101 type_system.c_str (),
1102 objmetadata.class_name ().c_str ());
1103 tc = objmetadata;
1104 }
1105 else if (classname == "FileWrapper__")
1106 {
1107 // "FileWrapper__" objects contain serialized object data as a cell
1108 // array. In MATLAB, this is an MCOS class with a constructor and
1109 // no properties.
1110 // Return the serialized data for these cases.
1111 tc = objmetadata;
1112 }
1113 else if (objmetadata.isstruct ())
1114 {
1115 warning_with_id ("Octave:load:classdef-not-supported",
1116 "load: MATLAB enumeration classes are not "
1117 "supported. Loading as %s",
1118 objmetadata.class_name ().c_str ());
1119 tc = objmetadata;
1120 }
1121 else
1122 {
1123 // "function_handle_workspace" objects contain data of the
1124 // workspace context of function handles.
1125 // FIXME: Add compatible implementation of this class.
1126 tc = octave::load_mcos_object (objmetadata,
1127 classname == "function_handle_workspace");
1128 }
1129 }
1130
1131 break;
1132
1134 {
1135 isclass = true;
1136
1137 if (read_mat5_tag (is, swap, type, len, is_small_data_element)
1138 || ! INT8 (type))
1139 error ("load: invalid class name");
1140
1141 {
1142 OCTAVE_LOCAL_BUFFER (char, name, len+1);
1143
1144 std::streampos tmp_pos = is.tellg ();
1145
1146 if (len)
1147 {
1148 if (! is.read (name, len))
1149 goto data_read_error;
1150
1151 is.seekg (tmp_pos + static_cast<std::streamoff>
1152 (READ_PAD (is_small_data_element, len)));
1153 }
1154
1155 name[len] = '\0';
1156 classname = name;
1157 }
1158 }
1159 // Fall-through
1160
1162 {
1163 octave_map m (dims);
1164 int32_t fn_type;
1165 int32_t fn_len;
1166 int32_t field_name_length;
1167
1168 // field name length subelement -- actually the maximum length
1169 // of a field name. The Matlab docs promise this will always
1170 // be 32. We read and use the actual value, on the theory
1171 // that eventually someone will recognize that's a waste of space.
1172 if (read_mat5_tag (is, swap, fn_type, fn_len, is_small_data_element)
1173 || fn_type != miINT32)
1174 error ("load: invalid field name length subelement");
1175
1176 if (! is.read (reinterpret_cast<char *> (&field_name_length), fn_len))
1177 goto data_read_error;
1178
1179 if (swap)
1180 swap_bytes<4> (&field_name_length);
1181
1182 // field name subelement. The length of this subelement tells
1183 // us how many fields there are.
1184 if (read_mat5_tag (is, swap, fn_type, fn_len, is_small_data_element)
1185 || ! INT8 (fn_type))
1186 error ("load: invalid field name subelement");
1187
1188 octave_idx_type n_fields = fn_len/field_name_length;
1189
1190 if (n_fields > 0)
1191 {
1192 fn_len = READ_PAD (is_small_data_element, fn_len);
1193
1194 OCTAVE_LOCAL_BUFFER (char, elname, fn_len);
1195
1196 if (! is.read (elname, fn_len))
1197 goto data_read_error;
1198
1199 std::vector<Cell> elt (n_fields);
1200
1201 for (octave_idx_type i = 0; i < n_fields; i++)
1202 elt[i] = Cell (dims);
1203
1204 octave_idx_type n = dims.numel ();
1205
1206 // fields subelements
1207 for (octave_idx_type j = 0; j < n; j++)
1208 {
1209 for (octave_idx_type i = 0; i < n_fields; i++)
1210 {
1211 octave_value fieldtc;
1212 read_mat5_binary_element (is, filename, swap, global,
1213 fieldtc);
1214 elt[i](j) = fieldtc;
1215 }
1216 }
1217
1218 for (octave_idx_type i = 0; i < n_fields; i++)
1219 {
1220 const char *key = elname + i*field_name_length;
1221
1222 m.assign (key, elt[i]);
1223 }
1224 }
1225
1226 if (isclass)
1227 {
1228 octave::cdef_manager& cdm = interp.get_cdef_manager ();
1229
1230 if (cdm.find_class (classname, false, true).ok ())
1231 {
1232 tc = m;
1233 warning_with_id ("Octave:load:classdef-to-struct",
1234 "load: classdef element has been converted to a struct");
1235 }
1236 else
1237 {
1238 octave_class *cls
1239 = new octave_class (m, classname,
1240 std::list<std::string> ());
1241
1242 if (cls->reconstruct_exemplar ())
1243 {
1244
1245 if (! cls->reconstruct_parents ())
1246 warning_with_id ("Octave:load:classdef-object-inheritance",
1247 "load: unable to reconstruct object inheritance");
1248
1249 tc = cls;
1250
1251 octave::load_path& lp = interp.get_load_path ();
1252
1253 if (lp.find_method (classname, "loadobj") != "")
1254 {
1255 try
1256 {
1257 octave_value_list tmp = interp.feval ("loadobj", tc, 1);
1258
1259 tc = tmp(0);
1260 }
1261 catch (const octave::execution_exception&)
1262 {
1263 goto data_read_error;
1264 }
1265 }
1266 }
1267 else
1268 {
1269 tc = m;
1270 warning_with_id ("Octave:load:classdef-to-struct",
1271 "load: element has been converted to a structure");
1272 }
1273 }
1274 }
1275 else
1276 tc = m;
1277 }
1278 break;
1279
1282 break;
1283
1285 {
1287
1288 // Logical variables can either be MAT_FILE_UINT8_CLASS or
1289 // MAT_FILE_DOUBLE_CLASS, so check if we have a logical
1290 // variable and convert it.
1291
1292 if (logicalvar)
1293 {
1295 octave_idx_type nel = in.numel ();
1296 boolNDArray out (dims);
1297
1298 for (octave_idx_type i = 0; i < nel; i++)
1299 out(i) = in(i).bool_value ();
1300
1301 tc = out;
1302 }
1303 }
1304 break;
1305
1308 break;
1309
1312 break;
1313
1316 break;
1317
1320 break;
1321
1324 break;
1325
1328 break;
1329
1331 {
1332 FloatNDArray re (dims);
1333
1334 // real data subelement
1335
1336 std::streampos tmp_pos;
1337
1338 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
1339 error ("load: reading matrix data for '%s'", retval.c_str ());
1340
1341 octave_idx_type n = re.numel ();
1342 tmp_pos = is.tellg ();
1343 read_mat5_binary_data (is, re.rwdata (), n, swap,
1344 static_cast<enum mat5_data_type> (type),
1345 flt_fmt);
1346
1347 if (! is)
1348 error ("load: reading matrix data for '%s'", retval.c_str ());
1349
1350 is.seekg (tmp_pos + static_cast<std::streamoff>
1351 (READ_PAD (is_small_data_element, len)));
1352
1353 if (imag)
1354 {
1355 // imaginary data subelement
1356
1357 FloatNDArray im (dims);
1358
1359 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
1360 error ("load: reading matrix data for '%s'", retval.c_str ());
1361
1362 n = im.numel ();
1363 read_mat5_binary_data (is, im.rwdata (), n, swap,
1364 static_cast<enum mat5_data_type> (type),
1365 flt_fmt);
1366
1367 if (! is)
1368 error ("load: reading imaginary matrix data for '%s'",
1369 retval.c_str ());
1370
1371 FloatComplexNDArray ctmp (dims);
1372
1373 for (octave_idx_type i = 0; i < n; i++)
1374 ctmp(i) = FloatComplex (re(i), im(i));
1375
1376 tc = ctmp;
1377 }
1378 else
1379 tc = re;
1380 }
1381 break;
1382
1384 // handle as a numerical array to start with
1385
1387 default:
1388 {
1389 NDArray re (dims);
1390
1391 // real data subelement
1392
1393 std::streampos tmp_pos;
1394
1395 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
1396 error ("load: reading matrix data for '%s'", retval.c_str ());
1397
1398 octave_idx_type n = re.numel ();
1399 tmp_pos = is.tellg ();
1400 read_mat5_binary_data (is, re.rwdata (), n, swap,
1401 static_cast<enum mat5_data_type> (type),
1402 flt_fmt);
1403
1404 if (! is)
1405 error ("load: reading matrix data for '%s'", retval.c_str ());
1406
1407 is.seekg (tmp_pos + static_cast<std::streamoff>
1408 (READ_PAD (is_small_data_element, len)));
1409
1410 if (logicalvar)
1411 {
1412 // Logical variables can either be MAT_FILE_UINT8_CLASS or
1413 // MAT_FILE_DOUBLE_CLASS, so check if we have a logical
1414 // variable and convert it.
1415
1416 boolNDArray out (dims);
1417
1418 for (octave_idx_type i = 0; i < n; i++)
1419 out (i) = static_cast<bool> (re (i));
1420
1421 tc = out;
1422 }
1423 else if (imag)
1424 {
1425 // imaginary data subelement
1426
1427 NDArray im (dims);
1428
1429 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
1430 error ("load: reading matrix data for '%s'", retval.c_str ());
1431
1432 n = im.numel ();
1433 read_mat5_binary_data (is, im.rwdata (), n, swap,
1434 static_cast<enum mat5_data_type> (type),
1435 flt_fmt);
1436
1437 if (! is)
1438 error ("load: reading imaginary matrix data for '%s'",
1439 retval.c_str ());
1440
1441 ComplexNDArray ctmp (dims);
1442
1443 for (octave_idx_type i = 0; i < n; i++)
1444 ctmp(i) = Complex (re(i), im(i));
1445
1446 tc = ctmp;
1447 }
1448 else if (arrayclass == MAT_FILE_CHAR_CLASS)
1449 {
1450 bool converted = false;
1451 if (re.isvector () && (type == miUTF16 || type == miUINT16))
1452 {
1453 uint16NDArray u16 = re;
1454 const uint16_t *u16_str
1455 = reinterpret_cast<const uint16_t *> (u16.data ());
1456
1457 // Convert to UTF-8.
1458 std::size_t n8;
1459 uint8_t *u8_str = octave_u16_to_u8_wrapper (u16_str,
1460 u16.numel (),
1461 nullptr, &n8);
1462 if (u8_str)
1463 {
1464 // FIXME: Is there a better way to construct a charMatrix
1465 // from a non zero terminated buffer?
1466 tc = charMatrix (std::string (reinterpret_cast<char *> (u8_str), n8));
1467 free (u8_str);
1468 converted = true;
1469 }
1470 }
1471 else if (re.isvector () && (type == miUTF32 || type == miUINT32))
1472 {
1473 uint32NDArray u32 = re;
1474 const uint32_t *u32_str
1475 = reinterpret_cast<const uint32_t *> (u32.data ());
1476
1477 // Convert to UTF-8.
1478 std::size_t n8;
1479 uint8_t *u8_str = octave_u32_to_u8_wrapper (u32_str,
1480 u32.numel (),
1481 nullptr, &n8);
1482 if (u8_str)
1483 {
1484 // FIXME: Is there a better way to construct a charMatrix
1485 // from a non zero terminated buffer?
1486 tc = charMatrix (std::string (reinterpret_cast<char *> (u8_str), n8));
1487 free (u8_str);
1488 converted = true;
1489 }
1490 }
1491 else if (type == miUTF8 || type == miUINT8)
1492 {
1493 // Octave's internal encoding is UTF-8. So we should be
1494 // able to use this natively.
1495 tc = re;
1496 tc = tc.convert_to_str (false, true, '\'');
1497 converted = true;
1498 }
1499
1500 if (! converted)
1501 {
1502 // Fall back to manually replacing non-ASCII
1503 // characters by "?".
1504 bool found_big_char = false;
1505 for (octave_idx_type i = 0; i < n; i++)
1506 {
1507 if (re(i) > 127)
1508 {
1509 re(i) = '?';
1510 found_big_char = true;
1511 }
1512 }
1513
1514 if (found_big_char)
1515 warning_with_id ("Octave:load:unsupported-utf-char",
1516 "load: failed to convert from input to UTF-8; "
1517 "replacing non-ASCII characters with '?'");
1518
1519 tc = re;
1520 tc = tc.convert_to_str (false, true, '\'');
1521 }
1522
1523 }
1524 else
1525 tc = re;
1526 }
1527 }
1528
1529 is.seekg (pos + static_cast<std::streamoff> (element_length));
1530
1531 if (is.eof ())
1532 is.clear ();
1533
1534 return retval;
1535
1536// FIXME: With short-circuiting error(), no need for goto in code
1537data_read_error:
1538 error ("load: trouble reading binary file '%s'", filename.c_str ());
1539
1540skip_ahead:
1541 warning_with_id ("Octave:load:skip-unsupported-element",
1542 "load: skipping over '%s'", retval.c_str ());
1543 is.seekg (pos + static_cast<std::streamoff> (element_length));
1544 return read_mat5_binary_element (is, filename, swap, global, tc);
1545}
1546
1547int
1548read_mat5_binary_file_header (std::istream& is, bool& swap, bool quiet,
1549 const std::string& filename)
1550{
1551 int16_t version = 0;
1552 int16_t magic = 0;
1553 uint64_t subsys_offset;
1554
1555 is.seekg (116, std::ios::beg);
1556 is.read (reinterpret_cast<char *> (&subsys_offset), 8);
1557
1558 is.seekg (124, std::ios::beg);
1559 is.read (reinterpret_cast<char *> (&version), 2);
1560 is.read (reinterpret_cast<char *> (&magic), 2);
1561
1562 if (magic == 0x4d49)
1563 swap = false;
1564 else if (magic == 0x494d)
1565 swap = true;
1566 else
1567 {
1568 if (! quiet)
1569 error ("load: can't read binary file");
1570
1571 return -1;
1572 }
1573
1574 if (! swap) // version number is inverse swapped!
1575 version = ((version >> 8) & 0xff) + ((version & 0xff) << 8);
1576
1577 if (version != 1 && ! quiet)
1578 warning_with_id ("Octave:load:unsupported-version",
1579 "load: found version %d binary MAT file, but only prepared for version 1",
1580 version);
1581
1582 if (swap)
1583 swap_bytes<8> (&subsys_offset, 1);
1584
1585 if (subsys_offset != UINT64_C (0x2020202020202020)
1586 && subsys_offset != UINT64_C (0))
1587 {
1588 // Read the subsystem data block
1589 is.seekg (subsys_offset, std::ios::beg);
1590
1591 octave_value tc;
1592 bool global;
1593 read_mat5_binary_element (is, filename, swap, global, tc);
1594
1595 if (! is)
1596 return -1;
1597
1598 if (tc.is_uint8_type ())
1599 {
1600 const uint8NDArray itmp = tc.uint8_array_value ();
1601 octave_idx_type ilen = itmp.numel ();
1602
1603 // Why should I have to initialize outbuf as just overwrite
1604 std::string outbuf (ilen - 7, ' ');
1605
1606 // FIXME: find a way to avoid casting away const here
1607 char *ctmp = const_cast<char *> (outbuf.c_str ());
1608 for (octave_idx_type j = 8; j < ilen; j++)
1609 ctmp[j-8] = itmp(j).char_value ();
1610
1611 std::istringstream fh_ws (outbuf);
1612 octave_value subsys_ov;
1613 read_mat5_binary_element (fh_ws, filename, swap, global, subsys_ov);
1614
1615 octave::subsystem_handler *sh = octave::__get_load_save_system__ ().get_subsystem_handler ();
1616 if (! sh->read_mat_subsystem (subsys_ov, swap))
1617 error ("load: unable to read subsystem data from MAT-file '%s'", filename.c_str ());
1618
1619 if (! is)
1620 return -1;
1621 }
1622 else
1623 return -1;
1624
1625 // Reposition to just after the header
1626 is.seekg (128, std::ios::beg);
1627 }
1628
1629 return 0;
1630}
1631
1632static int
1633write_mat5_tag (std::ostream& is, int type, octave_idx_type bytes)
1634{
1635 int32_t temp;
1636
1637 if (bytes > 0 && bytes <= 4)
1638 temp = (bytes << 16) + type;
1639 else
1640 {
1641 temp = type;
1642 if (! is.write (reinterpret_cast<char *> (&temp), 4))
1643 return 1;
1644 temp = bytes;
1645 }
1646
1647 if (! is.write (reinterpret_cast<char *> (&temp), 4))
1648 return 1;
1649
1650 return 0;
1651}
1652
1653// Have to use copy here to avoid writing over data accessed via
1654// Matrix::data().
1655
1656#define MAT5_DO_WRITE(TYPE, data, count, stream) \
1657 do \
1658 { \
1659 OCTAVE_LOCAL_BUFFER (TYPE, ptr, count); \
1660 for (octave_idx_type i = 0; i < count; i++) \
1661 ptr[i] = static_cast<TYPE> (data[i]); \
1662 std::streamsize n_bytes = sizeof (TYPE) * static_cast<std::streamsize> (count); \
1663 stream.write (reinterpret_cast<char *> (ptr), n_bytes); \
1664 } \
1665 while (0)
1666
1667// write out the numeric values in M to OS,
1668// preceded by the appropriate tag.
1669static void
1670write_mat5_array (std::ostream& os, const NDArray& m, bool save_as_floats)
1671{
1672 save_type st = LS_DOUBLE;
1673 const double *data = m.data ();
1674
1675 if (save_as_floats)
1676 {
1677 if (m.too_large_for_float ())
1678 {
1679 warning_with_id ("Octave:save:too-large-for-float",
1680 "save: some values too large to save as floats -- saving as doubles instead");
1681 }
1682 else
1683 st = LS_FLOAT;
1684 }
1685
1686 double max_val, min_val;
1687 if (m.all_integers (max_val, min_val))
1688 st = octave::get_save_type (max_val, min_val);
1689
1690 mat5_data_type mst;
1691 int size;
1692 switch (st)
1693 {
1694 default:
1695 case LS_DOUBLE: mst = miDOUBLE; size = 8; break;
1696 case LS_FLOAT: mst = miSINGLE; size = 4; break;
1697 case LS_U_CHAR: mst = miUINT8; size = 1; break;
1698 case LS_U_SHORT: mst = miUINT16; size = 2; break;
1699 case LS_U_INT: mst = miUINT32; size = 4; break;
1700 case LS_CHAR: mst = miINT8; size = 1; break;
1701 case LS_SHORT: mst = miINT16; size = 2; break;
1702 case LS_INT: mst = miINT32; size = 4; break;
1703 }
1704
1705 octave_idx_type nel = m.numel ();
1706 octave_idx_type len = nel*size;
1707
1708 write_mat5_tag (os, mst, len);
1709
1710 {
1711 switch (st)
1712 {
1713 case LS_U_CHAR:
1714 MAT5_DO_WRITE (uint8_t, data, nel, os);
1715 break;
1716
1717 case LS_U_SHORT:
1718 MAT5_DO_WRITE (uint16_t, data, nel, os);
1719 break;
1720
1721 case LS_U_INT:
1722 MAT5_DO_WRITE (uint32_t, data, nel, os);
1723 break;
1724
1725 case LS_U_LONG:
1726 MAT5_DO_WRITE (uint64_t, data, nel, os);
1727 break;
1728
1729 case LS_CHAR:
1730 MAT5_DO_WRITE (int8_t, data, nel, os);
1731 break;
1732
1733 case LS_SHORT:
1734 MAT5_DO_WRITE (int16_t, data, nel, os);
1735 break;
1736
1737 case LS_INT:
1738 MAT5_DO_WRITE (int32_t, data, nel, os);
1739 break;
1740
1741 case LS_LONG:
1742 MAT5_DO_WRITE (int64_t, data, nel, os);
1743 break;
1744
1745 case LS_FLOAT:
1746 MAT5_DO_WRITE (float, data, nel, os);
1747 break;
1748
1749 case LS_DOUBLE: // No conversion necessary.
1750 os.write (reinterpret_cast<const char *> (data), len);
1751 break;
1752
1753 default:
1754 error ("unrecognized data format requested");
1755 break;
1756 }
1757 }
1758 if (PAD (len) > len)
1759 {
1760 static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00";
1761 os.write (buf, PAD (len) - len);
1762 }
1763}
1764
1765static void
1766write_mat5_array (std::ostream& os, const FloatNDArray& m, bool)
1767{
1768 save_type st = LS_FLOAT;
1769 const float *data = m.data ();
1770
1771 float max_val, min_val;
1772 if (m.all_integers (max_val, min_val))
1773 st = octave::get_save_type (max_val, min_val);
1774
1775 mat5_data_type mst;
1776 int size;
1777 switch (st)
1778 {
1779 default:
1780 case LS_DOUBLE: mst = miDOUBLE; size = 8; break;
1781 case LS_FLOAT: mst = miSINGLE; size = 4; break;
1782 case LS_U_CHAR: mst = miUINT8; size = 1; break;
1783 case LS_U_SHORT: mst = miUINT16; size = 2; break;
1784 case LS_U_INT: mst = miUINT32; size = 4; break;
1785 case LS_CHAR: mst = miINT8; size = 1; break;
1786 case LS_SHORT: mst = miINT16; size = 2; break;
1787 case LS_INT: mst = miINT32; size = 4; break;
1788 }
1789
1790 octave_idx_type nel = m.numel ();
1791 octave_idx_type len = nel*size;
1792
1793 write_mat5_tag (os, mst, len);
1794
1795 {
1796 switch (st)
1797 {
1798 case LS_U_CHAR:
1799 MAT5_DO_WRITE (uint8_t, data, nel, os);
1800 break;
1801
1802 case LS_U_SHORT:
1803 MAT5_DO_WRITE (uint16_t, data, nel, os);
1804 break;
1805
1806 case LS_U_INT:
1807 MAT5_DO_WRITE (uint32_t, data, nel, os);
1808 break;
1809
1810 case LS_U_LONG:
1811 MAT5_DO_WRITE (uint64_t, data, nel, os);
1812 break;
1813
1814 case LS_CHAR:
1815 MAT5_DO_WRITE (int8_t, data, nel, os);
1816 break;
1817
1818 case LS_SHORT:
1819 MAT5_DO_WRITE (int16_t, data, nel, os);
1820 break;
1821
1822 case LS_INT:
1823 MAT5_DO_WRITE (int32_t, data, nel, os);
1824 break;
1825
1826 case LS_LONG:
1827 MAT5_DO_WRITE (int64_t, data, nel, os);
1828 break;
1829
1830 case LS_FLOAT: // No conversion necessary.
1831 os.write (reinterpret_cast<const char *> (data), len);
1832 break;
1833
1834 case LS_DOUBLE:
1835 MAT5_DO_WRITE (double, data, nel, os);
1836 break;
1837
1838 default:
1839 error ("unrecognized data format requested");
1840 break;
1841 }
1842 }
1843 if (PAD (len) > len)
1844 {
1845 static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00";
1846 os.write (buf, PAD (len) - len);
1847 }
1848}
1849
1850template <typename T>
1851void
1852write_mat5_integer_data (std::ostream& os, const T *m, int size,
1853 octave_idx_type nel)
1854{
1855 mat5_data_type mst;
1856 unsigned len;
1857
1858 switch (size)
1859 {
1860 case 1:
1861 mst = miUINT8;
1862 break;
1863 case 2:
1864 mst = miUINT16;
1865 break;
1866 case 4:
1867 mst = miUINT32;
1868 break;
1869 case 8:
1870 mst = miUINT64;
1871 break;
1872 case -1:
1873 mst = miINT8;
1874 size = - size;
1875 break;
1876 case -2:
1877 mst = miINT16;
1878 size = - size;
1879 break;
1880 case -4:
1881 mst = miINT32;
1882 size = - size;
1883 break;
1884 case -8:
1885 default:
1886 mst = miINT64;
1887 size = - size;
1888 break;
1889 }
1890
1891 len = nel*size;
1892 write_mat5_tag (os, mst, len);
1893
1894 os.write (reinterpret_cast<const char *> (m), len);
1895
1896 if (PAD (len) > len)
1897 {
1898 static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00";
1899 os.write (buf, PAD (len) - len);
1900 }
1901}
1902
1903template void
1904write_mat5_integer_data (std::ostream& os, const octave_int8 *m,
1905 int size, octave_idx_type nel);
1906
1907template void
1908write_mat5_integer_data (std::ostream& os, const octave_int16 *m,
1909 int size, octave_idx_type nel);
1910
1911template void
1912write_mat5_integer_data (std::ostream& os, const octave_int32 *m,
1913 int size, octave_idx_type nel);
1914
1915template void
1916write_mat5_integer_data (std::ostream& os, const octave_int64 *m,
1917 int size, octave_idx_type nel);
1918
1919template void
1920write_mat5_integer_data (std::ostream& os, const octave_uint8 *m,
1921 int size, octave_idx_type nel);
1922
1923template void
1924write_mat5_integer_data (std::ostream& os, const octave_uint16 *m,
1925 int size, octave_idx_type nel);
1926
1927template void
1928write_mat5_integer_data (std::ostream& os, const octave_uint32 *m,
1929 int size, octave_idx_type nel);
1930
1931template void
1932write_mat5_integer_data (std::ostream& os, const octave_uint64 *m,
1933 int size, octave_idx_type nel);
1934
1935template void
1936write_mat5_integer_data (std::ostream& os, const int *m,
1937 int size, octave_idx_type nel);
1938
1939// Write out cell element values in the cell array to OS, preceded by
1940// the appropriate tag.
1941
1942static bool
1943write_mat5_cell_array (std::ostream& os, const Cell& cell,
1944 bool mark_global, bool save_as_floats)
1945{
1946 octave_idx_type nel = cell.numel ();
1947
1948 for (octave_idx_type i = 0; i < nel; i++)
1949 {
1950 octave_value ov = cell(i);
1951
1952 if (! save_mat5_binary_element (os, ov, "", mark_global,
1953 false, save_as_floats))
1954 return false;
1955 }
1956
1957 return true;
1958}
1959
1960int
1962 bool save_as_floats)
1963{
1964 if (nel > 0)
1965 {
1966 int size = 8;
1967
1968 if (save_as_floats)
1969 {
1970 bool too_large_for_float = false;
1971 for (octave_idx_type i = 0; i < nel; i++)
1972 {
1973 double tmp = val[i];
1974
1975 if (octave::math::isfinite (tmp)
1976 && fabs (tmp) > std::numeric_limits<float>::max ())
1977 {
1978 too_large_for_float = true;
1979 break;
1980 }
1981 }
1982
1983 if (! too_large_for_float)
1984 size = 4;
1985 }
1986
1987 // The code below is disabled since get_save_type currently
1988 // doesn't deal with integer types. This will need to be
1989 // activated if get_save_type is changed.
1990
1991 // double max_val = val[0];
1992 // double min_val = val[0];
1993 // bool all_integers = true;
1994 //
1995 // for (int i = 0; i < nel; i++)
1996 // {
1997 // double val = val[i];
1998 //
1999 // if (val > max_val)
2000 // max_val = val;
2001 //
2002 // if (val < min_val)
2003 // min_val = val;
2004 //
2005 // if (octave::math::round (val) != val)
2006 // {
2007 // all_integers = false;
2008 // break;
2009 // }
2010 // }
2011 //
2012 // if (all_integers)
2013 // {
2014 // if (max_val < 256 && min_val > -1)
2015 // size = 1;
2016 // else if (max_val < 65536 && min_val > -1)
2017 // size = 2;
2018 // else if (max_val < 4294967295UL && min_val > -1)
2019 // size = 4;
2020 // else if (max_val < 128 && min_val >= -128)
2021 // size = 1;
2022 // else if (max_val < 32768 && min_val >= -32768)
2023 // size = 2;
2024 // else if (max_val <= 2147483647L && min_val >= -2147483647L)
2025 // size = 4;
2026 // }
2027
2028 return 8 + nel * size;
2029 }
2030 else
2031 return 8;
2032}
2033
2034int
2035save_mat5_array_length (const float * /* val */, octave_idx_type nel, bool)
2036{
2037 if (nel > 0)
2038 {
2039 int size = 4;
2040
2041 // The code below is disabled since get_save_type currently
2042 // doesn't deal with integer types. This will need to be
2043 // activated if get_save_type is changed.
2044
2045 // float max_val = val[0];
2046 // float min_val = val[0];
2047 // bool all_integers = true;
2048 //
2049 // for (int i = 0; i < nel; i++)
2050 // {
2051 // float val = val[i];
2052 //
2053 // if (val > max_val)
2054 // max_val = val;
2055 //
2056 // if (val < min_val)
2057 // min_val = val;
2058 //
2059 // if (octave::math::round (val) != val)
2060 // {
2061 // all_integers = false;
2062 // break;
2063 // }
2064 // }
2065 //
2066 // if (all_integers)
2067 // {
2068 // if (max_val < 256 && min_val > -1)
2069 // size = 1;
2070 // else if (max_val < 65536 && min_val > -1)
2071 // size = 2;
2072 // else if (max_val < 4294967295UL && min_val > -1)
2073 // size = 4;
2074 // else if (max_val < 128 && min_val >= -128)
2075 // size = 1;
2076 // else if (max_val < 32768 && min_val >= -32768)
2077 // size = 2;
2078 // else if (max_val <= 2147483647L && min_val >= -2147483647L)
2079 // size = 4;
2080 //
2081
2082 // Round nel up to nearest even number of elements.
2083 // Take into account short tags for 4 byte elements.
2084 return PAD ((nel * size <= 4 ? 4 : 8) + nel * size);
2085 }
2086 else
2087 return 8;
2088}
2089
2090int
2092 bool save_as_floats)
2093{
2094 int ret;
2095
2096 OCTAVE_LOCAL_BUFFER (double, tmp, nel);
2097
2098 for (octave_idx_type i = 1; i < nel; i++)
2099 tmp[i] = std::real (val[i]);
2100
2101 ret = save_mat5_array_length (tmp, nel, save_as_floats);
2102
2103 for (octave_idx_type i = 1; i < nel; i++)
2104 tmp[i] = std::imag (val[i]);
2105
2106 ret += save_mat5_array_length (tmp, nel, save_as_floats);
2107
2108 return ret;
2109}
2110
2111int
2113 bool save_as_floats)
2114{
2115 int ret;
2116
2117 OCTAVE_LOCAL_BUFFER (float, tmp, nel);
2118
2119 for (octave_idx_type i = 1; i < nel; i++)
2120 tmp[i] = std::real (val[i]);
2121
2122 ret = save_mat5_array_length (tmp, nel, save_as_floats);
2123
2124 for (octave_idx_type i = 1; i < nel; i++)
2125 tmp[i] = std::imag (val[i]);
2126
2127 ret += save_mat5_array_length (tmp, nel, save_as_floats);
2128
2129 return ret;
2130}
2131
2132static uint16_t *
2133maybe_convert_to_u16 (const charNDArray& chm, std::size_t& n16_str)
2134{
2135 uint16_t *u16_str;
2136 const dim_vector& dv = chm.dims ();
2137
2138 if (chm.ndims () == 2 && dv(0) == 1)
2139 {
2140 const uint8_t *u8_str = reinterpret_cast<const uint8_t *> (chm.data ());
2141 u16_str = octave_u8_to_u16_wrapper (u8_str, chm.numel (),
2142 nullptr, &n16_str);
2143 }
2144 else
2145 u16_str = nullptr;
2146
2147 return u16_str;
2148}
2149
2150int
2151save_mat5_element_length (const octave_value& tc_in, const std::string& name,
2152 bool save_as_floats, bool mat7_format)
2153{
2154 octave_value tc;
2155 if (tc_in.is_classdef_object ())
2156 tc = tc_in.classdef_object_value ()->map_value (false, false);
2157 else
2158 tc = tc_in;
2159
2160 std::size_t max_namelen = 63;
2161 std::size_t len = name.length ();
2162 std::string cname = tc.class_name ();
2163 int ret = 24;
2164
2165 if (len > 4)
2166 ret += PAD (len > max_namelen ? max_namelen : len);
2167
2168 if (! tc.is_classdef_object ())
2169 {
2170 // dimensions flag
2171 ret += 8;
2172 ret += PAD (4 * tc.ndims ());
2173 }
2174
2175 if (tc.is_string ())
2176 {
2177 charNDArray chm = tc.char_array_value ();
2178 // convert to UTF-16
2179 std::size_t n16_str;
2180 uint16_t *u16_str = maybe_convert_to_u16 (chm, n16_str);
2181 ret += 8;
2182
2183 octave_idx_type str_len;
2184 std::size_t sz_of = 1;
2185 if (u16_str)
2186 {
2187 free (u16_str);
2188 // Count number of elements in converted string
2189 str_len = n16_str;
2190 sz_of = 2;
2191 }
2192 else
2193 str_len = chm.numel ();
2194
2195 if (str_len > 2)
2196 ret += PAD (sz_of * str_len);
2197 }
2198 else if (tc.issparse ())
2199 {
2200 if (tc.iscomplex ())
2201 {
2203 octave_idx_type nc = m.cols ();
2204 octave_idx_type nnz = m.nnz ();
2205
2206 ret += 16 + save_mat5_array_length (m.data (), nnz, save_as_floats);
2207 if (nnz > 1)
2208 ret += PAD (nnz * sizeof (int32_t));
2209 if (nc > 0)
2210 ret += PAD ((nc + 1) * sizeof (int32_t));
2211 }
2212 else
2213 {
2214 const SparseMatrix m = tc.sparse_matrix_value ();
2215 octave_idx_type nc = m.cols ();
2216 octave_idx_type nnz = m.nnz ();
2217
2218 ret += 16 + save_mat5_array_length (m.data (), nnz, save_as_floats);
2219 if (nnz > 1)
2220 ret += PAD (nnz * sizeof (int32_t));
2221 if (nc > 0)
2222 ret += PAD ((nc + 1) * sizeof (int32_t));
2223 }
2224 }
2225
2226#define INT_LEN(nel, size) \
2227 { \
2228 ret += 8; \
2229 octave_idx_type sz = nel * size; \
2230 if (sz > 4) \
2231 ret += PAD (sz); \
2232 }
2233
2234 else if (cname == "int8")
2235 INT_LEN (tc.int8_array_value ().numel (), 1)
2236 else if (cname == "int16")
2237 INT_LEN (tc.int16_array_value ().numel (), 2)
2238 else if (cname == "int32")
2239 INT_LEN (tc.int32_array_value ().numel (), 4)
2240 else if (cname == "int64")
2241 INT_LEN (tc.int64_array_value ().numel (), 8)
2242 else if (cname == "uint8")
2243 INT_LEN (tc.uint8_array_value ().numel (), 1)
2244 else if (cname == "uint16")
2245 INT_LEN (tc.uint16_array_value ().numel (), 2)
2246 else if (cname == "uint32")
2247 INT_LEN (tc.uint32_array_value ().numel (), 4)
2248 else if (cname == "uint64")
2249 INT_LEN (tc.uint64_array_value ().numel (), 8)
2250 else if (tc.islogical ())
2251 INT_LEN (tc.bool_array_value ().numel (), 1)
2252 else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ())
2253 {
2254 if (tc.is_single_type ())
2255 {
2256 const FloatNDArray m = tc.float_array_value ();
2257 ret += save_mat5_array_length (m.data (), m.numel (), save_as_floats);
2258 }
2259 else
2260 {
2261 const NDArray m = tc.array_value ();
2262 ret += save_mat5_array_length (m.data (), m.numel (), save_as_floats);
2263 }
2264 }
2265 else if (tc.iscell ())
2266 {
2267 Cell cell = tc.cell_value ();
2268 octave_idx_type nel = cell.numel ();
2269
2270 for (int i = 0; i < nel; i++)
2271 ret += 8 +
2272 save_mat5_element_length (cell (i), "", save_as_floats, mat7_format);
2273 }
2274 else if (tc.is_complex_scalar () || tc.is_complex_matrix ())
2275 {
2276 if (tc.is_single_type ())
2277 {
2279 ret += save_mat5_array_length (m.data (), m.numel (), save_as_floats);
2280 }
2281 else
2282 {
2283 const ComplexNDArray m = tc.complex_array_value ();
2284 ret += save_mat5_array_length (m.data (), m.numel (), save_as_floats);
2285 }
2286 }
2287 else if (tc.is_classdef_object ())
2288 {
2289 // assuming MCOS objects only
2290 ret += 8; // for type system - MCOS uses small element format
2291
2292 std::size_t classlen = cname.length ();
2293 ret += 8;
2294 if (classlen > 4)
2295 ret += PAD (classlen > max_namelen ? max_namelen : classlen);
2296
2297 const dim_vector& dv = tc.dims ();
2298 int ndims = dv.ndims ();
2299 int nobjs = dv.numel ();
2300
2301 if (cname == "FileWrapper__")
2302 {
2303 octave::load_save_system& lss = octave::__get_load_save_system__ ();
2304 const octave_value& fwrap_data
2305 = lss.get_subsystem_handler ()->get_serialized_data ();
2306 ret += 8 + save_mat5_element_length (fwrap_data, "", save_as_floats, false);
2307 }
2308 else
2309 {
2310 //! Does not work for enumerations
2311 uint32NDArray mcos_metadata_arr (dim_vector (ndims + nobjs + 3, 1));
2312 ret += 8 + save_mat5_element_length (mcos_metadata_arr, "",
2313 save_as_floats, mat7_format);
2314 }
2315 }
2316 else if (tc.isstruct () || tc.is_inline_function () || tc.isobject ())
2317 {
2318 int fieldcnt = 0;
2319 const octave_map m = tc.map_value ();
2320 octave_idx_type nel = m.numel ();
2321
2322 if (tc.is_inline_function ())
2323 ret += 8 + PAD (6); // length of "inline" is 6
2324 else if (tc.isobject ())
2325 {
2326 std::size_t classlen = tc.class_name ().length ();
2327
2328 ret += 8 + PAD (classlen > max_namelen ? max_namelen : classlen);
2329 }
2330
2331 for (auto i = m.begin (); i != m.end (); i++)
2332 fieldcnt++;
2333
2334 ret += 16 + fieldcnt * (max_namelen + 1);
2335
2336 for (octave_idx_type j = 0; j < nel; j++)
2337 {
2338 for (auto i = m.begin (); i != m.end (); i++)
2339 {
2340 const Cell elts = m.contents (i);
2341
2342 ret += 8 + save_mat5_element_length (elts(j), "", save_as_floats,
2343 mat7_format);
2344 }
2345 }
2346 }
2347 else
2348 ret = -1;
2349
2350 return ret;
2351}
2352
2353static void
2354write_mat5_sparse_index_vector (std::ostream& os,
2355 const octave_idx_type *idx,
2356 octave_idx_type nel)
2357{
2358 int tmp = sizeof (int32_t);
2359
2360 OCTAVE_LOCAL_BUFFER (int32_t, tmp_idx, nel);
2361
2362 for (octave_idx_type i = 0; i < nel; i++)
2363 tmp_idx[i] = idx[i];
2364
2365 write_mat5_integer_data (os, tmp_idx, -tmp, nel);
2366}
2367
2368static void
2369warn_dim_too_large (const std::string& name)
2370{
2371 warning_with_id ("Octave:save:dimension-too-large",
2372 "save: skipping %s: dimension too large for MAT format",
2373 name.c_str ());
2374}
2375
2376// save the data from TC along with the corresponding NAME on stream
2377// OS in the MatLab version 5 binary format. Return true on success.
2378bool
2380 const octave_value& tc_in, const std::string& name,
2381 bool mark_global, bool mat7_format,
2382 bool save_as_floats, bool compressing)
2383{
2384 octave_value tc;
2385 if (tc_in.is_classdef_object ())
2386 {
2387 warning_with_id ("Octave:save:classdef:unsupported",
2388 "Saving classdef objects is not supported. "
2389 "Attempting to save object as struct.");
2390 tc = tc_in.classdef_object_value ()->map_value (false, false);
2391 }
2392 else
2393 tc = tc_in;
2394
2395 int32_t flags = 0;
2396 int32_t nnz_32 = 0;
2397 std::string cname = tc.class_name ();
2398 std::size_t max_namelen = 63;
2399
2400 const dim_vector& dv = tc.dims ();
2401 int nd = tc.ndims ();
2402 int dim_len = 4*nd;
2403
2404 static octave_idx_type max_dim_val = std::numeric_limits<int32_t>::max ();
2405
2406 // Strings need to be converted here (or dim-vector will be off).
2407 charNDArray chm;
2408 uint16_t *u16_str = nullptr;
2409 std::size_t n16_str;
2410 bool conv_u16 = false;
2411 if (tc.is_string ())
2412 {
2413 chm = tc.char_array_value ();
2414 u16_str = maybe_convert_to_u16 (chm, n16_str);
2415
2416 if (u16_str)
2417 conv_u16 = true;
2418 }
2419 // Guarantee that memory is freed regardless of path through code.
2420 octave::unwind_action free_memory ([u16_str] ()
2421 { if (u16_str != nullptr) free (u16_str); });
2422
2423 if (conv_u16)
2424 {
2425 if (n16_str > static_cast<std::size_t> (max_dim_val))
2426 {
2427 warn_dim_too_large (name);
2428 return true; // skip to next
2429 }
2430 }
2431 else
2432 {
2433 for (int i = 0; i < nd; i++)
2434 {
2435 if (dv(i) > max_dim_val)
2436 {
2437 warn_dim_too_large (name);
2438 return true; // skip to next
2439 }
2440 }
2441 }
2442
2443 if (tc.issparse ())
2444 {
2445 octave_idx_type nnz;
2446 octave_idx_type nc;
2447
2448 if (tc.iscomplex ())
2449 {
2451 nnz = scm.nzmax ();
2452 nc = scm.cols ();
2453 }
2454 else
2455 {
2457 nnz = sm.nzmax ();
2458 nc = sm.cols ();
2459 }
2460
2461 if (nnz > max_dim_val || nc + 1 > max_dim_val)
2462 {
2463 warn_dim_too_large (name);
2464 return true; // skip to next
2465 }
2466
2467 nnz_32 = nnz;
2468 }
2469 else if (dv.numel () > max_dim_val)
2470 {
2471 warn_dim_too_large (name);
2472 return true; // skip to next
2473 }
2474
2475#if defined (HAVE_ZLIB)
2476
2477 if (mat7_format && ! compressing)
2478 {
2479 bool ret = false;
2480
2481 std::ostringstream buf;
2482
2483 // The code seeks backwards in the stream to fix the header.
2484 // Can't do this with zlib, so use a stringstream.
2485 ret = save_mat5_binary_element (buf, tc, name, mark_global, true,
2486 save_as_floats, true);
2487
2488 if (ret)
2489 {
2490 // destLen must be at least 0.1% larger than source buffer
2491 // + 12 bytes. Reality is it must be larger again than that.
2492 std::string buf_str = buf.str ();
2493 uLongf srcLen = buf_str.length ();
2494 uLongf destLen = compressBound (srcLen);
2495 OCTAVE_LOCAL_BUFFER (char, out_buf, destLen);
2496
2497 if (compress (reinterpret_cast<Bytef *> (out_buf), &destLen,
2498 reinterpret_cast<const Bytef *> (buf_str.c_str ()),
2499 srcLen)
2500 != Z_OK)
2501 error ("save: error compressing data element");
2502
2503 write_mat5_tag (os, miCOMPRESSED,
2504 static_cast<octave_idx_type> (destLen));
2505
2506 os.write (out_buf, destLen);
2507 }
2508
2509 return ret;
2510 }
2511
2512#else
2513
2514 octave_unused_parameter (compressing);
2515
2516#endif
2517
2518 write_mat5_tag (os, miMATRIX, save_mat5_element_length
2519 (tc, name, save_as_floats, mat7_format));
2520
2521 // array flags subelement
2522 write_mat5_tag (os, miUINT32, 8);
2523
2524 if (tc.islogical ())
2525 flags |= 0x0200;
2526
2527 if (mark_global)
2528 flags |= 0x0400;
2529
2530 if (tc.is_complex_scalar () || tc.is_complex_matrix ())
2531 flags |= 0x0800;
2532
2533 if (tc.is_string ())
2534 flags |= MAT_FILE_CHAR_CLASS;
2535 else if (cname == "int8")
2536 flags |= MAT_FILE_INT8_CLASS;
2537 else if (cname == "int16")
2538 flags |= MAT_FILE_INT16_CLASS;
2539 else if (cname == "int32")
2540 flags |= MAT_FILE_INT32_CLASS;
2541 else if (cname == "int64")
2542 flags |= MAT_FILE_INT64_CLASS;
2543 else if (cname == "uint8" || tc.islogical ())
2544 flags |= MAT_FILE_UINT8_CLASS;
2545 else if (cname == "uint16")
2546 flags |= MAT_FILE_UINT16_CLASS;
2547 else if (cname == "uint32")
2548 flags |= MAT_FILE_UINT32_CLASS;
2549 else if (cname == "uint64")
2550 flags |= MAT_FILE_UINT64_CLASS;
2551 else if (tc.issparse ())
2552 flags |= MAT_FILE_SPARSE_CLASS;
2553 else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ()
2554 || tc.is_complex_scalar () || tc.is_complex_matrix ())
2555 {
2556 if (tc.is_single_type ())
2557 flags |= MAT_FILE_SINGLE_CLASS;
2558 else
2559 flags |= MAT_FILE_DOUBLE_CLASS;
2560 }
2561 else if (tc.isstruct ())
2562 flags |= MAT_FILE_STRUCT_CLASS;
2563 else if (tc.iscell ())
2564 flags |= MAT_FILE_CELL_CLASS;
2565 else if (tc.is_classdef_object ())
2566 flags |= MAT_FILE_WORKSPACE_CLASS;
2567 else if (tc.is_inline_function () || tc.isobject ())
2568 flags |= MAT_FILE_OBJECT_CLASS;
2569 else
2570 {
2571 // FIXME: Should this just error out rather than warn?
2572 warn_wrong_type_arg ("save", tc);
2573 error ("save: error while writing '%s' to MAT file", name.c_str ());
2574 }
2575
2576 os.write (reinterpret_cast<char *> (&flags), 4);
2577 // Matlab seems to have trouble reading files that have nzmax == 0 at
2578 // this point in the file.
2579 if (nnz_32 == 0)
2580 nnz_32 = 1;
2581 os.write (reinterpret_cast<char *> (&nnz_32), 4);
2582
2583 if (! tc.is_classdef_object ())
2584 {
2585 // classdef objects don't have dims subelement
2586 write_mat5_tag (os, miINT32, dim_len);
2587
2588 if (conv_u16)
2589 {
2590 int32_t n[2] = {1, static_cast<int32_t> (n16_str)};
2591 os.write (reinterpret_cast<char *> (&n), 8);
2592 }
2593 else
2594 for (int i = 0; i < nd; i++)
2595 {
2596 int32_t n = dv(i);
2597 os.write (reinterpret_cast<char *> (&n), 4);
2598 }
2599
2600 if (PAD (dim_len) > dim_len)
2601 {
2602 static char buf[9] = "\x00\x00\x00\x00\x00\x00\x00\x00";
2603 os.write (buf, PAD (dim_len) - dim_len);
2604 }
2605 }
2606
2607 // array name subelement
2608 {
2609 std::size_t namelen = name.length ();
2610
2611 if (namelen > max_namelen)
2612 namelen = max_namelen; // Truncate names if necessary
2613
2614 int paddedlength = PAD (namelen);
2615
2616 write_mat5_tag (os, miINT8, namelen);
2617 OCTAVE_LOCAL_BUFFER (char, paddedname, paddedlength);
2618 memset (paddedname, 0, paddedlength);
2619 strncpy (paddedname, name.c_str (), namelen);
2620 os.write (paddedname, paddedlength);
2621 }
2622
2623 if (tc.is_classdef_object ())
2624 {
2625 // type system
2626 std::string type_system;
2627 if (tc.type_name () == "object")
2628 type_system = "MCOS";
2629 std::size_t type_sys_len = type_system.length ();
2630 int paddedlength = PAD (type_sys_len);
2631 write_mat5_tag (os, miINT8, type_sys_len);
2632 OCTAVE_LOCAL_BUFFER (char, paddedtype, paddedlength);
2633 memset (paddedtype, 0, paddedlength);
2634 strncpy (paddedtype, type_system.c_str (), type_sys_len);
2635 os.write (paddedtype, paddedlength);
2636
2637 // class name
2638 std::size_t class_name_len = cname.length ();
2639 paddedlength = PAD (class_name_len);
2640 write_mat5_tag (os, miINT8, class_name_len);
2641 OCTAVE_LOCAL_BUFFER (char, paddedclass, paddedlength);
2642 memset (paddedclass, 0, paddedlength);
2643 strncpy (paddedclass, cname.c_str (), class_name_len);
2644 os.write (paddedclass, paddedlength);
2645 }
2646
2647 // data element
2648 if (tc.is_string ())
2649 {
2651 octave_idx_type paddedlength;
2652
2653 if (conv_u16)
2654 {
2655 // converted UTF-16
2656 len = n16_str*2;
2657 paddedlength = PAD (len);
2658
2659 write_mat5_tag (os, miUTF16, len);
2660
2661 os.write (reinterpret_cast<char *> (u16_str), len);
2662 }
2663 else
2664 {
2665 // write as UTF-8
2666 len = chm.numel ();
2667 paddedlength = PAD (len);
2668
2669 write_mat5_tag (os, miUTF8, len);
2670
2671 os.write (chm.data (), len);
2672 }
2673
2674 if (paddedlength > len)
2675 {
2676 static char padbuf[9] = "\x00\x00\x00\x00\x00\x00\x00\x00";
2677 os.write (padbuf, paddedlength - len);
2678 }
2679 }
2680 else if (tc.issparse ())
2681 {
2682 if (tc.iscomplex ())
2683 {
2685 octave_idx_type nnz = m.nnz ();
2686 octave_idx_type nc = m.cols ();
2687
2688 write_mat5_sparse_index_vector (os, m.ridx (), nnz);
2689 write_mat5_sparse_index_vector (os, m.cidx (), nc + 1);
2690
2691 NDArray buf (dim_vector (nnz, 1));
2692
2693 for (octave_idx_type i = 0; i < nnz; i++)
2694 buf (i) = std::real (m.data (i));
2695
2696 write_mat5_array (os, buf, save_as_floats);
2697
2698 for (octave_idx_type i = 0; i < nnz; i++)
2699 buf (i) = std::imag (m.data (i));
2700
2701 write_mat5_array (os, buf, save_as_floats);
2702 }
2703 else
2704 {
2705 const SparseMatrix m = tc.sparse_matrix_value ();
2706 octave_idx_type nnz = m.nnz ();
2707 octave_idx_type nc = m.cols ();
2708
2709 write_mat5_sparse_index_vector (os, m.ridx (), nnz);
2710 write_mat5_sparse_index_vector (os, m.cidx (), nc + 1);
2711
2712 // FIXME
2713 // Is there a way to easily do without this buffer
2714 NDArray buf (dim_vector (nnz, 1));
2715
2716 for (int i = 0; i < nnz; i++)
2717 buf (i) = m.data (i);
2718
2719 write_mat5_array (os, buf, save_as_floats);
2720 }
2721 }
2722 else if (cname == "int8")
2723 {
2724 int8NDArray m = tc.int8_array_value ();
2725
2726 write_mat5_integer_data (os, m.data (), -1, m.numel ());
2727 }
2728 else if (cname == "int16")
2729 {
2731
2732 write_mat5_integer_data (os, m.data (), -2, m.numel ());
2733 }
2734 else if (cname == "int32")
2735 {
2737
2738 write_mat5_integer_data (os, m.data (), -4, m.numel ());
2739 }
2740 else if (cname == "int64")
2741 {
2743
2744 write_mat5_integer_data (os, m.data (), -8, m.numel ());
2745 }
2746 else if (cname == "uint8")
2747 {
2749
2750 write_mat5_integer_data (os, m.data (), 1, m.numel ());
2751 }
2752 else if (cname == "uint16")
2753 {
2755
2756 write_mat5_integer_data (os, m.data (), 2, m.numel ());
2757 }
2758 else if (cname == "uint32")
2759 {
2761
2762 write_mat5_integer_data (os, m.data (), 4, m.numel ());
2763 }
2764 else if (cname == "uint64")
2765 {
2767
2768 write_mat5_integer_data (os, m.data (), 8, m.numel ());
2769 }
2770 else if (tc.islogical ())
2771 {
2773
2774 write_mat5_integer_data (os, m.data (), 1, m.numel ());
2775 }
2776 else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ())
2777 {
2778 if (tc.is_single_type ())
2779 {
2781
2782 write_mat5_array (os, m, save_as_floats);
2783 }
2784 else
2785 {
2786 NDArray m = tc.array_value ();
2787
2788 write_mat5_array (os, m, save_as_floats);
2789 }
2790 }
2791 else if (tc.iscell ())
2792 {
2793 Cell cell = tc.cell_value ();
2794
2795 if (! write_mat5_cell_array (os, cell, mark_global, save_as_floats))
2796 error ("save: error while writing '%s' to MAT file", name.c_str ());
2797 }
2798 else if (tc.is_complex_scalar () || tc.is_complex_matrix ())
2799 {
2800 if (tc.is_single_type ())
2801 {
2803
2804 write_mat5_array (os, ::real (m_cmplx), save_as_floats);
2805 write_mat5_array (os, ::imag (m_cmplx), save_as_floats);
2806 }
2807 else
2808 {
2809 ComplexNDArray m_cmplx = tc.complex_array_value ();
2810
2811 write_mat5_array (os, ::real (m_cmplx), save_as_floats);
2812 write_mat5_array (os, ::imag (m_cmplx), save_as_floats);
2813 }
2814 }
2815 else if (tc.is_classdef_object ())
2816 {
2817 octave::subsystem_handler *sh
2818 = octave::__get_load_save_system__ ().get_subsystem_handler ();
2819 octave_value objmetadata;
2820
2821 if (cname == "FileWrapper__")
2822 objmetadata = sh->get_serialized_data ();
2823 else if (sh->has_serialized_data ())
2824 {
2825 // MAT-files write metadata without MAT_FILE_WORKSPACE_CLASS header
2826 // in subsystem.
2827 // Current version writes header for these objects, which involves
2828 // modifying subsystem.
2829 // Workaround to prevent invalid memory access
2830 warning_with_id ("MATLAB:save:",
2831 "Object of class %s cannot be loaded in Octave due "
2832 "to issues with MAT-compatibility and is returned "
2833 "as a Cell",
2834 cname.c_str ());
2835 objmetadata = Cell (dim_vector (0, 0));
2836 }
2837 else
2838 objmetadata = sh->set_mcos_object_metadata (tc);
2839
2840 bool retval2 = save_mat5_binary_element (os, objmetadata, "", false,
2841 false, save_as_floats);
2842 if (! retval2)
2843 error ("save: error while writing '%s' to MAT file",
2844 name.c_str ());
2845 }
2846 else if (tc.isstruct () || tc.is_inline_function () || tc.isobject ())
2847 {
2848 if (tc.is_inline_function () || tc.isobject ())
2849 {
2850 std::string classname = (tc.isobject () ? tc.class_name ()
2851 : "inline");
2852 std::size_t namelen = classname.length ();
2853
2854 if (namelen > max_namelen)
2855 namelen = max_namelen; // Truncate names if necessary
2856
2857 int paddedlength = PAD (namelen);
2858
2859 write_mat5_tag (os, miINT8, namelen);
2860 OCTAVE_LOCAL_BUFFER (char, paddedname, paddedlength);
2861 memset (paddedname, 0, paddedlength);
2862 strncpy (paddedname, classname.c_str (), namelen);
2863 os.write (paddedname, paddedlength);
2864 }
2865
2866 octave_map m;
2867
2868 octave::interpreter& interp = octave::__get_interpreter__ ();
2869
2870 octave::load_path& lp = interp.get_load_path ();
2871
2872 if (tc.isobject ()
2873 && lp.find_method (tc.class_name (), "saveobj") != "")
2874 {
2875 try
2876 {
2877 octave_value_list tmp = interp.feval ("saveobj", tc, 1);
2878
2879 m = tmp(0).map_value ();
2880 }
2881 catch (const octave::execution_exception&)
2882 {
2883 error ("save: error while writing '%s' to MAT file",
2884 name.c_str ());
2885 }
2886 }
2887 else
2888 m = tc.map_value ();
2889
2890 // an Octave structure */
2891 // recursively write each element of the structure
2892 {
2893 char buf[64];
2894 int32_t maxfieldnamelength = max_namelen + 1;
2895
2896 octave_idx_type nf = m.nfields ();
2897
2898 write_mat5_tag (os, miINT32, 4);
2899 os.write (reinterpret_cast<char *> (&maxfieldnamelength), 4);
2900 write_mat5_tag (os, miINT8, nf*maxfieldnamelength);
2901
2902 // Iterating over the list of keys will preserve the order of
2903 // the fields.
2904 string_vector keys = m.keys ();
2905
2906 for (octave_idx_type i = 0; i < nf; i++)
2907 {
2908 std::string key = keys(i);
2909
2910 // write the name of each element
2911 memset (buf, 0, max_namelen + 1);
2912 // only 31 or 63 char names permitted
2913 strncpy (buf, key.c_str (), max_namelen);
2914 os.write (buf, max_namelen + 1);
2915 }
2916
2917 octave_idx_type len = m.numel ();
2918
2919 // Create temporary copy of structure contents to avoid
2920 // multiple calls of the contents method.
2921 std::vector<const octave_value *> elts (nf);
2922 for (octave_idx_type i = 0; i < nf; i++)
2923 elts[i] = m.contents (keys(i)).data ();
2924
2925 for (octave_idx_type j = 0; j < len; j++)
2926 {
2927 // write the data of each element
2928
2929 // Iterating over the list of keys will preserve the order
2930 // of the fields.
2931 for (octave_idx_type i = 0; i < nf; i++)
2932 {
2933 bool retval2 = save_mat5_binary_element (os, elts[i][j], "",
2934 mark_global, false,
2935 save_as_floats);
2936 if (! retval2)
2937 error ("save: error while writing '%s' to MAT file",
2938 name.c_str ());
2939 }
2940 }
2941 }
2942 }
2943 else
2944 // FIXME: Should this just error out rather than warn?
2945 warn_wrong_type_arg ("save", tc);
2946
2947 return true;
2948}
void swap_bytes< 8 >(void *ptr)
Definition byte-swap.h:71
void swap_bytes< 4 >(void *ptr)
Definition byte-swap.h:63
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition Array-base.h:529
void clear()
bool isvector() const
Size of the specified dimension.
Definition Array-base.h:677
int ndims() const
Size of the specified dimension.
Definition Array-base.h:701
const T * data() const
Size of the specified dimension.
Definition Array-base.h:687
T * rwdata()
Size of the specified dimension.
octave_idx_type numel() const
Number of elements in the array.
Definition Array-base.h:440
Definition Cell.h:41
bool all_integers(float &max_val, float &min_val) const
Definition fNDArray.cc:308
bool all_integers(double &max_val, double &min_val) const
Definition dNDArray.cc:351
bool too_large_for_float() const
Definition dNDArray.cc:387
octave_idx_type cols() const
Definition Sparse.h:351
octave_idx_type nzmax() const
Amount of storage for nonzero elements.
Definition Sparse.h:335
octave_idx_type * cidx()
Definition Sparse.h:595
T * data()
Definition Sparse.h:573
T * xdata()
Definition Sparse.h:575
octave_idx_type * ridx()
Definition Sparse.h:582
octave_idx_type nnz() const
Actual number of nonzero terms.
Definition Sparse.h:338
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:92
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition dim-vector.h:341
void resize(int n, int fill_value=0)
Definition dim-vector.h:278
octave_idx_type ndims() const
Number of dimensions.
Definition dim-vector.h:263
bool reconstruct_parents()
Definition ov-class.cc:1151
bool reconstruct_exemplar()
Definition ov-class.cc:1072
octave_map map_value() const
octave_value fcn_val()
octave_idx_type nfields() const
Definition oct-map.h:323
const_iterator end() const
Definition oct-map.h:298
string_vector keys() const
Definition oct-map.h:335
const Cell & contents(const_iterator p) const
Definition oct-map.h:310
octave_idx_type numel() const
Definition oct-map.h:368
void assign(const std::string &k, const Cell &val)
Definition oct-map.h:344
const_iterator begin() const
Definition oct-map.h:297
const octave_value & contents(const_iterator p) const
Definition oct-map.h:197
const_iterator end() const
Definition oct-map.h:185
const_iterator begin() const
Definition oct-map.h:184
octave_idx_type nfields() const
Definition oct-map.h:210
std::string key(const_iterator p) const
Definition oct-map.h:192
bool is_classdef_object() const
Definition ov.h:653
boolNDArray bool_array_value(bool warn=false) const
Definition ov.h:898
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition ov.h:907
std::string class_name() const
Definition ov.h:1360
bool is_inline_function() const
Definition ov.h:772
bool is_real_scalar() const
Definition ov.h:608
int32NDArray int32_array_value() const
Definition ov.h:963
uint16NDArray uint16_array_value() const
Definition ov.h:972
octave_classdef * classdef_object_value(bool silent=false) const
int16NDArray int16_array_value() const
Definition ov.h:960
Cell cell_value() const
int8NDArray int8_array_value() const
Definition ov.h:957
int ndims() const
Definition ov.h:549
octave_scalar_map scalar_map_value() const
bool is_string() const
Definition ov.h:635
bool is_complex_scalar() const
Definition ov.h:614
bool is_range() const
Definition ov.h:644
ComplexNDArray complex_array_value(bool frc_str_conv=false) const
Definition ov.h:882
bool is_single_type() const
Definition ov.h:696
bool is_defined() const
Definition ov.h:590
charNDArray char_array_value(bool frc_str_conv=false) const
Definition ov.h:904
bool isempty() const
Definition ov.h:599
bool is_uint8_type() const
Definition ov.h:716
uint64NDArray uint64_array_value() const
Definition ov.h:978
bool issparse() const
Definition ov.h:751
bool iscell() const
Definition ov.h:602
octave_map map_value() const
bool is_real_matrix() const
Definition ov.h:611
std::string string_value(bool force=false) const
Definition ov.h:981
bool iscomplex() const
Definition ov.h:739
octave_fcn_handle * fcn_handle_value(bool silent=false) const
int64NDArray int64_array_value() const
Definition ov.h:966
NDArray array_value(bool frc_str_conv=false) const
Definition ov.h:863
octave_idx_type length() const
octave_value convert_to_str(bool pad=false, bool force=false, char type='\'') const
Definition ov.h:1320
uint8NDArray uint8_array_value() const
Definition ov.h:969
std::string type_name() const
Definition ov.h:1358
FloatComplexNDArray float_complex_array_value(bool frc_str_conv=false) const
Definition ov.h:886
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition ov.h:866
bool isstruct() const
Definition ov.h:647
uint32NDArray uint32_array_value() const
Definition ov.h:975
bool is_complex_matrix() const
Definition ov.h:617
bool isobject() const
Definition ov.h:662
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition ov.h:911
bool islogical() const
Definition ov.h:733
dim_vector dims() const
Definition ov.h:539
ColumnVector real(const ComplexColumnVector &a)
ColumnVector imag(const ComplexColumnVector &a)
void read_int(std::istream &is, bool swap_bytes, T &val)
void read_doubles(std::istream &is, double *data, save_type type, octave_idx_type len, bool swap, octave::mach_info::float_format fmt)
Definition data-conv.cc:820
void read_floats(std::istream &is, float *data, save_type type, octave_idx_type len, bool swap, octave::mach_info::float_format fmt)
Definition data-conv.cc:884
save_type
Definition data-conv.h:85
@ LS_U_CHAR
Definition data-conv.h:86
@ LS_DOUBLE
Definition data-conv.h:93
@ LS_LONG
Definition data-conv.h:95
@ LS_U_LONG
Definition data-conv.h:94
@ LS_U_SHORT
Definition data-conv.h:87
@ LS_FLOAT
Definition data-conv.h:92
@ LS_SHORT
Definition data-conv.h:90
@ LS_CHAR
Definition data-conv.h:89
@ LS_INT
Definition data-conv.h:91
@ LS_U_INT
Definition data-conv.h:88
void warning_with_id(const char *id, const char *fmt,...)
Definition error.cc:1098
void error(const char *fmt,...)
Definition error.cc:1008
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition errwarn.cc:53
void warn_wrong_type_arg(const char *name, const octave_value &tc)
Definition errwarn.cc:373
bool too_large_for_float(double x)
Definition lo-utils.cc:56
#define INT8(l)
Definition ls-mat5.cc:91
#define PAD(l)
Definition ls-mat5.cc:90
#define READ_INTEGER_DATA(TYPE, swap, data, size, len, stream)
void write_mat5_integer_data(std::ostream &os, const T *m, int size, octave_idx_type nel)
Definition ls-mat5.cc:1852
bool save_mat5_binary_element(std::ostream &os, const octave_value &tc_in, const std::string &name, bool mark_global, bool mat7_format, bool save_as_floats, bool compressing)
Definition ls-mat5.cc:2379
#define MAT5_DO_WRITE(TYPE, data, count, stream)
Definition ls-mat5.cc:1656
int save_mat5_array_length(const double *val, octave_idx_type nel, bool save_as_floats)
Definition ls-mat5.cc:1961
#define OCTAVE_MAT5_INTEGER_READ(TYP)
Definition ls-mat5.cc:373
arrayclasstype
Definition ls-mat5.cc:101
@ MAT_FILE_INT64_CLASS
Definition ls-mat5.cc:115
@ MAT_FILE_UINT64_CLASS
Definition ls-mat5.cc:116
@ MAT_FILE_SINGLE_CLASS
Definition ls-mat5.cc:108
@ MAT_FILE_CELL_CLASS
Definition ls-mat5.cc:102
@ MAT_FILE_INT32_CLASS
Definition ls-mat5.cc:113
@ MAT_FILE_INT16_CLASS
Definition ls-mat5.cc:111
@ MAT_FILE_DOUBLE_CLASS
Definition ls-mat5.cc:107
@ MAT_FILE_OBJECT_CLASS
Definition ls-mat5.cc:104
@ MAT_FILE_WORKSPACE_CLASS
Definition ls-mat5.cc:118
@ MAT_FILE_SPARSE_CLASS
Definition ls-mat5.cc:106
@ MAT_FILE_FUNCTION_CLASS
Definition ls-mat5.cc:117
@ MAT_FILE_INT8_CLASS
Definition ls-mat5.cc:109
@ MAT_FILE_UINT32_CLASS
Definition ls-mat5.cc:114
@ MAT_FILE_UINT8_CLASS
Definition ls-mat5.cc:110
@ MAT_FILE_CHAR_CLASS
Definition ls-mat5.cc:105
@ MAT_FILE_STRUCT_CLASS
Definition ls-mat5.cc:103
@ MAT_FILE_UINT16_CLASS
Definition ls-mat5.cc:112
int save_mat5_element_length(const octave_value &tc_in, const std::string &name, bool save_as_floats, bool mat7_format)
Definition ls-mat5.cc:2151
int read_mat5_binary_file_header(std::istream &is, bool &swap, bool quiet, const std::string &filename)
Definition ls-mat5.cc:1548
#define INT_LEN(nel, size)
std::string read_mat5_binary_element(std::istream &is, const std::string &filename, bool swap, bool &global, octave_value &tc)
Definition ls-mat5.cc:478
#define READ_PAD(is_small_data_element, l)
Definition ls-mat5.cc:89
void read_mat5_integer_data(std::istream &is, T *m, octave_idx_type count, bool swap, mat5_data_type type)
Definition ls-mat5.cc:258
mat5_data_type
Definition ls-mat5.h:37
@ miUTF16
Definition ls-mat5.h:54
@ miINT64
Definition ls-mat5.h:49
@ miDOUBLE
Definition ls-mat5.h:46
@ miINT16
Definition ls-mat5.h:40
@ miINT32
Definition ls-mat5.h:42
@ miUINT16
Definition ls-mat5.h:41
@ miMATRIX
Definition ls-mat5.h:51
@ miINT8
Definition ls-mat5.h:38
@ miUTF8
Definition ls-mat5.h:53
@ miUINT32
Definition ls-mat5.h:43
@ miRESERVE1
Definition ls-mat5.h:45
@ miRESERVE2
Definition ls-mat5.h:47
@ miUINT64
Definition ls-mat5.h:50
@ miUTF32
Definition ls-mat5.h:55
@ miRESERVE3
Definition ls-mat5.h:48
@ miUINT8
Definition ls-mat5.h:39
@ miSINGLE
Definition ls-mat5.h:44
@ miCOMPRESSED
Definition ls-mat5.h:52
std::complex< double > Complex
Definition oct-cmplx.h:33
std::complex< float > FloatComplex
Definition oct-cmplx.h:34
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition oct-locbuf.h:44
void free(void *)
uint8_t * octave_u32_to_u8_wrapper(const uint32_t *src, size_t src_len, uint8_t *result_buf, size_t *lengthp)
uint16_t * octave_u8_to_u16_wrapper(const uint8_t *src, size_t src_len, uint16_t *result_buf, size_t *lengthp)
uint8_t * octave_u16_to_u8_wrapper(const uint16_t *src, size_t src_len, uint8_t *result_buf, size_t *lengthp)
F77_RET_T len
Definition xerbla.cc:61