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:: Vector{UInt32}
14+ _u7_metadata:: 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+ UInt32[],
31+ UInt32[],
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+ subsys_cache[]. _u6_metadata = reinterpret (UInt32, swap_bytes ? reverse (fwrap_metadata[region_offsets[6 ]+ 1 : region_offsets[7 ]]) : fwrap_metadata[region_offsets[6 ]+ 1 : region_offsets[7 ]])
90+ subsys_cache[]. _u7_metadata = reinterpret (UInt32, swap_bytes ? reverse (fwrap_metadata[region_offsets[7 ]+ 1 : region_offsets[8 ]]) : fwrap_metadata[region_offsets[7 ]+ 1 : region_offsets[8 ]])
91+
92+ if version < 4
93+ subsys_cache[]. prop_vals_saved = mcos_data[2 ][3 : end - 2 , 1 ]
94+ else
95+ subsys_cache[]. prop_vals_saved = mcos_data[2 ][3 : end - 3 , 1 ]
96+ subsys_cache[]. _c3 = mcos_data[2 ][end - 2 , 1 ]
97+ end
98+
99+ subsys_cache[]. _c2 = mcos_data[2 ][end - 1 , 1 ]
100+ subsys_cache[]. prop_vals_defaults = mcos_data[2 ][end , 1 ]
101+ end
102+
103+ function get_classname (class_id:: UInt32 )
104+ namespace_idx = subsys_cache[]. class_id_metadata[class_id* 4 + 1 ]
105+ classname_idx = subsys_cache[]. class_id_metadata[class_id* 4 + 2 ]
106+
107+ namespace = if namespace_idx == 0
108+ " "
109+ else
110+ subsys_cache[]. mcos_names[namespace_idx- 1 ] * " ."
111+ end
112+
113+ classname = namespace * subsys_cache[]. mcos_names[classname_idx- 1 ]
114+ return classname
115+ end
116+
117+ function get_object_metadata (object_id:: UInt32 )
118+ return subsys_cache[]. object_id_metadata[object_id* 6 + 1 : object_id* 6 + 6 ]
119+ end
120+
121+ function get_default_properties (class_id:: UInt32 )
122+ # FIXME Should we use deepcopy here
123+ return copy (subsys_cache[]. prop_vals_defaults[class_id+ 1 , 1 ])
124+ end
125+
126+ function get_property_idxs (obj_type_id:: UInt32 , saveobj_ret_type:: Bool )
127+ prop_field_idxs = saveobj_ret_type ? subsys_cache[]. saveobj_prop_metadata : subsys_cache[]. obj_prop_metadata
128+ nfields = 3
129+ offset = 1
130+ while obj_type_id > 0
131+ nprops = prop_field_idxs[offset]
132+ offset += 1 + (nfields * nprops)
133+ offset += (offset + 1 ) % 2 # Padding
134+ obj_type_id -= 1
135+ end
136+ nprops = prop_field_idxs[offset]
137+ offset += 1
138+ return prop_field_idxs[offset: offset+ nprops* nfields- 1 ]
139+ end
140+
141+ function get_saved_properties (obj_type_id:: UInt32 , saveobj_ret_type:: Bool )
142+ save_prop_map = Dict {String,Any} ()
143+ prop_field_idxs = get_property_idxs (obj_type_id, saveobj_ret_type)
144+ nprops = length (prop_field_idxs) ÷ 3
145+ for i in 0 : nprops- 1
146+ prop_name = subsys_cache[]. mcos_names[prop_field_idxs[i* 3 + 1 ]]
147+ prop_type = prop_field_idxs[i* 3 + 2 ]
148+ if prop_type == 0
149+ prop_value = subsys_cache[]. mcos_names[prop_field_idxs[i* 3 + 3 ]]
150+ elseif prop_type == 1
151+ # FIXME : Search for nested objects
152+ prop_value = subsys_cache[]. prop_vals_saved[prop_field_idxs[i* 3 + 3 ]+ 1 ]
153+ elseif prop_type == 2
154+ prop_value = prop_field_idxs[i* 3 + 3 ]
155+ else
156+ error (" Unknown property type ID: $prop_type encountered during deserialization" )
157+ end
158+ save_prop_map[prop_name] = prop_value
159+ end
160+ return save_prop_map
161+ end
162+
163+ function get_properties (object_id:: UInt32 )
164+ if object_id == 0
165+ return Dict {String,Any} ()
166+ end
167+
168+ class_id, _, _, saveobj_id, normobj_id, _ = get_object_metadata (object_id)
169+ if saveobj_id != 0
170+ saveobj_ret_type = true
171+ obj_type_id = saveobj_id
172+ else
173+ saveobj_ret_type = false
174+ obj_type_id = normobj_id
175+ end
176+
177+ prop_map = get_default_properties (class_id)
178+ merge! (prop_map, get_saved_properties (obj_type_id, saveobj_ret_type))
179+ # TODO : Add dynamic properties
180+ return prop_map
181+ end
182+
183+ function load_mcos_object (metadata:: Any , type_name:: String )
184+ # TODO : Add support for handle class objects
185+
186+ if type_name != " MCOS"
187+ @warn " Loading Type:$type_name is not implemented. Returning metadata."
188+ return metadata
189+ end
190+
191+ if isa (metadata, Dict)
192+ # TODO : Load Enumeration Instances
193+ @warn " Loading enumeration instances are not supported. Returning Metadata"
194+ return metadata
195+ end
196+
197+ if ! (metadata isa Array{UInt32})
198+ @warn " Expected MCOS metadata to be an Array{UInt32}, got $(typeof (metadata)) . Returning metadata."
199+ return metadata
200+ end
201+
202+ if metadata[1 , 1 ] != 0xDD000000
203+ @warn " MCOS object metadata is corrupted. Returning raw data."
204+ return metadata
205+ end
206+
207+ ndims = metadata[2 , 1 ]
208+ dims = metadata[3 : 2 + ndims, 1 ]
209+ nobjects = prod (dims)
210+ object_ids = metadata[3 + ndims: 2 + ndims+ nobjects, 1 ]
211+
212+ class_id = metadata[end , 1 ]
213+ classname = get_classname (class_id)
214+
215+ object_arr = Array {Dict{String,Any}} (undef, convert (Vector{Int}, dims)... )
216+ for i = 1 : length (object_arr)
217+ prop_dict = get_properties (object_ids[i])
218+ prop_dict[" __class__" ] = classname
219+ object_arr[i] = prop_dict
220+ end
221+
222+ return object_arr
223+
224+ end
225+
226+ end
0 commit comments