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