GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
ls-oct-binary.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 John W. Eaton
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
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
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
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <cfloat>
28 #include <cstring>
29 #include <cctype>
30 
31 #include <fstream>
32 #include <iomanip>
33 #include <iostream>
34 #include <string>
35 #include <vector>
36 
37 #include "byte-swap.h"
38 #include "data-conv.h"
39 #include "file-ops.h"
40 #include "glob-match.h"
41 #include "lo-mappers.h"
42 #include "mach-info.h"
43 #include "oct-env.h"
44 #include "oct-time.h"
45 #include "quit.h"
46 #include "str-vec.h"
47 #include "oct-locbuf.h"
48 
49 #include "Cell.h"
50 #include "defun.h"
51 #include "error.h"
52 #include "gripes.h"
53 #include "load-save.h"
54 #include "oct-obj.h"
55 #include "oct-map.h"
56 #include "ov-cell.h"
57 #include "pager.h"
58 #include "pt-exp.h"
59 #include "sysdep.h"
60 #include "unwind-prot.h"
61 #include "utils.h"
62 #include "variables.h"
63 #include "version.h"
64 #include "dMatrix.h"
65 
66 #include "ls-utils.h"
67 #include "ls-oct-binary.h"
68 
69 // Extract one value (scalar, matrix, string, etc.) from stream IS and
70 // place it in TC, returning the name of the variable. If the value
71 // is tagged as global in the file, return TRUE in GLOBAL. If SWAP
72 // is TRUE, swap bytes after reading.
73 //
74 // The data is expected to be in the following format:
75 //
76 // Header (one per file):
77 // =====================
78 //
79 // object type bytes
80 // ------ ---- -----
81 // magic number string 10
82 //
83 // float format integer 1
84 //
85 //
86 // Data (one set for each item):
87 // ============================
88 //
89 // object type bytes
90 // ------ ---- -----
91 // name_length integer 4
92 //
93 // name string name_length
94 //
95 // doc_length integer 4
96 //
97 // doc string doc_length
98 //
99 // global flag integer 1
100 //
101 // data type char 1
102 //
103 // In general "data type" is 255, and in that case the next arguments
104 // in the data set are
105 //
106 // object type bytes
107 // ------ ---- -----
108 // type_length integer 4
109 //
110 // type string type_length
111 //
112 // The string "type" is then used with octave_value_typeinfo::lookup_type
113 // to create an octave_value of the correct type. The specific load/save
114 // function is then called.
115 //
116 // For backward compatiablity "data type" can also be a value between 1
117 // and 7, where this defines a hardcoded octave_value of the type
118 //
119 // data type octave_value
120 // --------- ------------
121 // 1 scalar
122 // 2 matrix
123 // 3 complex scalar
124 // 4 complex matrix
125 // 5 string (old style storage)
126 // 6 range
127 // 7 string
128 //
129 // Except for "data type" equal 5 that requires special treatment, these
130 // old style "data type" value also cause the specific load/save functions
131 // to be called. FILENAME is used for error messages.
132 
133 std::string
134 read_binary_data (std::istream& is, bool swap,
136  const std::string& filename, bool& global,
137  octave_value& tc, std::string& doc)
138 {
139  std::string retval;
140 
141  unsigned char tmp = 0;
142 
143  int32_t name_len = 0;
144  int32_t doc_len = 0;
145 
146  doc.resize (0);
147 
148  // We expect to fail here, at the beginning of a record, so not
149  // being able to read another name should not result in an error.
150 
151  is.read (reinterpret_cast<char *> (&name_len), 4);
152  if (! is)
153  return retval;
154  if (swap)
155  swap_bytes<4> (&name_len);
156 
157  {
158  OCTAVE_LOCAL_BUFFER (char, name, name_len+1);
159  name[name_len] = '\0';
160  if (! is.read (reinterpret_cast<char *> (name), name_len))
161  goto data_read_error;
162  retval = name;
163  }
164 
165  is.read (reinterpret_cast<char *> (&doc_len), 4);
166  if (! is)
167  goto data_read_error;
168  if (swap)
169  swap_bytes<4> (&doc_len);
170 
171  {
172  OCTAVE_LOCAL_BUFFER (char, tdoc, doc_len+1);
173  tdoc[doc_len] = '\0';
174  if (! is.read (reinterpret_cast<char *> (tdoc), doc_len))
175  goto data_read_error;
176  doc = tdoc;
177  }
178 
179  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
180  goto data_read_error;
181  global = tmp ? 1 : 0;
182 
183  tmp = 0;
184  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
185  goto data_read_error;
186 
187  // All cases except 255 kept for backwards compatibility
188  switch (tmp)
189  {
190  case 1:
191  tc = octave_value_typeinfo::lookup_type ("scalar");
192  break;
193 
194  case 2:
195  tc = octave_value_typeinfo::lookup_type ("matrix");
196  break;
197 
198  case 3:
199  tc = octave_value_typeinfo::lookup_type ("complex scalar");
200  break;
201 
202  case 4:
203  tc = octave_value_typeinfo::lookup_type ("complex matrix");
204  break;
205 
206  case 5:
207  {
208  // FIXME:
209  // This is cruft, since its for a save type that is old. Maybe
210  // this is taking backward compatability too far!!
211  int32_t len;
212  if (! is.read (reinterpret_cast<char *> (&len), 4))
213  goto data_read_error;
214  if (swap)
215  swap_bytes<4> (&len);
216  OCTAVE_LOCAL_BUFFER (char, s, len+1);
217  if (! is.read (reinterpret_cast<char *> (s), len))
218  goto data_read_error;
219  s[len] = '\0';
220  tc = s;
221 
222  // Early return, since don't want rest of this function
223  return retval;
224  }
225  break;
226 
227  case 6:
228  tc = octave_value_typeinfo::lookup_type ("range");
229  break;
230 
231  case 7:
232  tc = octave_value_typeinfo::lookup_type ("string");
233  break;
234 
235  case 255:
236  {
237  // Read the saved variable type
238  int32_t len;
239  if (! is.read (reinterpret_cast<char *> (&len), 4))
240  goto data_read_error;
241  if (swap)
242  swap_bytes<4> (&len);
243  OCTAVE_LOCAL_BUFFER (char, s, len+1);
244  if (! is.read (s, len))
245  goto data_read_error;
246  s[len] = '\0';
247  std::string typ = s;
249  }
250  break;
251  default:
252  goto data_read_error;
253  break;
254  }
255 
256  if (!tc.load_binary (is, swap, fmt))
257  {
258  data_read_error:
259  error ("load: trouble reading binary file '%s'", filename.c_str ());
260  }
261 
262  return retval;
263 }
264 
265 // Save the data from TC along with the corresponding NAME, help
266 // string DOC, and global flag MARK_AS_GLOBAL on stream OS in the
267 // binary format described above for read_binary_data.
268 
269 bool
270 save_binary_data (std::ostream& os, const octave_value& tc,
271  const std::string& name, const std::string& doc,
272  bool mark_as_global, bool save_as_floats)
273 {
274  int32_t name_len = name.length ();
275 
276  os.write (reinterpret_cast<char *> (&name_len), 4);
277  os << name;
278 
279  int32_t doc_len = doc.length ();
280 
281  os.write (reinterpret_cast<char *> (&doc_len), 4);
282  os << doc;
283 
284  unsigned char tmp;
285 
286  tmp = mark_as_global;
287  os.write (reinterpret_cast<char *> (&tmp), 1);
288 
289  // 255 flags the new binary format
290  tmp = 255;
291  os.write (reinterpret_cast<char *> (&tmp), 1);
292 
293  // Write the string corresponding to the octave_value type
294  std::string typ = tc.type_name ();
295  int32_t len = typ.length ();
296  os.write (reinterpret_cast<char *> (&len), 4);
297  const char *btmp = typ.data ();
298  os.write (btmp, len);
299 
300  // The octave_value of tc is const. Make a copy...
301  octave_value val = tc;
302 
303  // Call specific save function
304  bool success = val.save_binary (os, save_as_floats);
305 
306  return (os && success);
307 }