@@ -5,36 +5,66 @@ namespace OpenLoco.Dat.FileParsing
5
5
{
6
6
public static class ByteReader
7
7
{
8
- public static object ReadT ( ReadOnlySpan < byte > data , Type t , int offset , int arrLength = 0 )
8
+ public static object ReadT ( ReadOnlySpan < byte > data , Type t , int offset , int arrLength = 0 , bool isVariableLoad = false )
9
9
{
10
10
if ( t == typeof ( uint8_t ) )
11
11
{
12
- return ByteReaderT . Read_uint8t ( data , offset ) ;
12
+ var val = ByteReaderT . Read_uint8t ( data , offset ) ;
13
+ if ( isVariableLoad && val != 0 )
14
+ {
15
+ throw new InvalidDataException ( $ "uint8_t at offset { offset } had non-zero variable-load data. Value={ val } ") ;
16
+ }
17
+ return val ;
13
18
}
14
19
15
20
if ( t == typeof ( int8_t ) )
16
21
{
17
- return ByteReaderT . Read_int8t ( data , offset ) ;
22
+ var val = ByteReaderT . Read_int8t ( data , offset ) ;
23
+ if ( isVariableLoad && val != 0 )
24
+ {
25
+ throw new InvalidDataException ( $ "int8_t at offset { offset } had non-zero variable-load data. Value={ val } ") ;
26
+ }
27
+ return val ;
18
28
}
19
29
20
30
if ( t == typeof ( uint16_t ) )
21
31
{
22
- return ByteReaderT . Read_uint16t ( data , offset ) ;
32
+ var val = ByteReaderT . Read_uint16t ( data , offset ) ;
33
+ if ( isVariableLoad && val != 0 )
34
+ {
35
+ throw new InvalidDataException ( $ "uint16_t at offset { offset } had non-zero variable-load data. Value={ val } ") ;
36
+ }
37
+ return val ;
23
38
}
24
39
25
40
if ( t == typeof ( int16_t ) )
26
41
{
27
- return ByteReaderT . Read_int16t ( data , offset ) ;
42
+ var val = ByteReaderT . Read_int16t ( data , offset ) ;
43
+ if ( isVariableLoad && val != 0 )
44
+ {
45
+ throw new InvalidDataException ( $ "int16_t at offset { offset } had non-zero variable-load data. Value={ val } ") ;
46
+ }
47
+ return val ;
28
48
}
29
49
30
50
if ( t == typeof ( uint32_t ) )
31
51
{
32
- return ByteReaderT . Read_uint32t ( data , offset ) ;
52
+ var val = ByteReaderT . Read_uint32t ( data , offset ) ;
53
+ if ( isVariableLoad && val != 0 )
54
+ {
55
+ throw new InvalidDataException ( $ "uint32_t at offset { offset } had non-zero variable-load data. Value={ val } ") ;
56
+ }
57
+ return val ;
33
58
}
34
59
35
60
if ( t == typeof ( int32_t ) )
36
61
{
37
- return ByteReaderT . Read_int32t ( data , offset ) ;
62
+ var val = ByteReaderT . Read_int32t ( data , offset ) ;
63
+ if ( isVariableLoad && val != 0 )
64
+ {
65
+ throw new InvalidDataException ( $ "int32_t at offset { offset } had non-zero variable-load data. Value={ val } ") ;
66
+ }
67
+ return val ;
38
68
}
39
69
40
70
if ( t == typeof ( string_id ) )
@@ -49,82 +79,97 @@ public static object ReadT(ReadOnlySpan<byte> data, Type t, int offset, int arrL
49
79
50
80
if ( t . IsArray )
51
81
{
52
- var elementType = t . GetElementType ( ) ?? throw new ArgumentNullException ( t . Name ) ;
53
- var size = ByteHelpers . GetObjectSize ( elementType ) ;
82
+ return ReadArray ( data , t , offset , arrLength , isVariableLoad ) ;
83
+ }
54
84
55
- var arr = Array . CreateInstance ( elementType , arrLength ) ;
56
- for ( var i = 0 ; i < arrLength ; i ++ )
57
- {
58
- arr . SetValue ( ReadT ( data , elementType , offset + ( i * size ) ) , i ) ; // why pass 'i' in here?
59
- }
85
+ if ( t . IsEnum ) // this is so big because we need special handling for 'flags' enums
86
+ {
87
+ return ReadEnum ( data , t , offset ) ;
88
+ }
60
89
61
- return arr ;
90
+ if ( t . IsClass )
91
+ {
92
+ return ReadClass ( data , t , offset ) ;
62
93
}
63
94
64
- if ( t . IsEnum ) // this is so big because we need special handling for 'flags' enums
95
+ throw new NotImplementedException ( t . ToString ( ) ) ;
96
+ }
97
+
98
+ private static object ReadArray ( ReadOnlySpan < byte > data , Type t , int offset , int arrLength , bool isVariableLoad )
99
+ {
100
+ var elementType = t . GetElementType ( ) ?? throw new ArgumentNullException ( t . Name ) ;
101
+ var size = ByteHelpers . GetObjectSize ( elementType ) ;
102
+
103
+ var arr = Array . CreateInstance ( elementType , arrLength ) ;
104
+ for ( var i = 0 ; i < arrLength ; i ++ )
65
105
{
66
- var underlyingType = t . GetEnumUnderlyingType ( ) ;
67
- var underlyingValue = ReadT ( data , underlyingType , offset ) ;
106
+ arr . SetValue ( ReadT ( data , elementType , offset + ( i * size ) , isVariableLoad : isVariableLoad ) , i ) ; // why pass 'i' in here?
107
+ }
68
108
69
- if ( ! t . IsDefined ( typeof ( FlagsAttribute ) , inherit : false ) )
70
- {
71
- return Enum . ToObject ( t , underlyingValue ) ;
72
- }
109
+ return arr ;
110
+ }
111
+
112
+ private static object ReadClass ( ReadOnlySpan < byte > data , Type t , int offset )
113
+ {
114
+ if ( t . Name == "ObjectHeader" )
115
+ {
116
+ return ObjectHeader . Read ( data [ ..ObjectHeader . StructLength ] ) ;
117
+ }
118
+ else if ( t . Name == "S5Header" )
119
+ {
120
+ return S5Header . Read ( data [ ..S5Header . StructLength ] ) ;
121
+ }
73
122
74
- var enumValues = Enum . GetValues ( t ) ;
123
+ var objectSize = ByteHelpers . GetObjectSize ( t ) ;
124
+ return ReadLocoStruct ( data [ offset ..( offset + objectSize ) ] , t ) ;
125
+ }
75
126
76
- if ( underlyingType == typeof ( int8_t ) || underlyingType == typeof ( int16_t ) || underlyingType == typeof ( int32_t ) )
77
- {
78
- var combinedValue = 0 ;
79
- foreach ( var enumValue in enumValues )
80
- {
81
- var parsed = Enum . Parse ( t , enumValue . ToString ( ) ! ) ;
82
- var enumValueInt = Convert . ToInt32 ( parsed ) ; // Convert to int
83
- if ( ( enumValueInt & Convert . ToInt32 ( underlyingValue ) ) != 0 ) // Convert to int
84
- {
85
- combinedValue |= enumValueInt ;
86
- }
87
- }
127
+ private static object ReadEnum ( ReadOnlySpan < byte > data , Type t , int offset )
128
+ {
129
+ var underlyingType = t . GetEnumUnderlyingType ( ) ;
130
+ var underlyingValue = ReadT ( data , underlyingType , offset ) ;
88
131
89
- return Enum . ToObject ( t , combinedValue ) ;
90
- }
91
- else if ( underlyingType == typeof ( uint8_t ) || underlyingType == typeof ( uint16_t ) || underlyingType == typeof ( uint32_t ) )
132
+ if ( ! t . IsDefined ( typeof ( FlagsAttribute ) , inherit : false ) )
133
+ {
134
+ return Enum . ToObject ( t , underlyingValue ) ;
135
+ }
136
+
137
+ var enumValues = Enum . GetValues ( t ) ;
138
+
139
+ if ( underlyingType == typeof ( int8_t ) || underlyingType == typeof ( int16_t ) || underlyingType == typeof ( int32_t ) )
140
+ {
141
+ var combinedValue = 0 ;
142
+ foreach ( var enumValue in enumValues )
92
143
{
93
- var combinedValue = 0U ;
94
- foreach ( var enumValue in enumValues )
144
+ var parsed = Enum . Parse ( t , enumValue . ToString ( ) ! ) ;
145
+ var enumValueInt = Convert . ToInt32 ( parsed ) ; // Convert to int
146
+ if ( ( enumValueInt & Convert . ToInt32 ( underlyingValue ) ) != 0 ) // Convert to int
95
147
{
96
- var parsed = Enum . Parse ( t , enumValue . ToString ( ) ! ) ;
97
- var enumValueInt = Convert . ToUInt32 ( parsed ) ; // Convert to int
98
- if ( ( enumValueInt & Convert . ToUInt32 ( underlyingValue ) ) != 0 ) // Convert to int
99
- {
100
- combinedValue |= enumValueInt ;
101
- }
148
+ combinedValue |= enumValueInt ;
102
149
}
103
-
104
- return Enum . ToObject ( t , combinedValue ) ;
105
- }
106
- else
107
- {
108
- throw new ArgumentOutOfRangeException ( nameof ( underlyingType ) , underlyingType , "unrecognised type" ) ;
109
150
}
110
- }
111
151
112
- if ( t . IsClass )
152
+ return Enum . ToObject ( t , combinedValue ) ;
153
+ }
154
+ else if ( underlyingType == typeof ( uint8_t ) || underlyingType == typeof ( uint16_t ) || underlyingType == typeof ( uint32_t ) )
113
155
{
114
- if ( t . Name == "ObjectHeader" )
156
+ var combinedValue = 0U ;
157
+ foreach ( var enumValue in enumValues )
115
158
{
116
- return ObjectHeader . Read ( data [ ..ObjectHeader . StructLength ] ) ;
117
- }
118
- else if ( t . Name == "S5Header" )
119
- {
120
- return S5Header . Read ( data [ ..S5Header . StructLength ] ) ;
159
+ var parsed = Enum . Parse ( t , enumValue . ToString ( ) ! ) ;
160
+ var enumValueInt = Convert . ToUInt32 ( parsed ) ; // Convert to int
161
+ if ( ( enumValueInt & Convert . ToUInt32 ( underlyingValue ) ) != 0 ) // Convert to int
162
+ {
163
+ combinedValue |= enumValueInt ;
164
+ }
121
165
}
122
166
123
- var objectSize = ByteHelpers . GetObjectSize ( t ) ;
124
- return ReadLocoStruct ( data [ offset ..( offset + objectSize ) ] , t ) ;
167
+ return Enum . ToObject ( t , combinedValue ) ;
168
+ }
169
+ else
170
+ {
171
+ throw new ArgumentOutOfRangeException ( nameof ( underlyingType ) , underlyingType , "unrecognised type" ) ;
125
172
}
126
-
127
- throw new NotImplementedException ( t . ToString ( ) ) ;
128
173
}
129
174
130
175
public static T ReadLocoStruct < T > ( ReadOnlySpan < byte > data ) where T : class
@@ -201,7 +246,7 @@ public static ILocoStruct ReadLocoStruct(ReadOnlySpan<byte> data, Type t)
201
246
continue ;
202
247
}
203
248
204
- args . Add ( ReadT ( data , p . PropertyType , offsetAttr . Offset , arrLength ) ) ;
249
+ args . Add ( ReadT ( data , p . PropertyType , offsetAttr . Offset , arrLength , variableAttr != null ) ) ;
205
250
}
206
251
207
252
return ( ILocoStruct ? ) Activator . CreateInstance ( t , [ .. args ] ) ?? throw new InvalidDataException ( "couldn't parse" ) ;
0 commit comments