1+ module MAT_subsys
2+
3+ const FWRAP_VERSION = 4
4+
5+ mutable struct Subsys
6+ num_names:: UInt32
7+ mcos_names:: Vector{String}
8+ class_id_metadata:: Vector{UInt32}
9+ object_id_metadata:: Vector{UInt32}
10+ saveobj_prop_metadata:: Vector{UInt32}
11+ obj_prop_metadata:: Vector{UInt32}
12+ dynprop_metadata:: Vector{UInt32}
13+ _u6_metadata:: Union{Nothing,Vector{UInt32}}
14+ _u7_metadata:: Union{Nothing,Vector{UInt32}}
15+ prop_vals_saved:: Vector{Any}
16+ _c3:: Any
17+ _c2:: Any
18+ prop_vals_defaults:: Any
19+ handle_data:: Any
20+ java_data:: Any
21+
22+ Subsys () = new (
23+ UInt32 (0 ),
24+ String[],
25+ UInt32[],
26+ UInt32[],
27+ UInt32[],
28+ UInt32[],
29+ UInt32[],
30+ nothing ,
31+ nothing ,
32+ Any[],
33+ nothing ,
34+ nothing ,
35+ nothing ,
36+ nothing ,
37+ nothing
38+ )
39+ end
40+
41+ const subsys_cache = Ref {Union{Nothing,Subsys}} (nothing )
42+
43+ function clear_subsys! ()
44+ subsys_cache[] = nothing
45+ end
46+
47+ function load_subsys! (subsystem_data:: Dict{String,Any} , swap_bytes:: Bool )
48+ subsys_cache[] = Subsys ()
49+ subsys_cache[]. handle_data = get (subsystem_data, " handle" , nothing )
50+ subsys_cache[]. java_data = get (subsystem_data, " java" , nothing )
51+ mcos_data = get (subsystem_data, " MCOS" , nothing )
52+ if mcos_data === nothing
53+ return
54+ end
55+
56+ fwrap_metadata = vec (mcos_data[2 ][1 , 1 ])
57+
58+ # FIXME : Is this the best way to read?
59+ # Integers are written as uint8 (with swap), interpret as uint32
60+ version = reinterpret (UInt32, swap_bytes ? reverse (fwrap_metadata[1 : 4 ]) : fwrap_metadata[1 : 4 ])[1 ]
61+ if version > FWRAP_VERSION
62+ error (" Unsupported FileWrapper version: $version " )
63+ end
64+
65+ subsys_cache[]. num_names = reinterpret (UInt32, swap_bytes ? reverse (fwrap_metadata[5 : 8 ]) : fwrap_metadata[5 : 8 ])[1 ]
66+ region_offsets = reinterpret (UInt32, swap_bytes ? reverse (fwrap_metadata[9 : 40 ]) : fwrap_metadata[9 : 40 ])
67+
68+ # Class and Property Names stored as list of null-terminated strings
69+ start = 41
70+ pos = start
71+ name_count = 0
72+ while name_count < subsys_cache[]. num_names
73+ if fwrap_metadata[pos] == 0x00
74+ push! (subsys_cache[]. mcos_names, String (fwrap_metadata[start: pos- 1 ]))
75+ name_count += 1
76+ start = pos + 1
77+ if name_count == subsys_cache[]. num_names
78+ break
79+ end
80+ end
81+ pos += 1
82+ end
83+
84+ subsys_cache[]. class_id_metadata = reinterpret (UInt32, swap_bytes ? reverse (fwrap_metadata[region_offsets[1 ]+ 1 : region_offsets[2 ]]) : fwrap_metadata[region_offsets[1 ]+ 1 : region_offsets[2 ]])
85+ subsys_cache[]. saveobj_prop_metadata = reinterpret (UInt32, swap_bytes ? reverse (fwrap_metadata[region_offsets[2 ]+ 1 : region_offsets[3 ]]) : fwrap_metadata[region_offsets[2 ]+ 1 : region_offsets[3 ]])
86+ subsys_cache[]. object_id_metadata = reinterpret (UInt32, swap_bytes ? reverse (fwrap_metadata[region_offsets[3 ]+ 1 : region_offsets[4 ]]) : fwrap_metadata[region_offsets[3 ]+ 1 : region_offsets[4 ]])
87+ subsys_cache[]. obj_prop_metadata = reinterpret (UInt32, swap_bytes ? reverse (fwrap_metadata[region_offsets[4 ]+ 1 : region_offsets[5 ]]) : fwrap_metadata[region_offsets[4 ]+ 1 : region_offsets[5 ]])
88+ subsys_cache[]. dynprop_metadata = reinterpret (UInt32, swap_bytes ? reverse (fwrap_metadata[region_offsets[5 ]+ 1 : region_offsets[6 ]]) : fwrap_metadata[region_offsets[5 ]+ 1 : region_offsets[6 ]])
89+
90+ subsys_cache[]. prop_vals_saved = mcos_data[2 ][3 : end - 2 , 1 ]
91+ subsys_cache[]. prop_vals_defaults = mcos_data[2 ][end , 1 ]
92+ end
93+
94+ function get_classname (class_id:: UInt32 )
95+ namespace_idx = subsys_cache[]. class_id_metadata[class_id* 4 + 1 ]
96+ classname_idx = subsys_cache[]. class_id_metadata[class_id* 4 + 2 ]
97+
98+ namespace = if namespace_idx == 0
99+ " "
100+ else
101+ subsys_cache[]. mcos_names[namespace_idx- 1 ] * " ."
102+ end
103+
104+ classname = namespace * subsys_cache[]. mcos_names[classname_idx- 1 ]
105+ return classname
106+ end
107+
108+ function get_object_metadata (object_id:: UInt32 )
109+ return subsys_cache[]. object_id_metadata[object_id* 6 + 1 : object_id* 6 + 6 ]
110+ end
111+
112+ function get_default_properties (class_id:: UInt32 )
113+ # FIXME Should we use deepcopy here
114+ return copy (subsys_cache[]. prop_vals_defaults[class_id+ 1 , 1 ])
115+ end
116+
117+ function get_property_idxs (obj_type_id:: UInt32 , saveobj_ret_type:: Bool )
118+ prop_field_idxs = saveobj_ret_type ? subsys_cache[]. saveobj_prop_metadata : subsys_cache[]. obj_prop_metadata
119+ nfields = 3
120+ offset = 1
121+ while obj_type_id > 0
122+ nprops = prop_field_idxs[offset]
123+ offset += 1 + (nfields * nprops)
124+ offset += (offset + 1 ) % 2 # Padding
125+ obj_type_id -= 1
126+ end
127+ nprops = prop_field_idxs[offset]
128+ offset += 1
129+ return prop_field_idxs[offset: offset+ nprops* nfields- 1 ]
130+ end
131+
132+ function get_saved_properties (obj_type_id:: UInt32 , saveobj_ret_type:: Bool )
133+ save_prop_map = Dict {String,Any} ()
134+ prop_field_idxs = get_property_idxs (obj_type_id, saveobj_ret_type)
135+ nprops = length (prop_field_idxs) ÷ 3
136+ for i in 0 : nprops- 1
137+ prop_name = subsys_cache[]. mcos_names[prop_field_idxs[i* 3 + 1 ]]
138+ prop_type = prop_field_idxs[i* 3 + 2 ]
139+ if prop_type == 0
140+ prop_value = subsys_cache[]. mcos_names[prop_field_idxs[i* 3 + 3 ]]
141+ elseif prop_type == 1
142+ # FIXME : Search for nested objects
143+ prop_value = subsys_cache[]. prop_vals_saved[prop_field_idxs[i* 3 + 3 ]+ 1 ]
144+ elseif prop_type == 2
145+ prop_value = prop_field_idxs[i* 3 + 3 ]
146+ else
147+ error (" Unknown property type ID: $prop_type encountered during deserialization" )
148+ end
149+ save_prop_map[prop_name] = prop_value
150+ end
151+ return save_prop_map
152+ end
153+
154+ function get_properties (object_id:: UInt32 )
155+ if object_id == 0
156+ return Dict {String,Any} ()
157+ end
158+
159+ class_id, _, _, saveobj_id, normobj_id, _ = get_object_metadata (object_id)
160+ if saveobj_id != 0
161+ saveobj_ret_type = true
162+ obj_type_id = saveobj_id
163+ else
164+ saveobj_ret_type = false
165+ obj_type_id = normobj_id
166+ end
167+
168+ prop_map = get_default_properties (class_id)
169+ merge! (prop_map, get_saved_properties (obj_type_id, saveobj_ret_type))
170+ # TODO : Add dynamic properties
171+ return prop_map
172+ end
173+
174+ function load_mcos_object (metadata:: Any , type_name:: String )
175+ # TODO : Add support for handle class objects
176+
177+ if type_name != " MCOS"
178+ @warn " Loading Type:$type_name is not implemented. Returning metadata."
179+ return metadata
180+ end
181+
182+ if isa (metadata, Dict)
183+ # TODO : Load Enumeration Instances
184+ @warn " Loading enumeration instances are not supported. Returning Metadata"
185+ return metadata
186+ end
187+
188+ if ! (metadata isa Array{UInt32})
189+ @warn " Expected MCOS metadata to be an Array{UInt32}, got $(typeof (metadata)) . Returning metadata."
190+ return metadata
191+ end
192+
193+ if metadata[1 , 1 ] != 0xDD000000
194+ @warn " MCOS object metadata is corrupted. Returning raw data."
195+ return metadata
196+ end
197+
198+ ndims = metadata[2 , 1 ]
199+ dims = metadata[3 : 2 + ndims, 1 ]
200+ nobjects = prod (dims)
201+ object_ids = metadata[3 + ndims: 2 + ndims+ nobjects, 1 ]
202+
203+ class_id = metadata[end , 1 ]
204+ classname = get_classname (class_id)
205+
206+ object_arr = Array {Dict{String,Any}} (undef, convert (Vector{Int}, dims)... )
207+ for i = 1 : length (object_arr)
208+ prop_dict = get_properties (object_ids[i])
209+ prop_dict[" __class__" ] = classname
210+ object_arr[i] = prop_dict
211+ end
212+
213+ return object_arr
214+
215+ end
216+
217+ end
0 commit comments