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