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