IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
CustomAttributeBuilder.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2008-2013 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24using System;
25using System.Collections.Generic;
26using System.Diagnostics;
27using System.Reflection.Metadata;
28using System.Text;
29
31
33{
34
35 internal sealed class CustomAttributeBuilder
36 {
37
38 internal static readonly ConstructorInfo LegacyPermissionSet = new ConstructorBuilder(null);
39 readonly ConstructorInfo con;
40 readonly byte[] blob;
41 readonly object[] constructorArgs;
42 readonly PropertyInfo[] namedProperties;
43 readonly object[] propertyValues;
44 readonly FieldInfo[] namedFields;
45 readonly object[] fieldValues;
46
52 internal CustomAttributeBuilder(ConstructorInfo con, byte[] blob)
53 {
54 this.con = con;
55 this.blob = blob;
56 }
57
64 private CustomAttributeBuilder(ConstructorInfo con, int securityAction, byte[] blob)
65 {
66 this.con = con;
67 this.blob = blob;
68 this.constructorArgs = new object[] { securityAction };
69 }
70
76 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs) :
77 this(con, constructorArgs, null, null, null, null)
78 {
79
80 }
81
89 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, FieldInfo[] namedFields, object[] fieldValues) :
90 this(con, constructorArgs, null, null, namedFields, fieldValues)
91 {
92
93 }
94
102 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues) :
103 this(con, constructorArgs, namedProperties, propertyValues, null, null)
104 {
105
106 }
107
117 public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues)
118 {
119 this.con = con;
120 this.constructorArgs = constructorArgs;
121 this.namedProperties = namedProperties;
122 this.propertyValues = propertyValues;
123 this.namedFields = namedFields;
124 this.fieldValues = fieldValues;
125 }
126
127 public static CustomAttributeBuilder __FromBlob(ConstructorInfo con, byte[] blob)
128 {
129 return new CustomAttributeBuilder(con, blob);
130 }
131
132 public static CustomAttributeBuilder __FromBlob(ConstructorInfo con, int securityAction, byte[] blob)
133 {
134 return new CustomAttributeBuilder(con, securityAction, blob);
135 }
136
137 public static CustomAttributeTypedArgument __MakeTypedArgument(Type type, object value)
138 {
139 return new CustomAttributeTypedArgument(type, value);
140 }
141
142 private sealed class BlobWriter
143 {
144
145 readonly Assembly assembly;
146 readonly CustomAttributeBuilder cab;
147 readonly ByteBuffer bb;
148
155 internal BlobWriter(Assembly assembly, CustomAttributeBuilder cab, ByteBuffer bb)
156 {
157 this.assembly = assembly;
158 this.cab = cab;
159 this.bb = bb;
160 }
161
162 internal void WriteCustomAttributeBlob()
163 {
164 // prolog
165 WriteUInt16(1);
166
167 var pi = cab.con.GetParameters();
168 for (int i = 0; i < pi.Length; i++)
169 WriteFixedArg(pi[i].ParameterType, cab.constructorArgs[i]);
170
171 WriteNamedArguments(false);
172 }
173
174 internal void WriteNamedArguments(bool forDeclSecurity)
175 {
176 // NumNamed
177 int named = 0;
178 if (cab.namedFields != null)
179 {
180 named += cab.namedFields.Length;
181 }
182 if (cab.namedProperties != null)
183 {
184 named += cab.namedProperties.Length;
185 }
186 if (forDeclSecurity)
187 {
188 WritePackedLen(named);
189 }
190 else
191 {
192 WriteUInt16((ushort)named);
193 }
194 if (cab.namedFields != null)
195 {
196 for (int i = 0; i < cab.namedFields.Length; i++)
197 {
198 WriteNamedArg(0x53, cab.namedFields[i].FieldType, cab.namedFields[i].Name, cab.fieldValues[i]);
199 }
200 }
201 if (cab.namedProperties != null)
202 {
203 for (int i = 0; i < cab.namedProperties.Length; i++)
204 {
205 WriteNamedArg(0x54, cab.namedProperties[i].PropertyType, cab.namedProperties[i].Name, cab.propertyValues[i]);
206 }
207 }
208 }
209
210 void WriteNamedArg(byte fieldOrProperty, Type type, string name, object value)
211 {
212 WriteByte(fieldOrProperty);
213 WriteFieldOrPropType(type);
214 WriteString(name);
215 WriteFixedArg(type, value);
216 }
217
218 void WriteByte(byte value)
219 {
220 bb.Write(value);
221 }
222
223 void WriteUInt16(ushort value)
224 {
225 bb.Write(value);
226 }
227
228 void WriteInt32(int value)
229 {
230 bb.Write(value);
231 }
232
233 void WriteFixedArg(Type type, object value)
234 {
235 var u = assembly.Universe;
236 if (type == u.System_String)
237 {
238 WriteString((string)value);
239 }
240 else if (type == u.System_Boolean)
241 {
242 WriteByte((bool)value ? (byte)1 : (byte)0);
243 }
244 else if (type == u.System_Char)
245 {
246 WriteUInt16((char)value);
247 }
248 else if (type == u.System_SByte)
249 {
250 WriteByte((byte)(sbyte)value);
251 }
252 else if (type == u.System_Byte)
253 {
254 WriteByte((byte)value);
255 }
256 else if (type == u.System_Int16)
257 {
258 WriteUInt16((ushort)(short)value);
259 }
260 else if (type == u.System_UInt16)
261 {
262 WriteUInt16((ushort)value);
263 }
264 else if (type == u.System_Int32)
265 {
266 WriteInt32((int)value);
267 }
268 else if (type == u.System_UInt32)
269 {
270 WriteInt32((int)(uint)value);
271 }
272 else if (type == u.System_Int64)
273 {
274 WriteInt64((long)value);
275 }
276 else if (type == u.System_UInt64)
277 {
278 WriteInt64((long)(ulong)value);
279 }
280 else if (type == u.System_Single)
281 {
282 WriteSingle((float)value);
283 }
284 else if (type == u.System_Double)
285 {
286 WriteDouble((double)value);
287 }
288 else if (type == u.System_Type)
289 {
290 WriteTypeName((Type)value);
291 }
292 else if (type == u.System_Object)
293 {
294 if (value == null)
295 {
296 type = u.System_String;
297 }
298 else if (value is Type)
299 {
300 // value.GetType() would return a subclass of Type, but we don't want to deal with that
301 type = u.System_Type;
302 }
303 else if (value is CustomAttributeTypedArgument)
304 {
305 CustomAttributeTypedArgument cta = (CustomAttributeTypedArgument)value;
306 value = cta.Value;
307 type = cta.ArgumentType;
308 }
309 else
310 {
311 type = u.Import(value.GetType());
312 }
313 WriteFieldOrPropType(type);
314 WriteFixedArg(type, value);
315 }
316 else if (type.IsArray)
317 {
318 if (value == null)
319 {
320 WriteInt32(-1);
321 }
322 else
323 {
324 Array array = (Array)value;
325 Type elemType = type.GetElementType();
326 WriteInt32(array.Length);
327 foreach (object val in array)
328 {
329 WriteFixedArg(elemType, val);
330 }
331 }
332 }
333 else if (type.IsEnum)
334 {
335 WriteFixedArg(type.GetEnumUnderlyingTypeImpl(), value);
336 }
337 else
338 {
339 throw new ArgumentException();
340 }
341 }
342
343 void WriteInt64(long value)
344 {
345 bb.Write(value);
346 }
347
348 void WriteSingle(float value)
349 {
350 bb.Write(value);
351 }
352
353 void WriteDouble(double value)
354 {
355 bb.Write(value);
356 }
357
358 void WriteTypeName(Type type)
359 {
360 string name = null;
361 if (type != null)
362 {
363 StringBuilder sb = new StringBuilder();
364 GetTypeName(sb, type, false);
365 name = sb.ToString();
366 }
367 WriteString(name);
368 }
369
370 void GetTypeName(StringBuilder sb, Type type, bool isTypeParam)
371 {
372 bool v1 = !assembly.ManifestModule.__IsMissing && assembly.ManifestModule.MDStreamVersion < 0x20000;
373 bool includeAssemblyName = type.Assembly != assembly && (!v1 || type.Assembly != type.Module.Universe.CoreLib);
374 if (isTypeParam && includeAssemblyName)
375 {
376 sb.Append('[');
377 }
378 GetTypeNameImpl(sb, type);
379 if (includeAssemblyName)
380 {
381 if (v1)
382 {
383 sb.Append(',');
384 }
385 else
386 {
387 sb.Append(", ");
388 }
389 if (isTypeParam)
390 {
391 sb.Append(type.Assembly.FullName.Replace("]", "\\]")).Append(']');
392 }
393 else
394 {
395 sb.Append(type.Assembly.FullName);
396 }
397 }
398 }
399
400 void GetTypeNameImpl(StringBuilder sb, Type type)
401 {
402 if (type.HasElementType)
403 {
404 GetTypeNameImpl(sb, type.GetElementType());
405 sb.Append(((ElementHolderType)type).GetSuffix());
406 }
407 else if (type.IsConstructedGenericType)
408 {
409 sb.Append(type.GetGenericTypeDefinition().FullName);
410 sb.Append('[');
411 string sep = "";
412 foreach (Type typeParam in type.GetGenericArguments())
413 {
414 sb.Append(sep);
415 GetTypeName(sb, typeParam, true);
416 sep = ",";
417 }
418 sb.Append(']');
419 }
420 else
421 {
422 sb.Append(type.FullName);
423 }
424 }
425
426 void WriteString(string val)
427 {
428 bb.Write(val);
429 }
430
431 void WritePackedLen(int len)
432 {
433 bb.WriteCompressedUInt(len);
434 }
435
436 void WriteFieldOrPropType(Type type)
437 {
438 var u = type.Module.Universe;
439 if (type == u.System_Type)
440 {
441 WriteByte(0x50);
442 }
443 else if (type == u.System_Object)
444 {
445 WriteByte(0x51);
446 }
447 else if (type == u.System_Boolean)
448 {
449 WriteByte(0x02);
450 }
451 else if (type == u.System_Char)
452 {
453 WriteByte(0x03);
454 }
455 else if (type == u.System_SByte)
456 {
457 WriteByte(0x04);
458 }
459 else if (type == u.System_Byte)
460 {
461 WriteByte(0x05);
462 }
463 else if (type == u.System_Int16)
464 {
465 WriteByte(0x06);
466 }
467 else if (type == u.System_UInt16)
468 {
469 WriteByte(0x07);
470 }
471 else if (type == u.System_Int32)
472 {
473 WriteByte(0x08);
474 }
475 else if (type == u.System_UInt32)
476 {
477 WriteByte(0x09);
478 }
479 else if (type == u.System_Int64)
480 {
481 WriteByte(0x0A);
482 }
483 else if (type == u.System_UInt64)
484 {
485 WriteByte(0x0B);
486 }
487 else if (type == u.System_Single)
488 {
489 WriteByte(0x0C);
490 }
491 else if (type == u.System_Double)
492 {
493 WriteByte(0x0D);
494 }
495 else if (type == u.System_String)
496 {
497 WriteByte(0x0E);
498 }
499 else if (type.IsArray)
500 {
501 WriteByte(0x1D);
502 WriteFieldOrPropType(type.GetElementType());
503 }
504 else if (type.IsEnum)
505 {
506 WriteByte(0x55);
507 WriteTypeName(type);
508 }
509 else
510 {
511 throw new ArgumentException();
512 }
513 }
514 }
515
516 internal ConstructorInfo Constructor
517 {
518 get { return con; }
519 }
520
521 internal BlobHandle WriteBlob(ModuleBuilder moduleBuilder)
522 {
523 ByteBuffer bb;
524 if (blob != null)
525 {
526 bb = ByteBuffer.Wrap(blob);
527 }
528 else
529 {
530 bb = new ByteBuffer(100);
531 var bw = new BlobWriter(moduleBuilder.Assembly, this, bb);
532 bw.WriteCustomAttributeBlob();
533 }
534
535 return moduleBuilder.GetOrAddBlob(bb.ToArray());
536 }
537
538 internal object GetConstructorArgument(int pos)
539 {
540 return constructorArgs[pos];
541 }
542
543 internal int ConstructorArgumentCount
544 {
545 get { return constructorArgs == null ? 0 : constructorArgs.Length; }
546 }
547
548 internal T? GetFieldValue<T>(string name) where T : struct
549 {
550 var val = GetFieldValue(name);
551 if (val is T t)
552 {
553 return t;
554 }
555 else if (val != null)
556 {
557 if (TypeUtil.IsEnum(typeof(T)))
558 {
559 Debug.Assert(Enum.GetUnderlyingType(typeof(T)) == val.GetType());
560 return (T)Enum.ToObject(typeof(T), val);
561 }
562 else
563 {
564 Debug.Assert(Enum.GetUnderlyingType(val.GetType()) == typeof(T));
565 return (T)Convert.ChangeType(val, typeof(T));
566 }
567 }
568 else
569 {
570 return null;
571 }
572 }
573
574 internal object GetFieldValue(string name)
575 {
576 if (namedFields != null)
577 {
578 for (int i = 0; i < namedFields.Length; i++)
579 {
580 if (namedFields[i].Name == name)
581 {
582 return fieldValues[i];
583 }
584 }
585 }
586 return null;
587 }
588
589 internal bool IsLegacyDeclSecurity
590 {
591 get
592 {
593 return ReferenceEquals(con, LegacyPermissionSet)
594 || (con.DeclaringType == con.Module.Universe.System_Security_Permissions_PermissionSetAttribute
595 && blob == null
596 && (namedFields == null || namedFields.Length == 0)
597 && namedProperties != null
598 && namedProperties.Length == 1
599 && namedProperties[0].Name == "XML"
600 && propertyValues[0] is string);
601 }
602 }
603
604 internal BlobHandle WriteLegacyDeclSecurityBlob(ModuleBuilder moduleBuilder)
605 {
606 if (blob != null)
607 {
608 return moduleBuilder.GetOrAddBlob(blob);
609 }
610 else
611 {
612 return moduleBuilder.GetOrAddBlob(Encoding.Unicode.GetBytes((string)propertyValues[0]));
613 }
614 }
615
616 internal void WriteNamedArgumentsForDeclSecurity(ModuleBuilder moduleBuilder, ByteBuffer bb)
617 {
618 if (blob != null)
619 {
620 bb.Write(blob);
621 }
622 else
623 {
624 var bw = new BlobWriter(moduleBuilder.Assembly, this, bb);
625 bw.WriteNamedArguments(true);
626 }
627 }
628
629 internal CustomAttributeData ToData(Assembly asm)
630 {
631 if (blob != null)
632 {
633 if (constructorArgs != null)
634 return new CustomAttributeData(asm, con, (int)constructorArgs[0], blob, -1);
635
636 return new CustomAttributeData(asm, con, new IKVM.Reflection.Reader.ByteReader(blob, 0, blob.Length));
637 }
638 else
639 {
640 var namedArgs = new List<CustomAttributeNamedArgument>();
641
642 if (namedProperties != null)
643 for (int i = 0; i < namedProperties.Length; i++)
644 namedArgs.Add(new CustomAttributeNamedArgument(namedProperties[i], RewrapValue(namedProperties[i].PropertyType, propertyValues[i])));
645
646 if (namedFields != null)
647 for (int i = 0; i < namedFields.Length; i++)
648 namedArgs.Add(new CustomAttributeNamedArgument(namedFields[i], RewrapValue(namedFields[i].FieldType, fieldValues[i])));
649
650 var args = new List<CustomAttributeTypedArgument>(constructorArgs.Length);
651 var parameters = Constructor.GetParameters();
652 for (int i = 0; i < constructorArgs.Length; i++)
653 args.Add(RewrapValue(parameters[i].ParameterType, constructorArgs[i]));
654
655 return new CustomAttributeData(asm.ManifestModule, con, args, namedArgs);
656 }
657 }
658
659 static CustomAttributeTypedArgument RewrapValue(Type type, object value)
660 {
661 if (value is Array)
662 {
663 var array = (Array)value;
664 var arrayType = type.Module.Universe.Import(array.GetType());
665 return RewrapArray(arrayType, array);
666 }
667 else if (value is CustomAttributeTypedArgument)
668 {
669 var arg = (CustomAttributeTypedArgument)value;
670 if (arg.Value is Array)
671 return RewrapArray(arg.ArgumentType, (Array)arg.Value);
672
673 return arg;
674 }
675 else
676 {
677 return new CustomAttributeTypedArgument(type, value);
678 }
679 }
680
681 static CustomAttributeTypedArgument RewrapArray(Type arrayType, Array array)
682 {
683 var elementType = arrayType.GetElementType();
684 var newArray = new CustomAttributeTypedArgument[array.Length];
685 for (int i = 0; i < newArray.Length; i++)
686 newArray[i] = RewrapValue(elementType, array.GetValue(i));
687
688 return new CustomAttributeTypedArgument(arrayType, newArray);
689 }
690
691 internal bool HasBlob
692 {
693 get { return blob != null; }
694 }
695
696 internal CustomAttributeBuilder DecodeBlob(Assembly asm)
697 {
698 if (blob == null)
699 {
700 return this;
701 }
702 else
703 {
704 return ToData(asm).__ToBuilder();
705 }
706 }
707
708 internal byte[] GetBlob(Assembly asm)
709 {
710 var bb = new ByteBuffer(100);
711 var bw = new BlobWriter(asm, this, bb);
712 bw.WriteCustomAttributeBlob();
713 return bb.ToArray();
714 }
715
716 internal KnownCA KnownCA
717 {
718 get
719 {
720 var attributeType = con.DeclaringType;
721 if (attributeType.IsConstructedGenericType)
722 return KnownCA.Unknown; // a constructed generic type doesn't have a TypeName and we already know it's not a Known CA
723
724 var typeName = attributeType.TypeName;
725 switch (typeName.Namespace)
726 {
727 case "System":
728 switch (typeName.Name)
729 {
730 case "SerializableAttribute":
731 return KnownCA.SerializableAttribute;
732 case "NonSerializedAttribute":
733 return KnownCA.NonSerializedAttribute;
734 }
735 break;
736 case "System.Runtime.CompilerServices":
737 switch (typeName.Name)
738 {
739 case "MethodImplAttribute":
740 return KnownCA.MethodImplAttribute;
741 case "SpecialNameAttribute":
742 return KnownCA.SpecialNameAttribute;
743 }
744 break;
745 case "System.Runtime.InteropServices":
746 switch (typeName.Name)
747 {
748 case "DllImportAttribute":
749 return KnownCA.DllImportAttribute;
750 case "ComImportAttribute":
751 return KnownCA.ComImportAttribute;
752 case "MarshalAsAttribute":
753 return KnownCA.MarshalAsAttribute;
754 case "PreserveSigAttribute":
755 return KnownCA.PreserveSigAttribute;
756 case "InAttribute":
757 return KnownCA.InAttribute;
758 case "OutAttribute":
759 return KnownCA.OutAttribute;
760 case "OptionalAttribute":
761 return KnownCA.OptionalAttribute;
762 case "StructLayoutAttribute":
763 return KnownCA.StructLayoutAttribute;
764 case "FieldOffsetAttribute":
765 return KnownCA.FieldOffsetAttribute;
766 }
767 break;
768 }
769
770 if (typeName.Matches("System.Security.SuppressUnmanagedCodeSecurityAttribute"))
771 return KnownCA.SuppressUnmanagedCodeSecurityAttribute;
772
773 return KnownCA.Unknown;
774 }
775 }
776
777 }
778
779}
IKVM.Reflection.Type Type
IKVM.Reflection.Assembly Assembly
IKVM.Reflection.ConstructorInfo ConstructorInfo
IKVM.Reflection.FieldInfo FieldInfo
IKVM.Reflection.PropertyInfo PropertyInfo
global::java.lang.invoke.LambdaForm.Name Name