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