GNU Octave  8.1.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-2023 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,
62  octave_value& retval)
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 = octave::__get_interpreter__ ();
117 
118  octave_value_list tmp_inl = interp.feval ("inline", args, 1);
119 
120  if (tmp_inl.length () > 0)
121  {
122  retval = tmp_inl(0);
123  return true;
124  }
125  }
126  }
127 
128  return false;
129 }
130 
131 // Extract one value (scalar, matrix, string, etc.) from stream IS and
132 // place it in TC, returning the name of the variable. If the value
133 // is tagged as global in the file, return TRUE in GLOBAL. If SWAP
134 // is TRUE, swap bytes after reading.
135 //
136 // The data is expected to be in the following format:
137 //
138 // Header (one per file):
139 // =====================
140 //
141 // object type bytes
142 // ------ ---- -----
143 // magic number string 10
144 //
145 // float format integer 1
146 //
147 //
148 // Data (one set for each item):
149 // ============================
150 //
151 // object type bytes
152 // ------ ---- -----
153 // name_length integer 4
154 //
155 // name string name_length
156 //
157 // doc_length integer 4
158 //
159 // doc string doc_length
160 //
161 // global flag integer 1
162 //
163 // data type char 1
164 //
165 // In general "data type" is 255, and in that case the next arguments
166 // in the data set are
167 //
168 // object type bytes
169 // ------ ---- -----
170 // type_length integer 4
171 //
172 // type string type_length
173 //
174 // The string "type" is then used with octave::type_info::lookup_type
175 // to create an octave_value of the correct type. The specific load/save
176 // function is then called.
177 //
178 // For backward compatibility "data type" can also be a value between 1
179 // and 7, where this defines a hardcoded octave_value of the type
180 //
181 // data type octave_value
182 // --------- ------------
183 // 1 scalar
184 // 2 matrix
185 // 3 complex scalar
186 // 4 complex matrix
187 // 5 string (old style storage)
188 // 6 range
189 // 7 string
190 //
191 // Except for "data type" equal 5 that requires special treatment, these
192 // old style "data type" value also cause the specific load/save functions
193 // to be called. FILENAME is used for error messages.
194 
195 std::string
196 read_binary_data (std::istream& is, bool swap,
198  const std::string& filename, bool& global,
199  octave_value& tc, std::string& doc)
200 {
201  std::string retval;
202 
203  unsigned char tmp = 0;
204 
205  int32_t name_len = 0;
206  int32_t doc_len = 0;
207 
208  doc.clear ();
209 
210  // We expect to fail here, at the beginning of a record, so not
211  // being able to read another name should not result in an error.
212 
213  is.read (reinterpret_cast<char *> (&name_len), 4);
214  if (! is)
215  return retval;
216  if (swap)
217  swap_bytes<4> (&name_len);
218 
219  {
220  OCTAVE_LOCAL_BUFFER (char, name, name_len+1);
221  name[name_len] = '\0';
222  if (! is.read (reinterpret_cast<char *> (name), name_len))
223  error ("load: trouble reading binary file '%s'", filename.c_str ());
224  retval = name;
225  }
226 
227  is.read (reinterpret_cast<char *> (&doc_len), 4);
228  if (! is)
229  error ("load: trouble reading binary file '%s'", filename.c_str ());
230  if (swap)
231  swap_bytes<4> (&doc_len);
232 
233  {
234  OCTAVE_LOCAL_BUFFER (char, tdoc, doc_len+1);
235  tdoc[doc_len] = '\0';
236  if (! is.read (reinterpret_cast<char *> (tdoc), doc_len))
237  error ("load: trouble reading binary file '%s'", filename.c_str ());
238  doc = tdoc;
239  }
240 
241  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
242  error ("load: trouble reading binary file '%s'", filename.c_str ());
243  global = (tmp ? 1 : 0);
244 
245  tmp = 0;
246  if (! is.read (reinterpret_cast<char *> (&tmp), 1))
247  error ("load: trouble reading binary file '%s'", filename.c_str ());
248 
249  octave::type_info& type_info = octave::__get_type_info__ ();
250 
251  // All cases except 255 kept for backwards compatibility
252  switch (tmp)
253  {
254  case 1:
255  tc = type_info.lookup_type ("scalar");
256  break;
257 
258  case 2:
259  tc = type_info.lookup_type ("matrix");
260  break;
261 
262  case 3:
263  tc = type_info.lookup_type ("complex scalar");
264  break;
265 
266  case 4:
267  tc = type_info.lookup_type ("complex matrix");
268  break;
269 
270  case 5:
271  {
272  // FIXME:
273  // This is cruft, since its for a save type that is old.
274  // Maybe this is taking backward compatibility too far!
275  int32_t len;
276  if (! is.read (reinterpret_cast<char *> (&len), 4))
277  error ("load: trouble reading binary file '%s'", filename.c_str ());
278  if (swap)
279  swap_bytes<4> (&len);
280  OCTAVE_LOCAL_BUFFER (char, s, len+1);
281  if (! is.read (reinterpret_cast<char *> (s), len))
282  error ("load: trouble reading binary file '%s'", filename.c_str ());
283  s[len] = '\0';
284  tc = s;
285 
286  // Early return, since don't want rest of this function
287  return retval;
288  }
289  break;
290 
291  case 6:
292  tc = type_info.lookup_type ("range");
293  break;
294 
295  case 7:
296  tc = type_info.lookup_type ("string");
297  break;
298 
299  case 255:
300  {
301  // Read the saved variable type
302  int32_t len;
303  if (! is.read (reinterpret_cast<char *> (&len), 4))
304  error ("load: trouble reading binary file '%s'", filename.c_str ());
305  if (swap)
306  swap_bytes<4> (&len);
307  OCTAVE_LOCAL_BUFFER (char, s, len+1);
308  if (! is.read (s, len))
309  error ("load: trouble reading binary file '%s'", filename.c_str ());
310  s[len] = '\0';
311  std::string typ = s;
312 
313  if (typ == "inline function")
314  {
315  // Special case for loading old octave_inline_fcn objects.
316  if (! load_inline_fcn (is, swap, fmt, tc))
317  error ("load: trouble reading binary file '%s'", filename.c_str ());
318  return retval;
319  }
320 
321  tc = type_info.lookup_type (typ);
322  }
323  break;
324  default:
325  error ("load: trouble reading binary file '%s'", filename.c_str ());
326  break;
327  }
328 
329  if (! tc.load_binary (is, swap, fmt))
330  error ("load: trouble reading binary file '%s'", filename.c_str ());
331 
332  return retval;
333 }
334 
335 // Save the data from TC along with the corresponding NAME, help
336 // string DOC, and global flag MARK_AS_GLOBAL on stream OS in the
337 // binary format described above for read_binary_data.
338 
339 bool
340 save_binary_data (std::ostream& os, const octave_value& tc,
341  const std::string& name, const std::string& doc,
342  bool mark_global, bool save_as_floats)
343 {
344  int32_t name_len = name.length ();
345 
346  os.write (reinterpret_cast<char *> (&name_len), 4);
347  os << name;
348 
349  int32_t doc_len = doc.length ();
350 
351  os.write (reinterpret_cast<char *> (&doc_len), 4);
352  os << doc;
353 
354  unsigned char tmp;
355 
356  tmp = mark_global;
357  os.write (reinterpret_cast<char *> (&tmp), 1);
358 
359  // 255 flags the new binary format
360  tmp = 255;
361  os.write (reinterpret_cast<char *> (&tmp), 1);
362 
363  // Write the string corresponding to the octave_value type
364  std::string typ = tc.type_name ();
365  int32_t len = typ.length ();
366  os.write (reinterpret_cast<char *> (&len), 4);
367  const char *btmp = typ.data ();
368  os.write (btmp, len);
369 
370  // The octave_value of tc is const. Make a copy...
371  octave_value val = tc;
372 
373  // Call specific save function
374  bool success = val.save_binary (os, save_as_floats);
375 
376  return (os && success);
377 }
void swap_bytes< 4 >(void *ptr)
Definition: byte-swap.h:63
octave_idx_type length(void) const
Definition: ovl.h:113
bool save_binary(std::ostream &os, bool save_as_floats)
Definition: ov.h:1494
OCTINTERP_API bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
std::string type_name(void) const
Definition: ov.h:1452
octave_value lookup_type(const std::string &nm)
Definition: ov-typeinfo.cc:481
void error(const char *fmt,...)
Definition: error.cc:979
interpreter & __get_interpreter__(void)
type_info & __get_type_info__(void)
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)
float_format
Definition: mach-info.h:38
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
F77_RET_T len
Definition: xerbla.cc:61