예제 #1
0
        public IDictionary <IMetadataMember, MetadataToken> UnlockMetadata(IMetadataBuilder builder)
        {
            if (!IsLocked)
            {
                throw new InvalidOperationException("Cannot unlock the metadata if it has not already been locked.");
            }

            var image = Image;

            // Construct new metadata streams.
            var buffer = builder.Rebuild(image);

            // Create resources.
            NetDirectory.ResourcesManifest = buffer.ResourcesBuffer.CreateDirectory();

            // Serialize new streams.
            var newStreams = new MetadataStreamBuffer[]
            {
                buffer.TableStreamBuffer,
                buffer.BlobStreamBuffer,
                buffer.GuidStreamBuffer,
                buffer.StringStreamBuffer,
                buffer.UserStringStreamBuffer
            }.ToDictionary(x => x, x => x.CreateStream());

            // Determine new entrypoint token.
            var  newTokenMapping = buffer.TableStreamBuffer.GetNewTokenMapping();
            uint entrypointToken;

            if (image.ManagedEntrypoint == null)
            {
                entrypointToken = 0u;
            }
            else
            {
                if (newTokenMapping.TryGetValue(image.ManagedEntrypoint, out var token))
                {
                    entrypointToken = token.ToUInt32();
                }
                else
                {
                    throw new MemberNotImportedException(image.ManagedEntrypoint);
                }
            }

            // Unlock metadata, commit changes to streams.
            Image = null;
            foreach (var entry in newStreams)
            {
                var header = StreamHeaders.FirstOrDefault(x => x.Name == entry.Key.Name);

                if (header == null)
                {
                    header = new MetadataStreamHeader(entry.Key.Name);
                    StreamHeaders.Add(header);
                }

                header.Stream = entry.Value;
            }

            // Update managed entrypoint.
            NetDirectory.EntryPointToken = entrypointToken;
            return(newTokenMapping);
        }