GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ls-oct-binary.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <istream>
31 #include <ostream>
32 #include <string>
33 
34 #include "byte-swap.h"
35 #include "data-conv.h"
36 #include "file-ops.h"
37 #include "glob-match.h"
38 #include "lo-mappers.h"
39 #include "mach-info.h"
40 #include "oct-env.h"
41 #include "oct-locbuf.h"
42 #include "oct-time.h"
43 
44 #include "defun.h"
45 #include "error.h"
46 #include "errwarn.h"
47 #include "interpreter.h"
48 #include "interpreter-private.h"
49 #include "load-save.h"
50 #include "ls-oct-binary.h"
51 #include "ls-utils.h"
52 #include "ov-cell.h"
53 #include "ov.h"
54 #include "pager.h"
55 #include "sysdep.h"
56 #include "utils.h"
57 #include "variables.h"
58 #include "version.h"
59 
60 static bool
61 load_inline_fcn (std::istream& is, bool swap, octave::mach_info::float_format,
63 {
64  int32_t nargs;
65  if (! is.read (reinterpret_cast<char *> (&nargs), 4))
66  return false;
67  if (swap)
68  swap_bytes<4> (&nargs);
69 
70  if (nargs < 1)
71  return false;
72  else
73  {
74  int32_t tmp;
75  octave_value_list args (nargs+1);
76  for (int i = 0; i < nargs; i++)
77  {
78  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
79  return false;
80  if (swap)
81  swap_bytes<4> (&tmp);
82 
83  OCTAVE_LOCAL_BUFFER (char, ctmp, tmp+1);
84  is.read (ctmp, tmp);
85  args(i+1) = std::string (ctmp);
86 
87  if (! is)
88  return false;
89  }
90 
91  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
92  return false;
93  if (swap)
94  swap_bytes<4> (&tmp);
95 
96  OCTAVE_LOCAL_BUFFER (char, ctmp1, tmp+1);
97  is.read (ctmp1, tmp);
98  // NAME is obsolete and unused.
99  // std::string name (ctmp1);
100 
101  if (! is)
102  return false;
103 
104  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
105  return false;
106  if (swap)
107  swap_bytes<4> (&tmp);
108 
109  OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
110  is.read (ctmp2, tmp);
111 
112  if (is)
113  {
114  args(0) = std::string (ctmp2);
115 
116  octave::interpreter& interp
117  = octave::__get_interpreter__ ("load_inline_fcn");
118 
119  octave_value_list tmp_inl = interp.feval ("inline", args, 1);
120 
121  if (tmp_inl.length () > 0)
122  {
123  retval = tmp_inl(0);
124  return true;
125  }
126  }
127  }
128 
129  return false;
130 }
131 
132 // Extract one value (scalar, matrix, string, etc.) from stream IS and
133 // place it in TC, returning the name of the variable. If the value
134 // is tagged as global in the file, return TRUE in GLOBAL. If SWAP
135 // is TRUE, swap bytes after reading.
136 //
137 // The data is expected to be in the following format:
138 //
139 // Header (one per file):
140 // =====================
141 //
142 // object type bytes
143 // ------ ---- -----
144 // magic number string 10
145 //
146 // float format integer 1
147 //
148 //
149 // Data (one set for each item):
150 // ============================
151 //
152 // object type bytes
153 // ------ ---- -----
154 // name_length integer 4
155 //
156 // name string name_length
157 //
158 // doc_length integer 4
159 //
160 // doc string doc_length
161 //
162 // global flag integer 1
163 //
164 // data type char 1
165 //
166 // In general "data type" is 255, and in that case the next arguments
167 // in the data set are
168 //
169 // object type bytes
170 // ------ ---- -----
171 // type_length integer 4
172 //
173 // type string type_length
174 //
175 // The string "type" is then used with octave::type_info::lookup_type
176 // to create an octave_value of the correct type. The specific load/save
177 // function is then called.
178 //
179 // For backward compatibility "data type" can also be a value between 1
180 // and 7, where this defines a hardcoded octave_value of the type
181 //
182 // data type octave_value
183 // --------- ------------
184 // 1 scalar
185 // 2 matrix
186 // 3 complex scalar
187 // 4 complex matrix
188 // 5 string (old style storage)
189 // 6 range
190 // 7 string
191 //
192 // Except for "data type" equal 5 that requires special treatment, these
193 // old style "data type" value also cause the specific load/save functions
194 // to be called. FILENAME is used for error messages.
195 
196 std::string
197 read_binary_data (std::istream& is, bool swap,
199  const std::string& filename, bool& global,
200  octave_value& tc, std::string& doc)
201 {
202  std::string retval;
203 
204  unsigned char tmp = 0;
205 
206  int32_t name_len = 0;
207  int32_t doc_len = 0;
208 
209  doc.clear ();
210 
211  // We expect to fail here, at the beginning of a record, so not
212  // being able to read another name should not result in an error.
213 
214  is.read (reinterpret_cast<char *> (&name_len), 4);
215  if (! is)
216  return retval;
217  if (swap)
218  swap_bytes<4> (&name_len);
219 
220  {
221  OCTAVE_LOCAL_BUFFER (char, name, name_len+1);
222  name[name_len] = '\0';
223  if (! is.read (reinterpret_cast<char *> (name), name_len))
224  error ("load: trouble reading binary file '%s'", filename.c_str ());
225  retval = name;
226  }
227 
228  is.read (reinterpret_cast<char *> (&doc_len), 4);
229  if (! is)
230  error ("load: trouble reading binary file '%s'", filename.c_str ());
231  if (swap)
232  swap_bytes<4> (&doc_len);
233 
234  {
235  OCTAVE_LOCAL_BUFFER (char, tdoc, doc_len+1);
236  tdoc[doc_len] = '\0';
237  if (! is.read (reinterpret_cast<char *> (tdoc), doc_len))
238  error ("load: trouble reading binary file '%s'", filename.c_str ());
239  doc = tdoc;
240  }
241 
242  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
243  error ("load: trouble reading binary file '%s'", filename.c_str ());
244  global = (tmp ? 1 : 0);
245 
246  tmp = 0;
247  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
248  error ("load: trouble reading binary file '%s'", filename.c_str ());
249 
250  octave::type_info& type_info
251  = octave::__get_type_info__ ("read_binary_data");
252 
253  // All cases except 255 kept for backwards compatibility
254  switch (tmp)
255  {
256  case 1:
257  tc = type_info.lookup_type ("scalar");
258  break;
259 
260  case 2:
261  tc = type_info.lookup_type ("matrix");
262  break;
263 
264  case 3:
265  tc = type_info.lookup_type ("complex scalar");
266  break;
267 
268  case 4:
269  tc = type_info.lookup_type ("complex matrix");
270  break;
271 
272  case 5:
273  {
274  // FIXME:
275  // This is cruft, since its for a save type that is old.
276  // Maybe this is taking backward compatibility too far!
277  int32_t len;
278  if (! is.read (reinterpret_cast<char *> (&len), 4))
279  error ("load: trouble reading binary file '%s'", filename.c_str ());
280  if (swap)
281  swap_bytes<4> (&len);
282  OCTAVE_LOCAL_BUFFER (char, s, len+1);
283  if (! is.read (reinterpret_cast<char *> (s), len))
284  error ("load: trouble reading binary file '%s'", filename.c_str ());
285  s[len] = '\0';
286  tc = s;
287 
288  // Early return, since don't want rest of this function
289  return retval;
290  }
291  break;
292 
293  case 6:
294  tc = type_info.lookup_type ("range");
295  break;
296 
297  case 7:
298  tc = type_info.lookup_type ("string");
299  break;
300 
301  case 255:
302  {
303  // Read the saved variable type
304  int32_t len;
305  if (! is.read (reinterpret_cast<char *> (&len), 4))
306  error ("load: trouble reading binary file '%s'", filename.c_str ());
307  if (swap)
308  swap_bytes<4> (&len);
309  OCTAVE_LOCAL_BUFFER (char, s, len+1);
310  if (! is.read (s, len))
311  error ("load: trouble reading binary file '%s'", filename.c_str ());
312  s[len] = '\0';
313  std::string typ = s;
314 
315  if (typ == "inline function")
316  {
317  // Special case for loading old octave_inline_fcn objects.
318  if (! load_inline_fcn (is, swap, fmt, tc))
319  error ("load: trouble reading binary file '%s'", filename.c_str ());
320  return retval;
321  }
322 
323  tc = type_info.lookup_type (typ);
324  }
325  break;
326  default:
327  error ("load: trouble reading binary file '%s'", filename.c_str ());
328  break;
329  }
330 
331  if (! tc.load_binary (is, swap, fmt))
332  error ("load: trouble reading binary file '%s'", filename.c_str ());
333 
334  return retval;
335 }
336 
337 // Save the data from TC along with the corresponding NAME, help
338 // string DOC, and global flag MARK_AS_GLOBAL on stream OS in the
339 // binary format described above for read_binary_data.
340 
341 bool
342 save_binary_data (std::ostream& os, const octave_value& tc,
343  const std::string& name, const std::string& doc,
344  bool mark_global, bool save_as_floats)
345 {
346  int32_t name_len = name.length ();
347 
348  os.write (reinterpret_cast<char *> (&name_len), 4);
349  os << name;
350 
351  int32_t doc_len = doc.length ();
352 
353  os.write (reinterpret_cast<char *> (&doc_len), 4);
354  os << doc;
355 
356  unsigned char tmp;
357 
358  tmp = mark_global;
359  os.write (reinterpret_cast<char *> (&tmp), 1);
360 
361  // 255 flags the new binary format
362  tmp = 255;
363  os.write (reinterpret_cast<char *> (&tmp), 1);
364 
365  // Write the string corresponding to the octave_value type
366  std::string typ = tc.type_name ();
367  int32_t len = typ.length ();
368  os.write (reinterpret_cast<char *> (&len), 4);
369  const char *btmp = typ.data ();
370  os.write (btmp, len);
371 
372  // The octave_value of tc is const. Make a copy...
373  octave_value val = tc;
374 
375  // Call specific save function
376  bool success = val.save_binary (os, save_as_floats);
377 
378  return (os && success);
379 }
void swap_bytes< 4 >(void *ptr)
Definition: byte-swap.h:63
void clear(void)
Definition: Array.cc:87
octave_value_list feval(const char *name, const octave_value_list &args=octave_value_list(), int nargout=0)
Evaluate an Octave function (built-in or interpreted) and return the list of result values.
octave_value lookup_type(const std::string &nm)
Definition: ov-typeinfo.cc:479
octave_idx_type length(void) const
Definition: ovl.h:113
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
Definition: ov.h:1306
bool save_binary(std::ostream &os, bool save_as_floats)
Definition: ov.h:1303
std::string type_name(void) const
Definition: ov.h:1254
void error(const char *fmt,...)
Definition: error.cc:968
QString name
std::string read_binary_data(std::istream &is, bool swap, octave::mach_info::float_format fmt, const std::string &filename, bool &global, octave_value &tc, std::string &doc)
bool save_binary_data(std::ostream &os, const octave_value &tc, const std::string &name, const std::string &doc, bool mark_global, bool save_as_floats)
static bool load_inline_fcn(std::istream &is, bool swap, octave::mach_info::float_format, octave_value &retval)
type_info & __get_type_info__(const std::string &who)
interpreter & __get_interpreter__(const std::string &who)
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
F77_RET_T len
Definition: xerbla.cc:61