GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
ls-oct-binary.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-2026 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 "mach-info.h"
39#include "mappers.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-classdef.h"
54#include "ov.h"
55#include "pager.h"
56#include "sysdep.h"
57#include "utils.h"
58#include "variables.h"
59#include "version.h"
60
61static bool
62load_inline_fcn (std::istream& is, bool swap, octave::mach_info::float_format,
63 octave_value& retval)
64{
65 int32_t nargs;
66 if (! is.read (reinterpret_cast<char *> (&nargs), 4))
67 return false;
68 if (swap)
69 swap_bytes<4> (&nargs);
70
71 if (nargs < 1)
72 return false;
73 else
74 {
75 int32_t tmp;
76 octave_value_list args (nargs+1);
77 for (int i = 0; i < nargs; i++)
78 {
79 if (! is.read (reinterpret_cast<char *> (&tmp), 4))
80 return false;
81 if (swap)
82 swap_bytes<4> (&tmp);
83
84 OCTAVE_LOCAL_BUFFER (char, ctmp, tmp+1);
85 is.read (ctmp, tmp);
86 args(i+1) = std::string (ctmp);
87
88 if (! is)
89 return false;
90 }
91
92 if (! is.read (reinterpret_cast<char *> (&tmp), 4))
93 return false;
94 if (swap)
95 swap_bytes<4> (&tmp);
96
97 OCTAVE_LOCAL_BUFFER (char, ctmp1, tmp+1);
98 is.read (ctmp1, tmp);
99 // NAME is obsolete and unused.
100 // std::string name (ctmp1);
101
102 if (! is)
103 return false;
104
105 if (! is.read (reinterpret_cast<char *> (&tmp), 4))
106 return false;
107 if (swap)
108 swap_bytes<4> (&tmp);
109
110 OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
111 is.read (ctmp2, tmp);
112
113 if (is)
114 {
115 args(0) = std::string (ctmp2);
116
117 octave::interpreter& interp = octave::__get_interpreter__ ();
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
196std::string
197read_binary_data (std::istream& is, bool swap,
198 octave::mach_info::float_format fmt,
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 = octave::__get_type_info__ ();
251
252 // All cases except 255 kept for backwards compatibility
253 switch (tmp)
254 {
255 case 1:
256 tc = type_info.lookup_type ("scalar");
257 break;
258
259 case 2:
260 tc = type_info.lookup_type ("matrix");
261 break;
262
263 case 3:
264 tc = type_info.lookup_type ("complex scalar");
265 break;
266
267 case 4:
268 tc = type_info.lookup_type ("complex matrix");
269 break;
270
271 case 5:
272 {
273 // FIXME:
274 // This is cruft, since its for a save type that is old.
275 // Maybe this is taking backward compatibility too far!
276 int32_t len;
277 if (! is.read (reinterpret_cast<char *> (&len), 4))
278 error ("load: trouble reading binary file '%s'", filename.c_str ());
279 if (swap)
281 OCTAVE_LOCAL_BUFFER (char, s, len+1);
282 if (! is.read (reinterpret_cast<char *> (s), len))
283 error ("load: trouble reading binary file '%s'", filename.c_str ());
284 s[len] = '\0';
285 tc = s;
286
287 // Early return, since don't want rest of this function
288 return retval;
289 }
290 break;
291
292 case 6:
293 tc = type_info.lookup_type ("range");
294 break;
295
296 case 7:
297 tc = type_info.lookup_type ("string");
298 break;
299
300 case 255:
301 {
302 // Read the saved variable type
303 int32_t len;
304 if (! is.read (reinterpret_cast<char *> (&len), 4))
305 error ("load: trouble reading binary file '%s'", filename.c_str ());
306 if (swap)
308 OCTAVE_LOCAL_BUFFER (char, s, len+1);
309 if (! is.read (s, len))
310 error ("load: trouble reading binary file '%s'", filename.c_str ());
311 s[len] = '\0';
312 std::string typ = s;
313
314 if (typ == "inline function")
315 {
316 // Special case for loading old octave_inline_fcn objects.
317 if (! load_inline_fcn (is, swap, fmt, tc))
318 error ("load: trouble reading binary file '%s'", filename.c_str ());
319 return retval;
320 }
321
322 tc = type_info.lookup_type (typ);
323 }
324 break;
325 default:
326 error ("load: trouble reading binary file '%s'", filename.c_str ());
327 break;
328 }
329
330 if (! tc.load_binary (is, swap, fmt))
331 error ("load: trouble reading binary file '%s'", filename.c_str ());
332
333 return retval;
334}
335
336// Save the data from TC along with the corresponding NAME, help
337// string DOC, and global flag MARK_AS_GLOBAL on stream OS in the
338// binary format described above for read_binary_data.
339
340bool
341save_binary_data (std::ostream& os, const octave_value& tc_in,
342 const std::string& name, const std::string& doc,
343 bool mark_global, bool save_as_floats)
344{
345 octave_value tc;
346 if (tc_in.is_classdef_object ())
347 {
348 warning_with_id ("Octave:save:classdef:unsupported",
349 "Saving classdef objects is not supported. "
350 "Attempting to save '%s' as struct.",
351 name.c_str ());
352 tc = tc_in.classdef_object_value ()->map_value (false, false);
353 }
354 else
355 tc = tc_in;
356
357 constexpr octave_idx_type max_dim_val = std::numeric_limits<int32_t>::max () - 1;
358
359 dim_vector dv = tc.dims ();
360 if (dv.ndims () > max_dim_val)
361 {
362 warning_with_id ("Octave:save:dimension-too-large",
363 "save: skipping %s: number of dimensions too large for binary format",
364 name.c_str ());
365 return true;
366 }
367
368 for (octave_idx_type i_dim = 0; i_dim < dv.ndims (); i_dim++)
369 {
370 if (dv(i_dim) > max_dim_val)
371 {
372 warning_with_id ("Octave:save:dimension-too-large",
373 "save: skipping %s: dimensions too large for binary format",
374 name.c_str ());
375 return true;
376 }
377 }
378
379 int32_t name_len = name.length ();
380
381 os.write (reinterpret_cast<char *> (&name_len), 4);
382 os << name;
383
384 int32_t doc_len = doc.length ();
385
386 os.write (reinterpret_cast<char *> (&doc_len), 4);
387 os << doc;
388
389 unsigned char tmp;
390
391 tmp = mark_global;
392 os.write (reinterpret_cast<char *> (&tmp), 1);
393
394 // 255 flags the new binary format
395 tmp = 255;
396 os.write (reinterpret_cast<char *> (&tmp), 1);
397
398 // Write the string corresponding to the octave_value type
399 std::string typ = tc.type_name ();
400 int32_t len = typ.length ();
401 os.write (reinterpret_cast<char *> (&len), 4);
402 const char *btmp = typ.data ();
403 os.write (btmp, len);
404
405 // The octave_value of tc is const. Make a copy...
406 octave_value val = tc;
407
408 // Call specific save function
409 bool success = val.save_binary (os, save_as_floats);
410
411 return (os && success);
412}
void swap_bytes< 4 >(void *ptr)
Definition byte-swap.h:63
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:92
octave_idx_type ndims() const
Number of dimensions.
Definition dim-vector.h:263
octave_map map_value() const
octave_idx_type length() const
Definition ovl.h:111
bool is_classdef_object() const
Definition ov.h:653
octave_classdef * classdef_object_value(bool silent=false) const
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format fmt)
bool save_binary(std::ostream &os, bool save_as_floats)
Definition ov.h:1383
std::string type_name() const
Definition ov.h:1358
dim_vector dims() const
Definition ov.h:539
octave_value lookup_type(const std::string &nm)
void warning_with_id(const char *id, const char *fmt,...)
Definition error.cc:1098
void error(const char *fmt,...)
Definition error.cc:1008
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_in, const std::string &name, const std::string &doc, bool mark_global, bool save_as_floats)
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition oct-locbuf.h:44
F77_RET_T len
Definition xerbla.cc:61