| File: System\Reflection\Metadata\BlobWriterImpl.cs | Web Access |
| Project: src\runtime\src\libraries\System.Reflection.Metadata\src\System.Reflection.Metadata.csproj (System.Reflection.Metadata) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers.Binary; using System.Diagnostics; namespace System.Reflection.Metadata { internal static class BlobWriterImpl { internal const int SingleByteCompressedIntegerMaxValue = 0x7f; internal const int TwoByteCompressedIntegerMaxValue = 0x3fff; internal const int MaxCompressedIntegerValue = 0x1fffffff; internal const int MinSignedCompressedIntegerValue = unchecked((int)0xF0000000); internal const int MaxSignedCompressedIntegerValue = 0x0FFFFFFF; internal const int MaxScalarConstantSize = sizeof(ulong); internal static int GetCompressedIntegerSize(int value) { Debug.Assert(value <= MaxCompressedIntegerValue); if (value <= SingleByteCompressedIntegerMaxValue) { return 1; } if (value <= TwoByteCompressedIntegerMaxValue) { return 2; } return 4; } internal static void WriteCompressedInteger(ref BlobWriter writer, uint value) { unchecked { if (value <= SingleByteCompressedIntegerMaxValue) { writer.WriteByte((byte)value); } else if (value <= TwoByteCompressedIntegerMaxValue) { writer.WriteUInt16BE((ushort)(0x8000 | value)); } else if (value <= MaxCompressedIntegerValue) { writer.WriteUInt32BE(0xc0000000 | value); } else { Throw.ValueArgumentOutOfRange(); } } } internal static void WriteCompressedInteger(BlobBuilder writer, uint value) { unchecked { if (value <= SingleByteCompressedIntegerMaxValue) { writer.WriteByte((byte)value); } else if (value <= TwoByteCompressedIntegerMaxValue) { writer.WriteUInt16BE((ushort)(0x8000 | value)); } else if (value <= MaxCompressedIntegerValue) { writer.WriteUInt32BE(0xc0000000 | value); } else { Throw.ValueArgumentOutOfRange(); } } } internal static void WriteCompressedSignedInteger(ref BlobWriter writer, int value) { unchecked { const int b6 = (1 << 6) - 1; const int b13 = (1 << 13) - 1; const int b28 = (1 << 28) - 1; // 0xffffffff for negative value // 0x00000000 for non-negative int signMask = value >> 31; if ((value & ~b6) == (signMask & ~b6)) { int n = ((value & b6) << 1) | (signMask & 1); writer.WriteByte((byte)n); } else if ((value & ~b13) == (signMask & ~b13)) { int n = ((value & b13) << 1) | (signMask & 1); writer.WriteUInt16BE((ushort)(0x8000 | n)); } else if ((value & ~b28) == (signMask & ~b28)) { int n = ((value & b28) << 1) | (signMask & 1); writer.WriteUInt32BE(0xc0000000 | (uint)n); } else { Throw.ValueArgumentOutOfRange(); } } } internal static void WriteCompressedSignedInteger(BlobBuilder writer, int value) { unchecked { const int b6 = (1 << 6) - 1; const int b13 = (1 << 13) - 1; const int b28 = (1 << 28) - 1; // 0xffffffff for negative value // 0x00000000 for non-negative int signMask = value >> 31; if ((value & ~b6) == (signMask & ~b6)) { int n = ((value & b6) << 1) | (signMask & 1); writer.WriteByte((byte)n); } else if ((value & ~b13) == (signMask & ~b13)) { int n = ((value & b13) << 1) | (signMask & 1); writer.WriteUInt16BE((ushort)(0x8000 | n)); } else if ((value & ~b28) == (signMask & ~b28)) { int n = ((value & b28) << 1) | (signMask & 1); writer.WriteUInt32BE(0xc0000000 | (uint)n); } else { Throw.ValueArgumentOutOfRange(); } } } /// <summary> /// Writes a scalar (non-string) constant to a span. /// </summary> /// <param name="bytes">The span where the content will be encoded.</param> /// <param name="value">The constant value.</param> /// <returns>The number of bytes that was written.</returns> internal static int WriteScalarConstant(Span<byte> bytes, object? value) { if (value == null) { // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 4-byte zero. BinaryPrimitives.WriteUInt32LittleEndian(bytes, 0); return sizeof(uint); } var type = value.GetType(); if (type.IsEnum) { type = Enum.GetUnderlyingType(type); } if (type == typeof(bool)) { bytes[0] = (byte)((bool)value ? 1 : 0); return sizeof(bool); } else if (type == typeof(int)) { BinaryPrimitives.WriteInt32LittleEndian(bytes, (int)value); return sizeof(int); } else if (type == typeof(byte)) { bytes[0] = (byte)value; return sizeof(byte); } else if (type == typeof(char)) { BinaryPrimitives.WriteUInt16LittleEndian(bytes, (char)value); return sizeof(char); } else if (type == typeof(double)) { #if NET BinaryPrimitives.WriteDoubleLittleEndian(bytes, (double)value); #else double v = (double)value; unsafe { BinaryPrimitives.WriteUInt64LittleEndian(bytes, *(ulong*)(&v)); } #endif return sizeof(double); } else if (type == typeof(short)) { BinaryPrimitives.WriteInt16LittleEndian(bytes, (short)value); return sizeof(short); } else if (type == typeof(long)) { BinaryPrimitives.WriteInt64LittleEndian(bytes, (long)value); return sizeof(long); } else if (type == typeof(sbyte)) { bytes[0] = (byte)(sbyte)value; return sizeof(sbyte); } else if (type == typeof(float)) { #if NET BinaryPrimitives.WriteSingleLittleEndian(bytes, (float)value); #else float v = (float)value; unsafe { BinaryPrimitives.WriteUInt32LittleEndian(bytes, *(uint*)(&v)); } #endif return sizeof(float); } else if (type == typeof(ushort)) { BinaryPrimitives.WriteUInt16LittleEndian(bytes, (ushort)value); return sizeof(ushort); } else if (type == typeof(uint)) { BinaryPrimitives.WriteUInt32LittleEndian(bytes, (uint)value); return sizeof(uint); } else if (type == typeof(ulong)) { BinaryPrimitives.WriteUInt64LittleEndian(bytes, (ulong)value); return sizeof(ulong); } else { throw new ArgumentException(SR.Format(SR.InvalidConstantValueOfType, type)); } } internal static void WriteConstant(ref BlobWriter writer, object? value) { if (value == null) { // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 4-byte zero. writer.WriteUInt32(0); return; } var type = value.GetType(); if (type.IsEnum) { type = Enum.GetUnderlyingType(type); } if (type == typeof(bool)) { writer.WriteBoolean((bool)value); } else if (type == typeof(int)) { writer.WriteInt32((int)value); } else if (type == typeof(string)) { writer.WriteUTF16((string)value); } else if (type == typeof(byte)) { writer.WriteByte((byte)value); } else if (type == typeof(char)) { writer.WriteUInt16((char)value); } else if (type == typeof(double)) { writer.WriteDouble((double)value); } else if (type == typeof(short)) { writer.WriteInt16((short)value); } else if (type == typeof(long)) { writer.WriteInt64((long)value); } else if (type == typeof(sbyte)) { writer.WriteSByte((sbyte)value); } else if (type == typeof(float)) { writer.WriteSingle((float)value); } else if (type == typeof(ushort)) { writer.WriteUInt16((ushort)value); } else if (type == typeof(uint)) { writer.WriteUInt32((uint)value); } else if (type == typeof(ulong)) { writer.WriteUInt64((ulong)value); } else { throw new ArgumentException(SR.Format(SR.InvalidConstantValueOfType, type)); } } internal static void WriteConstant(BlobBuilder writer, object? value) { if (value == null) { // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 4-byte zero. writer.WriteUInt32(0); return; } var type = value.GetType(); if (type.IsEnum) { type = Enum.GetUnderlyingType(type); } if (type == typeof(bool)) { writer.WriteBoolean((bool)value); } else if (type == typeof(int)) { writer.WriteInt32((int)value); } else if (type == typeof(string)) { writer.WriteUTF16((string)value); } else if (type == typeof(byte)) { writer.WriteByte((byte)value); } else if (type == typeof(char)) { writer.WriteUInt16((char)value); } else if (type == typeof(double)) { writer.WriteDouble((double)value); } else if (type == typeof(short)) { writer.WriteInt16((short)value); } else if (type == typeof(long)) { writer.WriteInt64((long)value); } else if (type == typeof(sbyte)) { writer.WriteSByte((sbyte)value); } else if (type == typeof(float)) { writer.WriteSingle((float)value); } else if (type == typeof(ushort)) { writer.WriteUInt16((ushort)value); } else if (type == typeof(uint)) { writer.WriteUInt32((uint)value); } else if (type == typeof(ulong)) { writer.WriteUInt64((ulong)value); } else { throw new ArgumentException(SR.Format(SR.InvalidConstantValueOfType, type)); } } } }