26#if defined (HAVE_CONFIG_H)
40static uint32_t MIN_FILEWRAPPER_VERSION = 2;
41static uint32_t MCOS_MAGIC_NUMBER = 0xDD000000;
55 if (md.
contains (
"EnumerationInstanceTag"))
62 "load: MATLAB enumeration class object cannot be loaded. "
83 if (
static_cast<uint32_t
> (md(0, 0)) != MCOS_MAGIC_NUMBER)
92search_mcos_classdef_objects (
const octave_value& val,
bool save_mode)
96 subsystem_handler *sh = octave::__get_load_save_system__ ().get_subsystem_handler ();
99 else if (! save_mode && is_valid_mcos_object (val))
109 cv(i) = search_mcos_classdef_objects (cv(i), save_mode);
120 for (
auto it = mv.
begin (); it != mv.
end (); ++it)
122 std::string field_name = mv.
key (it);
125 search_mcos_classdef_objects (field_val, save_mode));
137 std::string field_name = field_names[field_idx];
141 field_values(i) = search_mcos_classdef_objects (field_values(i),
144 mv.
assign (field_name, field_values);
162 octave::load_save_system& lss = octave::__get_load_save_system__ ();
163 octave::subsystem_handler *sh = lss.get_subsystem_handler ();
166 if (
static_cast<uint32_t
>(dt[0]) != MCOS_MAGIC_NUMBER)
169 "load: invalid MCOS object metadata. Returning as %s",
173 int32_t objdims = dt[1];
180 int nobjects = dv.
numel ();
181 std::vector<std::tuple<octave_map, uint32_t, bool>> m (nobjects);
184 std::get<uint32_t> (m[i]) = dt[2 + objdims + i];
186 uint32_t class_id = dt[2 + objdims + nobjects];
187 std::string classname = sh->get_class_name (class_id);
189 bool skip_constructor =
true;
190 octave::cdef_class cls;
196 if (classname ==
"function_handle_workspace")
200 cls = octave::lookup_class (classname,
false,
true);
204 "load: classdef not found. Element loaded as %s",
210 skip_constructor = ! cls.get (
"ConstructOnLoad").bool_value ();
216 uint32_t obj_id = std::get<uint32_t> (m[i]);
221 "load: object of class '%s' was deleted in MATLAB "
222 "and cannot be loaded. Returning metadata",
226 if (! lss.is_mcos_object_cache_entry (obj_id))
233 lss.set_mcos_object_cache_entry (obj_id, ovc);
236 auto [saveobj_type, obj_type_id, obj_dep_id]
237 = sh->get_object_dependencies (obj_id);
239 std::get<octave_map> (m[i])
240 = sh->get_object_properties (obj_type_id, class_id, saveobj_type,
242 std::get<bool> (m[i]) = saveobj_type;
244 if (! as_struct && sh->check_dyn_props (obj_dep_id))
246 "load: dynamic properties cannot be loaded and "
258 if ((std::get<octave_map> (m[i])).isfield (
"any"))
263 = ((std::get<octave_map> (m[i])).getfield (
"any"))(0);
270 map_list[j] = any_cell(1).scalar_map_value ();
274 map_list[j] = std::get<octave_map> (m[i]);
315 m_type_java = java_data;
322 m_type_handle = handle_data;
339 std::memcpy (&version, fwrap_metadata_array.
data (), sizeof (version));
342 if (version > m_filewrapper_version || version < MIN_FILEWRAPPER_VERSION)
343 error (
"load: filewrapper version %u is not supported. MCOS objects cannot be loaded.",
347 std::memcpy (&m_num_names, fwrap_metadata_array.
data () + 4,
348 sizeof (m_num_names));
355 std::memcpy (m_region_offsets.data () + i,
356 fwrap_metadata_array.
data () + 8 + i * 4,
364 m_prop_class_names.
resize (m_num_names);
365 size_t name_offset = 40;
366 for (uint32_t i = 0; i < m_num_names; i++)
368 size_t start_offset = name_offset;
369 while (
static_cast<uint8_t
> (fwrap_metadata_array(name_offset)) != 0)
373 for (
size_t j = start_offset; j < name_offset; j++)
374 name +=
static_cast<char> (fwrap_metadata_array(j));
376 m_prop_class_names[i] = name;
383 int prop_vals_idx_end = version - 1;
386 if (prop_vals_size > 0)
388 m_fwrap_prop_vals.resize (prop_vals_size);
390 m_fwrap_prop_vals[i] = fwrap_data(2 + i);
393 m_fwrap_prop_vals.clear ();
396 m_fwrap_default_vals = fwrap_data(fwrap_data.
numel () - 1).cell_value ();
401 size_t class_name_size = (m_region_offsets[1] - m_region_offsets[0]) / 4;
402 m_class_name_refs.resize (class_name_size);
403 for (
size_t i = 0; i < class_name_size; i++)
407 fwrap_metadata_array.
data () + m_region_offsets[0] + i * 4,
411 m_class_name_refs[i] = val;
416 size_t object_id_size = (m_region_offsets[3] - m_region_offsets[2]) / 4;
417 m_object_id_refs.resize (object_id_size);
418 for (
size_t i = 0; i < object_id_size; i++)
422 fwrap_metadata_array.
data () + m_region_offsets[2] + i * 4,
426 m_object_id_refs[i] = val;
431 size_t object_prop_size = (m_region_offsets[4] - m_region_offsets[3]) / 4;
432 m_object_prop_fields.resize (object_prop_size);
433 for (
size_t i = 0; i < object_prop_size; i++)
437 fwrap_metadata_array.
data () + m_region_offsets[3] + i * 4,
441 m_object_prop_fields[i] = val;
446 size_t saveobj_prop_size = (m_region_offsets[2] - m_region_offsets[1]) / 4;
447 m_saveobj_prop_fields.resize (saveobj_prop_size);
448 for (
size_t i = 0; i < saveobj_prop_size; i++)
452 fwrap_metadata_array.
data () + m_region_offsets[1] + i * 4,
456 m_saveobj_prop_fields[i] = val;
461 size_t dynamic_prop_size = (m_region_offsets[5] - m_region_offsets[4]) / 4;
462 m_dynamic_prop_refs.resize (dynamic_prop_size);
463 for (
size_t i = 0; i < dynamic_prop_size; i++)
467 fwrap_metadata_array.
data () + m_region_offsets[4] + i * 4,
471 m_dynamic_prop_refs[i] = val;
483 constexpr int block_size = 4;
484 uint32_t namespace_idx = m_class_name_refs[class_id * block_size];
485 uint32_t class_idx = m_class_name_refs[class_id * block_size + 1];
487 std::string classname;
489 classname = m_prop_class_names[namespace_idx - 1] +
".";
490 classname += m_prop_class_names[class_idx - 1];
494std::tuple<bool, uint32_t, uint32_t>
500 constexpr int block_size = 6;
501 bool saveobj_type =
true;
503 uint32_t obj_dep_id = m_object_id_refs[obj_id * block_size + 5];
504 uint32_t obj_con_id = m_object_id_refs[obj_id * block_size + 3];
507 saveobj_type =
false;
508 obj_con_id = m_object_id_refs[obj_id * block_size + 4];
511 return {saveobj_type, obj_con_id, obj_dep_id};
516 const uint32_t class_id,
517 const bool saveobj_ret_type,
523 const std::vector<uint32_t>& offset_fields
524 = saveobj_ret_type ? m_saveobj_prop_fields : m_object_prop_fields;
525 const uint32_t* ptr = offset_fields.data();
526 const uint32_t* end_ptr = ptr + offset_fields.size();
529 constexpr int block_size = 3;
530 for (uint32_t current_id = 0; current_id < obj_type_id; current_id++)
532 uint32_t nprops = *ptr++;
533 ptr += nprops * block_size;
534 ptr += (1 + (nprops * block_size)) % 2;
536 error (
"Could not load file");
543 octave_value& default_vals = m_fwrap_default_vals(class_id);
544 default_vals = search_mcos_classdef_objects (default_vals,
false);
550 uint32_t prop_name_idx = *ptr++;
551 uint32_t prop_val_type = *ptr++;
552 uint32_t prop_val_idx = *ptr++;
554 const std::string& prop_name = m_prop_class_names[prop_name_idx - 1];
556 switch (prop_val_type)
562 "load: property '%s' is an enum reference. "
563 "This may not be supported and is read as a string.",
565 const std::string& prop_val = m_prop_class_names[prop_val_idx - 1];
573 octave_value& prop_val = m_fwrap_prop_vals[prop_val_idx];
574 prop_val = search_mcos_classdef_objects (prop_val,
false);
575 prop_vals.
assign (prop_name, prop_val);
587 warning (
"load: unknown property value type %u for property '%s'",
588 prop_val_type, prop_name.c_str ());
607 if (m_dynamic_prop_refs.empty () || (! obj_dep_id))
610 const uint32_t *ptr = m_dynamic_prop_refs.data ();
611 const uint32_t *end_ptr = ptr + m_dynamic_prop_refs.size ();
613 bool has_dyn_props =
false;
614 for (uint32_t current_id = 0; current_id < obj_dep_id; current_id++)
616 uint32_t nprops = *ptr++;
618 ptr += (1 + nprops) % 2;
623 uint32_t nprops = *ptr++;
625 has_dyn_props =
true;
626 return has_dyn_props;
629std::pair<std::string, std::string>
630subsystem_handler::parse_class_name (
const std::string& full_class_name)
632 std::string namespace_name;
633 std::string class_name;
636 size_t last_dot_pos = full_class_name.find_last_of (
'.');
637 if (last_dot_pos != std::string::npos)
639 namespace_name = full_class_name.substr (0, last_dot_pos);
640 class_name = full_class_name.substr (last_dot_pos + 1);
645 class_name = full_class_name;
648 return std::make_pair (namespace_name, class_name);
652subsystem_handler::get_name_index (
const std::string& name)
656 if (m_prop_class_names[i] == name)
660 m_prop_class_names.
append (name);
661 m_num_names = m_prop_class_names.
numel ();
666subsystem_handler::get_or_create_class_id (
const std::string& namespace_name,
667 const std::string& class_name)
669 uint32_t current_class_id = 1;
670 bool class_exists =
false;
673 for (
size_t i = 0; i < m_class_name_refs.size(); i += 4)
675 uint32_t existing_namespace_idx = m_class_name_refs[i];
676 uint32_t existing_class_idx = m_class_name_refs[i + 1];
678 std::string existing_namespace
679 = ((existing_namespace_idx > 0)
680 ? m_prop_class_names[existing_namespace_idx - 1] :
"");
681 std::string existing_class = m_prop_class_names[existing_class_idx - 1];
683 if (existing_namespace == namespace_name && existing_class == class_name)
693 m_class_id_counter++;
696 uint32_t namespace_idx = (namespace_name.empty()
697 ? 0 : get_name_index (namespace_name));
698 uint32_t class_name_idx = get_name_index (class_name);
700 m_class_name_refs.push_back (namespace_idx);
701 m_class_name_refs.push_back (class_name_idx);
702 m_class_name_refs.push_back (0);
703 m_class_name_refs.push_back (0);
706 return current_class_id;
710subsystem_handler::create_metadata_array (
const dim_vector& obj_dims,
711 const std::vector<uint32_t>& object_ids,
714 uint32_t obj_ndims = obj_dims.
ndims ();
715 uint32_t nobjects = obj_dims.
numel ();
721 metadata(0) = MCOS_MAGIC_NUMBER;
722 metadata(1) = obj_ndims;
724 for (uint32_t i = 0; i < obj_ndims; i++)
725 metadata(2 + i) = obj_dims(i);
727 for (uint32_t i = 0; i < nobjects; i++)
728 metadata(2 + obj_ndims + i) = object_ids[i];
730 metadata(2 + obj_ndims + nobjects) = class_id;
736subsystem_handler::process_object_properties (
const std::vector<std::tuple<octave_map, uint32_t, bool>>& saveobj_data,
737 const std::vector<bool>& is_new,
741 size_t object_id_refs_pos = m_object_id_refs.size ();
742 size_t object_prop_fields_pos = m_object_prop_fields.size ();
743 size_t saveobj_prop_fields_pos = m_saveobj_prop_fields.size ();
746 std::vector<uint32_t> local_object_id_refs;
747 std::vector<uint32_t> local_object_prop_fields;
748 std::vector<uint32_t> local_saveobj_prop_fields;
749 std::vector<uint32_t> local_dynamic_prop_refs;
751 for (
size_t obj_idx = 0; obj_idx < saveobj_data.size (); obj_idx++)
753 const auto& obj_tuple = saveobj_data[obj_idx];
754 const octave_map& prop_map = std::get<octave_map> (obj_tuple);
755 bool saveobj_ret_type = std::get<bool> (obj_tuple);
759 uint32_t saveobj_object_id = 0;
760 uint32_t normal_object_id = 0;
761 std::vector<uint32_t>& target_prop_fields
762 = (saveobj_ret_type ? local_saveobj_prop_fields
763 : local_object_prop_fields);
765 if (saveobj_ret_type)
766 saveobj_object_id = ++m_saveobj_object_counter;
768 normal_object_id = ++m_normal_object_counter;
771 local_object_id_refs.push_back (class_id);
772 local_object_id_refs.push_back (0);
773 local_object_id_refs.push_back (0);
774 local_object_id_refs.push_back (saveobj_object_id);
775 local_object_id_refs.push_back (normal_object_id);
776 local_object_id_refs.push_back (0);
780 target_prop_fields.push_back (num_props);
784 std::string prop_name = prop_names[prop_idx];
787 prop_value = search_mcos_classdef_objects (prop_value,
true);
789 uint32_t field_name_idx = get_name_index (prop_name);
790 uint32_t cell_number_idx = m_fwrap_prop_vals.size ();
791 m_fwrap_prop_vals.push_back (prop_value);
794 target_prop_fields.push_back (field_name_idx);
795 target_prop_fields.push_back (1);
796 target_prop_fields.push_back (cell_number_idx);
801 if ((num_props * 3 + 1) % 2 != 0)
802 target_prop_fields.push_back (0);
805 local_dynamic_prop_refs.push_back (0);
806 local_dynamic_prop_refs.push_back (0);
811 m_object_id_refs.insert (m_object_id_refs.begin () + object_id_refs_pos,
812 local_object_id_refs.begin (),
813 local_object_id_refs.end ());
814 m_object_prop_fields.insert (m_object_prop_fields.begin () + object_prop_fields_pos,
815 local_object_prop_fields.begin (),
816 local_object_prop_fields.end ());
817 m_saveobj_prop_fields.insert (m_saveobj_prop_fields.begin () + saveobj_prop_fields_pos,
818 local_saveobj_prop_fields.begin (),
819 local_saveobj_prop_fields.end ());
820 m_dynamic_prop_refs.insert (m_dynamic_prop_refs.end (),
821 local_dynamic_prop_refs.begin (),
822 local_dynamic_prop_refs.end ());
828 std::string full_class_name = obj.
class_name ();
829 auto [namespace_name, class_name] = parse_class_name (full_class_name);
831 uint32_t current_class_id = get_or_create_class_id (namespace_name, class_name);
833 std::vector<bool> is_new (obj.
numel ());
834 std::vector<std::tuple<octave_map, uint32_t, bool>> saveobj_data
838 std::vector<uint32_t> actual_object_ids;
839 actual_object_ids.reserve (obj_dims.
numel ());
841 for (
const auto& obj_tuple : saveobj_data)
843 uint32_t obj_id = std::get<uint32_t> (obj_tuple);
844 actual_object_ids.push_back (obj_id);
848 process_object_properties (saveobj_data, is_new, current_class_id);
850 return create_metadata_array (obj_dims, actual_object_ids, current_class_id);
858 auto write_object_id_0 = [](uint8_t*& ptr,
int count) ->
void
861 for (
int i = 0; i < count; i++)
863 std::memcpy (ptr, &zero, 4);
869 size_t current_offset = 40;
872 current_offset += m_prop_class_names[i].length () + 1;
875 size_t padding_length = 0;
876 if (current_offset % 8 != 0)
878 padding_length = 8 - (current_offset % 8);
879 current_offset += padding_length;
882 m_region_offsets[0] = current_offset;
884 current_offset += (m_class_name_refs.size () + 4) * 4;
885 m_region_offsets[1] = current_offset;
887 current_offset += m_saveobj_prop_fields.size () * 4;
888 if (m_saveobj_prop_fields.size () > 0)
890 m_region_offsets[2] = current_offset;
892 current_offset += (m_object_id_refs.size () + 6) * 4;
893 m_region_offsets[3] = current_offset;
895 current_offset += m_object_prop_fields.size () * 4;
896 if (m_object_prop_fields.size () > 0)
898 m_region_offsets[4] = current_offset;
901 current_offset += m_dynamic_prop_refs.size () * 4;
903 m_region_offsets[5] = current_offset;
904 m_region_offsets[6] = current_offset;
906 m_region_offsets[7] = current_offset;
908 uint32_t& metadata_size = m_region_offsets[7];
916 uint8_t* metadata_ptr =
reinterpret_cast<uint8_t*
> (metadata.
rwdata ());
918 uint32_t version = m_filewrapper_version;
919 std::memcpy (metadata_ptr, &version, 4);
922 std::memcpy (metadata_ptr, &m_num_names, 4);
925 for (
int i = 0; i < 8; i++)
927 uint32_t offset_value =
static_cast<uint32_t
> (m_region_offsets[i]);
928 std::memcpy (metadata_ptr, &offset_value, 4);
934 const std::string& name = m_prop_class_names[i];
935 std::memcpy (metadata_ptr, name.c_str (), name.length ());
936 metadata_ptr += name.length ();
939 for (
size_t i = 0; i < padding_length; i++)
942 write_object_id_0 (metadata_ptr, 4);
943 for (
size_t i = 0; i < m_class_name_refs.size (); i++)
945 uint32_t value = m_class_name_refs[i];
946 std::memcpy (metadata_ptr, &value, 4);
950 if (m_saveobj_prop_fields.size () > 0)
951 write_object_id_0 (metadata_ptr, 2);
952 for (
size_t i = 0; i < m_saveobj_prop_fields.size (); i++)
954 uint32_t value = m_saveobj_prop_fields[i];
955 std::memcpy (metadata_ptr, &value, 4);
959 write_object_id_0 (metadata_ptr, 6);
960 for (
size_t i = 0; i < m_object_id_refs.size (); i++)
962 uint32_t value = m_object_id_refs[i];
963 std::memcpy (metadata_ptr, &value, 4);
967 if (m_object_prop_fields.size () > 0)
968 write_object_id_0 (metadata_ptr, 2);
969 for (
size_t i = 0; i < m_object_prop_fields.size (); i++)
971 uint32_t value = m_object_prop_fields[i];
972 std::memcpy (metadata_ptr, &value, 4);
976 write_object_id_0 (metadata_ptr, 2);
977 for (
size_t i = 0; i < m_dynamic_prop_refs.size (); i++)
979 uint32_t value = m_dynamic_prop_refs[i];
980 std::memcpy (metadata_ptr, &value, 4);
985 for (
int i = 0; i < 8; i++)
994 if (! m_class_id_counter)
1006 for (
size_t i = 0; i < m_fwrap_prop_vals.size (); i++)
1007 result(i + 2) = m_fwrap_prop_vals[i];
1013 uint32_t num_class_ids = m_class_id_counter + 1;
1016 for (uint32_t i = 0; i < num_class_ids; i++)
1021 for (uint32_t i = 0; i < num_class_ids; i++)
1027 for (uint32_t i = 0; i < num_class_ids; i++)
1029 result(base_idx + 2) =
octave_value (m_fwrap_default_vals);
1033 m_serialized_data = result;
1036OCTAVE_END_NAMESPACE(octave)
void swap_bytes< 4 >(void *ptr)
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
int ndims() const
Size of the specified dimension.
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
const T * data() const
Size of the specified dimension.
T * rwdata()
Size of the specified dimension.
octave_idx_type numel() const
Number of elements in the array.
Vector representing the dimensions (size) of an Array.
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
void resize(int n, int fill_value=0)
octave_idx_type ndims() const
Number of dimensions.
void loadobj(std::vector< std::tuple< octave_map, uint32_t, bool > > &m, dim_vector &dv)
std::vector< std::tuple< octave_map, uint32_t, bool > > saveobj(std::vector< bool > &is_new)
string_vector fieldnames() const
const Cell & contents(const_iterator p) const
void assign(const std::string &k, const Cell &val)
static octave_map cat(int dim, octave_idx_type n, const octave_scalar_map *map_list)
const octave_value & contents(const_iterator p) const
const_iterator end() const
bool contains(const std::string &name) const
const_iterator begin() const
void assign(const std::string &k, const octave_value &val)
std::string key(const_iterator p) const
bool is_classdef_object() const
bool is_uint32_type() const
std::string class_name() const
octave_classdef * classdef_object_value(bool silent=false) const
bool is_scalar_type() const
octave_scalar_map scalar_map_value() const
octave_uint32 uint32_scalar_value() const
bool is_uint8_type() const
octave_idx_type numel() const
octave_map map_value() const
uint8NDArray uint8_array_value() const
uint32NDArray uint32_array_value() const
string_vector & append(const std::string &s)
void resize(octave_idx_type n, const std::string &rfv="")
octave_idx_type numel() const
uint8NDArray create_filewrapper_metadata()
std::string get_class_name(const uint32_t class_id)
bool read_mat_subsystem(const octave_value &subsys, bool swap)
bool read_filewrapper(const Cell &fwrap_data, bool swap)
octave_map get_object_properties(const uint32_t obj_type_id, const uint32_t class_id, const bool saveobj_type, bool as_struct=false)
bool check_dyn_props(const uint32_t obj_dep_id)
uint32NDArray set_mcos_object_metadata(const octave_value &obj)
std::tuple< bool, uint32_t, uint32_t > get_object_dependencies(const uint32_t obj_id)
void serialize_to_cell_array()
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void warning(const char *fmt,...)
void warning_with_id(const char *id, const char *fmt,...)
void error(const char *fmt,...)
octave_value load_mcos_object(const octave_value &objmetadata, bool as_struct)
#define OCTAVE_LOCAL_BUFFER(T, buf, size)