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