| File: Actions\GrammarActions.Manifest.Assembly.cs | Web Access |
| Project: ILAssembler.csproj (ILAssembler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Immutable; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Text; using Antlr4.Runtime; namespace ILAssembler; #pragma warning disable CA1822 // Parser actions are invoked through the per-parser GrammarActions instance. internal sealed partial class GrammarActions { internal void SetAssemblyAttribute(CILParser.AsmAttrAnyContext context) { (AssemblyFlags value, AssemblyFlags mask) = context.Start.Text switch { "retargetable" => (AssemblyFlags.Retargetable, (AssemblyFlags)0), "windowsruntime" => (AssemblyFlags.WindowsRuntime, (AssemblyFlags)0), "noplatform" => (AssemblyFlags.NoPlatform, (AssemblyFlags)0), "legacy library" => ((AssemblyFlags)0, (AssemblyFlags)0), "cil" => (GetFlagForArch(ProcessorArchitecture.MSIL), AssemblyFlags.ArchitectureMask), "x86" => (GetFlagForArch(ProcessorArchitecture.X86), AssemblyFlags.ArchitectureMask), "amd64" => (GetFlagForArch(ProcessorArchitecture.Amd64), AssemblyFlags.ArchitectureMask), "arm" => (GetFlagForArch(ProcessorArchitecture.Arm), AssemblyFlags.ArchitectureMask), "arm64" => (GetFlagForArch((ProcessorArchitecture)6), AssemblyFlags.ArchitectureMask), _ => ((AssemblyFlags)0, (AssemblyFlags)0) }; context.Value = value; context.Mask = mask; } internal AssemblyFlags AddAssemblyAttribute( AssemblyFlags attributes, AssemblyFlags value, AssemblyFlags mask) => mask == 0 ? attributes | value : (attributes & ~mask) | value; internal AssemblyDefinitionValue CreateAssemblyDefinition( AssemblyFlags attributes, string name, ImmutableArray<AssemblyDeclarationValue> declarations) => new(attributes, name, declarations); internal AssemblyDeclarationValue CreateAssemblyHashAlgorithmDeclaration(IToken value) => new AssemblyHashAlgorithmDirectiveValue((AssemblyHashAlgorithm)ParseInt32(value)); internal AssemblyDeclarationValue CreateAssemblySecurityDeclaration( SecurityDeclarationValue? value, IToken location) => new AssemblySecurityDirectiveValue(value, location); internal AssemblyDeclarationValue CreateAssemblyPublicKeyDeclaration( ImmutableArray<byte> value) => new AssemblyPublicKeyDirectiveValue(value); internal AssemblyDeclarationValue CreateAssemblyVersionDeclaration( int? major, int? minor, int? build, int? revision) => new AssemblyVersionDirectiveValue(new( major ?? 0, minor ?? 0, build ?? 0, revision ?? 0)); internal AssemblyDeclarationValue CreateAssemblyLocaleDeclaration(string value) => new AssemblyLocaleDirectiveValue(value); internal AssemblyDeclarationValue CreateAssemblyLocaleDeclaration( ImmutableArray<byte> value) => new AssemblyLocaleDirectiveValue(Encoding.Unicode.GetString(value.AsSpan())); internal AssemblyDeclarationValue CreateAssemblyCustomAttributeDeclaration( CustomAttributeDeclarationValue? value, IToken location) => new AssemblyCustomAttributeDirectiveValue(value, location); private static AssemblyFlags GetFlagForArch(ProcessorArchitecture architecture) => (AssemblyFlags)((int)architecture << 4); private static (ProcessorArchitecture Architecture, AssemblyFlags Flags) GetArchAndFlags( AssemblyFlags flags) { ProcessorArchitecture architecture = (ProcessorArchitecture)(((int)flags & 0xF0) >> 4); return (architecture, flags & ~GetFlagForArch(architecture)); } private void MaterializeAssemblyDefinition(AssemblyDefinitionValue definition) { string assemblyName = _options.AssemblyName ?? definition.Name; _entityRegistry.Assembly ??= new EntityRegistry.AssemblyEntity(assemblyName); EntityRegistry.AssemblyEntity assembly = _entityRegistry.Assembly; (assembly.ProcessorArchitecture, assembly.Flags) = GetArchAndFlags(definition.Attributes); foreach (AssemblyDeclarationValue declaration in definition.Declarations) { switch (declaration) { case AssemblyHashAlgorithmDirectiveValue hashAlgorithm: assembly.HashAlgorithm = hashAlgorithm.Value; break; case AssemblySecurityDirectiveValue security: if (security.Value is { } securityValue && MaterializeSecurityDeclaration(securityValue, security.Location) is { } entity) { entity.Parent = assembly; } break; default: ApplyAssemblyOrReferenceDirective(assembly, declaration); break; } } if (_options.KeyFile is not null) { ApplyKeyFile(_options.KeyFile); } } private void ApplyAssemblyOrReferenceDirective( EntityRegistry.AssemblyOrRefEntity target, AssemblyDeclarationValue declaration) { switch (declaration) { case AssemblyPublicKeyDirectiveValue publicKey: // COMPAT: A reference's public key token wins regardless of declaration order. if (target is not EntityRegistry.AssemblyReferenceEntity assemblyReference || assemblyReference.PublicKeyOrToken is null || assemblyReference.Flags.HasFlag(AssemblyFlags.PublicKey)) { target.PublicKeyOrToken = CreateManifestBlob(publicKey.Value); target.Flags |= AssemblyFlags.PublicKey; } break; case AssemblyVersionDirectiveValue version: target.Version = version.Value; break; case AssemblyLocaleDirectiveValue locale: target.Culture = locale.Value; break; case AssemblyCustomAttributeDirectiveValue customAttribute: if (MaterializeCustomAttributeDeclaration( customAttribute.Value, customAttribute.Location) is { } attribute) { attribute.Owner ??= target; } break; } } private static BlobBuilder CreateManifestBlob(ImmutableArray<byte> value) { BlobBuilder blob = new(value.Length); blob.WriteBytes(value); return blob; } private void ApplyKeyFile(string keyFilePath) { if (_entityRegistry.Assembly is null) { return; } try { byte[] keyBytes = File.ReadAllBytes(keyFilePath); BlobBuilder blob = new(keyBytes.Length); blob.WriteBytes(keyBytes); _entityRegistry.Assembly.PublicKeyOrToken = blob; _entityRegistry.Assembly.Flags |= AssemblyFlags.PublicKey; } catch (Exception ex) { SourceText? firstDocument = _documents.Values.FirstOrDefault(); Location location = firstDocument is not null ? new Location(new SourceSpan(0, 0), firstDocument) : new Location(new SourceSpan(0, 0), new SourceText(string.Empty, keyFilePath)); _diagnostics.Add(new Diagnostic( DiagnosticIds.KeyFileError, DiagnosticSeverity.Error, $"Failed to read key file '{keyFilePath}': {ex.Message}", location)); } } internal void MaterializeAssemblyDefinition(CILParser.AssemblyBlockContext context) { if (context.Value is AssemblyDefinitionValue definition) { MaterializeAssemblyDefinition(definition); } } }