1 /*
2 
3 Copyright (C) 2016-2019 Olaf Till <i7tiol@t-online.de>
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 
20 #include <octave/oct.h>
21 
22 #include <octave/load-save.h>
23 
24 #include <octave/byte-swap.h>
25 
26 #include <octave/ls-mat4.h>
27 
28 #include "error-helpers.h"
29 
30 DEFUN_DLD (bytea2var, args, nout,
31            "-*- texinfo -*-\n\
32 @deftypefn {Loadable Function} {} bytea2var (@var{value}, @dots{})\n\
33 Restore variable values from uint8 arrays generated with @code{var2bytea}.\n\
34 \n\
35 Returns as many output variables as input variables are given.\n\
36 \n\
37 @seealso{var2bytea}\n\
38 @end deftypefn")
39 {
40   std::string fname ("bytea2var");
41 
42   octave_idx_type nargs = args.length ();
43 
44   octave_idx_type nvars = nout < nargs ? nout : nargs;
45 
46   octave_value_list retval (nvars);
47 
48   bool err = false;
49 
50   octave_idx_type i;
51 
52   for (i = 0; i < nvars; i++)
53     {
54       uint8NDArray m;
55 
56       octave_value val;
57 
58       CHECK_ERROR (m = args(i).uint8_array_value (), retval,
59                    "%s: could not convert argument %li to uint8 array",
60                    fname.c_str (), i + 1);
61 
62       octave_idx_type nel = m.numel ();
63 
64       std::string s ((char *) m.fortran_vec (), nel);
65 
66       std::istringstream is (s);
67 
68       bool swap;
69       OCTAVE__MACH_INFO::float_format flt_fmt;
70 
71       /*
72         slightly changed from load-save.cc (read_binary_file_header())
73         to reduce storage size
74       */
75 
76       const int magic_len = 2;
77       char magic[magic_len+1];
78       is.read (magic, magic_len);
79       magic[magic_len] = '\0';
80 
81       if (strncmp (magic, "1L", magic_len) == 0)
82         swap = OCTAVE__MACH_INFO::words_big_endian ();
83       else if (strncmp (magic, "1B", magic_len) == 0)
84         swap = ! OCTAVE__MACH_INFO::words_big_endian ();
85       else
86         {
87           error ("%s: could not read binary header", fname.c_str ());
88 
89           return retval;
90         }
91 
92       char tmp = 0;
93       is.read (&tmp, 1);
94 
95       flt_fmt = mopt_digit_to_float_format (tmp);
96 
97       if (flt_fmt == OCTAVE__MACH_INFO::flt_fmt_unknown)
98         {
99           error ("%s: unrecognized binary format", fname.c_str ());
100 
101           return retval;
102         }
103 
104       int32_t len;
105       if (! is.read (reinterpret_cast<char *> (&len), 4))
106         {
107           err = true;
108 
109           break;
110         }
111 
112       if (swap)
113         swap_bytes<4> (&len);
114 
115       {
116         OCTAVE_LOCAL_BUFFER (char, buf, len+1);
117         if (! is.read (buf, len))
118           {
119             err = true;
120 
121             break;
122           }
123         buf[len] = '\0';
124         std::string typ (buf);
125         val = octave_value_typeinfo::lookup_type (typ);
126       }
127 
128       if (! val.load_binary (is, swap, flt_fmt))
129         {
130           err = true;
131 
132           break;
133         }
134 
135       retval(i) = val;
136     }
137 
138   if (err)
139     error ("%s: could not load variable %li", fname.c_str (), i + 1);
140 
141   return retval;
142 }
143