@@ -37,7 +37,7 @@ public class CSharpCodeGenerator : ICodeGenerator
37
37
[ typeof ( Vector2Node ) ] = "Vector2" ,
38
38
[ typeof ( Vector3Node ) ] = "Vector3" ,
39
39
[ typeof ( Vector4Node ) ] = "Vector4"
40
- } ;
40
+ } ;
41
41
42
42
public Language Language => Language . CSharp ;
43
43
@@ -77,21 +77,42 @@ public string GenerateCode(IReadOnlyList<ClassNode> classes, IReadOnlyList<EnumD
77
77
. Where ( c => c . Nodes . None ( n => n is FunctionNode ) ) // Skip class which contains FunctionNodes because these are not data classes.
78
78
. Distinct ( ) ;
79
79
80
+ var unicodeStringClassLengthsToGenerate = new HashSet < int > ( ) ;
81
+
80
82
using ( var en = classesToWrite . GetEnumerator ( ) )
81
83
{
82
84
if ( en . MoveNext ( ) )
83
85
{
86
+ void FindUnicodeStringClasses ( IEnumerable < BaseNode > nodes )
87
+ {
88
+ unicodeStringClassLengthsToGenerate . UnionWith ( nodes . OfType < Utf16TextNode > ( ) . Select ( n => n . Length ) ) ;
89
+ }
90
+
91
+ FindUnicodeStringClasses ( en . Current ! . Nodes ) ;
92
+
84
93
WriteClass ( iw , en . Current , logger ) ;
85
94
86
95
while ( en . MoveNext ( ) )
87
96
{
88
97
iw . WriteLine ( ) ;
89
98
99
+ FindUnicodeStringClasses ( en . Current ! . Nodes ) ;
100
+
90
101
WriteClass ( iw , en . Current , logger ) ;
91
102
}
92
103
}
93
104
}
94
105
106
+ if ( unicodeStringClassLengthsToGenerate . Any ( ) )
107
+ {
108
+ foreach ( var length in unicodeStringClassLengthsToGenerate )
109
+ {
110
+ iw . WriteLine ( ) ;
111
+
112
+ WriteUnicodeStringClass ( iw , length ) ;
113
+ }
114
+ }
115
+
95
116
return sw . ToString ( ) ;
96
117
}
97
118
@@ -152,7 +173,7 @@ private static void WriteClass(IndentedTextWriter writer, ClassNode @class, ILog
152
173
Contract . Requires ( @class != null ) ;
153
174
Contract . Requires ( logger != null ) ;
154
175
155
- writer . WriteLine ( "[StructLayout(LayoutKind.Explicit)]" ) ;
176
+ writer . WriteLine ( "[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi )]" ) ;
156
177
writer . Write ( "public struct " ) ;
157
178
writer . Write ( @class . Name ) ;
158
179
@@ -171,13 +192,19 @@ private static void WriteClass(IndentedTextWriter writer, ClassNode @class, ILog
171
192
. WhereNot ( n => n is FunctionNode || n is BaseHexNode ) ;
172
193
foreach ( var node in nodes )
173
194
{
174
- var type = GetTypeDefinition ( node ) ;
195
+ var ( type , attribute ) = GetTypeDefinition ( node ) ;
175
196
if ( type != null )
176
197
{
177
- writer . Write ( $ "[FieldOffset(0x{ node . Offset : X} )] public readonly { type } { node . Name } ;") ;
198
+ if ( attribute != null )
199
+ {
200
+ writer . WriteLine ( attribute ) ;
201
+ }
202
+
203
+ writer . WriteLine ( $ "[FieldOffset(0x{ node . Offset : X} )]") ;
204
+ writer . Write ( $ "public readonly { type } { node . Name } ;") ;
178
205
if ( ! string . IsNullOrEmpty ( node . Comment ) )
179
206
{
180
- writer . Write ( " " ) ;
207
+ writer . Write ( " // " ) ;
181
208
writer . Write ( node . Comment ) ;
182
209
}
183
210
writer . WriteLine ( ) ;
@@ -193,11 +220,11 @@ private static void WriteClass(IndentedTextWriter writer, ClassNode @class, ILog
193
220
}
194
221
195
222
/// <summary>
196
- /// Gets the type definition for the given node. If the node is not a simple node <c>null</c> is returned.
223
+ /// Gets the type definition for the given node. If the node is not expressible <c>null</c> as typename is returned.
197
224
/// </summary>
198
225
/// <param name="node">The target node.</param>
199
- /// <returns>The type definition for the node or null if no simple type is available .</returns>
200
- private static string GetTypeDefinition ( BaseNode node )
226
+ /// <returns>The type definition for the node or null as typename if the node is not expressible .</returns>
227
+ private static ( string typeName , string attribute ) GetTypeDefinition ( BaseNode node )
201
228
{
202
229
Contract . Requires ( node != null ) ;
203
230
@@ -210,15 +237,39 @@ private static string GetTypeDefinition(BaseNode node)
210
237
211
238
if ( nodeTypeToTypeDefinationMap . TryGetValue ( node . GetType ( ) , out var type ) )
212
239
{
213
- return type ;
240
+ return ( type , null ) ;
214
241
}
215
242
216
- if ( node is EnumNode enumNode )
243
+ return node switch
217
244
{
218
- return enumNode . Enum . Name ;
219
- }
245
+ EnumNode enumNode => ( enumNode . Enum . Name , null ) ,
246
+ Utf8TextNode utf8TextNode => ( "string" , $ "[MarshalAs(UnmanagedType.ByValTStr, SizeConst = { utf8TextNode . Length } )]") ,
247
+ Utf16TextNode utf16TextNode => ( GetUnicodeStringClassName ( utf16TextNode . Length ) , "[MarshalAs(UnmanagedType.Struct)]" ) ,
248
+ _ => ( null , null )
249
+ } ;
250
+ }
251
+
252
+ private static string GetUnicodeStringClassName ( int length ) => $ "__UnicodeString{ length } ";
253
+
254
+ /// <summary>
255
+ /// Writes a helper class for unicode strings with the specific length.
256
+ /// </summary>
257
+ /// <param name="writer">The writer to output to.</param>
258
+ /// <param name="length">The string length for this class.</param>
259
+ private static void WriteUnicodeStringClass ( IndentedTextWriter writer , int length )
260
+ {
261
+ var className = GetUnicodeStringClassName ( length ) ;
220
262
221
- return null ;
263
+ writer . WriteLine ( "[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]" ) ;
264
+ writer . WriteLine ( $ "public struct { className } ") ;
265
+ writer . WriteLine ( "{" ) ;
266
+ writer . Indent ++ ;
267
+ writer . WriteLine ( $ "[MarshalAs(UnmanagedType.ByValTStr, SizeConst = { length } )]") ;
268
+ writer . WriteLine ( "public string Value;" ) ;
269
+ writer . WriteLine ( ) ;
270
+ writer . WriteLine ( $ "public static implicit operator string({ className } value) => value.Value;") ;
271
+ writer . Indent -- ;
272
+ writer . WriteLine ( "}" ) ;
222
273
}
223
274
}
224
275
}
0 commit comments