1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2004-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 // This file should not include config.h.  It is only included in other
27 // C++ source files that should have included config.h before including
28 // this file.
29 
30 #include <istream>
31 #include <limits>
32 #include <ostream>
33 #include <sstream>
34 #include <vector>
35 
36 #include "dNDArray.h"
37 #include "fNDArray.h"
38 #include "int8NDArray.h"
39 #include "int16NDArray.h"
40 #include "int32NDArray.h"
41 #include "int64NDArray.h"
42 #include "uint8NDArray.h"
43 #include "uint16NDArray.h"
44 #include "uint32NDArray.h"
45 #include "uint64NDArray.h"
46 
47 #include "lo-ieee.h"
48 #include "lo-utils.h"
49 #include "mx-base.h"
50 #include "quit.h"
51 #include "oct-locbuf.h"
52 
53 #include "defun.h"
54 #include "errwarn.h"
55 #include "ovl.h"
56 #include "oct-lvalue.h"
57 #include "oct-hdf5.h"
58 #include "oct-stream.h"
59 #include "ops.h"
60 #include "ov-base.h"
61 #include "ov-base-mat.h"
62 #include "ov-base-mat.cc"
63 #include "ov-base-scalar.h"
64 #include "ov-base-scalar.cc"
65 #include "ov-base-int.h"
66 #include "ov-int-traits.h"
67 #include "pr-output.h"
68 #include "variables.h"
69 
70 #include "byte-swap.h"
71 #include "ls-oct-text.h"
72 #include "ls-utils.h"
73 #include "ls-hdf5.h"
74 
75 // We have all the machinery below (octave_base_int_helper and
76 // octave_base_int_helper_traits) to avoid a few warnings from GCC
77 // about comparisons always false due to limited range of data types.
78 // Ugh.  The cure may be worse than the disease.
79 
80 template <typename T, bool is_signed = true, bool can_be_too_big = true>
81 struct octave_base_int_helper
82 {
83   static bool
char_value_out_of_rangeoctave_base_int_helper84   char_value_out_of_range (T val)
85   {
86     return val < 0 || val > std::numeric_limits<unsigned char>::max ();
87   }
88 };
89 
90 template <typename T>
91 struct octave_base_int_helper<T, false, false>
92 {
char_value_out_of_rangeoctave_base_int_helper93   static bool char_value_out_of_range (T) { return false; }
94 };
95 
96 template <typename T>
97 struct octave_base_int_helper<T, false, true>
98 {
char_value_out_of_rangeoctave_base_int_helper99   static bool char_value_out_of_range (T val)
100   {
101     return val > std::numeric_limits<unsigned char>::max ();
102   }
103 };
104 
105 template <typename T>
106 struct octave_base_int_helper<T, true, false>
107 {
char_value_out_of_rangeoctave_base_int_helper108   static bool char_value_out_of_range (T val) { return val < 0; }
109 };
110 
111 // For all types other than char, signed char, and unsigned char, we
112 // assume that the upper limit for the range of allowable values is
113 // larger than the range for unsigned char.  If that's not true, we
114 // are still OK, but will see the warnings again for any other types
115 // that do not meet this assumption.
116 
117 template <typename T>
118 struct octave_base_int_helper_traits
119 {
120   static const bool can_be_larger_than_uchar_max = true;
121 };
122 
123 template <>
124 struct octave_base_int_helper_traits<char>
125 {
126   static const bool can_be_larger_than_uchar_max = false;
127 };
128 
129 template <>
130 struct octave_base_int_helper_traits<signed char>
131 {
132   static const bool can_be_larger_than_uchar_max = false;
133 };
134 
135 template <>
136 struct octave_base_int_helper_traits<unsigned char>
137 {
138   static const bool can_be_larger_than_uchar_max = false;
139 };
140 
141 template <typename T>
142 octave_base_value *
try_narrowing_conversion(void)143 octave_base_int_matrix<T>::try_narrowing_conversion (void)
144 {
145   octave_base_value *retval = nullptr;
146 
147   if (this->matrix.numel () == 1)
148     retval = new typename octave_value_int_traits<T>::scalar_type
149                (this->matrix (0));
150 
151   return retval;
152 }
153 
154 template <typename T>
155 octave_value
convert_to_str_internal(bool,bool,char type) const156 octave_base_int_matrix<T>::convert_to_str_internal (bool, bool, char type) const
157 {
158   octave_value retval;
159   dim_vector dv = this->dims ();
160   octave_idx_type nel = dv.numel ();
161 
162   charNDArray chm (dv);
163 
164   bool warned = false;
165 
166   for (octave_idx_type i = 0; i < nel; i++)
167     {
168       octave_quit ();
169 
170       typename T::element_type tmp = this->matrix(i);
171 
172       typedef typename T::element_type::val_type val_type;
173 
174       val_type ival = tmp.value ();
175 
176       static const bool is_signed = std::numeric_limits<val_type>::is_signed;
177       static const bool can_be_larger_than_uchar_max
178         = octave_base_int_helper_traits<val_type>::can_be_larger_than_uchar_max;
179 
180       if (octave_base_int_helper<val_type, is_signed,
181           can_be_larger_than_uchar_max>::char_value_out_of_range (ival))
182         {
183           // FIXME: is there something better we could do?
184 
185           ival = 0;
186 
187           if (! warned)
188             {
189               ::warning ("range error for conversion to character value");
190               warned = true;
191             }
192         }
193       else
194         chm (i) = static_cast<char> (ival);
195     }
196 
197   retval = octave_value (chm, type);
198 
199   return retval;
200 }
201 
202 template <typename MT>
203 octave_value
as_double(void) const204 octave_base_int_matrix<MT>::as_double (void) const
205 {
206   return NDArray (this->matrix);
207 }
208 
209 template <typename MT>
210 octave_value
as_single(void) const211 octave_base_int_matrix<MT>::as_single (void) const
212 {
213   return FloatNDArray (this->matrix);
214 }
215 
216 template <typename MT>
217 octave_value
as_int8(void) const218 octave_base_int_matrix<MT>::as_int8 (void) const
219 {
220   return int8NDArray (this->matrix);
221 }
222 
223 template <typename MT>
224 octave_value
as_int16(void) const225 octave_base_int_matrix<MT>::as_int16 (void) const
226 {
227   return int16NDArray (this->matrix);
228 }
229 
230 template <typename MT>
231 octave_value
as_int32(void) const232 octave_base_int_matrix<MT>::as_int32 (void) const
233 {
234   return int32NDArray (this->matrix);
235 }
236 
237 template <typename MT>
238 octave_value
as_int64(void) const239 octave_base_int_matrix<MT>::as_int64 (void) const
240 {
241   return int64NDArray (this->matrix);
242 }
243 
244 template <typename MT>
245 octave_value
as_uint8(void) const246 octave_base_int_matrix<MT>::as_uint8 (void) const
247 {
248   return uint8NDArray (this->matrix);
249 }
250 
251 template <typename MT>
252 octave_value
as_uint16(void) const253 octave_base_int_matrix<MT>::as_uint16 (void) const
254 {
255   return uint16NDArray (this->matrix);
256 }
257 
258 template <typename MT>
259 octave_value
as_uint32(void) const260 octave_base_int_matrix<MT>::as_uint32 (void) const
261 {
262   return uint32NDArray (this->matrix);
263 }
264 
265 template <typename MT>
266 octave_value
as_uint64(void) const267 octave_base_int_matrix<MT>::as_uint64 (void) const
268 {
269   return uint64NDArray (this->matrix);
270 }
271 
272 template <typename T>
273 std::string
edit_display(const float_display_format & fmt,octave_idx_type i,octave_idx_type j) const274 octave_base_int_matrix<T>::edit_display (const float_display_format& fmt,
275                                          octave_idx_type i,
276                                          octave_idx_type j) const
277 {
278   std::ostringstream buf;
279   octave_print_internal (buf, fmt, this->matrix(i,j));
280   return buf.str ();
281 }
282 
283 template <typename T>
284 bool
save_ascii(std::ostream & os)285 octave_base_int_matrix<T>::save_ascii (std::ostream& os)
286 {
287   dim_vector dv = this->dims ();
288 
289   os << "# ndims: " << dv.ndims () << "\n";
290 
291   for (int i = 0; i < dv.ndims (); i++)
292     os << ' ' << dv(i);
293 
294   os << "\n" << this->matrix;
295 
296   return true;
297 }
298 
299 template <typename T>
300 bool
load_ascii(std::istream & is)301 octave_base_int_matrix<T>::load_ascii (std::istream& is)
302 {
303   int mdims = 0;
304 
305   if (! extract_keyword (is, "ndims", mdims, true))
306     error ("load: failed to extract number of dimensions");
307 
308   if (mdims < 0)
309     error ("load: failed to extract number of rows and columns");
310 
311   dim_vector dv;
312   dv.resize (mdims);
313 
314   for (int i = 0; i < mdims; i++)
315     is >> dv(i);
316 
317   T tmp(dv);
318 
319   is >> tmp;
320 
321   if (! is)
322     error ("load: failed to load matrix constant");
323 
324   this->matrix = tmp;
325 
326   return true;
327 }
328 
329 template <typename T>
330 bool
save_binary(std::ostream & os,bool)331 octave_base_int_matrix<T>::save_binary (std::ostream& os, bool)
332 {
333   dim_vector dv = this->dims ();
334   if (dv.ndims () < 1)
335     return false;
336 
337   // Use negative value for ndims to differentiate with old format!!
338   int32_t tmp = - dv.ndims ();
339   os.write (reinterpret_cast<char *> (&tmp), 4);
340   for (int i=0; i < dv.ndims (); i++)
341     {
342       tmp = dv(i);
343       os.write (reinterpret_cast<char *> (&tmp), 4);
344     }
345 
346   os.write (reinterpret_cast<const char *> (this->matrix.data ()),
347             this->byte_size ());
348 
349   return true;
350 }
351 
352 template <typename T>
353 bool
load_binary(std::istream & is,bool swap,octave::mach_info::float_format)354 octave_base_int_matrix<T>::load_binary (std::istream& is, bool swap,
355                                         octave::mach_info::float_format)
356 {
357   int32_t mdims;
358   if (! is.read (reinterpret_cast<char *> (&mdims), 4))
359     return false;
360   if (swap)
361     swap_bytes<4> (&mdims);
362   if (mdims >= 0)
363     return false;
364 
365   mdims = - mdims;
366   int32_t di;
367   dim_vector dv;
368   dv.resize (mdims);
369 
370   for (int i = 0; i < mdims; i++)
371     {
372       if (! is.read (reinterpret_cast<char *> (&di), 4))
373         return false;
374       if (swap)
375         swap_bytes<4> (&di);
376       dv(i) = di;
377     }
378 
379   // Convert an array with a single dimension to be a row vector.
380   // Octave should never write files like this, other software
381   // might.
382 
383   if (mdims == 1)
384     {
385       mdims = 2;
386       dv.resize (mdims);
387       dv(1) = dv(0);
388       dv(0) = 1;
389     }
390 
391   T m (dv);
392 
393   if (! is.read (reinterpret_cast<char *> (m.fortran_vec ()), m.byte_size ()))
394     return false;
395 
396   if (swap)
397     {
398       int nel = dv.numel ();
399       int bytes = nel / m.byte_size ();
400       for (int i = 0; i < nel; i++)
401         switch (bytes)
402           {
403           case 8:
404             swap_bytes<8> (&m(i));
405             break;
406           case 4:
407             swap_bytes<4> (&m(i));
408             break;
409           case 2:
410             swap_bytes<2> (&m(i));
411             break;
412           case 1:
413           default:
414             break;
415           }
416     }
417 
418   this->matrix = m;
419   return true;
420 }
421 
422 template <typename T>
423 bool
save_hdf5_internal(octave_hdf5_id loc_id,octave_hdf5_id save_type,const char * name,bool)424 octave_base_int_matrix<T>::save_hdf5_internal (octave_hdf5_id loc_id,
425                                                octave_hdf5_id save_type,
426                                                const char *name, bool)
427 {
428   bool retval = false;
429 
430 #if defined (HAVE_HDF5)
431 
432   hid_t save_type_hid = save_type;
433   dim_vector dv = this->dims ();
434   int empty = save_hdf5_empty (loc_id, name, dv);
435   if (empty)
436     return (empty > 0);
437 
438   int rank = dv.ndims ();
439   hid_t space_hid, data_hid;
440   space_hid = data_hid = -1;
441   OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
442 
443   // Octave uses column-major, while HDF5 uses row-major ordering
444   for (int i = 0; i < rank; i++)
445     hdims[i] = dv(rank-i-1);
446 
447   space_hid = H5Screate_simple (rank, hdims, nullptr);
448 
449   if (space_hid < 0) return false;
450 #if defined (HAVE_HDF5_18)
451   data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
452                         octave_H5P_DEFAULT, octave_H5P_DEFAULT, octave_H5P_DEFAULT);
453 #else
454   data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
455                         octave_H5P_DEFAULT);
456 #endif
457   if (data_hid < 0)
458     {
459       H5Sclose (space_hid);
460       return false;
461     }
462 
463   retval = H5Dwrite (data_hid, save_type_hid, octave_H5S_ALL, octave_H5S_ALL,
464                      octave_H5P_DEFAULT, this->matrix.data ()) >= 0;
465 
466   H5Dclose (data_hid);
467   H5Sclose (space_hid);
468 
469 #else
470   octave_unused_parameter (loc_id);
471   octave_unused_parameter (save_type);
472   octave_unused_parameter (name);
473 
474   this->warn_save ("hdf5");
475 #endif
476 
477   return retval;
478 }
479 
480 template <typename T>
481 bool
load_hdf5_internal(octave_hdf5_id loc_id,octave_hdf5_id save_type,const char * name)482 octave_base_int_matrix<T>::load_hdf5_internal (octave_hdf5_id loc_id,
483                                                octave_hdf5_id save_type,
484                                                const char *name)
485 {
486   bool retval = false;
487 
488 #if defined (HAVE_HDF5)
489 
490   hid_t save_type_hid = save_type;
491   dim_vector dv;
492   int empty = load_hdf5_empty (loc_id, name, dv);
493   if (empty > 0)
494     this->matrix.resize (dv);
495   if (empty)
496     return (empty > 0);
497 
498 #if defined (HAVE_HDF5_18)
499   hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT);
500 #else
501   hid_t data_hid = H5Dopen (loc_id, name);
502 #endif
503   hid_t space_id = H5Dget_space (data_hid);
504 
505   hsize_t rank = H5Sget_simple_extent_ndims (space_id);
506 
507   if (rank < 1)
508     {
509       H5Sclose (space_id);
510       H5Dclose (data_hid);
511       return false;
512     }
513 
514   OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
515   OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
516 
517   H5Sget_simple_extent_dims (space_id, hdims, maxdims);
518 
519   // Octave uses column-major, while HDF5 uses row-major ordering
520   if (rank == 1)
521     {
522       dv.resize (2);
523       dv(0) = 1;
524       dv(1) = hdims[0];
525     }
526   else
527     {
528       dv.resize (rank);
529       for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
530         dv(j) = hdims[i];
531     }
532 
533   T m (dv);
534   if (H5Dread (data_hid, save_type_hid, octave_H5S_ALL, octave_H5S_ALL,
535                octave_H5P_DEFAULT, m.fortran_vec ()) >= 0)
536     {
537       retval = true;
538       this->matrix = m;
539     }
540 
541   H5Sclose (space_id);
542   H5Dclose (data_hid);
543 
544 #else
545   octave_unused_parameter (loc_id);
546   octave_unused_parameter (save_type);
547   octave_unused_parameter (name);
548 
549   this->warn_load ("hdf5");
550 #endif
551 
552   return retval;
553 }
554 
555 template <typename T>
556 void
print_raw(std::ostream & os,bool pr_as_read_syntax) const557 octave_base_int_matrix<T>::print_raw (std::ostream& os,
558                                       bool pr_as_read_syntax) const
559 {
560   octave_print_internal (os, this->matrix, pr_as_read_syntax,
561                          this->current_print_indent_level ());
562 }
563 
564 template <typename T>
565 octave_value
convert_to_str_internal(bool,bool,char type) const566 octave_base_int_scalar<T>::convert_to_str_internal (bool, bool, char type) const
567 {
568   octave_value retval;
569 
570   T tmp = this->scalar;
571 
572   typedef typename T::val_type val_type;
573 
574   val_type ival = tmp.value ();
575 
576   static const bool is_signed = std::numeric_limits<val_type>::is_signed;
577   static const bool can_be_larger_than_uchar_max
578     = octave_base_int_helper_traits<val_type>::can_be_larger_than_uchar_max;
579 
580   if (octave_base_int_helper<val_type, is_signed,
581       can_be_larger_than_uchar_max>::char_value_out_of_range (ival))
582     {
583       // FIXME: is there something better we could do?
584 
585       ival = 0;
586 
587       ::warning ("range error for conversion to character value");
588     }
589   else
590     retval = octave_value (std::string (1, static_cast<char> (ival)), type);
591 
592   return retval;
593 }
594 
595 template <typename T>
596 octave_value
as_double(void) const597 octave_base_int_scalar<T>::as_double (void) const
598 {
599   return static_cast<double> (this->scalar);
600 }
601 
602 template <typename T>
603 octave_value
as_single(void) const604 octave_base_int_scalar<T>::as_single (void) const
605 {
606   return static_cast<float> (this->scalar);
607 }
608 
609 template <typename T>
610 octave_value
as_int8(void) const611 octave_base_int_scalar<T>::as_int8 (void) const
612 {
613   return octave_int8 (this->scalar);
614 }
615 
616 template <typename T>
617 octave_value
as_int16(void) const618 octave_base_int_scalar<T>::as_int16 (void) const
619 {
620   return octave_int16 (this->scalar);
621 }
622 
623 template <typename T>
624 octave_value
as_int32(void) const625 octave_base_int_scalar<T>::as_int32 (void) const
626 {
627   return octave_int32 (this->scalar);
628 }
629 
630 template <typename T>
631 octave_value
as_int64(void) const632 octave_base_int_scalar<T>::as_int64 (void) const
633 {
634   return octave_int64 (this->scalar);
635 }
636 
637 template <typename T>
638 octave_value
as_uint8(void) const639 octave_base_int_scalar<T>::as_uint8 (void) const
640 {
641   return octave_uint8 (this->scalar);
642 }
643 
644 template <typename T>
645 octave_value
as_uint16(void) const646 octave_base_int_scalar<T>::as_uint16 (void) const
647 {
648   return octave_uint16 (this->scalar);
649 }
650 
651 template <typename T>
652 octave_value
as_uint32(void) const653 octave_base_int_scalar<T>::as_uint32 (void) const
654 {
655   return octave_uint32 (this->scalar);
656 }
657 
658 template <typename T>
659 octave_value
as_uint64(void) const660 octave_base_int_scalar<T>::as_uint64 (void) const
661 {
662   return octave_uint64 (this->scalar);
663 }
664 
665 template <typename ST>
666 std::string
edit_display(const float_display_format & fmt,octave_idx_type,octave_idx_type) const667 octave_base_int_scalar<ST>::edit_display (const float_display_format& fmt,
668                                           octave_idx_type,
669                                           octave_idx_type) const
670 {
671   std::ostringstream buf;
672   octave_print_internal (buf, fmt, this->scalar);
673   return buf.str ();
674 }
675 
676 template <typename T>
677 bool
save_ascii(std::ostream & os)678 octave_base_int_scalar<T>::save_ascii (std::ostream& os)
679 {
680   os << this->scalar << "\n";
681   return true;
682 }
683 
684 template <typename T>
685 bool
load_ascii(std::istream & is)686 octave_base_int_scalar<T>::load_ascii (std::istream& is)
687 {
688   is >> this->scalar;
689   if (! is)
690     error ("load: failed to load scalar constant");
691 
692   return true;
693 }
694 
695 template <typename T>
696 bool
save_binary(std::ostream & os,bool)697 octave_base_int_scalar<T>::save_binary (std::ostream& os, bool)
698 {
699   os.write (reinterpret_cast<char *> (&(this->scalar)), this->byte_size ());
700   return true;
701 }
702 
703 template <typename T>
704 bool
load_binary(std::istream & is,bool swap,octave::mach_info::float_format)705 octave_base_int_scalar<T>::load_binary (std::istream& is, bool swap,
706                                         octave::mach_info::float_format)
707 {
708   T tmp;
709 
710   if (! is.read (reinterpret_cast<char *> (&tmp), this->byte_size ()))
711     return false;
712 
713   if (swap)
714     swap_bytes<sizeof (T)> (&tmp);
715 
716   this->scalar = tmp;
717 
718   return true;
719 }
720 
721 template <typename T>
722 bool
save_hdf5_internal(octave_hdf5_id loc_id,octave_hdf5_id save_type,const char * name,bool)723 octave_base_int_scalar<T>::save_hdf5_internal (octave_hdf5_id loc_id,
724                                                octave_hdf5_id save_type,
725                                                const char *name, bool)
726 {
727   bool retval = false;
728 
729 #if defined (HAVE_HDF5)
730 
731   hid_t save_type_hid = save_type;
732   hsize_t dimens[3];
733   hid_t space_hid, data_hid;
734   space_hid = data_hid = -1;
735 
736   space_hid = H5Screate_simple (0, dimens, nullptr);
737   if (space_hid < 0) return false;
738 
739 #if defined (HAVE_HDF5_18)
740   data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
741                         octave_H5P_DEFAULT, octave_H5P_DEFAULT, octave_H5P_DEFAULT);
742 #else
743   data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
744                         octave_H5P_DEFAULT);
745 #endif
746   if (data_hid < 0)
747     {
748       H5Sclose (space_hid);
749       return false;
750     }
751 
752   retval = H5Dwrite (data_hid, save_type_hid, octave_H5S_ALL, octave_H5S_ALL,
753                      octave_H5P_DEFAULT, &(this->scalar)) >= 0;
754 
755   H5Dclose (data_hid);
756   H5Sclose (space_hid);
757 
758 #else
759   octave_unused_parameter (loc_id);
760   octave_unused_parameter (save_type);
761   octave_unused_parameter (name);
762 
763   this->warn_save ("hdf5");
764 #endif
765 
766   return retval;
767 }
768 
769 template <typename T>
770 bool
load_hdf5_internal(octave_hdf5_id loc_id,octave_hdf5_id save_type,const char * name)771 octave_base_int_scalar<T>::load_hdf5_internal (octave_hdf5_id loc_id,
772                                                octave_hdf5_id save_type,
773                                                const char *name)
774 {
775 #if defined (HAVE_HDF5)
776 
777   hid_t save_type_hid = save_type;
778 #if defined (HAVE_HDF5_18)
779   hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT);
780 #else
781   hid_t data_hid = H5Dopen (loc_id, name);
782 #endif
783   hid_t space_id = H5Dget_space (data_hid);
784 
785   hsize_t rank = H5Sget_simple_extent_ndims (space_id);
786 
787   if (rank != 0)
788     {
789       H5Dclose (data_hid);
790       return false;
791     }
792 
793   T tmp;
794   if (H5Dread (data_hid, save_type_hid, octave_H5S_ALL, octave_H5S_ALL,
795                octave_H5P_DEFAULT, &tmp) < 0)
796     {
797       H5Dclose (data_hid);
798       return false;
799     }
800 
801   this->scalar = tmp;
802 
803   H5Dclose (data_hid);
804 
805   return true;
806 
807 #else
808   octave_unused_parameter (loc_id);
809   octave_unused_parameter (save_type);
810   octave_unused_parameter (name);
811 
812   this->warn_load ("hdf5");
813 
814   return false;
815 #endif
816 }
817