GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ls-mat5.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-2022 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 "lo-mappers.h"
47#include "mach-info.h"
48#include "oct-env.h"
49#include "oct-locbuf.h"
50#include "oct-time.h"
51#include "quit.h"
52#include "str-vec.h"
53#include "unistr-wrappers.h"
54
55#include "Cell.h"
56#include "defaults.h"
57#include "defun.h"
58#include "error.h"
59#include "errwarn.h"
60#include "interpreter-private.h"
61#include "interpreter.h"
62#include "load-path.h"
63#include "load-save.h"
64#include "ls-mat5.h"
65#include "ls-utils.h"
66#include "oct-map.h"
67#include "ov-cell.h"
68#include "ov-class.h"
69#include "ov.h"
70#include "ovl.h"
71#include "pager.h"
72#include "parse.h"
73#include "pt-eval.h"
74#include "stack-frame.h"
75#include "sysdep.h"
76#include "unwind-prot.h"
77#include "utils.h"
78#include "variables.h"
79#include "version.h"
80
81#if defined (HAVE_ZLIB)
82# include <zlib.h>
83#endif
84
85#define READ_PAD(is_small_data_element, l) ((is_small_data_element) ? 4 : (((l)+7)/8)*8)
86#define PAD(l) (((l) > 0 && (l) <= 4) ? 4 : (((l)+7)/8)*8)
87#define INT8(l) ((l) == miINT8 || (l) == miUINT8 || (l) == miUTF8)
88
89
90// The subsystem data block
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,
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,
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.fortran_vec (), 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.fortran_vec (), 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
500
501 // MAT files always use IEEE floating point
503 if ((flt_fmt_is_big_endian && ! swap) || (! flt_fmt_is_big_endian && swap))
505 else
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
516 = octave::__get_interpreter__ ("read_mat5_binary_element");
517
518 if (type == miCOMPRESSED)
519 {
520#if defined (HAVE_ZLIB)
521 // If C++ allowed us direct access to the file descriptor of an
522 // ifstream in a uniform way, the code below could be vastly
523 // simplified, and additional copies of the data in memory
524 // wouldn't be needed.
525
526 OCTAVE_LOCAL_BUFFER (char, inbuf, element_length);
527 is.read (inbuf, element_length);
528
529 // We uncompress the first 8 bytes of the header to get the buffer length
530 // This will fail with an error Z_MEM_ERROR
531 uLongf destLen = 8;
532 uLongf elt_len = element_length;
533 OCTAVE_LOCAL_BUFFER (unsigned int, tmp, 2);
534 if (uncompress2 (reinterpret_cast<Bytef *> (tmp), &destLen,
535 reinterpret_cast<Bytef *> (inbuf), &elt_len)
536 == Z_MEM_ERROR)
537 error ("load: error probing size of compressed data element");
538
539 // Why should I have to initialize outbuf as I'll just overwrite!!
540 if (swap)
541 swap_bytes<4> (tmp, 2);
542
543 destLen = tmp[1] + 8;
544 std::string outbuf (destLen, ' ');
545
546 // FIXME: find a way to avoid casting away const here!
547
548 elt_len = element_length;
549 int err = uncompress2 (reinterpret_cast<Bytef *>
550 (const_cast<char *> (outbuf.c_str ())),
551 &destLen, reinterpret_cast<Bytef *> (inbuf),
552 &elt_len);
553
554 // Ignore buffer error if we have consumed all the input buffer
555 // and uncompressing the data generated as many bytes of output as
556 // we were expecting given the data element size that was stored
557 // in the Matlab data element header.
558 if (err == Z_BUF_ERROR && destLen == tmp[1] + 8
559 && elt_len == static_cast<uLongf> (element_length))
560 err = Z_OK;
561
562 if (err != Z_OK)
563 {
564 std::string msg;
565 switch (err)
566 {
567 case Z_STREAM_END:
568 msg = "stream end";
569 break;
570
571 case Z_NEED_DICT:
572 msg = "need dict";
573 break;
574
575 case Z_ERRNO:
576 msg = "errno case";
577 break;
578
579 case Z_STREAM_ERROR:
580 msg = "stream error";
581 break;
582
583 case Z_DATA_ERROR:
584 msg = "data error";
585 break;
586
587 case Z_MEM_ERROR:
588 msg = "mem error";
589 break;
590
591 case Z_BUF_ERROR:
592 msg = "buf error";
593 break;
594
595 case Z_VERSION_ERROR:
596 msg = "version error";
597 break;
598 }
599
600 error ("load: error uncompressing data element (%s from zlib)",
601 msg.c_str ());
602 }
603 else
604 {
605 std::istringstream gz_is (outbuf);
606 retval = read_mat5_binary_element (gz_is, filename,
607 swap, global, tc);
608 }
609
610 return retval;
611
612#else
613 err_disabled_feature ("load", "compressed data elements (zlib)");
614#endif
615 }
616
617 std::streampos pos;
618
619 if (type != miMATRIX)
620 {
621 pos = is.tellg ();
622 error ("load: invalid element type = %d", type);
623 }
624
625 if (element_length == 0)
626 {
627 tc = Matrix ();
628 return retval;
629 }
630
631 pos = is.tellg ();
632
633 // array flags subelement
634 int32_t len;
635 if (read_mat5_tag (is, swap, type, len, is_small_data_element)
636 || type != miUINT32 || len != 8 || is_small_data_element)
637 error ("load: invalid array flags subelement");
638
639 int32_t flags;
640 read_int (is, swap, flags);
641
642 imag = (flags & 0x0800) != 0; // has an imaginary part?
643
644 global = (flags & 0x0400) != 0; // global variable?
645
646 logicalvar = (flags & 0x0200) != 0; // boolean ?
647
648 arrayclass = static_cast<arrayclasstype> (flags & 0xff);
649
650 int32_t tmp_nzmax;
651 read_int (is, swap, tmp_nzmax); // max number of nonzero in sparse
652 nzmax = tmp_nzmax;
653
654 // dimensions array subelement
655 if (arrayclass != MAT_FILE_WORKSPACE_CLASS)
656 {
657 int32_t dim_len;
658
659 if (read_mat5_tag (is, swap, type, dim_len, is_small_data_element)
660 || type != miINT32)
661 error ("load: invalid dimensions array subelement");
662
663 int ndims = dim_len / 4;
664 if (ndims == 1)
665 {
666 // R and Python can create a 1-D object which is really an Nx1 object
667 dims.resize (2);
668 dims(1) = 1;
669 }
670 else
671 dims.resize (ndims);
672
673 for (int i = 0; i < ndims; i++)
674 {
675 int32_t n;
676 read_int (is, swap, n);
677 dims(i) = n;
678 }
679
680 std::streampos tmp_pos = is.tellg ();
681 is.seekg (tmp_pos + static_cast<std::streamoff>
682 (READ_PAD (is_small_data_element, dim_len) - dim_len));
683 }
684 else
685 {
686 // Why did mathworks decide to not have dims for a workspace!!!
687 dims.resize (2);
688 dims(0) = 1;
689 dims(1) = 1;
690 }
691
692 if (read_mat5_tag (is, swap, type, len, is_small_data_element)
693 || ! INT8(type))
694 error ("load: invalid array name subelement");
695
696 {
697 OCTAVE_LOCAL_BUFFER (char, name, len+1);
698
699 // Structure field subelements have zero-length array name subelements.
700
701 std::streampos tmp_pos = is.tellg ();
702
703 if (len)
704 {
705 if (! is.read (name, len))
706 goto data_read_error;
707
708 is.seekg (tmp_pos + static_cast<std::streamoff>
709 (READ_PAD (is_small_data_element, len)));
710 }
711
712 name[len] = '\0';
713 retval = name;
714 }
715
716 switch (arrayclass)
717 {
719 {
720 Cell cell_array (dims);
721
722 octave_idx_type n = cell_array.numel ();
723
724 for (octave_idx_type i = 0; i < n; i++)
725 {
726 octave_value tc2;
727
728 std::string nm
729 = read_mat5_binary_element (is, filename, swap, global, tc2);
730
731 if (! is)
732 error ("load: reading cell data for '%s'", nm.c_str ());
733
734 cell_array(i) = tc2;
735 }
736
737 tc = cell_array;
738 }
739 break;
740
742 {
743 octave_idx_type nr = dims(0);
744 octave_idx_type nc = dims(1);
745 SparseMatrix sm;
747 octave_idx_type *ridx;
748 octave_idx_type *cidx;
749 double *data;
750
751 // Setup return value
752 if (imag)
753 {
754 scm = SparseComplexMatrix (nr, nc, nzmax);
755 ridx = scm.ridx ();
756 cidx = scm.cidx ();
757 data = nullptr;
758 }
759 else
760 {
761 sm = SparseMatrix (nr, nc, nzmax);
762 ridx = sm.ridx ();
763 cidx = sm.cidx ();
764 data = sm.data ();
765 }
766
767 // row indices
768 std::streampos tmp_pos;
769
770 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
771 error ("load: reading sparse row data for '%s'", retval.c_str ());
772
773 tmp_pos = is.tellg ();
774
775 read_mat5_integer_data (is, ridx, nzmax, swap,
776 static_cast<enum mat5_data_type> (type));
777
778 if (! is)
779 error ("load: reading sparse row data for '%s'", retval.c_str ());
780
781 is.seekg (tmp_pos + static_cast<std::streamoff>
782 (READ_PAD (is_small_data_element, len)));
783
784 // col indices
785 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
786 error ("load: reading sparse column data for '%s'",
787 retval.c_str ());
788
789 tmp_pos = is.tellg ();
790
791 read_mat5_integer_data (is, cidx, nc + 1, swap,
792 static_cast<enum mat5_data_type> (type));
793
794 if (! is)
795 error ("load: reading sparse column data for '%s'",
796 retval.c_str ());
797
798 is.seekg (tmp_pos + static_cast<std::streamoff>
799 (READ_PAD (is_small_data_element, len)));
800
801 // real data subelement
802 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
803 error ("load: reading sparse matrix data for '%s'",
804 retval.c_str ());
805
806 octave_idx_type nnz = cidx[nc];
807 NDArray re;
808 if (imag)
809 {
810 re = NDArray (dim_vector (nnz, 1));
811 data = re.fortran_vec ();
812 }
813
814 tmp_pos = is.tellg ();
815 read_mat5_binary_data (is, data, nnz, swap,
816 static_cast<enum mat5_data_type> (type),
817 flt_fmt);
818
819 if (! is)
820 error ("load: reading sparse matrix data for '%s'",
821 retval.c_str ());
822
823 is.seekg (tmp_pos + static_cast<std::streamoff>
824 (READ_PAD (is_small_data_element, len)));
825
826 // imaginary data subelement
827 if (imag)
828 {
829 NDArray im (dim_vector (static_cast<int> (nnz), 1));
830
831 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
832 error ("load: reading sparse matrix data for '%s'",
833 retval.c_str ());
834
835 read_mat5_binary_data (is, im.fortran_vec (), nnz, swap,
836 static_cast<enum mat5_data_type> (type),
837 flt_fmt);
838
839 if (! is)
840 error ("load: reading imaginary sparse matrix data for '%s'",
841 retval.c_str ());
842
843 for (octave_idx_type i = 0; i < nnz; i++)
844 scm.xdata (i) = Complex (re (i), im (i));
845
846 tc = scm;
847 }
848 else
849 tc = sm;
850 }
851 break;
852
854 {
855 octave_value tc2;
856 std::string nm
857 = read_mat5_binary_element (is, filename, swap, global, tc2);
858
859 if (! is)
860 goto data_read_error;
861
862 // Octave can handle both "/" and "\" as a directory separator
863 // and so can ignore the separator field of m0. I think the
864 // sentinel field is also save to ignore.
867 = m0.contents ("function_handle").scalar_map_value ();
868 std::string ftype = m1.contents ("type").string_value ();
869 std::string fname = m1.contents ("function").string_value ();
870 std::string fpath = m1.contents ("file").string_value ();
871
872 if (ftype == "simple" || ftype == "scopedfunction")
873 {
874 if (fpath.empty ())
875 {
876 octave::tree_evaluator& tw = interp.get_evaluator ();
877
878 // We have a builtin function
879 // XXX FCN_HANDLE: SIMPLE/SCOPED
880 tc = tw.make_fcn_handle (fname);
881 }
882 else
883 {
884 std::string mroot = m0.contents ("matlabroot").string_value ();
885
886 if ((fpath.length () >= mroot.length ())
887 && fpath.substr (0, mroot.length ()) == mroot
889 {
890 // If fpath starts with matlabroot, and matlabroot
891 // doesn't equal __octave_config_info__ ("exec_prefix")
892 // then the function points to a version of Octave
893 // or Matlab other than the running version. In that
894 // case we replace with the same function in the
895 // running version of Octave?
896
897 // First check if just replacing matlabroot is enough
898 std::string str
900 + fpath.substr (mroot.length ()));
901 octave::sys::file_stat fs (str);
902
903 if (fs.exists ())
904 {
905 std::size_t xpos
906 = str.find_last_of (octave::sys::file_ops::dir_sep_chars ());
907
908 std::string dir_name = str.substr (0, xpos);
909
910 octave_value ov_fcn
911 = octave::load_fcn_from_file (str, dir_name,
912 "", "", fname);
913
914 if (ov_fcn.is_defined ())
915 // XXX FCN_HANDLE: SIMPLE/SCOPED
916 tc = octave_value (new octave_fcn_handle (ov_fcn, fname));
917 }
918 else
919 {
920 // Next just search for it anywhere in the system path
921 std::list<std::string> names;
922 names.push_back (fname + ".oct");
923 names.push_back (fname + ".mex");
924 names.push_back (fname + ".m");
925
926 octave::load_path& lp = interp.get_load_path ();
927
928 octave::directory_path p (lp.system_path ());
929
931
932 std::size_t xpos
933 = str.find_last_of (octave::sys::file_ops::dir_sep_chars ());
934
935 std::string dir_name = str.substr (0, xpos);
936
937 octave_value ov_fcn
938 = octave::load_fcn_from_file (str, dir_name,
939 "", "", fname);
940
941 if (ov_fcn.is_defined ())
942 // XXX FCN_HANDLE: SIMPLE/SCOPED
943 tc = octave_value (new octave_fcn_handle (ov_fcn, fname));
944 else
945 {
946 warning_with_id ("Octave:load:file-not-found",
947 "load: can't find the file %s",
948 fpath.c_str ());
949 goto skip_ahead;
950 }
951 }
952 }
953 else
954 {
955 std::size_t xpos
956 = fpath.find_last_of (octave::sys::file_ops::dir_sep_chars ());
957
958 std::string dir_name = fpath.substr (0, xpos);
959
960 octave_value ov_fcn
961 = octave::load_fcn_from_file (fpath, dir_name,
962 "", "", fname);
963
964 if (ov_fcn.is_defined ())
965 // XXX FCN_HANDLE: SIMPLE/SCOPED
966 tc = octave_value (new octave_fcn_handle (ov_fcn, fname));
967 else
968 {
969 warning_with_id ("Octave:load:file-not-found",
970 "load: can't find the file %s",
971 fpath.c_str ());
972 goto skip_ahead;
973 }
974 }
975 }
976 }
977 else if (ftype == "nested")
978 {
979 warning_with_id ("Octave:load:unsupported-type",
980 "load: can't load nested function");
981 goto skip_ahead;
982 }
983 else if (ftype == "anonymous")
984 {
986 = m1.contents ("workspace").scalar_map_value ();
987 uint32NDArray MCOS = m2.contents ("MCOS").uint32_array_value ();
989 = static_cast<octave_idx_type> (MCOS(4).double_value ());
991 m2 = m2.contents ("MCOS").scalar_map_value ();
992 tc2 = m2.contents ("MCOS").cell_value ()(1 + off).cell_value ()(1);
993
995
996 if (! tc2.isempty ())
997 {
998 m2 = tc2.scalar_map_value ();
999
1000 if (m2.nfields () > 0)
1001 {
1002 octave_value tmp;
1003
1004 for (auto p0 = m2.begin (); p0 != m2.end (); p0++)
1005 {
1006 std::string key = m2.key (p0);
1007 octave_value val = m2.contents (p0);
1008
1009 local_vars[key] = val;
1010 }
1011 }
1012 }
1013
1014 // Set up temporary scope to use for evaluating the text
1015 // that defines the anonymous function so that we don't
1016 // pick up values of random variables that might be in the
1017 // current scope.
1018
1019 octave::tree_evaluator& tw = interp.get_evaluator ();
1020 tw.push_dummy_scope ("read_mat5_binary_element");
1021
1022 octave::unwind_action act ([&tw] () { tw.pop_scope (); });
1023
1024 // FIXME: If evaluation of the string gives us an anonymous
1025 // function handle object, then why extract the function and
1026 // create a new anonymous function object? Why not just
1027 // attach the workspace values to the object returned by
1028 // eval_string? This code is also is duplicated in
1029 // anon_fcn_handle::parse_anon_fcn_handle.
1030
1031 int parse_status;
1032 octave_value anon_fcn_handle
1033 = interp.eval_string (fname.substr (4), true, parse_status);
1034
1035 if (parse_status != 0)
1036 error ("load: failed to load anonymous function handle");
1037
1038 octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
1039
1040 if (! fh)
1041 error ("load: failed to load anonymous function handle");
1042
1043 // XXX FCN_HANDLE: ANONYMOUS
1044 tc = octave_value (new octave_fcn_handle (fh->fcn_val (), local_vars));
1045 }
1046 else
1047 error ("load: invalid function handle type");
1048 }
1049 break;
1050
1052 {
1053 octave_map m (dim_vector (1, 1));
1054 int n_fields = 2;
1055 string_vector field (n_fields);
1056
1057 for (int i = 0; i < n_fields; i++)
1058 {
1059 int32_t fn_type;
1060 int32_t fn_len;
1061 if (read_mat5_tag (is, swap, fn_type, fn_len, is_small_data_element)
1062 || ! INT8(fn_type))
1063 error ("load: invalid field name subelement");
1064
1065 OCTAVE_LOCAL_BUFFER (char, elname, fn_len + 1);
1066
1067 std::streampos tmp_pos = is.tellg ();
1068
1069 if (fn_len)
1070 {
1071 if (! is.read (elname, fn_len))
1072 goto data_read_error;
1073
1074 is.seekg (tmp_pos + static_cast<std::streamoff>
1075 (READ_PAD (is_small_data_element, fn_len)));
1076 }
1077
1078 elname[fn_len] = '\0';
1079
1080 field(i) = elname;
1081 }
1082
1083 std::vector<Cell> elt (n_fields);
1084
1085 for (octave_idx_type i = 0; i < n_fields; i++)
1086 elt[i] = Cell (dims);
1087
1088 octave_idx_type n = dims.numel ();
1089
1090 // fields subelements
1091 for (octave_idx_type j = 0; j < n; j++)
1092 {
1093 for (octave_idx_type i = 0; i < n_fields; i++)
1094 {
1095 if (field(i) == "MCOS")
1096 {
1097 octave_value fieldtc;
1098 read_mat5_binary_element (is, filename, swap, global,
1099 fieldtc);
1100 if (! is)
1101 goto data_read_error;
1102
1103 elt[i](j) = fieldtc;
1104 }
1105 else
1106 elt[i](j) = octave_value ();
1107 }
1108 }
1109
1110 for (octave_idx_type i = 0; i < n_fields; i++)
1111 m.assign (field (i), elt[i]);
1112 tc = m;
1113 }
1114 break;
1115
1117 {
1118 isclass = true;
1119
1120 if (read_mat5_tag (is, swap, type, len, is_small_data_element)
1121 || ! INT8(type))
1122 error ("load: invalid class name");
1123
1124 {
1125 OCTAVE_LOCAL_BUFFER (char, name, len+1);
1126
1127 std::streampos tmp_pos = is.tellg ();
1128
1129 if (len)
1130 {
1131 if (! is.read (name, len))
1132 goto data_read_error;
1133
1134 is.seekg (tmp_pos + static_cast<std::streamoff>
1135 (READ_PAD (is_small_data_element, len)));
1136 }
1137
1138 name[len] = '\0';
1139 classname = name;
1140 }
1141 }
1142 // Fall-through
1143
1145 {
1146 octave_map m (dims);
1147 int32_t fn_type;
1148 int32_t fn_len;
1149 int32_t field_name_length;
1150
1151 // field name length subelement -- actually the maximum length
1152 // of a field name. The Matlab docs promise this will always
1153 // be 32. We read and use the actual value, on the theory
1154 // that eventually someone will recognize that's a waste of space.
1155 if (read_mat5_tag (is, swap, fn_type, fn_len, is_small_data_element)
1156 || fn_type != miINT32)
1157 error ("load: invalid field name length subelement");
1158
1159 if (! is.read (reinterpret_cast<char *> (&field_name_length), fn_len))
1160 goto data_read_error;
1161
1162 if (swap)
1163 swap_bytes<4> (&field_name_length);
1164
1165 // field name subelement. The length of this subelement tells
1166 // us how many fields there are.
1167 if (read_mat5_tag (is, swap, fn_type, fn_len, is_small_data_element)
1168 || ! INT8(fn_type))
1169 error ("load: invalid field name subelement");
1170
1171 octave_idx_type n_fields = fn_len/field_name_length;
1172
1173 if (n_fields > 0)
1174 {
1175 fn_len = READ_PAD (is_small_data_element, fn_len);
1176
1177 OCTAVE_LOCAL_BUFFER (char, elname, fn_len);
1178
1179 if (! is.read (elname, fn_len))
1180 goto data_read_error;
1181
1182 std::vector<Cell> elt (n_fields);
1183
1184 for (octave_idx_type i = 0; i < n_fields; i++)
1185 elt[i] = Cell (dims);
1186
1187 octave_idx_type n = dims.numel ();
1188
1189 // fields subelements
1190 for (octave_idx_type j = 0; j < n; j++)
1191 {
1192 for (octave_idx_type i = 0; i < n_fields; i++)
1193 {
1194 octave_value fieldtc;
1195 read_mat5_binary_element (is, filename, swap, global,
1196 fieldtc);
1197 elt[i](j) = fieldtc;
1198 }
1199 }
1200
1201 for (octave_idx_type i = 0; i < n_fields; i++)
1202 {
1203 const char *key = elname + i*field_name_length;
1204
1205 m.assign (key, elt[i]);
1206 }
1207 }
1208
1209 if (isclass)
1210 {
1211 octave::cdef_manager& cdm = interp.get_cdef_manager ();
1212
1213 if (cdm.find_class (classname, false, true).ok ())
1214 {
1215 tc = m;
1216 warning_with_id ("Octave:load:classdef-to-struct",
1217 "load: classdef element has been converted to a struct");
1218 }
1219 else
1220 {
1221 octave_class *cls
1222 = new octave_class (m, classname,
1223 std::list<std::string> ());
1224
1225 if (cls->reconstruct_exemplar ())
1226 {
1227
1228 if (! cls->reconstruct_parents ())
1229 warning_with_id ("Octave:load:classdef-object-inheritance",
1230 "load: unable to reconstruct object inheritance");
1231
1232 tc = cls;
1233
1234 octave::load_path& lp = interp.get_load_path ();
1235
1236 if (lp.find_method (classname, "loadobj") != "")
1237 {
1238 try
1239 {
1240 octave_value_list tmp = octave::feval ("loadobj", tc, 1);
1241
1242 tc = tmp(0);
1243 }
1244 catch (const octave::execution_exception&)
1245 {
1246 goto data_read_error;
1247 }
1248 }
1249 }
1250 else
1251 {
1252 tc = m;
1253 warning_with_id ("Octave:load:classdef-to-struct",
1254 "load: element has been converted to a structure");
1255 }
1256 }
1257 }
1258 else
1259 tc = m;
1260 }
1261 break;
1262
1265 break;
1266
1268 {
1270
1271 // Logical variables can either be MAT_FILE_UINT8_CLASS or
1272 // MAT_FILE_DOUBLE_CLASS, so check if we have a logical
1273 // variable and convert it.
1274
1275 if (logicalvar)
1276 {
1278 octave_idx_type nel = in.numel ();
1279 boolNDArray out (dims);
1280
1281 for (octave_idx_type i = 0; i < nel; i++)
1282 out(i) = in(i).bool_value ();
1283
1284 tc = out;
1285 }
1286 }
1287 break;
1288
1291 break;
1292
1295 break;
1296
1299 break;
1300
1303 break;
1304
1307 break;
1308
1311 break;
1312
1314 {
1315 FloatNDArray re (dims);
1316
1317 // real data subelement
1318
1319 std::streampos tmp_pos;
1320
1321 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
1322 error ("load: reading matrix data for '%s'", retval.c_str ());
1323
1324 octave_idx_type n = re.numel ();
1325 tmp_pos = is.tellg ();
1326 read_mat5_binary_data (is, re.fortran_vec (), n, swap,
1327 static_cast<enum mat5_data_type> (type),
1328 flt_fmt);
1329
1330 if (! is)
1331 error ("load: reading matrix data for '%s'", retval.c_str ());
1332
1333 is.seekg (tmp_pos + static_cast<std::streamoff>
1334 (READ_PAD (is_small_data_element, len)));
1335
1336 if (imag)
1337 {
1338 // imaginary data subelement
1339
1340 FloatNDArray im (dims);
1341
1342 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
1343 error ("load: reading matrix data for '%s'", retval.c_str ());
1344
1345 n = im.numel ();
1346 read_mat5_binary_data (is, im.fortran_vec (), n, swap,
1347 static_cast<enum mat5_data_type> (type),
1348 flt_fmt);
1349
1350 if (! is)
1351 error ("load: reading imaginary matrix data for '%s'",
1352 retval.c_str ());
1353
1354 FloatComplexNDArray ctmp (dims);
1355
1356 for (octave_idx_type i = 0; i < n; i++)
1357 ctmp(i) = FloatComplex (re(i), im(i));
1358
1359 tc = ctmp;
1360 }
1361 else
1362 tc = re;
1363 }
1364 break;
1365
1367 // handle as a numerical array to start with
1368
1370 default:
1371 {
1372 NDArray re (dims);
1373
1374 // real data subelement
1375
1376 std::streampos tmp_pos;
1377
1378 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
1379 error ("load: reading matrix data for '%s'", retval.c_str ());
1380
1381 octave_idx_type n = re.numel ();
1382 tmp_pos = is.tellg ();
1383 read_mat5_binary_data (is, re.fortran_vec (), n, swap,
1384 static_cast<enum mat5_data_type> (type),
1385 flt_fmt);
1386
1387 if (! is)
1388 error ("load: reading matrix data for '%s'", retval.c_str ());
1389
1390 is.seekg (tmp_pos + static_cast<std::streamoff>
1391 (READ_PAD (is_small_data_element, len)));
1392
1393 if (logicalvar)
1394 {
1395 // Logical variables can either be MAT_FILE_UINT8_CLASS or
1396 // MAT_FILE_DOUBLE_CLASS, so check if we have a logical
1397 // variable and convert it.
1398
1399 boolNDArray out (dims);
1400
1401 for (octave_idx_type i = 0; i < n; i++)
1402 out (i) = static_cast<bool> (re (i));
1403
1404 tc = out;
1405 }
1406 else if (imag)
1407 {
1408 // imaginary data subelement
1409
1410 NDArray im (dims);
1411
1412 if (read_mat5_tag (is, swap, type, len, is_small_data_element))
1413 error ("load: reading matrix data for '%s'", retval.c_str ());
1414
1415 n = im.numel ();
1416 read_mat5_binary_data (is, im.fortran_vec (), n, swap,
1417 static_cast<enum mat5_data_type> (type),
1418 flt_fmt);
1419
1420 if (! is)
1421 error ("load: reading imaginary matrix data for '%s'",
1422 retval.c_str ());
1423
1424 ComplexNDArray ctmp (dims);
1425
1426 for (octave_idx_type i = 0; i < n; i++)
1427 ctmp(i) = Complex (re(i), im(i));
1428
1429 tc = ctmp;
1430 }
1431 else if (arrayclass == MAT_FILE_CHAR_CLASS)
1432 {
1433 bool converted = false;
1434 if (re.isvector () && (type == miUTF16 || type == miUINT16))
1435 {
1436 uint16NDArray u16 = re;
1437 const uint16_t *u16_str
1438 = reinterpret_cast<const uint16_t *> (u16.data ());
1439
1440 // Convert to UTF-8.
1441 std::size_t n8;
1442 uint8_t *u8_str = octave_u16_to_u8_wrapper (u16_str,
1443 u16.numel (),
1444 nullptr, &n8);
1445 if (u8_str)
1446 {
1447 // FIXME: Is there a better way to construct a charMatrix
1448 // from a non zero terminated buffer?
1449 tc = charMatrix (std::string (reinterpret_cast<char *> (u8_str), n8));
1450 free (u8_str);
1451 converted = true;
1452 }
1453 }
1454 else if (re.isvector () && (type == miUTF32 || type == miUINT32))
1455 {
1456 uint32NDArray u32 = re;
1457 const uint32_t *u32_str
1458 = reinterpret_cast<const uint32_t *> (u32.data ());
1459
1460 // Convert to UTF-8.
1461 std::size_t n8;
1462 uint8_t *u8_str = octave_u32_to_u8_wrapper (u32_str,
1463 u32.numel (),
1464 nullptr, &n8);
1465 if (u8_str)
1466 {
1467 // FIXME: Is there a better way to construct a charMatrix
1468 // from a non zero terminated buffer?
1469 tc = charMatrix (std::string (reinterpret_cast<char *> (u8_str), n8));
1470 free (u8_str);
1471 converted = true;
1472 }
1473 }
1474 else if (type == miUTF8 || type == miUINT8)
1475 {
1476 // Octave's internal encoding is UTF-8. So we should be
1477 // able to use this natively.
1478 tc = re;
1479 tc = tc.convert_to_str (false, true, '\'');
1480 converted = true;
1481 }
1482
1483 if (! converted)
1484 {
1485 // Fall back to manually replacing non-ASCII
1486 // characters by "?".
1487 bool found_big_char = false;
1488 for (octave_idx_type i = 0; i < n; i++)
1489 {
1490 if (re(i) > 127)
1491 {
1492 re(i) = '?';
1493 found_big_char = true;
1494 }
1495 }
1496
1497 if (found_big_char)
1498 warning_with_id ("Octave:load:unsupported-utf-char",
1499 "load: failed to convert from input to UTF-8; "
1500 "replacing non-ASCII characters with '?'");
1501
1502 tc = re;
1503 tc = tc.convert_to_str (false, true, '\'');
1504 }
1505
1506 }
1507 else
1508 tc = re;
1509 }
1510 }
1511
1512 is.seekg (pos + static_cast<std::streamoff> (element_length));
1513
1514 if (is.eof ())
1515 is.clear ();
1516
1517 return retval;
1518
1519// FIXME: With short-circuiting error(), no need for goto in code
1520data_read_error:
1521 error ("load: trouble reading binary file '%s'", filename.c_str ());
1522
1523skip_ahead:
1524 warning_with_id ("Octave:load:skip-unsupported-element",
1525 "load: skipping over '%s'", retval.c_str ());
1526 is.seekg (pos + static_cast<std::streamoff> (element_length));
1527 return read_mat5_binary_element (is, filename, swap, global, tc);
1528}
1529
1530int
1531read_mat5_binary_file_header (std::istream& is, bool& swap, bool quiet,
1532 const std::string& filename)
1533{
1534 int16_t version = 0;
1535 int16_t magic = 0;
1536 uint64_t subsys_offset;
1537
1538 is.seekg (116, std::ios::beg);
1539 is.read (reinterpret_cast<char *> (&subsys_offset), 8);
1540
1541 is.seekg (124, std::ios::beg);
1542 is.read (reinterpret_cast<char *> (&version), 2);
1543 is.read (reinterpret_cast<char *> (&magic), 2);
1544
1545 if (magic == 0x4d49)
1546 swap = false;
1547 else if (magic == 0x494d)
1548 swap = true;
1549 else
1550 {
1551 if (! quiet)
1552 error ("load: can't read binary file");
1553
1554 return -1;
1555 }
1556
1557 if (! swap) // version number is inverse swapped!
1558 version = ((version >> 8) & 0xff) + ((version & 0xff) << 8);
1559
1560 if (version != 1 && ! quiet)
1561 warning_with_id ("Octave:load:unsupported-version",
1562 "load: found version %d binary MAT file, but only prepared for version 1",
1563 version);
1564
1565 if (swap)
1566 swap_bytes<8> (&subsys_offset, 1);
1567
1568 if (subsys_offset != 0x2020202020202020ULL && subsys_offset != 0ULL)
1569 {
1570 // Read the subsystem data block
1571 is.seekg (subsys_offset, std::ios::beg);
1572
1573 octave_value tc;
1574 bool global;
1575 read_mat5_binary_element (is, filename, swap, global, tc);
1576
1577 if (! is)
1578 return -1;
1579
1580 if (tc.is_uint8_type ())
1581 {
1582 const uint8NDArray itmp = tc.uint8_array_value ();
1583 octave_idx_type ilen = itmp.numel ();
1584
1585 // Why should I have to initialize outbuf as just overwrite
1586 std::string outbuf (ilen - 7, ' ');
1587
1588 // FIXME: find a way to avoid casting away const here
1589 char *ctmp = const_cast<char *> (outbuf.c_str ());
1590 for (octave_idx_type j = 8; j < ilen; j++)
1591 ctmp[j-8] = itmp(j).char_value ();
1592
1593 std::istringstream fh_ws (outbuf);
1594
1595 read_mat5_binary_element (fh_ws, filename, swap, global, subsys_ov);
1596
1597 if (! is)
1598 return -1;
1599 }
1600 else
1601 return -1;
1602
1603 // Reposition to just after the header
1604 is.seekg (128, std::ios::beg);
1605 }
1606
1607 return 0;
1608}
1609
1610static int
1611write_mat5_tag (std::ostream& is, int type, octave_idx_type bytes)
1612{
1613 int32_t temp;
1614
1615 if (bytes > 0 && bytes <= 4)
1616 temp = (bytes << 16) + type;
1617 else
1618 {
1619 temp = type;
1620 if (! is.write (reinterpret_cast<char *> (&temp), 4))
1621 return 1;
1622 temp = bytes;
1623 }
1624
1625 if (! is.write (reinterpret_cast<char *> (&temp), 4))
1626 return 1;
1627
1628 return 0;
1629}
1630
1631// Have to use copy here to avoid writing over data accessed via
1632// Matrix::data().
1633
1634#define MAT5_DO_WRITE(TYPE, data, count, stream) \
1635 do \
1636 { \
1637 OCTAVE_LOCAL_BUFFER (TYPE, ptr, count); \
1638 for (octave_idx_type i = 0; i < count; i++) \
1639 ptr[i] = static_cast<TYPE> (data[i]); \
1640 std::streamsize n_bytes = sizeof (TYPE) * static_cast<std::streamsize> (count); \
1641 stream.write (reinterpret_cast<char *> (ptr), n_bytes); \
1642 } \
1643 while (0)
1644
1645// write out the numeric values in M to OS,
1646// preceded by the appropriate tag.
1647static void
1648write_mat5_array (std::ostream& os, const NDArray& m, bool save_as_floats)
1649{
1650 save_type st = LS_DOUBLE;
1651 const double *data = m.data ();
1652
1653 if (save_as_floats)
1654 {
1655 if (m.too_large_for_float ())
1656 {
1657 warning_with_id ("Octave:save:too-large-for-float",
1658 "save: some values too large to save as floats -- saving as doubles instead");
1659 }
1660 else
1661 st = LS_FLOAT;
1662 }
1663
1664 double max_val, min_val;
1665 if (m.all_integers (max_val, min_val))
1666 st = octave::get_save_type (max_val, min_val);
1667
1668 mat5_data_type mst;
1669 int size;
1670 switch (st)
1671 {
1672 default:
1673 case LS_DOUBLE: mst = miDOUBLE; size = 8; break;
1674 case LS_FLOAT: mst = miSINGLE; size = 4; break;
1675 case LS_U_CHAR: mst = miUINT8; size = 1; break;
1676 case LS_U_SHORT: mst = miUINT16; size = 2; break;
1677 case LS_U_INT: mst = miUINT32; size = 4; break;
1678 case LS_CHAR: mst = miINT8; size = 1; break;
1679 case LS_SHORT: mst = miINT16; size = 2; break;
1680 case LS_INT: mst = miINT32; size = 4; break;
1681 }
1682
1683 octave_idx_type nel = m.numel ();
1684 octave_idx_type len = nel*size;
1685
1686 write_mat5_tag (os, mst, len);
1687
1688 {
1689 switch (st)
1690 {
1691 case LS_U_CHAR:
1692 MAT5_DO_WRITE (uint8_t, data, nel, os);
1693 break;
1694
1695 case LS_U_SHORT:
1696 MAT5_DO_WRITE (uint16_t, data, nel, os);
1697 break;
1698
1699 case LS_U_INT:
1700 MAT5_DO_WRITE (uint32_t, data, nel, os);
1701 break;
1702
1703 case LS_U_LONG:
1704 MAT5_DO_WRITE (uint64_t, data, nel, os);
1705 break;
1706
1707 case LS_CHAR:
1708 MAT5_DO_WRITE (int8_t, data, nel, os);
1709 break;
1710
1711 case LS_SHORT:
1712 MAT5_DO_WRITE (int16_t, data, nel, os);
1713 break;
1714
1715 case LS_INT:
1716 MAT5_DO_WRITE (int32_t, data, nel, os);
1717 break;
1718
1719 case LS_LONG:
1720 MAT5_DO_WRITE (int64_t, data, nel, os);
1721 break;
1722
1723 case LS_FLOAT:
1724 MAT5_DO_WRITE (float, data, nel, os);
1725 break;
1726
1727 case LS_DOUBLE: // No conversion necessary.
1728 os.write (reinterpret_cast<const char *> (data), len);
1729 break;
1730
1731 default:
1732 error ("unrecognized data format requested");
1733 break;
1734 }
1735 }
1736 if (PAD (len) > len)
1737 {
1738 static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00";
1739 os.write (buf, PAD (len) - len);
1740 }
1741}
1742
1743static void
1744write_mat5_array (std::ostream& os, const FloatNDArray& m, bool)
1745{
1746 save_type st = LS_FLOAT;
1747 const float *data = m.data ();
1748
1749 float max_val, min_val;
1750 if (m.all_integers (max_val, min_val))
1751 st = octave::get_save_type (max_val, min_val);
1752
1753 mat5_data_type mst;
1754 int size;
1755 switch (st)
1756 {
1757 default:
1758 case LS_DOUBLE: mst = miDOUBLE; size = 8; break;
1759 case LS_FLOAT: mst = miSINGLE; size = 4; break;
1760 case LS_U_CHAR: mst = miUINT8; size = 1; break;
1761 case LS_U_SHORT: mst = miUINT16; size = 2; break;
1762 case LS_U_INT: mst = miUINT32; size = 4; break;
1763 case LS_CHAR: mst = miINT8; size = 1; break;
1764 case LS_SHORT: mst = miINT16; size = 2; break;
1765 case LS_INT: mst = miINT32; size = 4; break;
1766 }
1767
1768 octave_idx_type nel = m.numel ();
1769 octave_idx_type len = nel*size;
1770
1771 write_mat5_tag (os, mst, len);
1772
1773 {
1774 switch (st)
1775 {
1776 case LS_U_CHAR:
1777 MAT5_DO_WRITE (uint8_t, data, nel, os);
1778 break;
1779
1780 case LS_U_SHORT:
1781 MAT5_DO_WRITE (uint16_t, data, nel, os);
1782 break;
1783
1784 case LS_U_INT:
1785 MAT5_DO_WRITE (uint32_t, data, nel, os);
1786 break;
1787
1788 case LS_U_LONG:
1789 MAT5_DO_WRITE (uint64_t, data, nel, os);
1790 break;
1791
1792 case LS_CHAR:
1793 MAT5_DO_WRITE (int8_t, data, nel, os);
1794 break;
1795
1796 case LS_SHORT:
1797 MAT5_DO_WRITE (int16_t, data, nel, os);
1798 break;
1799
1800 case LS_INT:
1801 MAT5_DO_WRITE (int32_t, data, nel, os);
1802 break;
1803
1804 case LS_LONG:
1805 MAT5_DO_WRITE (int64_t, data, nel, os);
1806 break;
1807
1808 case LS_FLOAT: // No conversion necessary.
1809 os.write (reinterpret_cast<const char *> (data), len);
1810 break;
1811
1812 case LS_DOUBLE:
1813 MAT5_DO_WRITE (double, data, nel, os);
1814 break;
1815
1816 default:
1817 error ("unrecognized data format requested");
1818 break;
1819 }
1820 }
1821 if (PAD (len) > len)
1822 {
1823 static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00";
1824 os.write (buf, PAD (len) - len);
1825 }
1826}
1827
1828template <typename T>
1829void
1830write_mat5_integer_data (std::ostream& os, const T *m, int size,
1831 octave_idx_type nel)
1832{
1833 mat5_data_type mst;
1834 unsigned len;
1835
1836 switch (size)
1837 {
1838 case 1:
1839 mst = miUINT8;
1840 break;
1841 case 2:
1842 mst = miUINT16;
1843 break;
1844 case 4:
1845 mst = miUINT32;
1846 break;
1847 case 8:
1848 mst = miUINT64;
1849 break;
1850 case -1:
1851 mst = miINT8;
1852 size = - size;
1853 break;
1854 case -2:
1855 mst = miINT16;
1856 size = - size;
1857 break;
1858 case -4:
1859 mst = miINT32;
1860 size = - size;
1861 break;
1862 case -8:
1863 default:
1864 mst = miINT64;
1865 size = - size;
1866 break;
1867 }
1868
1869 len = nel*size;
1870 write_mat5_tag (os, mst, len);
1871
1872 os.write (reinterpret_cast<const char *> (m), len);
1873
1874 if (PAD (len) > len)
1875 {
1876 static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00";
1877 os.write (buf, PAD (len) - len);
1878 }
1879}
1880
1881template void
1882write_mat5_integer_data (std::ostream& os, const octave_int8 *m,
1883 int size, octave_idx_type nel);
1884
1885template void
1886write_mat5_integer_data (std::ostream& os, const octave_int16 *m,
1887 int size, octave_idx_type nel);
1888
1889template void
1890write_mat5_integer_data (std::ostream& os, const octave_int32 *m,
1891 int size, octave_idx_type nel);
1892
1893template void
1894write_mat5_integer_data (std::ostream& os, const octave_int64 *m,
1895 int size, octave_idx_type nel);
1896
1897template void
1898write_mat5_integer_data (std::ostream& os, const octave_uint8 *m,
1899 int size, octave_idx_type nel);
1900
1901template void
1902write_mat5_integer_data (std::ostream& os, const octave_uint16 *m,
1903 int size, octave_idx_type nel);
1904
1905template void
1906write_mat5_integer_data (std::ostream& os, const octave_uint32 *m,
1907 int size, octave_idx_type nel);
1908
1909template void
1910write_mat5_integer_data (std::ostream& os, const octave_uint64 *m,
1911 int size, octave_idx_type nel);
1912
1913template void
1914write_mat5_integer_data (std::ostream& os, const int *m,
1915 int size, octave_idx_type nel);
1916
1917// Write out cell element values in the cell array to OS, preceded by
1918// the appropriate tag.
1919
1920static bool
1921write_mat5_cell_array (std::ostream& os, const Cell& cell,
1922 bool mark_global, bool save_as_floats)
1923{
1924 octave_idx_type nel = cell.numel ();
1925
1926 for (octave_idx_type i = 0; i < nel; i++)
1927 {
1928 octave_value ov = cell(i);
1929
1930 if (! save_mat5_binary_element (os, ov, "", mark_global,
1931 false, save_as_floats))
1932 return false;
1933 }
1934
1935 return true;
1936}
1937
1938int
1940 bool save_as_floats)
1941{
1942 if (nel > 0)
1943 {
1944 int size = 8;
1945
1946 if (save_as_floats)
1947 {
1948 bool too_large_for_float = false;
1949 for (octave_idx_type i = 0; i < nel; i++)
1950 {
1951 double tmp = val[i];
1952
1953 if (octave::math::isfinite (tmp)
1954 && fabs (tmp) > std::numeric_limits<float>::max ())
1955 {
1956 too_large_for_float = true;
1957 break;
1958 }
1959 }
1960
1961 if (! too_large_for_float)
1962 size = 4;
1963 }
1964
1965 // The code below is disabled since get_save_type currently
1966 // doesn't deal with integer types. This will need to be
1967 // activated if get_save_type is changed.
1968
1969 // double max_val = val[0];
1970 // double min_val = val[0];
1971 // bool all_integers = true;
1972 //
1973 // for (int i = 0; i < nel; i++)
1974 // {
1975 // double val = val[i];
1976 //
1977 // if (val > max_val)
1978 // max_val = val;
1979 //
1980 // if (val < min_val)
1981 // min_val = val;
1982 //
1983 // if (octave::math::x_nint (val) != val)
1984 // {
1985 // all_integers = false;
1986 // break;
1987 // }
1988 // }
1989 //
1990 // if (all_integers)
1991 // {
1992 // if (max_val < 256 && min_val > -1)
1993 // size = 1;
1994 // else if (max_val < 65536 && min_val > -1)
1995 // size = 2;
1996 // else if (max_val < 4294967295UL && min_val > -1)
1997 // size = 4;
1998 // else if (max_val < 128 && min_val >= -128)
1999 // size = 1;
2000 // else if (max_val < 32768 && min_val >= -32768)
2001 // size = 2;
2002 // else if (max_val <= 2147483647L && min_val >= -2147483647L)
2003 // size = 4;
2004 // }
2005
2006 return 8 + nel * size;
2007 }
2008 else
2009 return 8;
2010}
2011
2012int
2013save_mat5_array_length (const float * /* val */, octave_idx_type nel, bool)
2014{
2015 if (nel > 0)
2016 {
2017 int size = 4;
2018
2019 // The code below is disabled since get_save_type currently
2020 // doesn't deal with integer types. This will need to be
2021 // activated if get_save_type is changed.
2022
2023 // float max_val = val[0];
2024 // float min_val = val[0];
2025 // bool all_integers = true;
2026 //
2027 // for (int i = 0; i < nel; i++)
2028 // {
2029 // float val = val[i];
2030 //
2031 // if (val > max_val)
2032 // max_val = val;
2033 //
2034 // if (val < min_val)
2035 // min_val = val;
2036 //
2037 // if (octave::math::x_nint (val) != val)
2038 // {
2039 // all_integers = false;
2040 // break;
2041 // }
2042 // }
2043 //
2044 // if (all_integers)
2045 // {
2046 // if (max_val < 256 && min_val > -1)
2047 // size = 1;
2048 // else if (max_val < 65536 && min_val > -1)
2049 // size = 2;
2050 // else if (max_val < 4294967295UL && min_val > -1)
2051 // size = 4;
2052 // else if (max_val < 128 && min_val >= -128)
2053 // size = 1;
2054 // else if (max_val < 32768 && min_val >= -32768)
2055 // size = 2;
2056 // else if (max_val <= 2147483647L && min_val >= -2147483647L)
2057 // size = 4;
2058 //
2059
2060 // Round nel up to nearest even number of elements.
2061 // Take into account short tags for 4 byte elements.
2062 return PAD ((nel * size <= 4 ? 4 : 8) + nel * size);
2063 }
2064 else
2065 return 8;
2066}
2067
2068int
2070 bool save_as_floats)
2071{
2072 int ret;
2073
2074 OCTAVE_LOCAL_BUFFER (double, tmp, nel);
2075
2076 for (octave_idx_type i = 1; i < nel; i++)
2077 tmp[i] = std::real (val[i]);
2078
2079 ret = save_mat5_array_length (tmp, nel, save_as_floats);
2080
2081 for (octave_idx_type i = 1; i < nel; i++)
2082 tmp[i] = std::imag (val[i]);
2083
2084 ret += save_mat5_array_length (tmp, nel, save_as_floats);
2085
2086 return ret;
2087}
2088
2089int
2091 bool save_as_floats)
2092{
2093 int ret;
2094
2095 OCTAVE_LOCAL_BUFFER (float, tmp, nel);
2096
2097 for (octave_idx_type i = 1; i < nel; i++)
2098 tmp[i] = std::real (val[i]);
2099
2100 ret = save_mat5_array_length (tmp, nel, save_as_floats);
2101
2102 for (octave_idx_type i = 1; i < nel; i++)
2103 tmp[i] = std::imag (val[i]);
2104
2105 ret += save_mat5_array_length (tmp, nel, save_as_floats);
2106
2107 return ret;
2108}
2109
2110static uint16_t *
2111maybe_convert_to_u16 (const charNDArray& chm, std::size_t& n16_str)
2112{
2113 uint16_t *u16_str;
2114 dim_vector dv = chm.dims ();
2115
2116 if (chm.ndims () == 2 && dv(0) == 1)
2117 {
2118 const uint8_t *u8_str = reinterpret_cast<const uint8_t *> (chm.data ());
2119 u16_str = octave_u8_to_u16_wrapper (u8_str, chm.numel (),
2120 nullptr, &n16_str);
2121 }
2122 else
2123 u16_str = nullptr;
2124
2125 return u16_str;
2126}
2127
2128int
2129save_mat5_element_length (const octave_value& tc, const std::string& name,
2130 bool save_as_floats, bool mat7_format)
2131{
2132 std::size_t max_namelen = 63;
2133 std::size_t len = name.length ();
2134 std::string cname = tc.class_name ();
2135 int ret = 32;
2136
2137 if (len > 4)
2138 ret += PAD (len > max_namelen ? max_namelen : len);
2139
2140 ret += PAD (4 * tc.ndims ());
2141
2142 if (tc.is_string ())
2143 {
2144 charNDArray chm = tc.char_array_value ();
2145 // convert to UTF-16
2146 std::size_t n16_str;
2147 uint16_t *u16_str = maybe_convert_to_u16 (chm, n16_str);
2148 ret += 8;
2149
2150 octave_idx_type str_len;
2151 std::size_t sz_of = 1;
2152 if (u16_str)
2153 {
2154 free (u16_str);
2155 // Count number of elements in converted string
2156 str_len = n16_str;
2157 sz_of = 2;
2158 }
2159 else
2160 str_len = chm.numel ();
2161
2162 if (str_len > 2)
2163 ret += PAD (sz_of * str_len);
2164 }
2165 else if (tc.issparse ())
2166 {
2167 if (tc.iscomplex ())
2168 {
2170 octave_idx_type nc = m.cols ();
2171 octave_idx_type nnz = m.nnz ();
2172
2173 ret += 16 + save_mat5_array_length (m.data (), nnz, save_as_floats);
2174 if (nnz > 1)
2175 ret += PAD (nnz * sizeof (int32_t));
2176 if (nc > 0)
2177 ret += PAD ((nc + 1) * sizeof (int32_t));
2178 }
2179 else
2180 {
2181 const SparseMatrix m = tc.sparse_matrix_value ();
2182 octave_idx_type nc = m.cols ();
2183 octave_idx_type nnz = m.nnz ();
2184
2185 ret += 16 + save_mat5_array_length (m.data (), nnz, save_as_floats);
2186 if (nnz > 1)
2187 ret += PAD (nnz * sizeof (int32_t));
2188 if (nc > 0)
2189 ret += PAD ((nc + 1) * sizeof (int32_t));
2190 }
2191 }
2192
2193#define INT_LEN(nel, size) \
2194 { \
2195 ret += 8; \
2196 octave_idx_type sz = nel * size; \
2197 if (sz > 4) \
2198 ret += PAD (sz); \
2199 }
2200
2201 else if (cname == "int8")
2202 INT_LEN (tc.int8_array_value ().numel (), 1)
2203 else if (cname == "int16")
2204 INT_LEN (tc.int16_array_value ().numel (), 2)
2205 else if (cname == "int32")
2206 INT_LEN (tc.int32_array_value ().numel (), 4)
2207 else if (cname == "int64")
2208 INT_LEN (tc.int64_array_value ().numel (), 8)
2209 else if (cname == "uint8")
2210 INT_LEN (tc.uint8_array_value ().numel (), 1)
2211 else if (cname == "uint16")
2212 INT_LEN (tc.uint16_array_value ().numel (), 2)
2213 else if (cname == "uint32")
2214 INT_LEN (tc.uint32_array_value ().numel (), 4)
2215 else if (cname == "uint64")
2216 INT_LEN (tc.uint64_array_value ().numel (), 8)
2217 else if (tc.islogical ())
2218 INT_LEN (tc.bool_array_value ().numel (), 1)
2219 else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ())
2220 {
2221 if (tc.is_single_type ())
2222 {
2223 const FloatNDArray m = tc.float_array_value ();
2224 ret += save_mat5_array_length (m.data (), m.numel (), save_as_floats);
2225 }
2226 else
2227 {
2228 const NDArray m = tc.array_value ();
2229 ret += save_mat5_array_length (m.data (), m.numel (), save_as_floats);
2230 }
2231 }
2232 else if (tc.iscell ())
2233 {
2234 Cell cell = tc.cell_value ();
2235 octave_idx_type nel = cell.numel ();
2236
2237 for (int i = 0; i < nel; i++)
2238 ret += 8 +
2239 save_mat5_element_length (cell (i), "", save_as_floats, mat7_format);
2240 }
2241 else if (tc.is_complex_scalar () || tc.is_complex_matrix ())
2242 {
2243 if (tc.is_single_type ())
2244 {
2246 ret += save_mat5_array_length (m.data (), m.numel (), save_as_floats);
2247 }
2248 else
2249 {
2250 const ComplexNDArray m = tc.complex_array_value ();
2251 ret += save_mat5_array_length (m.data (), m.numel (), save_as_floats);
2252 }
2253 }
2254 else if (tc.isstruct () || tc.is_inline_function () || tc.isobject ())
2255 {
2256 int fieldcnt = 0;
2257 const octave_map m = tc.map_value ();
2258 octave_idx_type nel = m.numel ();
2259
2260 if (tc.is_inline_function ())
2261 ret += 8 + PAD (6); // length of "inline" is 6
2262 else if (tc.isobject ())
2263 {
2264 std::size_t classlen = tc.class_name ().length ();
2265
2266 ret += 8 + PAD (classlen > max_namelen ? max_namelen : classlen);
2267 }
2268
2269 for (auto i = m.begin (); i != m.end (); i++)
2270 fieldcnt++;
2271
2272 ret += 16 + fieldcnt * (max_namelen + 1);
2273
2274 for (octave_idx_type j = 0; j < nel; j++)
2275 {
2276 for (auto i = m.begin (); i != m.end (); i++)
2277 {
2278 const Cell elts = m.contents (i);
2279
2280 ret += 8 + save_mat5_element_length (elts(j), "", save_as_floats,
2281 mat7_format);
2282 }
2283 }
2284 }
2285 else
2286 ret = -1;
2287
2288 return ret;
2289}
2290
2291static void
2293 const octave_idx_type *idx,
2294 octave_idx_type nel)
2295{
2296 int tmp = sizeof (int32_t);
2297
2298 OCTAVE_LOCAL_BUFFER (int32_t, tmp_idx, nel);
2299
2300 for (octave_idx_type i = 0; i < nel; i++)
2301 tmp_idx[i] = idx[i];
2302
2303 write_mat5_integer_data (os, tmp_idx, -tmp, nel);
2304}
2305
2306static void
2307warn_dim_too_large (const std::string& name)
2308{
2309 warning_with_id ("Octave:save:dimension-too-large",
2310 "save: skipping %s: dimension too large for MAT format",
2311 name.c_str ());
2312}
2313
2314// save the data from TC along with the corresponding NAME on stream
2315// OS in the MatLab version 5 binary format. Return true on success.
2316
2317bool
2319 const octave_value& tc, const std::string& name,
2320 bool mark_global, bool mat7_format,
2321 bool save_as_floats, bool compressing)
2322{
2323 int32_t flags = 0;
2324 int32_t nnz_32 = 0;
2325 std::string cname = tc.class_name ();
2326 std::size_t max_namelen = 63;
2327
2328 dim_vector dv = tc.dims ();
2329 int nd = tc.ndims ();
2330 int dim_len = 4*nd;
2331
2332 static octave_idx_type max_dim_val = std::numeric_limits<int32_t>::max ();
2333
2334 for (int i = 0; i < nd; i++)
2335 {
2336 if (dv(i) > max_dim_val)
2337 {
2339 return true; // skip to next
2340 }
2341 }
2342
2343 if (tc.issparse ())
2344 {
2345 octave_idx_type nnz;
2346 octave_idx_type nc;
2347
2348 if (tc.iscomplex ())
2349 {
2351 nnz = scm.nzmax ();
2352 nc = scm.cols ();
2353 }
2354 else
2355 {
2357 nnz = sm.nzmax ();
2358 nc = sm.cols ();
2359 }
2360
2361 if (nnz > max_dim_val || nc + 1 > max_dim_val)
2362 {
2364 return true; // skip to next
2365 }
2366
2367 nnz_32 = nnz;
2368 }
2369 else if (dv.numel () > max_dim_val)
2370 {
2372 return true; // skip to next
2373 }
2374
2375#if defined (HAVE_ZLIB)
2376
2377 if (mat7_format && ! compressing)
2378 {
2379 bool ret = false;
2380
2381 std::ostringstream buf;
2382
2383 // The code seeks backwards in the stream to fix the header.
2384 // Can't do this with zlib, so use a stringstream.
2385 ret = save_mat5_binary_element (buf, tc, name, mark_global, true,
2386 save_as_floats, true);
2387
2388 if (ret)
2389 {
2390 // destLen must be at least 0.1% larger than source buffer
2391 // + 12 bytes. Reality is it must be larger again than that.
2392 std::string buf_str = buf.str ();
2393 uLongf srcLen = buf_str.length ();
2394 uLongf destLen = compressBound (srcLen);
2395 OCTAVE_LOCAL_BUFFER (char, out_buf, destLen);
2396
2397 if (compress (reinterpret_cast<Bytef *> (out_buf), &destLen,
2398 reinterpret_cast<const Bytef *> (buf_str.c_str ()),
2399 srcLen)
2400 != Z_OK)
2401 error ("save: error compressing data element");
2402
2404 static_cast<octave_idx_type> (destLen));
2405
2406 os.write (out_buf, destLen);
2407 }
2408
2409 return ret;
2410 }
2411
2412#else
2413
2414 octave_unused_parameter (compressing);
2415
2416#endif
2417
2419 (tc, name, save_as_floats, mat7_format));
2420
2421 // array flags subelement
2422 write_mat5_tag (os, miUINT32, 8);
2423
2424 if (tc.islogical ())
2425 flags |= 0x0200;
2426
2427 if (mark_global)
2428 flags |= 0x0400;
2429
2430 if (tc.is_complex_scalar () || tc.is_complex_matrix ())
2431 flags |= 0x0800;
2432
2433 if (tc.is_string ())
2434 flags |= MAT_FILE_CHAR_CLASS;
2435 else if (cname == "int8")
2436 flags |= MAT_FILE_INT8_CLASS;
2437 else if (cname == "int16")
2438 flags |= MAT_FILE_INT16_CLASS;
2439 else if (cname == "int32")
2440 flags |= MAT_FILE_INT32_CLASS;
2441 else if (cname == "int64")
2442 flags |= MAT_FILE_INT64_CLASS;
2443 else if (cname == "uint8" || tc.islogical ())
2444 flags |= MAT_FILE_UINT8_CLASS;
2445 else if (cname == "uint16")
2446 flags |= MAT_FILE_UINT16_CLASS;
2447 else if (cname == "uint32")
2448 flags |= MAT_FILE_UINT32_CLASS;
2449 else if (cname == "uint64")
2450 flags |= MAT_FILE_UINT64_CLASS;
2451 else if (tc.issparse ())
2452 flags |= MAT_FILE_SPARSE_CLASS;
2453 else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ()
2454 || tc.is_complex_scalar () || tc.is_complex_matrix ())
2455 {
2456 if (tc.is_single_type ())
2457 flags |= MAT_FILE_SINGLE_CLASS;
2458 else
2459 flags |= MAT_FILE_DOUBLE_CLASS;
2460 }
2461 else if (tc.isstruct ())
2462 flags |= MAT_FILE_STRUCT_CLASS;
2463 else if (tc.iscell ())
2464 flags |= MAT_FILE_CELL_CLASS;
2465 else if (tc.is_inline_function () || tc.isobject ())
2466 flags |= MAT_FILE_OBJECT_CLASS;
2467 else
2468 {
2469 // FIXME: Should this just error out rather than warn?
2470 warn_wrong_type_arg ("save", tc);
2471 error ("save: error while writing '%s' to MAT file", name.c_str ());
2472 }
2473
2474 os.write (reinterpret_cast<char *> (&flags), 4);
2475 // Matlab seems to have trouble reading files that have nzmax == 0 at
2476 // this point in the file.
2477 if (nnz_32 == 0)
2478 nnz_32 = 1;
2479 os.write (reinterpret_cast<char *> (&nnz_32), 4);
2480
2481 write_mat5_tag (os, miINT32, dim_len);
2482
2483 // Strings need to be converted here (or dim-vector will be off).
2484 charNDArray chm;
2485 uint16_t *u16_str;
2486 std::size_t n16_str;
2487 bool conv_u16 = false;
2488 if (tc.is_string ())
2489 {
2490 chm = tc.char_array_value ();
2491 u16_str = maybe_convert_to_u16 (chm, n16_str);
2492
2493 if (u16_str)
2494 conv_u16 = true;
2495 }
2496
2497 if (conv_u16)
2498 {
2499 int32_t n = 1;
2500 os.write (reinterpret_cast<char *> (&n), 4);
2501 os.write (reinterpret_cast<char *> (&n16_str), 4);
2502 }
2503 else
2504 for (int i = 0; i < nd; i++)
2505 {
2506 int32_t n = dv(i);
2507 os.write (reinterpret_cast<char *> (&n), 4);
2508 }
2509
2510 if (PAD (dim_len) > dim_len)
2511 {
2512 static char buf[9] = "\x00\x00\x00\x00\x00\x00\x00\x00";
2513 os.write (buf, PAD (dim_len) - dim_len);
2514 }
2515
2516 // array name subelement
2517 {
2518 std::size_t namelen = name.length ();
2519
2520 if (namelen > max_namelen)
2521 namelen = max_namelen; // Truncate names if necessary
2522
2523 int paddedlength = PAD (namelen);
2524
2525 write_mat5_tag (os, miINT8, namelen);
2526 OCTAVE_LOCAL_BUFFER (char, paddedname, paddedlength);
2527 memset (paddedname, 0, paddedlength);
2528 strncpy (paddedname, name.c_str (), namelen);
2529 os.write (paddedname, paddedlength);
2530 }
2531
2532 // data element
2533 if (tc.is_string ())
2534 {
2536 octave_idx_type paddedlength;
2537
2538 if (conv_u16)
2539 {
2540 // converted UTF-16
2541 len = n16_str*2;
2542 paddedlength = PAD (len);
2543
2544 write_mat5_tag (os, miUTF16, len);
2545
2546 os.write (reinterpret_cast<char *> (u16_str), len);
2547
2548 free (u16_str);
2549 }
2550 else
2551 {
2552 // write as UTF-8
2553 len = chm.numel ();
2554 paddedlength = PAD (len);
2555
2556 write_mat5_tag (os, miUTF8, len);
2557
2558 os.write (chm.data (), len);
2559 }
2560
2561 if (paddedlength > len)
2562 {
2563 static char padbuf[9] = "\x00\x00\x00\x00\x00\x00\x00\x00";
2564 os.write (padbuf, paddedlength - len);
2565 }
2566 }
2567 else if (tc.issparse ())
2568 {
2569 if (tc.iscomplex ())
2570 {
2572 octave_idx_type nnz = m.nnz ();
2573 octave_idx_type nc = m.cols ();
2574
2575 write_mat5_sparse_index_vector (os, m.ridx (), nnz);
2576 write_mat5_sparse_index_vector (os, m.cidx (), nc + 1);
2577
2578 NDArray buf (dim_vector (nnz, 1));
2579
2580 for (octave_idx_type i = 0; i < nnz; i++)
2581 buf (i) = std::real (m.data (i));
2582
2583 write_mat5_array (os, buf, save_as_floats);
2584
2585 for (octave_idx_type i = 0; i < nnz; i++)
2586 buf (i) = std::imag (m.data (i));
2587
2588 write_mat5_array (os, buf, save_as_floats);
2589 }
2590 else
2591 {
2592 const SparseMatrix m = tc.sparse_matrix_value ();
2593 octave_idx_type nnz = m.nnz ();
2594 octave_idx_type nc = m.cols ();
2595
2596 write_mat5_sparse_index_vector (os, m.ridx (), nnz);
2597 write_mat5_sparse_index_vector (os, m.cidx (), nc + 1);
2598
2599 // FIXME
2600 // Is there a way to easily do without this buffer
2601 NDArray buf (dim_vector (nnz, 1));
2602
2603 for (int i = 0; i < nnz; i++)
2604 buf (i) = m.data (i);
2605
2606 write_mat5_array (os, buf, save_as_floats);
2607 }
2608 }
2609 else if (cname == "int8")
2610 {
2611 int8NDArray m = tc.int8_array_value ();
2612
2613 write_mat5_integer_data (os, m.data (), -1, m.numel ());
2614 }
2615 else if (cname == "int16")
2616 {
2618
2619 write_mat5_integer_data (os, m.data (), -2, m.numel ());
2620 }
2621 else if (cname == "int32")
2622 {
2624
2625 write_mat5_integer_data (os, m.data (), -4, m.numel ());
2626 }
2627 else if (cname == "int64")
2628 {
2630
2631 write_mat5_integer_data (os, m.data (), -8, m.numel ());
2632 }
2633 else if (cname == "uint8")
2634 {
2636
2637 write_mat5_integer_data (os, m.data (), 1, m.numel ());
2638 }
2639 else if (cname == "uint16")
2640 {
2642
2643 write_mat5_integer_data (os, m.data (), 2, m.numel ());
2644 }
2645 else if (cname == "uint32")
2646 {
2648
2649 write_mat5_integer_data (os, m.data (), 4, m.numel ());
2650 }
2651 else if (cname == "uint64")
2652 {
2654
2655 write_mat5_integer_data (os, m.data (), 8, m.numel ());
2656 }
2657 else if (tc.islogical ())
2658 {
2660
2661 write_mat5_integer_data (os, m.data (), 1, m.numel ());
2662 }
2663 else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ())
2664 {
2665 if (tc.is_single_type ())
2666 {
2668
2669 write_mat5_array (os, m, save_as_floats);
2670 }
2671 else
2672 {
2673 NDArray m = tc.array_value ();
2674
2675 write_mat5_array (os, m, save_as_floats);
2676 }
2677 }
2678 else if (tc.iscell ())
2679 {
2680 Cell cell = tc.cell_value ();
2681
2682 if (! write_mat5_cell_array (os, cell, mark_global, save_as_floats))
2683 error ("save: error while writing '%s' to MAT file", name.c_str ());
2684 }
2685 else if (tc.is_complex_scalar () || tc.is_complex_matrix ())
2686 {
2687 if (tc.is_single_type ())
2688 {
2690
2691 write_mat5_array (os, ::real (m_cmplx), save_as_floats);
2692 write_mat5_array (os, ::imag (m_cmplx), save_as_floats);
2693 }
2694 else
2695 {
2696 ComplexNDArray m_cmplx = tc.complex_array_value ();
2697
2698 write_mat5_array (os, ::real (m_cmplx), save_as_floats);
2699 write_mat5_array (os, ::imag (m_cmplx), save_as_floats);
2700 }
2701 }
2702 else if (tc.isstruct () || tc.is_inline_function () || tc.isobject ())
2703 {
2704 if (tc.is_inline_function () || tc.isobject ())
2705 {
2706 std::string classname = (tc.isobject () ? tc.class_name () : "inline");
2707 std::size_t namelen = classname.length ();
2708
2709 if (namelen > max_namelen)
2710 namelen = max_namelen; // Truncate names if necessary
2711
2712 int paddedlength = PAD (namelen);
2713
2714 write_mat5_tag (os, miINT8, namelen);
2715 OCTAVE_LOCAL_BUFFER (char, paddedname, paddedlength);
2716 memset (paddedname, 0, paddedlength);
2717 strncpy (paddedname, classname.c_str (), namelen);
2718 os.write (paddedname, paddedlength);
2719 }
2720
2721 octave_map m;
2722
2723 octave::load_path& lp
2724 = octave::__get_load_path__ ("save_mat5_binary_element");
2725
2726 if (tc.isobject ()
2727 && lp.find_method (tc.class_name (), "saveobj") != "")
2728 {
2729 try
2730 {
2731 octave_value_list tmp = octave::feval ("saveobj", tc, 1);
2732
2733 m = tmp(0).map_value ();
2734 }
2735 catch (const octave::execution_exception&)
2736 {
2737 error ("save: error while writing '%s' to MAT file",
2738 name.c_str ());
2739 }
2740 }
2741 else
2742 m = tc.map_value ();
2743
2744 // an Octave structure */
2745 // recursively write each element of the structure
2746 {
2747 char buf[64];
2748 int32_t maxfieldnamelength = max_namelen + 1;
2749
2750 octave_idx_type nf = m.nfields ();
2751
2752 write_mat5_tag (os, miINT32, 4);
2753 os.write (reinterpret_cast<char *> (&maxfieldnamelength), 4);
2754 write_mat5_tag (os, miINT8, nf*maxfieldnamelength);
2755
2756 // Iterating over the list of keys will preserve the order of
2757 // the fields.
2758 string_vector keys = m.keys ();
2759
2760 for (octave_idx_type i = 0; i < nf; i++)
2761 {
2762 std::string key = keys(i);
2763
2764 // write the name of each element
2765 memset (buf, 0, max_namelen + 1);
2766 // only 31 or 63 char names permitted
2767 strncpy (buf, key.c_str (), max_namelen);
2768 os.write (buf, max_namelen + 1);
2769 }
2770
2771 octave_idx_type len = m.numel ();
2772
2773 // Create temporary copy of structure contents to avoid
2774 // multiple calls of the contents method.
2775 std::vector<const octave_value *> elts (nf);
2776 for (octave_idx_type i = 0; i < nf; i++)
2777 elts[i] = m.contents (keys(i)).data ();
2778
2779 for (octave_idx_type j = 0; j < len; j++)
2780 {
2781 // write the data of each element
2782
2783 // Iterating over the list of keys will preserve the order
2784 // of the fields.
2785 for (octave_idx_type i = 0; i < nf; i++)
2786 {
2787 bool retval2 = save_mat5_binary_element (os, elts[i][j], "",
2788 mark_global,
2789 false,
2790 save_as_floats);
2791 if (! retval2)
2792 error ("save: error while writing '%s' to MAT file",
2793 name.c_str ());
2794 }
2795 }
2796 }
2797 }
2798 else
2799 // FIXME: Should this just error out rather than warn?
2800 warn_wrong_type_arg ("save", tc);
2801
2802 return true;
2803}
void swap_bytes< 8 >(void *ptr)
Definition: byte-swap.h:71
void swap_bytes< 4 >(void *ptr)
Definition: byte-swap.h:63
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
OCTARRAY_API void clear(void)
Definition: Array.cc:87
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:411
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:487
bool isvector(void) const
Size of the specified dimension.
Definition: Array.h:609
const T * data(void) const
Size of the specified dimension.
Definition: Array.h:616
OCTARRAY_API T * fortran_vec(void)
Size of the specified dimension.
Definition: Array.cc:1744
int ndims(void) const
Size of the specified dimension.
Definition: Array.h:627
Definition: Cell.h:43
OCTAVE_API bool all_integers(float &max_val, float &min_val) const
Definition: fNDArray.cc:308
OCTAVE_API bool all_integers(double &max_val, double &min_val) const
Definition: dNDArray.cc:351
OCTAVE_API bool too_large_for_float(void) const
Definition: dNDArray.cc:387
T * data(void)
Definition: Sparse.h:574
T * xdata(void)
Definition: Sparse.h:576
octave_idx_type nnz(void) const
Actual number of nonzero terms.
Definition: Sparse.h:339
octave_idx_type * ridx(void)
Definition: Sparse.h:583
octave_idx_type * cidx(void)
Definition: Sparse.h:596
octave_idx_type nzmax(void) const
Amount of storage for nonzero elements.
Definition: Sparse.h:336
octave_idx_type cols(void) const
Definition: Sparse.h:352
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:335
void resize(int n, int fill_value=0)
Definition: dim-vector.h:272
OCTINTERP_API cdef_class find_class(const std::string &name, bool error_if_not_found=true, bool load_if_not_found=true)
bool ok(void) const
Definition: cdef-object.h:310
std::string find_first_of(const std::list< std::string > &names)
Definition: pathsearch.cc:86
std::map< std::string, octave_value > local_vars_map
Definition: stack-frame.h:112
bool exists(void) const
Definition: file-stat.h:147
static std::string make_absolute(const std::string &s, const std::string &dot_path=get_current_directory())
Definition: oct-env.cc:131
OCTINTERP_API bool reconstruct_parents(void)
Definition: ov-class.cc:1121
OCTINTERP_API bool reconstruct_exemplar(void)
Definition: ov-class.cc:1041
octave_value fcn_val(void)
octave_idx_type nfields(void) const
Definition: oct-map.h:344
const Cell & contents(const_iterator p) const
Definition: oct-map.h:331
octave_idx_type numel(void) const
Definition: oct-map.h:389
void assign(const std::string &k, const Cell &val)
Definition: oct-map.h:365
const_iterator begin(void) const
Definition: oct-map.h:318
const_iterator end(void) const
Definition: oct-map.h:319
string_vector keys(void) const
Definition: oct-map.h:356
const octave_value & contents(const_iterator p) const
Definition: oct-map.h:205
octave_idx_type nfields(void) const
Definition: oct-map.h:218
const_iterator end(void) const
Definition: oct-map.h:193
const_iterator begin(void) const
Definition: oct-map.h:192
std::string key(const_iterator p) const
Definition: oct-map.h:200
int32NDArray int32_array_value(void) const
Definition: ov.h:1001
boolNDArray bool_array_value(bool warn=false) const
Definition: ov.h:936
uint16NDArray uint16_array_value(void) const
Definition: ov.h:1010
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:945
bool iscell(void) const
Definition: ov.h:649
bool is_complex_matrix(void) const
Definition: ov.h:664
bool issparse(void) const
Definition: ov.h:798
OCTINTERP_API octave_scalar_map scalar_map_value(void) const
OCTINTERP_API octave_fcn_handle * fcn_handle_value(bool silent=false) const
bool is_string(void) const
Definition: ov.h:682
ComplexNDArray complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:923
bool is_defined(void) const
Definition: ov.h:637
charNDArray char_array_value(bool frc_str_conv=false) const
Definition: ov.h:942
Cell cell_value(void) const
std::string class_name(void) const
Definition: ov.h:1451
int8NDArray int8_array_value(void) const
Definition: ov.h:995
int ndims(void) const
Definition: ov.h:596
int64NDArray int64_array_value(void) const
Definition: ov.h:1004
bool isstruct(void) const
Definition: ov.h:694
uint8NDArray uint8_array_value(void) const
Definition: ov.h:1007
std::string string_value(bool force=false) const
Definition: ov.h:1019
uint64NDArray uint64_array_value(void) const
Definition: ov.h:1016
bool is_range(void) const
Definition: ov.h:691
bool isempty(void) const
Definition: ov.h:646
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:904
bool is_real_matrix(void) const
Definition: ov.h:658
bool is_single_type(void) const
Definition: ov.h:743
uint32NDArray uint32_array_value(void) const
Definition: ov.h:1013
octave_value convert_to_str(bool pad=false, bool force=false, char type='\'') const
Definition: ov.h:1411
OCTINTERP_API octave_map map_value(void) const
bool isobject(void) const
Definition: ov.h:709
bool is_real_scalar(void) const
Definition: ov.h:655
FloatComplexNDArray float_complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:927
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:907
bool is_uint8_type(void) const
Definition: ov.h:763
int16NDArray int16_array_value(void) const
Definition: ov.h:998
bool is_inline_function(void) const
Definition: ov.h:819
bool iscomplex(void) const
Definition: ov.h:786
bool is_complex_scalar(void) const
Definition: ov.h:661
bool islogical(void) const
Definition: ov.h:780
dim_vector dims(void) const
Definition: ov.h:586
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:949
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:137
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:143
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:776
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:836
save_type
Definition: data-conv.h:87
@ LS_U_CHAR
Definition: data-conv.h:88
@ LS_DOUBLE
Definition: data-conv.h:95
@ LS_LONG
Definition: data-conv.h:97
@ LS_U_LONG
Definition: data-conv.h:96
@ LS_U_SHORT
Definition: data-conv.h:89
@ LS_FLOAT
Definition: data-conv.h:94
@ LS_SHORT
Definition: data-conv.h:92
@ LS_CHAR
Definition: data-conv.h:91
@ LS_INT
Definition: data-conv.h:93
@ LS_U_INT
Definition: data-conv.h:90
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1070
void error(const char *fmt,...)
Definition: error.cc:980
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:372
QString name
#define INT8(l)
Definition: ls-mat5.cc:87
static octave_value subsys_ov
Definition: ls-mat5.cc:91
#define PAD(l)
Definition: ls-mat5.cc:86
#define READ_INTEGER_DATA(TYPE, swap, data, size, len, stream)
static void read_int(std::istream &is, bool swap, int32_t &val)
Definition: ls-mat5.cc:461
void write_mat5_integer_data(std::ostream &os, const T *m, int size, octave_idx_type nel)
Definition: ls-mat5.cc:1830
static int write_mat5_tag(std::ostream &is, int type, octave_idx_type bytes)
Definition: ls-mat5.cc:1611
static int read_mat5_tag(std::istream &is, bool swap, int32_t &type, int32_t &bytes, bool &is_small_data_element)
Definition: ls-mat5.cc:426
static bool write_mat5_cell_array(std::ostream &os, const Cell &cell, bool mark_global, bool save_as_floats)
Definition: ls-mat5.cc:1921
#define MAT5_DO_WRITE(TYPE, data, count, stream)
Definition: ls-mat5.cc:1634
int save_mat5_array_length(const double *val, octave_idx_type nel, bool save_as_floats)
Definition: ls-mat5.cc:1939
#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
static uint16_t * maybe_convert_to_u16(const charNDArray &chm, std::size_t &n16_str)
Definition: ls-mat5.cc:2111
static void read_mat5_binary_data(std::istream &is, double *data, octave_idx_type count, bool swap, mat5_data_type type, octave::mach_info::float_format flt_fmt)
Definition: ls-mat5.cc:127
int read_mat5_binary_file_header(std::istream &is, bool &swap, bool quiet, const std::string &filename)
Definition: ls-mat5.cc:1531
#define INT_LEN(nel, size)
bool save_mat5_binary_element(std::ostream &os, const octave_value &tc, const std::string &name, bool mark_global, bool mat7_format, bool save_as_floats, bool compressing)
Definition: ls-mat5.cc:2318
static void write_mat5_array(std::ostream &os, const NDArray &m, bool save_as_floats)
Definition: ls-mat5.cc:1648
int save_mat5_element_length(const octave_value &tc, const std::string &name, bool save_as_floats, bool mat7_format)
Definition: ls-mat5.cc:2129
static void warn_dim_too_large(const std::string &name)
Definition: ls-mat5.cc:2307
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:85
static void write_mat5_sparse_index_vector(std::ostream &os, const octave_idx_type *idx, octave_idx_type nel)
Definition: ls-mat5.cc:2292
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
OCTAVE_NAMESPACE_BEGIN save_type get_save_type(double, double)
Definition: ls-utils.cc:40
class OCTAVE_API charMatrix
Definition: mx-fwd.h:36
class OCTAVE_API NDArray
Definition: mx-fwd.h:38
class OCTAVE_API Matrix
Definition: mx-fwd.h:31
class OCTAVE_API SparseMatrix
Definition: mx-fwd.h:55
class OCTAVE_API SparseComplexMatrix
Definition: mx-fwd.h:56
std::string octave_exec_home(void)
Definition: defaults.cc:164
float_format native_float_format(void)
Definition: mach-info.cc:65
@ flt_fmt_ieee_little_endian
Definition: mach-info.h:43
bool isfinite(double x)
Definition: lo-mappers.h:192
std::string dir_sep_chars(void)
Definition: file-ops.cc:247
OCTINTERP_API octave_value_list feval(const char *name, const octave_value_list &args=octave_value_list(), int nargout=0)
interpreter & __get_interpreter__(const std::string &who)
OCTINTERP_API octave_value load_fcn_from_file(const std::string &file_name, const std::string &dir_name="", const std::string &dispatch_type="", const std::string &package_name="", const std::string &fcn_name="", bool autoload=false)
load_path & __get_load_path__(const std::string &who)
bool too_large_for_float(double x)
Definition: lo-utils.cc:55
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 *)
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
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