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