Mercurial > octave-nkf
annotate src/ls-mat5.cc @ 9636:74be4b7273e4 ss-3-3-50
update version info for snapshot
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Sat, 12 Sep 2009 06:55:13 -0400 |
parents | 17af7cce7d1b |
children | 2cd940306a06 |
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 |
807 str = octave_env::make_absolute | |
808 (p.find_first_of (names), octave_env::getcwd ()); | |
809 | |
8007
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7901
diff
changeset
|
810 size_t xpos |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7901
diff
changeset
|
811 = str.find_last_of (file_ops::dir_sep_chars ()); |
6625 | 812 |
7336 | 813 std::string dir_name = str.substr (0, xpos); |
6625 | 814 |
7336 | 815 octave_function *fcn |
816 = load_fcn_from_file (str, dir_name, "", fname); | |
6625 | 817 |
7336 | 818 if (fcn) |
819 { | |
820 octave_value tmp (fcn); | |
6625 | 821 |
7336 | 822 tc = octave_value (new octave_fcn_handle (tmp, fname)); |
6625 | 823 } |
824 else | |
825 { | |
826 warning ("load: can't find the file %s", | |
827 fpath.c_str()); | |
828 goto skip_ahead; | |
829 } | |
830 } | |
831 } | |
832 else | |
833 { | |
8007
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7901
diff
changeset
|
834 size_t xpos |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7901
diff
changeset
|
835 = fpath.find_last_of (file_ops::dir_sep_chars ()); |
6625 | 836 |
7336 | 837 std::string dir_name = fpath.substr (0, xpos); |
6625 | 838 |
7336 | 839 octave_function *fcn |
840 = load_fcn_from_file (fpath, dir_name, "", fname); | |
6625 | 841 |
7336 | 842 if (fcn) |
843 { | |
844 octave_value tmp (fcn); | |
6625 | 845 |
7336 | 846 tc = octave_value (new octave_fcn_handle (tmp, fname)); |
6625 | 847 } |
848 else | |
849 { | |
850 warning ("load: can't find the file %s", | |
851 fpath.c_str()); | |
852 goto skip_ahead; | |
853 } | |
854 } | |
855 } | |
856 } | |
857 else if (ftype == "nested") | |
858 { | |
859 warning ("load: can't load nested function"); | |
860 goto skip_ahead; | |
861 } | |
862 else if (ftype == "anonymous") | |
863 { | |
864 Octave_map m2 = m1.contents("workspace")(0).map_value(); | |
865 uint32NDArray MCOS = m2.contents("MCOS")(0).uint32_array_value(); | |
7198 | 866 octave_idx_type off = static_cast<octave_idx_type>(MCOS(4).double_value ()); |
6625 | 867 m2 = subsys_ov.map_value(); |
868 m2 = m2.contents("MCOS")(0).map_value(); | |
869 tc2 = m2.contents("MCOS")(0).cell_value()(1 + off).cell_value()(1); | |
870 m2 = tc2.map_value(); | |
7336 | 871 |
9377
610bf90fce2a
update unwind_protect usage everywhere
Jaroslav Hajek <highegg@gmail.com>
parents:
9206
diff
changeset
|
872 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame (); |
9144
c6463412aebb
eliminate symbol_table::scope_stack; fix scoping issue with evalin
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
873 |
c6463412aebb
eliminate symbol_table::scope_stack; fix scoping issue with evalin
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
874 // 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
|
875 // 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
|
876 |
7336 | 877 symbol_table::scope_id local_scope = symbol_table::alloc_scope (); |
9396
17af7cce7d1b
yet more unwind_protect improvements
Jaroslav Hajek <highegg@gmail.com>
parents:
9395
diff
changeset
|
878 unwind_protect::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
|
879 |
c6463412aebb
eliminate symbol_table::scope_stack; fix scoping issue with evalin
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
880 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
|
881 |
c6463412aebb
eliminate symbol_table::scope_stack; fix scoping issue with evalin
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
882 octave_call_stack::push (local_scope, 0); |
9396
17af7cce7d1b
yet more unwind_protect improvements
Jaroslav Hajek <highegg@gmail.com>
parents:
9395
diff
changeset
|
883 unwind_protect::add_fcn (octave_call_stack::pop); |
7336 | 884 |
6639 | 885 if (m2.nfields() > 0) |
6625 | 886 { |
887 octave_value tmp; | |
7336 | 888 |
6625 | 889 for (Octave_map::iterator p0 = m2.begin() ; |
890 p0 != m2.end(); p0++) | |
891 { | |
892 std::string key = m2.key(p0); | |
893 octave_value val = m2.contents(p0)(0); | |
894 | |
7901 | 895 symbol_table::varref (key, local_scope, 0) = val; |
6625 | 896 } |
897 } | |
898 | |
899 int parse_status; | |
900 octave_value anon_fcn_handle = | |
901 eval_string (fname.substr (4), true, parse_status); | |
902 | |
903 if (parse_status == 0) | |
904 { | |
905 octave_fcn_handle *fh = | |
906 anon_fcn_handle.fcn_handle_value (); | |
7761
5adeea5de26c
symbol table reporting functions
John W. Eaton <jwe@octave.org>
parents:
7336
diff
changeset
|
907 |
6625 | 908 if (fh) |
7761
5adeea5de26c
symbol table reporting functions
John W. Eaton <jwe@octave.org>
parents:
7336
diff
changeset
|
909 tc = new octave_fcn_handle (fh->fcn_val (), "@<anonymous>"); |
6625 | 910 else |
911 { | |
912 error ("load: failed to load anonymous function handle"); | |
913 goto skip_ahead; | |
914 } | |
915 } | |
916 else | |
917 { | |
918 error ("load: failed to load anonymous function handle"); | |
919 goto skip_ahead; | |
920 } | |
921 | |
9377
610bf90fce2a
update unwind_protect usage everywhere
Jaroslav Hajek <highegg@gmail.com>
parents:
9206
diff
changeset
|
922 unwind_protect::run_frame (uwp_frame); |
6625 | 923 } |
924 else | |
925 { | |
926 error ("load: invalid function handle type"); | |
927 goto skip_ahead; | |
928 } | |
929 } | |
930 break; | |
931 | |
932 case MAT_FILE_WORKSPACE_CLASS: | |
933 { | |
934 Octave_map m (dim_vector (1, 1)); | |
935 int n_fields = 2; | |
936 string_vector field (n_fields); | |
937 | |
938 for (int i = 0; i < n_fields; i++) | |
939 { | |
940 int32_t fn_type; | |
941 int32_t fn_len; | |
942 if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT8) | |
943 { | |
944 error ("load: invalid field name subelement"); | |
945 goto data_read_error; | |
946 } | |
947 | |
948 OCTAVE_LOCAL_BUFFER (char, elname, fn_len + 1); | |
949 | |
950 std::streampos tmp_pos = is.tellg (); | |
951 | |
952 if (fn_len) | |
953 { | |
954 if (! is.read (elname, fn_len)) | |
955 goto data_read_error; | |
956 | |
957 is.seekg (tmp_pos + | |
958 static_cast<std::streamoff> (PAD (fn_len))); | |
959 } | |
960 | |
961 elname[fn_len] = '\0'; | |
962 | |
963 field(i) = elname; | |
964 } | |
965 | |
966 std::vector<Cell> elt (n_fields); | |
967 | |
968 for (octave_idx_type i = 0; i < n_fields; i++) | |
969 elt[i] = Cell (dims); | |
970 | |
971 octave_idx_type n = dims.numel (); | |
972 | |
973 // fields subelements | |
974 for (octave_idx_type j = 0; j < n; j++) | |
975 { | |
976 for (octave_idx_type i = 0; i < n_fields; i++) | |
977 { | |
978 if (field(i) == "MCOS") | |
979 { | |
980 octave_value fieldtc; | |
981 read_mat5_binary_element (is, filename, swap, global, | |
982 fieldtc); | |
983 if (! is || error_state) | |
984 goto data_read_error; | |
985 | |
986 elt[i](j) = fieldtc; | |
987 } | |
988 else | |
989 elt[i](j) = octave_value (); | |
990 } | |
991 } | |
992 | |
993 for (octave_idx_type i = 0; i < n_fields; i++) | |
994 m.assign (field (i), elt[i]); | |
995 tc = m; | |
996 } | |
997 break; | |
998 | |
999 case MAT_FILE_OBJECT_CLASS: | |
1000 { | |
1001 isclass = true; | |
1002 | |
1003 if (read_mat5_tag (is, swap, type, len) || type != miINT8) | |
1004 { | |
1005 error ("load: invalid class name"); | |
1006 goto skip_ahead; | |
1007 } | |
1008 | |
1009 { | |
1010 OCTAVE_LOCAL_BUFFER (char, name, len+1); | |
1011 | |
1012 std::streampos tmp_pos = is.tellg (); | |
1013 | |
1014 if (len) | |
1015 { | |
1016 if (! is.read (name, len )) | |
1017 goto data_read_error; | |
1018 | |
1019 is.seekg (tmp_pos + static_cast<std::streamoff> (PAD (len))); | |
1020 } | |
1021 | |
1022 name[len] = '\0'; | |
1023 classname = name; | |
1024 } | |
1025 } | |
1026 // Fall-through | |
5900 | 1027 case MAT_FILE_STRUCT_CLASS: |
4634 | 1028 { |
6292 | 1029 Octave_map m (dim_vector (1, 1)); |
5828 | 1030 int32_t fn_type; |
1031 int32_t fn_len; | |
1032 int32_t field_name_length; | |
4634 | 1033 |
1034 // field name length subelement -- actually the maximum length | |
1035 // of a field name. The Matlab docs promise this will always | |
1036 // be 32. We read and use the actual value, on the theory | |
1037 // that eventually someone will recognize that's a waste of | |
1038 // space. | |
1039 if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT32) | |
1040 { | |
6292 | 1041 error ("load: invalid field name length subelement"); |
4634 | 1042 goto data_read_error; |
1043 } | |
1044 | |
5760 | 1045 if (! is.read (reinterpret_cast<char *> (&field_name_length), fn_len )) |
4634 | 1046 goto data_read_error; |
1047 | |
1048 if (swap) | |
4944 | 1049 swap_bytes<4> (&field_name_length); |
4634 | 1050 |
1051 // field name subelement. The length of this subelement tells | |
1052 // us how many fields there are. | |
1053 if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT8) | |
1054 { | |
1055 error ("load: invalid field name subelement"); | |
1056 goto data_read_error; | |
1057 } | |
1058 | |
5336 | 1059 octave_idx_type n_fields = fn_len/field_name_length; |
4634 | 1060 |
6292 | 1061 if (n_fields > 0) |
1062 { | |
1063 fn_len = PAD (fn_len); | |
4634 | 1064 |
6292 | 1065 OCTAVE_LOCAL_BUFFER (char, elname, fn_len); |
4634 | 1066 |
6292 | 1067 if (! is.read (elname, fn_len)) |
1068 goto data_read_error; | |
4634 | 1069 |
6292 | 1070 std::vector<Cell> elt (n_fields); |
1071 | |
1072 for (octave_idx_type i = 0; i < n_fields; i++) | |
1073 elt[i] = Cell (dims); | |
4634 | 1074 |
6292 | 1075 octave_idx_type n = dims.numel (); |
5336 | 1076 |
6292 | 1077 // fields subelements |
1078 for (octave_idx_type j = 0; j < n; j++) | |
1079 { | |
1080 for (octave_idx_type i = 0; i < n_fields; i++) | |
1081 { | |
1082 octave_value fieldtc; | |
1083 read_mat5_binary_element (is, filename, swap, global, | |
1084 fieldtc); | |
1085 elt[i](j) = fieldtc; | |
1086 } | |
1087 } | |
4634 | 1088 |
5336 | 1089 for (octave_idx_type i = 0; i < n_fields; i++) |
4634 | 1090 { |
6292 | 1091 const char *key = elname + i*field_name_length; |
5336 | 1092 |
6292 | 1093 m.assign (key, elt[i]); |
1094 } | |
4634 | 1095 } |
1096 | |
6625 | 1097 if (isclass) |
1098 { | |
1099 if (classname == "inline") | |
1100 { | |
1101 // inline is not an object in Octave but rather an | |
1102 // overload of a function handle. Special case. | |
1103 tc = | |
1104 new octave_fcn_inline (m.contents("expr")(0).string_value(), | |
1105 m.contents("args")(0).string_value()); | |
1106 } | |
1107 else | |
1108 { | |
9206
5f36c6c9be13
Handle loading of objects with inheritance from MAT files.
Robert T. Short <octave@phaselockedsystems.com>
parents:
9203
diff
changeset
|
1109 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
|
1110 cls->reconstruct_exemplar (); |
8212
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1111 |
9206
5f36c6c9be13
Handle loading of objects with inheritance from MAT files.
Robert T. Short <octave@phaselockedsystems.com>
parents:
9203
diff
changeset
|
1112 if (! cls->reconstruct_parents ()) |
5f36c6c9be13
Handle loading of objects with inheritance from MAT files.
Robert T. Short <octave@phaselockedsystems.com>
parents:
9203
diff
changeset
|
1113 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
|
1114 |
5f36c6c9be13
Handle loading of objects with inheritance from MAT files.
Robert T. Short <octave@phaselockedsystems.com>
parents:
9203
diff
changeset
|
1115 tc = cls; |
8212
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1116 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
|
1117 std::string()) |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1118 { |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1119 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
|
1120 |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1121 if (! error_state) |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1122 tc = tmp(0); |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1123 else |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1124 goto data_read_error; |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1125 } |
6625 | 1126 } |
1127 } | |
1128 else | |
1129 tc = m; | |
4634 | 1130 } |
1131 break; | |
1132 | |
5900 | 1133 case MAT_FILE_INT8_CLASS: |
5089 | 1134 OCTAVE_MAT5_INTEGER_READ (int8NDArray); |
1135 break; | |
1136 | |
5900 | 1137 case MAT_FILE_UINT8_CLASS: |
5269 | 1138 { |
1139 OCTAVE_MAT5_INTEGER_READ (uint8NDArray); | |
1140 | |
5900 | 1141 // Logical variables can either be MAT_FILE_UINT8_CLASS or |
1142 // MAT_FILE_DOUBLE_CLASS, so check if we have a logical | |
1143 // variable and convert it. | |
5269 | 1144 |
1145 if (logicalvar) | |
1146 { | |
1147 uint8NDArray in = tc.uint8_array_value (); | |
1148 int nel = in.nelem (); | |
1149 boolNDArray out (dims); | |
1150 | |
1151 for (int i = 0; i < nel; i++) | |
7198 | 1152 out (i) = in(i).bool_value (); |
5269 | 1153 |
1154 tc = out; | |
1155 } | |
1156 } | |
5089 | 1157 break; |
1158 | |
5900 | 1159 case MAT_FILE_INT16_CLASS: |
5089 | 1160 OCTAVE_MAT5_INTEGER_READ (int16NDArray); |
1161 break; | |
1162 | |
5900 | 1163 case MAT_FILE_UINT16_CLASS: |
5089 | 1164 OCTAVE_MAT5_INTEGER_READ (uint16NDArray); |
1165 break; | |
1166 | |
5900 | 1167 case MAT_FILE_INT32_CLASS: |
5089 | 1168 OCTAVE_MAT5_INTEGER_READ (int32NDArray); |
1169 break; | |
1170 | |
5900 | 1171 case MAT_FILE_UINT32_CLASS: |
5089 | 1172 OCTAVE_MAT5_INTEGER_READ (uint32NDArray); |
1173 break; | |
1174 | |
5900 | 1175 case MAT_FILE_INT64_CLASS: |
5089 | 1176 OCTAVE_MAT5_INTEGER_READ (int64NDArray); |
1177 break; | |
1178 | |
5900 | 1179 case MAT_FILE_UINT64_CLASS: |
5089 | 1180 OCTAVE_MAT5_INTEGER_READ (uint64NDArray); |
1181 break; | |
1182 | |
5900 | 1183 case MAT_FILE_CHAR_CLASS: |
4634 | 1184 // handle as a numerical array to start with |
1185 | |
5900 | 1186 case MAT_FILE_DOUBLE_CLASS: |
1187 case MAT_FILE_SINGLE_CLASS: | |
4634 | 1188 default: |
5089 | 1189 { |
1190 NDArray re (dims); | |
4634 | 1191 |
5089 | 1192 // real data subelement |
1193 | |
4634 | 1194 std::streampos tmp_pos; |
5089 | 1195 |
4634 | 1196 if (read_mat5_tag (is, swap, type, len)) |
1197 { | |
1198 error ("load: reading matrix data for `%s'", retval.c_str ()); | |
1199 goto data_read_error; | |
1200 } | |
1201 | |
1202 int n = re.length (); | |
1203 tmp_pos = is.tellg (); | |
1204 read_mat5_binary_data (is, re.fortran_vec (), n, swap, | |
5760 | 1205 static_cast<enum mat5_data_type> (type), flt_fmt); |
4634 | 1206 |
1207 if (! is || error_state) | |
1208 { | |
1209 error ("load: reading matrix data for `%s'", retval.c_str ()); | |
1210 goto data_read_error; | |
1211 } | |
1212 | |
1213 is.seekg (tmp_pos + static_cast<std::streamoff> (PAD (len))); | |
5089 | 1214 |
5269 | 1215 if (logicalvar) |
5089 | 1216 { |
5900 | 1217 // Logical variables can either be MAT_FILE_UINT8_CLASS or |
1218 // MAT_FILE_DOUBLE_CLASS, so check if we have a logical | |
1219 // variable and convert it. | |
5269 | 1220 |
1221 boolNDArray out (dims); | |
1222 | |
1223 for (int i = 0; i < n; i++) | |
1224 out (i) = static_cast<bool> (re (i)); | |
1225 | |
1226 tc = out; | |
1227 } | |
1228 else if (imag) | |
1229 { | |
1230 // imaginary data subelement | |
1231 | |
5089 | 1232 NDArray im (dims); |
4634 | 1233 |
5089 | 1234 if (read_mat5_tag (is, swap, type, len)) |
1235 { | |
1236 error ("load: reading matrix data for `%s'", retval.c_str ()); | |
1237 goto data_read_error; | |
1238 } | |
4634 | 1239 |
5089 | 1240 n = im.length (); |
1241 read_mat5_binary_data (is, im.fortran_vec (), n, swap, | |
5760 | 1242 static_cast<enum mat5_data_type> (type), flt_fmt); |
4634 | 1243 |
5089 | 1244 if (! is || error_state) |
1245 { | |
1246 error ("load: reading imaginary matrix data for `%s'", | |
1247 retval.c_str ()); | |
1248 goto data_read_error; | |
1249 } | |
4634 | 1250 |
5089 | 1251 ComplexNDArray ctmp (dims); |
4634 | 1252 |
5089 | 1253 for (int i = 0; i < n; i++) |
1254 ctmp(i) = Complex (re(i), im(i)); | |
4634 | 1255 |
5089 | 1256 tc = ctmp; |
1257 } | |
1258 else | |
5269 | 1259 { |
5900 | 1260 if (arrayclass == MAT_FILE_CHAR_CLASS) |
5351 | 1261 { |
1262 if (type == miUTF16 || type == miUTF32) | |
1263 { | |
6954 | 1264 bool found_big_char = false; |
1265 for (int i = 0; i < n; i++) | |
1266 { | |
1267 if (re(i) > 127) { | |
1268 re(i) = '?'; | |
1269 found_big_char = true; | |
1270 } | |
1271 } | |
1272 | |
1273 if (found_big_char) | |
1274 { | |
1275 warning ("load: can not read non-ASCII portions of UTF characters."); | |
1276 warning (" Replacing unreadable characters with '?'."); | |
1277 } | |
5351 | 1278 } |
1279 else if (type == miUTF8) | |
1280 { | |
1281 // Search for multi-byte encoded UTF8 characters and | |
1282 // replace with 0x3F for '?'... Give the user a warning | |
4634 | 1283 |
5351 | 1284 bool utf8_multi_byte = false; |
1285 for (int i = 0; i < n; i++) | |
1286 { | |
5352 | 1287 unsigned char a = static_cast<unsigned char> (re(i)); |
5351 | 1288 if (a > 0x7f) |
1289 utf8_multi_byte = true; | |
1290 } | |
1291 | |
1292 if (utf8_multi_byte) | |
1293 { | |
1294 warning ("load: can not read multi-byte encoded UTF8 characters."); | |
1295 warning (" Replacing unreadable characters with '?'."); | |
1296 for (int i = 0; i < n; i++) | |
1297 { | |
5352 | 1298 unsigned char a = static_cast<unsigned char> (re(i)); |
5351 | 1299 if (a > 0x7f) |
5352 | 1300 re(i) = '?'; |
5351 | 1301 } |
1302 } | |
1303 } | |
1304 tc = re; | |
1305 tc = tc.convert_to_str (false, true, '\''); | |
1306 } | |
1307 else | |
1308 tc = re; | |
5269 | 1309 } |
5089 | 1310 } |
4634 | 1311 } |
1312 | |
1313 is.seekg (pos + static_cast<std::streamoff> (element_length)); | |
1314 | |
1315 if (is.eof ()) | |
1316 is.clear (); | |
1317 | |
1318 return retval; | |
1319 | |
1320 data_read_error: | |
1321 early_read_error: | |
1322 error ("load: trouble reading binary file `%s'", filename.c_str ()); | |
1323 return std::string (); | |
1324 | |
1325 skip_ahead: | |
1326 warning ("skipping over `%s'", retval.c_str ()); | |
1327 is.seekg (pos + static_cast<std::streamoff> (element_length)); | |
1328 return read_mat5_binary_element (is, filename, swap, global, tc); | |
1329 } | |
1330 | |
1331 int | |
6625 | 1332 read_mat5_binary_file_header (std::istream& is, bool& swap, bool quiet, |
1333 const std::string& filename) | |
4634 | 1334 { |
5828 | 1335 int16_t version=0, magic=0; |
6625 | 1336 uint64_t subsys_offset; |
1337 | |
1338 is.seekg (116, std::ios::beg); | |
1339 is.read (reinterpret_cast<char *> (&subsys_offset), 8); | |
4634 | 1340 |
1341 is.seekg (124, std::ios::beg); | |
5760 | 1342 is.read (reinterpret_cast<char *> (&version), 2); |
1343 is.read (reinterpret_cast<char *> (&magic), 2); | |
4634 | 1344 |
1345 if (magic == 0x4d49) | |
1346 swap = 0; | |
1347 else if (magic == 0x494d) | |
1348 swap = 1; | |
1349 else | |
1350 { | |
1351 if (! quiet) | |
1352 error ("load: can't read binary file"); | |
1353 return -1; | |
1354 } | |
1355 | |
1356 if (! swap) // version number is inverse swapped! | |
1357 version = ((version >> 8) & 0xff) + ((version & 0xff) << 8); | |
1358 | |
1359 if (version != 1 && !quiet) | |
1360 warning ("load: found version %d binary MAT file, " | |
1361 "but only prepared for version 1", version); | |
1362 | |
6625 | 1363 if (swap) |
1364 swap_bytes<8> (&subsys_offset, 1); | |
1365 | |
1366 if (subsys_offset != 0x2020202020202020ULL && subsys_offset != 0ULL) | |
1367 { | |
1368 // Read the subsystem data block | |
1369 is.seekg (subsys_offset, std::ios::beg); | |
1370 | |
1371 octave_value tc; | |
1372 bool global; | |
1373 read_mat5_binary_element (is, filename, swap, global, tc); | |
1374 | |
1375 if (!is || error_state) | |
1376 return -1; | |
1377 | |
1378 if (tc.is_uint8_type ()) | |
1379 { | |
1380 const uint8NDArray itmp = tc.uint8_array_value(); | |
1381 octave_idx_type ilen = itmp.nelem (); | |
1382 | |
1383 // Why should I have to initialize outbuf as just overwrite | |
1384 std::string outbuf (ilen - 7, ' '); | |
1385 | |
1386 // FIXME -- find a way to avoid casting away const here | |
1387 char *ctmp = const_cast<char *> (outbuf.c_str ()); | |
1388 for (octave_idx_type j = 8; j < ilen; j++) | |
7198 | 1389 ctmp[j-8] = itmp(j).char_value (); |
6625 | 1390 |
1391 std::istringstream fh_ws (outbuf); | |
1392 | |
1393 read_mat5_binary_element (fh_ws, filename, swap, global, subsys_ov); | |
1394 | |
1395 if (error_state) | |
1396 return -1; | |
1397 } | |
1398 else | |
1399 return -1; | |
1400 | |
1401 // Reposition to just after the header | |
1402 is.seekg (128, std::ios::beg); | |
1403 } | |
1404 | |
4634 | 1405 return 0; |
1406 } | |
1407 | |
1408 static int | |
1409 write_mat5_tag (std::ostream& is, int type, int bytes) | |
1410 { | |
5828 | 1411 int32_t temp; |
4634 | 1412 |
6292 | 1413 if (bytes > 0 && bytes <= 4) |
4634 | 1414 temp = (bytes << 16) + type; |
1415 else | |
1416 { | |
1417 temp = type; | |
5760 | 1418 if (! is.write (reinterpret_cast<char *> (&temp), 4)) |
4634 | 1419 goto data_write_error; |
1420 temp = bytes; | |
1421 } | |
1422 | |
5760 | 1423 if (! is.write (reinterpret_cast<char *> (&temp), 4)) |
4634 | 1424 goto data_write_error; |
1425 | |
1426 return 0; | |
1427 | |
1428 data_write_error: | |
1429 return 1; | |
1430 } | |
1431 | |
1432 // write out the numeric values in M to OS, | |
1433 // preceded by the appropriate tag. | |
1434 static void | |
1435 write_mat5_array (std::ostream& os, const NDArray& m, bool save_as_floats) | |
1436 { | |
1437 int nel = m.nelem (); | |
1438 double max_val, min_val; | |
1439 save_type st = LS_DOUBLE; | |
1440 mat5_data_type mst; | |
1441 int size; | |
1442 unsigned len; | |
1443 const double *data = m.data (); | |
1444 | |
1445 // Have to use copy here to avoid writing over data accessed via | |
1446 // Matrix::data(). | |
1447 | |
5760 | 1448 #define MAT5_DO_WRITE(TYPE, data, count, stream) \ |
1449 do \ | |
1450 { \ | |
1451 OCTAVE_LOCAL_BUFFER (TYPE, ptr, count); \ | |
1452 for (int i = 0; i < count; i++) \ | |
1453 ptr[i] = static_cast<TYPE> (data[i]); \ | |
1454 stream.write (reinterpret_cast<char *> (ptr), count * sizeof (TYPE)); \ | |
1455 } \ | |
4634 | 1456 while (0) |
1457 | |
1458 if (save_as_floats) | |
1459 { | |
1460 if (m.too_large_for_float ()) | |
1461 { | |
1462 warning ("save: some values too large to save as floats --"); | |
1463 warning ("save: saving as doubles instead"); | |
1464 } | |
1465 else | |
1466 st = LS_FLOAT; | |
1467 } | |
1468 | |
1469 if (m.all_integers (max_val, min_val)) | |
1470 st = get_save_type (max_val, min_val); | |
1471 | |
1472 switch (st) | |
1473 { | |
1474 default: | |
1475 case LS_DOUBLE: mst = miDOUBLE; size = 8; break; | |
1476 case LS_FLOAT: mst = miSINGLE; size = 4; break; | |
1477 case LS_U_CHAR: mst = miUINT8; size = 1; break; | |
1478 case LS_U_SHORT: mst = miUINT16; size = 2; break; | |
1479 case LS_U_INT: mst = miUINT32; size = 4; break; | |
1480 case LS_CHAR: mst = miINT8; size = 1; break; | |
1481 case LS_SHORT: mst = miINT16; size = 2; break; | |
1482 case LS_INT: mst = miINT32; size = 4; break; | |
1483 } | |
1484 | |
1485 len = nel*size; | |
1486 write_mat5_tag (os, mst, len); | |
1487 | |
1488 { | |
1489 switch (st) | |
1490 { | |
1491 case LS_U_CHAR: | |
5828 | 1492 MAT5_DO_WRITE (uint8_t, data, nel, os); |
4634 | 1493 break; |
1494 | |
1495 case LS_U_SHORT: | |
5828 | 1496 MAT5_DO_WRITE (uint16_t, data, nel, os); |
4634 | 1497 break; |
1498 | |
1499 case LS_U_INT: | |
5828 | 1500 MAT5_DO_WRITE (uint32_t, data, nel, os); |
4634 | 1501 break; |
1502 | |
1503 case LS_U_LONG: | |
5828 | 1504 MAT5_DO_WRITE (uint64_t, data, nel, os); |
4634 | 1505 break; |
1506 | |
1507 case LS_CHAR: | |
5828 | 1508 MAT5_DO_WRITE (int8_t, data, nel, os); |
4634 | 1509 break; |
1510 | |
1511 case LS_SHORT: | |
5828 | 1512 MAT5_DO_WRITE (int16_t, data, nel, os); |
4634 | 1513 break; |
1514 | |
1515 case LS_INT: | |
5828 | 1516 MAT5_DO_WRITE (int32_t, data, nel, os); |
4634 | 1517 break; |
1518 | |
1519 case LS_LONG: | |
5828 | 1520 MAT5_DO_WRITE (int64_t, data, nel, os); |
4634 | 1521 break; |
1522 | |
1523 case LS_FLOAT: | |
1524 MAT5_DO_WRITE (float, data, nel, os); | |
1525 break; | |
1526 | |
1527 case LS_DOUBLE: // No conversion necessary. | |
5760 | 1528 os.write (reinterpret_cast<const char *> (data), len); |
4634 | 1529 break; |
1530 | |
1531 default: | |
1532 (*current_liboctave_error_handler) | |
1533 ("unrecognized data format requested"); | |
1534 break; | |
1535 } | |
1536 } | |
1537 if (PAD (len) > len) | |
1538 { | |
1539 static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; | |
1540 os.write (buf, PAD (len) - len); | |
1541 } | |
1542 } | |
1543 | |
5089 | 1544 template <class T> |
1545 void | |
5164 | 1546 write_mat5_integer_data (std::ostream& os, const T *m, int size, int nel) |
5089 | 1547 { |
1548 mat5_data_type mst; | |
1549 unsigned len; | |
1550 | |
1551 switch (size) | |
1552 { | |
1553 case 1: | |
1554 mst = miUINT8; | |
1555 break; | |
1556 case 2: | |
1557 mst = miUINT16; | |
1558 break; | |
5164 | 1559 case 4: |
5089 | 1560 mst = miUINT32; |
1561 break; | |
5164 | 1562 case 8: |
5089 | 1563 mst = miUINT64; |
1564 break; | |
1565 case -1: | |
1566 mst = miINT8; | |
1567 size = - size; | |
1568 break; | |
1569 case -2: | |
1570 mst = miINT16; | |
1571 size = - size; | |
1572 break; | |
5164 | 1573 case -4: |
5089 | 1574 mst = miINT32; |
1575 size = - size; | |
1576 break; | |
5164 | 1577 case -8: |
5089 | 1578 default: |
1579 mst = miINT64; | |
1580 size = - size; | |
1581 break; | |
1582 } | |
1583 | |
1584 len = nel*size; | |
1585 write_mat5_tag (os, mst, len); | |
1586 | |
5760 | 1587 os.write (reinterpret_cast<const char *> (m), len); |
5089 | 1588 |
1589 if (PAD (len) > len) | |
1590 { | |
1591 static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; | |
1592 os.write (buf, PAD (len) - len); | |
1593 } | |
1594 } | |
1595 | |
5164 | 1596 template void write_mat5_integer_data (std::ostream& os, const octave_int8 *m, |
1597 int size, int nel); | |
1598 template void write_mat5_integer_data (std::ostream& os, const octave_int16 *m, | |
1599 int size, int nel); | |
1600 template void write_mat5_integer_data (std::ostream& os, const octave_int32 *m, | |
1601 int size, int nel); | |
1602 template void write_mat5_integer_data (std::ostream& os, const octave_int64 *m, | |
1603 int size, int nel); | |
1604 template void write_mat5_integer_data (std::ostream& os, const octave_uint8 *m, | |
1605 int size, int nel); | |
1606 template void write_mat5_integer_data (std::ostream& os, const octave_uint16 *m, | |
1607 int size, int nel); | |
1608 template void write_mat5_integer_data (std::ostream& os, const octave_uint32 *m, | |
1609 int size, int nel); | |
1610 template void write_mat5_integer_data (std::ostream& os, const octave_uint64 *m, | |
1611 int size, int nel); | |
1612 template void write_mat5_integer_data (std::ostream& os, const int *m, | |
1613 int size, int nel); | |
5089 | 1614 |
4634 | 1615 // Write out cell element values in the cell array to OS, preceded by |
1616 // the appropriate tag. | |
1617 | |
1618 static bool | |
4701 | 1619 write_mat5_cell_array (std::ostream& os, const Cell& cell, |
1620 bool mark_as_global, bool save_as_floats) | |
4634 | 1621 { |
1622 int nel = cell.nelem (); | |
1623 | |
1624 for (int i = 0; i < nel; i++) | |
1625 { | |
1626 octave_value ov = cell(i); | |
1627 | |
1628 if (! save_mat5_binary_element (os, ov, "", mark_as_global, | |
5269 | 1629 false, save_as_floats)) |
4634 | 1630 return false; |
1631 } | |
1632 | |
1633 return true; | |
1634 } | |
1635 | |
5269 | 1636 int |
1637 save_mat5_array_length (const double* val, int nel, bool save_as_floats) | |
1638 { | |
1639 if (nel > 0) | |
1640 { | |
1641 int size = 8; | |
1642 | |
1643 if (save_as_floats) | |
1644 { | |
1645 bool too_large_for_float = false; | |
1646 for (int i = 0; i < nel; i++) | |
1647 { | |
1648 double tmp = val [i]; | |
1649 | |
5389 | 1650 if (! (xisnan (tmp) || xisinf (tmp)) |
5388 | 1651 && fabs (tmp) > FLT_MAX) |
5269 | 1652 { |
1653 too_large_for_float = true; | |
1654 break; | |
1655 } | |
1656 } | |
1657 | |
1658 if (!too_large_for_float) | |
1659 size = 4; | |
1660 } | |
1661 | |
1662 // The code below is disabled since get_save_type currently doesn't | |
1663 // deal with integer types. This will need to be activated if get_save_type | |
1664 // is changed. | |
1665 | |
1666 // double max_val = val[0]; | |
1667 // double min_val = val[0]; | |
1668 // bool all_integers = true; | |
1669 // | |
1670 // for (int i = 0; i < nel; i++) | |
1671 // { | |
1672 // double val = val[i]; | |
1673 // | |
1674 // if (val > max_val) | |
1675 // max_val = val; | |
1676 // | |
1677 // if (val < min_val) | |
1678 // min_val = val; | |
1679 // | |
1680 // if (D_NINT (val) != val) | |
1681 // { | |
1682 // all_integers = false; | |
1683 // break; | |
1684 // } | |
1685 // } | |
1686 // | |
1687 // if (all_integers) | |
1688 // { | |
1689 // if (max_val < 256 && min_val > -1) | |
1690 // size = 1; | |
1691 // else if (max_val < 65536 && min_val > -1) | |
1692 // size = 2; | |
1693 // else if (max_val < 4294967295UL && min_val > -1) | |
1694 // size = 4; | |
1695 // else if (max_val < 128 && min_val >= -128) | |
1696 // size = 1; | |
1697 // else if (max_val < 32768 && min_val >= -32768) | |
1698 // size = 2; | |
1699 // else if (max_val <= 2147483647L && min_val >= -2147483647L) | |
1700 // size = 4; | |
1701 // } | |
1702 | |
1703 return 8 + nel * size; | |
1704 } | |
1705 else | |
1706 return 8; | |
1707 } | |
1708 | |
1709 int | |
1710 save_mat5_array_length (const Complex* val, int nel, bool save_as_floats) | |
1711 { | |
1712 int ret; | |
1713 | |
1714 OCTAVE_LOCAL_BUFFER (double, tmp, nel); | |
1715 | |
1716 for (int i = 1; i < nel; i++) | |
1717 tmp[i] = std::real (val[i]); | |
1718 | |
1719 ret = save_mat5_array_length (tmp, nel, save_as_floats); | |
1720 | |
1721 for (int i = 1; i < nel; i++) | |
1722 tmp[i] = std::imag (val[i]); | |
1723 | |
1724 ret += save_mat5_array_length (tmp, nel, save_as_floats); | |
1725 | |
1726 return ret; | |
1727 } | |
1728 | |
1729 int | |
1730 save_mat5_element_length (const octave_value& tc, const std::string& name, | |
1731 bool save_as_floats, bool mat7_format) | |
1732 { | |
1733 int max_namelen = (mat7_format ? 63 : 31); | |
1734 int len = name.length (); | |
1735 std::string cname = tc.class_name (); | |
1736 int ret = 32; | |
1737 | |
1738 if (len > 4) | |
1739 ret += PAD (len > max_namelen ? max_namelen : len); | |
1740 | |
1741 ret += PAD (4 * tc.ndims ()); | |
1742 | |
1743 if (tc.is_string ()) | |
1744 { | |
5933 | 1745 charNDArray chm = tc.char_array_value (); |
5384 | 1746 ret += 8; |
5933 | 1747 if (chm.nelem () > 2) |
1748 ret += PAD (2 * chm.nelem ()); | |
5269 | 1749 } |
6823 | 1750 else if (tc.is_sparse_type ()) |
5269 | 1751 { |
1752 if (tc.is_complex_type ()) | |
1753 { | |
1754 SparseComplexMatrix m = tc.sparse_complex_matrix_value (); | |
1755 int nc = m.cols (); | |
5604 | 1756 int nnz = m.nzmax (); |
5269 | 1757 |
1758 ret += 16 + PAD (nnz * sizeof (int)) + PAD ((nc + 1) * sizeof (int)) + | |
1759 save_mat5_array_length (m.data (), m.nelem (), save_as_floats); | |
1760 } | |
1761 else | |
1762 { | |
1763 SparseMatrix m = tc.sparse_matrix_value (); | |
1764 int nc = m.cols (); | |
5604 | 1765 int nnz = m.nzmax (); |
5269 | 1766 |
1767 ret += 16 + PAD (nnz * sizeof (int)) + PAD ((nc + 1) * sizeof (int)) + | |
1768 save_mat5_array_length (m.data (), m.nelem (), save_as_floats); | |
1769 } | |
1770 } | |
1771 | |
1772 #define INT_LEN(nel, size) \ | |
1773 { \ | |
1774 ret += 8; \ | |
1775 int sz = nel * size; \ | |
1776 if (sz > 4) \ | |
1777 ret += PAD (sz); \ | |
1778 } | |
1779 | |
1780 else if (cname == "int8") | |
1781 INT_LEN (tc.int8_array_value ().nelem (), 1) | |
1782 else if (cname == "int16") | |
1783 INT_LEN (tc.int16_array_value ().nelem (), 2) | |
1784 else if (cname == "int32") | |
1785 INT_LEN (tc.int32_array_value ().nelem (), 4) | |
1786 else if (cname == "int64") | |
1787 INT_LEN (tc.int64_array_value ().nelem (), 8) | |
1788 else if (cname == "uint8") | |
1789 INT_LEN (tc.uint8_array_value ().nelem (), 1) | |
1790 else if (cname == "uint16") | |
1791 INT_LEN (tc.uint16_array_value ().nelem (), 2) | |
1792 else if (cname == "uint32") | |
1793 INT_LEN (tc.uint32_array_value ().nelem (), 4) | |
1794 else if (cname == "uint64") | |
1795 INT_LEN (tc.uint64_array_value ().nelem (), 8) | |
1796 else if (tc.is_bool_type ()) | |
1797 INT_LEN (tc.bool_array_value ().nelem (), 1) | |
1798 else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ()) | |
1799 { | |
1800 NDArray m = tc.array_value (); | |
1801 ret += save_mat5_array_length (m.fortran_vec (), m.nelem (), | |
1802 save_as_floats); | |
1803 } | |
1804 else if (tc.is_cell ()) | |
1805 { | |
1806 Cell cell = tc.cell_value (); | |
1807 int nel = cell.nelem (); | |
1808 | |
1809 for (int i = 0; i < nel; i++) | |
1810 ret += 8 + | |
1811 save_mat5_element_length (cell (i), "", save_as_floats, mat7_format); | |
1812 } | |
1813 else if (tc.is_complex_scalar () || tc.is_complex_matrix ()) | |
1814 { | |
1815 ComplexNDArray m = tc.complex_array_value (); | |
1816 ret += save_mat5_array_length (m.fortran_vec (), m.nelem (), | |
1817 save_as_floats); | |
1818 } | |
8212
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1819 else if (tc.is_map () || tc.is_inline_function () || tc.is_object ()) |
5269 | 1820 { |
1821 int fieldcnt = 0; | |
1822 const Octave_map m = tc.map_value (); | |
1823 int nel = m.numel (); | |
1824 | |
6625 | 1825 if (tc.is_inline_function ()) |
1826 // length of "inline" is 6 | |
1827 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
|
1828 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
|
1829 { |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1830 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
|
1831 |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
1832 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
|
1833 } |
6625 | 1834 |
5269 | 1835 for (Octave_map::const_iterator i = m.begin (); i != m.end (); i++) |
1836 fieldcnt++; | |
1837 | |
1838 ret += 16 + fieldcnt * (max_namelen + 1); | |
1839 | |
1840 | |
1841 for (int j = 0; j < nel; j++) | |
1842 { | |
1843 | |
1844 for (Octave_map::const_iterator i = m.begin (); i != m.end (); i++) | |
1845 { | |
9203
a542fc158175
improve performance of saving large structs in MAT file format
John W. Eaton <jwe@octave.org>
parents:
9144
diff
changeset
|
1846 const Cell elts = m.contents (i); |
5269 | 1847 |
9203
a542fc158175
improve performance of saving large structs in MAT file format
John W. Eaton <jwe@octave.org>
parents:
9144
diff
changeset
|
1848 ret += 8 + save_mat5_element_length (elts(j), "", |
5269 | 1849 save_as_floats, mat7_format); |
1850 } | |
1851 } | |
1852 } | |
1853 else | |
1854 ret = -1; | |
1855 | |
1856 return ret; | |
1857 } | |
1858 | |
4634 | 1859 // save the data from TC along with the corresponding NAME on stream |
1860 // OS in the MatLab version 5 binary format. Return true on success. | |
1861 | |
1862 bool | |
1863 save_mat5_binary_element (std::ostream& os, | |
1864 const octave_value& tc, const std::string& name, | |
5269 | 1865 bool mark_as_global, bool mat7_format, |
1866 bool save_as_floats, bool compressing) | |
4634 | 1867 { |
5828 | 1868 int32_t flags=0; |
1869 int32_t nnz=0; | |
4634 | 1870 std::streampos fixup, contin; |
5089 | 1871 std::string cname = tc.class_name (); |
5269 | 1872 int max_namelen = (mat7_format ? 63 : 31); |
1873 | |
1874 #ifdef HAVE_ZLIB | |
1875 if (mat7_format && !compressing) | |
1876 { | |
1877 bool ret = false; | |
1878 | |
5765 | 1879 std::ostringstream buf; |
5269 | 1880 |
1881 // The code seeks backwards in the stream to fix the header. Can't | |
1882 // do this with zlib, so use a stringstream. | |
1883 ret = save_mat5_binary_element (buf, tc, name, mark_as_global, true, | |
1884 save_as_floats, true); | |
1885 | |
1886 if (ret) | |
1887 { | |
5351 | 1888 // destLen must be at least 0.1% larger than source buffer |
1889 // + 12 bytes. Reality is it must be larger again than that. | |
5765 | 1890 std::string buf_str = buf.str (); |
1891 uLongf srcLen = buf_str.length (); | |
5351 | 1892 uLongf destLen = srcLen * 101 / 100 + 12; |
5269 | 1893 OCTAVE_LOCAL_BUFFER (char, out_buf, destLen); |
1894 | |
5760 | 1895 if (compress (reinterpret_cast<Bytef *> (out_buf), &destLen, |
5765 | 1896 reinterpret_cast<const Bytef *> (buf_str.c_str ()), srcLen) == Z_OK) |
5269 | 1897 { |
5760 | 1898 write_mat5_tag (os, miCOMPRESSED, static_cast<int> (destLen)); |
5269 | 1899 os.write (out_buf, destLen); |
1900 } | |
1901 else | |
1902 { | |
1903 error ("save: error compressing data element"); | |
1904 ret = false; | |
1905 } | |
1906 } | |
1907 | |
1908 return ret; | |
1909 } | |
1910 #endif | |
4634 | 1911 |
1912 // element type and length | |
1913 fixup = os.tellp (); | |
5269 | 1914 write_mat5_tag (os, miMATRIX, save_mat5_element_length |
1915 (tc, name, save_as_floats, mat7_format)); | |
4634 | 1916 |
1917 // array flags subelement | |
1918 write_mat5_tag (os, miUINT32, 8); | |
1919 | |
5269 | 1920 if (tc.is_bool_type ()) |
1921 flags |= 0x0200; | |
1922 | |
4634 | 1923 if (mark_as_global) |
1924 flags |= 0x0400; | |
1925 | |
1926 if (tc.is_complex_scalar () || tc.is_complex_matrix ()) | |
1927 flags |= 0x0800; | |
1928 | |
1929 if (tc.is_string ()) | |
5900 | 1930 flags |= MAT_FILE_CHAR_CLASS; |
5089 | 1931 else if (cname == "int8") |
5900 | 1932 flags |= MAT_FILE_INT8_CLASS; |
5089 | 1933 else if (cname == "int16") |
5900 | 1934 flags |= MAT_FILE_INT16_CLASS; |
5089 | 1935 else if (cname == "int32") |
5900 | 1936 flags |= MAT_FILE_INT32_CLASS; |
5089 | 1937 else if (cname == "int64") |
5900 | 1938 flags |= MAT_FILE_INT64_CLASS; |
5269 | 1939 else if (cname == "uint8" || tc.is_bool_type ()) |
5900 | 1940 flags |= MAT_FILE_UINT8_CLASS; |
5089 | 1941 else if (cname == "uint16") |
5900 | 1942 flags |= MAT_FILE_UINT16_CLASS; |
5089 | 1943 else if (cname == "uint32") |
5900 | 1944 flags |= MAT_FILE_UINT32_CLASS; |
5089 | 1945 else if (cname == "uint64") |
5900 | 1946 flags |= MAT_FILE_UINT64_CLASS; |
6823 | 1947 else if (tc.is_sparse_type ()) |
5164 | 1948 { |
5900 | 1949 flags |= MAT_FILE_SPARSE_CLASS; |
5164 | 1950 if (tc.is_complex_type ()) |
1951 { | |
1952 SparseComplexMatrix scm = tc.sparse_complex_matrix_value (); | |
5604 | 1953 nnz = scm.nzmax (); |
5164 | 1954 } |
1955 else | |
1956 { | |
1957 SparseMatrix sm = tc.sparse_matrix_value (); | |
5604 | 1958 nnz = sm.nzmax (); |
5164 | 1959 } |
1960 } | |
4634 | 1961 else if (tc.is_real_scalar ()) |
5900 | 1962 flags |= MAT_FILE_DOUBLE_CLASS; |
4634 | 1963 else if (tc.is_real_matrix () || tc.is_range ()) |
5900 | 1964 flags |= MAT_FILE_DOUBLE_CLASS; |
4634 | 1965 else if (tc.is_complex_scalar ()) |
5900 | 1966 flags |= MAT_FILE_DOUBLE_CLASS; |
4634 | 1967 else if (tc.is_complex_matrix ()) |
5900 | 1968 flags |= MAT_FILE_DOUBLE_CLASS; |
4634 | 1969 else if (tc.is_map ()) |
5900 | 1970 flags |= MAT_FILE_STRUCT_CLASS; |
4634 | 1971 else if (tc.is_cell ()) |
5900 | 1972 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
|
1973 else if (tc.is_inline_function () || tc.is_object ()) |
6625 | 1974 flags |= MAT_FILE_OBJECT_CLASS; |
4634 | 1975 else |
1976 { | |
1977 gripe_wrong_type_arg ("save", tc, false); | |
1978 goto error_cleanup; | |
1979 } | |
1980 | |
5760 | 1981 os.write (reinterpret_cast<char *> (&flags), 4); |
1982 os.write (reinterpret_cast<char *> (&nnz), 4); | |
4634 | 1983 |
1984 { | |
1985 dim_vector dv = tc.dims (); | |
1986 int nd = tc.ndims (); | |
4638 | 1987 int dim_len = 4*nd; |
4634 | 1988 |
4638 | 1989 write_mat5_tag (os, miINT32, dim_len); |
4634 | 1990 |
1991 for (int i = 0; i < nd; i++) | |
1992 { | |
5828 | 1993 int32_t n = dv(i); |
5760 | 1994 os.write (reinterpret_cast<char *> (&n), 4); |
4634 | 1995 } |
4638 | 1996 |
1997 if (PAD (dim_len) > dim_len) | |
1998 { | |
1999 static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; | |
2000 os.write (buf, PAD (dim_len) - dim_len); | |
2001 } | |
4634 | 2002 } |
2003 | |
2004 // array name subelement | |
2005 { | |
2006 int namelen = name.length (); | |
2007 | |
5269 | 2008 if (namelen > max_namelen) |
2009 namelen = max_namelen; // only 31 or 63 char names permitted in mat file | |
4634 | 2010 |
2011 int paddedlength = PAD (namelen); | |
2012 | |
2013 write_mat5_tag (os, miINT8, namelen); | |
2014 OCTAVE_LOCAL_BUFFER (char, paddedname, paddedlength); | |
2015 memset (paddedname, 0, paddedlength); | |
2016 strncpy (paddedname, name.c_str (), namelen); | |
2017 os.write (paddedname, paddedlength); | |
2018 } | |
2019 | |
2020 // data element | |
2021 if (tc.is_string ()) | |
2022 { | |
5933 | 2023 charNDArray chm = tc.char_array_value (); |
2024 int nel = chm.nelem (); | |
2025 int len = nel*2; | |
2026 int paddedlength = PAD (len); | |
4634 | 2027 |
5933 | 2028 OCTAVE_LOCAL_BUFFER (int16_t, buf, nel+3); |
4634 | 2029 write_mat5_tag (os, miUINT16, len); |
2030 | |
5933 | 2031 const char *s = chm.data (); |
4634 | 2032 |
5933 | 2033 for (int i = 0; i < nel; i++) |
2034 buf[i] = *s++ & 0x00FF; | |
2035 | |
2036 os.write (reinterpret_cast<char *> (buf), len); | |
4634 | 2037 |
2038 if (paddedlength > len) | |
5933 | 2039 { |
2040 static char padbuf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; | |
2041 os.write (padbuf, paddedlength - len); | |
2042 } | |
4634 | 2043 } |
6823 | 2044 else if (tc.is_sparse_type ()) |
5164 | 2045 { |
2046 if (tc.is_complex_type ()) | |
2047 { | |
2048 SparseComplexMatrix m = tc.sparse_complex_matrix_value (); | |
2049 int nc = m.cols (); | |
2050 | |
5941 | 2051 int tmp = sizeof (int); |
2052 | |
2053 write_mat5_integer_data (os, m.ridx (), -tmp, nnz); | |
2054 write_mat5_integer_data (os, m.cidx (), -tmp, nc + 1); | |
5164 | 2055 |
2056 NDArray buf (dim_vector (nnz, 1)); | |
2057 | |
2058 for (int i = 0; i < nnz; i++) | |
5261 | 2059 buf (i) = std::real (m.data (i)); |
5164 | 2060 |
2061 write_mat5_array (os, buf, save_as_floats); | |
2062 | |
2063 for (int i = 0; i < nnz; i++) | |
5261 | 2064 buf (i) = std::imag (m.data (i)); |
5164 | 2065 |
2066 write_mat5_array (os, buf, save_as_floats); | |
2067 } | |
2068 else | |
2069 { | |
2070 SparseMatrix m = tc.sparse_matrix_value (); | |
2071 int nc = m.cols (); | |
2072 | |
5941 | 2073 int tmp = sizeof (int); |
2074 | |
2075 write_mat5_integer_data (os, m.ridx (), -tmp, nnz); | |
2076 write_mat5_integer_data (os, m.cidx (), -tmp, nc + 1); | |
5164 | 2077 |
5775 | 2078 // FIXME |
5164 | 2079 // Is there a way to easily do without this buffer |
2080 NDArray buf (dim_vector (nnz, 1)); | |
2081 | |
2082 for (int i = 0; i < nnz; i++) | |
2083 buf (i) = m.data (i); | |
2084 | |
2085 write_mat5_array (os, buf, save_as_floats); | |
2086 } | |
2087 } | |
5089 | 2088 else if (cname == "int8") |
2089 { | |
2090 int8NDArray m = tc.int8_array_value (); | |
2091 | |
5164 | 2092 write_mat5_integer_data (os, m.fortran_vec (), -1, m.nelem ()); |
5089 | 2093 } |
2094 else if (cname == "int16") | |
2095 { | |
2096 int16NDArray m = tc.int16_array_value (); | |
2097 | |
5164 | 2098 write_mat5_integer_data (os, m.fortran_vec (), -2, m.nelem ()); |
5089 | 2099 } |
2100 else if (cname == "int32") | |
2101 { | |
2102 int32NDArray m = tc.int32_array_value (); | |
2103 | |
5164 | 2104 write_mat5_integer_data (os, m.fortran_vec (), -4, m.nelem ()); |
5089 | 2105 } |
2106 else if (cname == "int64") | |
2107 { | |
2108 int64NDArray m = tc.int64_array_value (); | |
2109 | |
5164 | 2110 write_mat5_integer_data (os, m.fortran_vec (), -8, m.nelem ()); |
5089 | 2111 } |
2112 else if (cname == "uint8") | |
2113 { | |
2114 uint8NDArray m = tc.uint8_array_value (); | |
2115 | |
5164 | 2116 write_mat5_integer_data (os, m.fortran_vec (), 1, m.nelem ()); |
5089 | 2117 } |
2118 else if (cname == "uint16") | |
2119 { | |
2120 uint16NDArray m = tc.uint16_array_value (); | |
2121 | |
5164 | 2122 write_mat5_integer_data (os, m.fortran_vec (), 2, m.nelem ()); |
5089 | 2123 } |
2124 else if (cname == "uint32") | |
2125 { | |
2126 uint32NDArray m = tc.uint32_array_value (); | |
2127 | |
5164 | 2128 write_mat5_integer_data (os, m.fortran_vec (), 4, m.nelem ()); |
5089 | 2129 } |
2130 else if (cname == "uint64") | |
2131 { | |
2132 uint64NDArray m = tc.uint64_array_value (); | |
2133 | |
5164 | 2134 write_mat5_integer_data (os, m.fortran_vec (), 8, m.nelem ()); |
5089 | 2135 } |
5269 | 2136 else if (tc.is_bool_type ()) |
2137 { | |
2138 uint8NDArray m (tc.bool_array_value ()); | |
2139 | |
2140 write_mat5_integer_data (os, m.fortran_vec (), 1, m.nelem ()); | |
2141 } | |
4634 | 2142 else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ()) |
2143 { | |
2144 NDArray m = tc.array_value (); | |
2145 | |
2146 write_mat5_array (os, m, save_as_floats); | |
2147 } | |
2148 else if (tc.is_cell ()) | |
2149 { | |
2150 Cell cell = tc.cell_value (); | |
2151 | |
2152 if (! write_mat5_cell_array (os, cell, mark_as_global, save_as_floats)) | |
2153 goto error_cleanup; | |
2154 } | |
2155 else if (tc.is_complex_scalar () || tc.is_complex_matrix ()) | |
2156 { | |
5269 | 2157 ComplexNDArray m_cmplx = tc.complex_array_value (); |
4634 | 2158 |
2159 write_mat5_array (os, ::real (m_cmplx), save_as_floats); | |
2160 write_mat5_array (os, ::imag (m_cmplx), save_as_floats); | |
2161 } | |
8212
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2162 else if (tc.is_map () || tc.is_inline_function() || tc.is_object ()) |
4634 | 2163 { |
8212
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2164 if (tc.is_inline_function () || tc.is_object ()) |
6625 | 2165 { |
8212
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2166 std::string classname = tc.is_object() ? tc.class_name () : "inline"; |
6625 | 2167 int namelen = classname.length (); |
2168 | |
2169 if (namelen > max_namelen) | |
2170 namelen = max_namelen; // only 31 or 63 char names permitted | |
2171 | |
2172 int paddedlength = PAD (namelen); | |
2173 | |
2174 write_mat5_tag (os, miINT8, namelen); | |
2175 OCTAVE_LOCAL_BUFFER (char, paddedname, paddedlength); | |
2176 memset (paddedname, 0, paddedlength); | |
2177 strncpy (paddedname, classname.c_str (), namelen); | |
2178 os.write (paddedname, paddedlength); | |
2179 } | |
2180 | |
8212
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2181 Octave_map m; |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2182 |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2183 if (tc.is_object () && |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2184 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
|
2185 { |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2186 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
|
2187 if (! error_state) |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2188 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
|
2189 else |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2190 goto error_cleanup; |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2191 } |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2192 else |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2193 m = tc.map_value (); |
ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
David Bateman <dbateman@free.fr>
parents:
8007
diff
changeset
|
2194 |
4634 | 2195 // an Octave structure */ |
2196 // recursively write each element of the structure | |
2197 { | |
5269 | 2198 char buf[64]; |
5828 | 2199 int32_t maxfieldnamelength = max_namelen + 1; |
4634 | 2200 |
8907
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2201 octave_idx_type nf = m.nfields (); |
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2202 |
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2203 int fieldcnt = nf; |
4634 | 2204 |
2205 write_mat5_tag (os, miINT32, 4); | |
5760 | 2206 os.write (reinterpret_cast<char *> (&maxfieldnamelength), 4); |
5269 | 2207 write_mat5_tag (os, miINT8, fieldcnt*maxfieldnamelength); |
4634 | 2208 |
8907
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2209 // 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
|
2210 // the fields. |
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2211 string_vector keys = m.keys (); |
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2212 |
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2213 for (octave_idx_type i = 0; i < nf; i++) |
4634 | 2214 { |
8907
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2215 std::string key = keys(i); |
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2216 |
4634 | 2217 // write the name of each element |
5269 | 2218 memset (buf, 0, max_namelen + 1); |
8907
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2219 // only 31 or 63 char names permitted |
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2220 strncpy (buf, key.c_str (), max_namelen); |
5269 | 2221 os.write (buf, max_namelen + 1); |
4634 | 2222 } |
2223 | |
2224 int len = m.numel (); | |
2225 | |
9203
a542fc158175
improve performance of saving large structs in MAT file format
John W. Eaton <jwe@octave.org>
parents:
9144
diff
changeset
|
2226 // 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
|
2227 // 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
|
2228 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
|
2229 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
|
2230 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
|
2231 |
5058 | 2232 for (int j = 0; j < len; j++) |
4634 | 2233 { |
2234 // write the data of each element | |
2235 | |
8907
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2236 // 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
|
2237 // of the fields. |
5a956c026b6c
preserve field order when saving structs
John W. Eaton <jwe@octave.org>
parents:
8377
diff
changeset
|
2238 for (octave_idx_type i = 0; i < nf; i++) |
4634 | 2239 { |
9203
a542fc158175
improve performance of saving large structs in MAT file format
John W. Eaton <jwe@octave.org>
parents:
9144
diff
changeset
|
2240 bool retval2 = save_mat5_binary_element (os, elts[i][j], "", |
4634 | 2241 mark_as_global, |
5269 | 2242 false, |
4634 | 2243 save_as_floats); |
2244 if (! retval2) | |
2245 goto error_cleanup; | |
2246 } | |
2247 } | |
2248 } | |
2249 } | |
2250 else | |
2251 gripe_wrong_type_arg ("save", tc, false); | |
2252 | |
2253 contin = os.tellp (); | |
2254 | |
2255 return true; | |
2256 | |
2257 error_cleanup: | |
2258 error ("save: error while writing `%s' to MAT file", name.c_str ()); | |
2259 | |
2260 return false; | |
2261 } | |
2262 | |
2263 /* | |
2264 ;;; Local Variables: *** | |
2265 ;;; mode: C++ *** | |
2266 ;;; End: *** | |
2267 */ | |
2268 |