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