@@ -129,7 +129,7 @@ public override void CLIMarshalToManaged(MarshalContext ctx)
129
129
encoding = Context . Options . Encoding ;
130
130
131
131
string param ;
132
- if ( Equals ( encoding , Encoding . ASCII ) )
132
+ if ( Equals ( encoding , Encoding . ASCII ) || Equals ( encoding , Encoding . UTF8 ) )
133
133
param = "E_UTF8" ;
134
134
else if ( Equals ( encoding , Encoding . Unicode ) ||
135
135
Equals ( encoding , Encoding . BigEndianUnicode ) )
@@ -154,8 +154,9 @@ public override Type CSharpSignatureType(TypePrinterContext ctx)
154
154
return new CustomType ( typePrinter . IntPtrType ) ;
155
155
}
156
156
157
- if ( Context . Options . Encoding == Encoding . ASCII )
158
- return new CustomType ( "string" ) ;
157
+ if ( Context . Options . Encoding == Encoding . ASCII ||
158
+ Context . Options . Encoding == Encoding . UTF8 )
159
+ return new CustomType ( "[MarshalAs(UnmanagedType.LPUTF8Str)] string" ) ;
159
160
160
161
if ( Context . Options . Encoding == Encoding . Unicode ||
161
162
Context . Options . Encoding == Encoding . BigEndianUnicode )
@@ -183,19 +184,14 @@ public override void CSharpMarshalToNative(CSharpMarshalContext ctx)
183
184
if ( substitution != null )
184
185
param = $ "({ substitution . Replacement } ) (object) { param } ";
185
186
186
- if ( Equals ( Context . Options . Encoding , Encoding . ASCII ) )
187
- {
188
- ctx . Return . Write ( $ "Marshal.StringToHGlobalAnsi({ param } )") ;
189
- return ;
190
- }
191
- if ( Equals ( Context . Options . Encoding , Encoding . Unicode ) ||
192
- Equals ( Context . Options . Encoding , Encoding . BigEndianUnicode ) )
193
- {
194
- ctx . Return . Write ( $ "Marshal.StringToHGlobalUni({ param } )") ;
195
- return ;
196
- }
197
- throw new System . NotSupportedException (
198
- $ "{ Context . Options . Encoding . EncodingName } is not supported yet.") ;
187
+ string bytes = $ "__bytes{ ctx . ParameterIndex } ";
188
+ string bytePtr = $ "__bytePtr{ ctx . ParameterIndex } ";
189
+ ctx . Before . WriteLine ( $@ "byte[] { bytes } = global::System.Text.Encoding.{
190
+ GetEncodingClass ( ctx . Parameter ) } .GetBytes({ param } );" ) ;
191
+ ctx . Before . WriteLine ( $ "fixed (byte* { bytePtr } = { bytes } )") ;
192
+ ctx . HasCodeBlock = true ;
193
+ ctx . Before . WriteOpenBraceAndIndent ( ) ;
194
+ ctx . Return . Write ( $ "new global::System.IntPtr({ bytePtr } )") ;
199
195
}
200
196
201
197
public override void CSharpMarshalToManaged ( CSharpMarshalContext ctx )
@@ -207,49 +203,93 @@ public override void CSharpMarshalToManaged(CSharpMarshalContext ctx)
207
203
return ;
208
204
}
209
205
210
- Type type = Type . Desugar ( ) ;
211
- Type pointee = type . GetPointee ( ) . Desugar ( ) ;
212
- var isChar = type . IsPointerToPrimitiveType ( PrimitiveType . Char ) ||
213
- ( pointee . IsPointerToPrimitiveType ( PrimitiveType . Char ) &&
214
- ctx . Parameter != null &&
215
- ( ctx . Parameter . IsInOut || ctx . Parameter . IsOut ) ) ;
216
- var encoding = isChar ? Encoding . ASCII : Encoding . Unicode ;
217
-
218
- if ( Equals ( encoding , Encoding . ASCII ) )
219
- encoding = Context . Options . Encoding ;
220
-
221
206
string returnVarName = ctx . ReturnVarName ;
207
+ string nullPtr = "global::System.IntPtr.Zero" ;
222
208
if ( ctx . Function != null )
223
209
{
224
210
Type returnType = ctx . Function . ReturnType . Type . Desugar ( ) ;
225
211
if ( returnType . IsAddress ( ) &&
226
212
returnType . GetPointee ( ) . Desugar ( ) . IsAddress ( ) )
227
213
{
228
- returnVarName = $ "new global::System.IntPtr(*{ returnVarName } )";
214
+ returnVarName = $ "*{ returnVarName } ";
215
+ nullPtr = "null" ;
229
216
}
230
217
}
231
218
232
- if ( Equals ( encoding , Encoding . ASCII ) )
219
+ TextGenerator textGenerator ;
220
+ if ( ctx . Parameter == null )
233
221
{
234
- ctx . Return . Write ( $ "Marshal.PtrToStringAnsi({ returnVarName } )") ;
235
- return ;
222
+ textGenerator = ctx . Before ;
223
+ textGenerator . WriteLine ( $ "if ({ ctx . ReturnVarName } == { nullPtr } )") ;
224
+ textGenerator . WriteLineIndent ( $ "return default({ ctx . ReturnType } );") ;
236
225
}
237
- if ( Equals ( encoding , Encoding . UTF8 ) )
226
+ else
238
227
{
239
- ctx . Return . Write ( $ "Marshal.PtrToStringUTF8({ returnVarName } )") ;
240
- return ;
228
+ textGenerator = ctx . Cleanup ;
229
+ textGenerator . WriteLine ( $ "if ({ ctx . ReturnVarName } == { nullPtr } )") ;
230
+ textGenerator . WriteOpenBraceAndIndent ( ) ;
231
+ textGenerator . WriteLine ( $ "{ ctx . Parameter . Name } = default({ Type . Desugar ( ) } );") ;
232
+ textGenerator . WriteLine ( "return;" ) ;
233
+ textGenerator . UnindentAndWriteCloseBrace ( ) ;
241
234
}
242
235
243
- // If we reach this, we know the string is Unicode.
244
- if ( isChar || ctx . Context . TargetInfo . WCharWidth == 16 )
236
+ string encoding = GetEncodingClass ( ctx . Parameter ) ;
237
+ string type = GetTypeForCodePoint ( encoding ) ;
238
+ textGenerator . WriteLine ( $ "var __retPtr = ({ type } *) { returnVarName } ;") ;
239
+ textGenerator . WriteLine ( "int __length = 0;" ) ;
240
+ textGenerator . WriteLine ( $ "while (*(__retPtr++) != 0) __length += sizeof({ type } );") ;
241
+
242
+ ctx . Return . Write ( $@ "global::System.Text.Encoding.{
243
+ encoding } .GetString((byte*) { returnVarName } , __length)" ) ;
244
+ }
245
+
246
+ private string GetEncodingClass ( Parameter parameter )
247
+ {
248
+ Type type = Type . Desugar ( ) ;
249
+ Type pointee = type . GetPointee ( ) . Desugar ( ) ;
250
+ var isChar = type . IsPointerToPrimitiveType ( PrimitiveType . Char ) ||
251
+ ( pointee . IsPointerToPrimitiveType ( PrimitiveType . Char ) &&
252
+ parameter != null &&
253
+ ( parameter . IsInOut || parameter . IsOut ) ) ;
254
+
255
+ if ( ! isChar )
256
+ return ( Context . TargetInfo . WCharWidth == 16 ) ?
257
+ nameof ( Encoding . Unicode ) : nameof ( Encoding . UTF32 ) ;
258
+
259
+ if ( Context . Options . Encoding == Encoding . ASCII )
260
+ return nameof ( Encoding . ASCII ) ;
261
+
262
+ if ( Context . Options . Encoding == Encoding . BigEndianUnicode )
263
+ return nameof ( Encoding . BigEndianUnicode ) ;
264
+
265
+ if ( Context . Options . Encoding == Encoding . Unicode )
266
+ return nameof ( Encoding . Unicode ) ;
267
+
268
+ if ( Context . Options . Encoding == Encoding . UTF32 )
269
+ return nameof ( Encoding . UTF32 ) ;
270
+
271
+ if ( Context . Options . Encoding == Encoding . UTF7 )
272
+ return nameof ( Encoding . UTF7 ) ;
273
+
274
+ if ( Context . Options . Encoding == Encoding . UTF8 )
275
+ return nameof ( Encoding . UTF8 ) ;
276
+
277
+ throw new System . NotSupportedException (
278
+ $ "{ Context . Options . Encoding . EncodingName } is not supported yet.") ;
279
+ }
280
+
281
+ private static string GetTypeForCodePoint ( string encoding )
282
+ {
283
+ switch ( encoding )
245
284
{
246
- ctx . Return . Write ( $ "Marshal.PtrToStringUni({ returnVarName } )") ;
247
- return ;
285
+ case nameof ( Encoding . UTF32 ) :
286
+ return "int" ;
287
+ case nameof ( Encoding . Unicode ) :
288
+ case nameof ( Encoding . BigEndianUnicode ) :
289
+ return "short" ;
290
+ default :
291
+ return "byte" ;
248
292
}
249
- // If we reach this, we should have an UTF-32 wide string.
250
- const string encodingName = "System.Text.Encoding.UTF32" ;
251
- ctx . Return . Write ( $@ "CppSharp.Runtime.Helpers.MarshalEncodedString({
252
- returnVarName } , { encodingName } )" ) ;
253
293
}
254
294
}
255
295
0 commit comments