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