Exemple #1
0
        private void WriteEnumerationFile
        (
            [NotNull] string enumOutputDirectory,
            [NotNull] EnumerationSignature enumeration
        )
        {
            var tempEnumFilePath = Path.GetTempFileName();

            using (var outputFile = File.Open(tempEnumFilePath, FileMode.OpenOrCreate))
            {
                using (var sw = new SourceWriter(new StreamWriter(outputFile)))
                {
                    sw.WriteLine(EmbeddedResources.LicenseText);
                    sw.WriteLineNoTabs();

                    if (enumeration.IsFlagEnum)
                    {
                        sw.WriteLine("using System;");
                        sw.WriteLineNoTabs();
                    }

                    sw.WriteLine("// ReSharper disable InconsistentNaming");
                    sw.WriteLine("#pragma warning disable SA1139 // Use literal suffix notation instead of casting");
                    sw.WriteLineNoTabs();

                    sw.WriteLine($"namespace {_generatorSettings.Namespace}");
                    using (sw.BeginBlock())
                    {
                        // Document which functions use this enum.
                        sw.WriteLine("/// <summary>");
                        sw.WriteLine($"/// {GetEnumUsageString(enumeration)}");
                        sw.WriteLine("/// </summary>");

                        if (enumeration.IsFlagEnum)
                        {
                            sw.WriteLine("[Flags]");
                        }

                        sw.WriteLine($"public enum {enumeration.Name}");
                        using (sw.BeginBlock())
                        {
                            WriteTokens(sw, enumeration.Tokens);
                        }
                    }
                }
            }

            var outputEnumPath = Path.Combine(enumOutputDirectory, $"{enumeration.Name}.cs");

            if (File.Exists(outputEnumPath))
            {
                File.Delete(outputEnumPath);
            }

            File.Move(tempEnumFilePath, outputEnumPath);
        }
Exemple #2
0
        private void WriteTokens([NotNull] SourceWriter sw, [NotNull] IEnumerable <TokenSignature> tokens)
        {
            // Make sure everything is sorted. This will avoid random changes between
            // consecutive runs of the program.
            tokens = tokens.OrderBy(c => c.Value).ThenBy(c => c.Name).ToList();

            foreach (var token in tokens)
            {
                var valueString = $"0x{token.Value:X}";

                sw.WriteLine("/// <summary>");
                var originalTokenName = $"{_generatorSettings.ConstantPrefix}{token.Name.Underscore().ToUpperInvariant()}";
                sw.WriteLine($"/// Original was {originalTokenName} = {valueString}");
                sw.WriteLine("/// </summary>");

                var needsCasting = token.Value > int.MaxValue || token.Value < 0;
                if (needsCasting)
                {
                    Debug.WriteLine($"Warning: casting overflowing enum value \"{token.Name}\" from 64-bit to 32-bit.");
                    valueString = $"unchecked((int){valueString})";
                }

                if (token != tokens.Last())
                {
                    sw.WriteLine($"{token.Name} = {valueString},");
                    sw.WriteLineNoTabs();
                }
                else
                {
                    sw.WriteLine($"{token.Name} = {valueString}");
                }
            }
        }
Exemple #3
0
        private void WriteWrapperClassConstructorFile([NotNull] string wrappersOutputDirectory)
        {
            var tempInteropFilePath = Path.GetTempFileName();

            using (var outputFile = File.Open(tempInteropFilePath, FileMode.OpenOrCreate))
            {
                using (var sw = new SourceWriter(new StreamWriter(outputFile)))
                {
                    sw.WriteLine(EmbeddedResources.LicenseText);
                    sw.WriteLineNoTabs();

                    sw.WriteLine("using System;");
                    sw.WriteLine("using System.Runtime.InteropServices;");
                    sw.WriteLine("using System.Text;");
                    sw.WriteLineNoTabs();

                    sw.WriteLine($"namespace {_generatorSettings.Namespace}");
                    using (sw.BeginBlock())
                    {
                        sw.WriteLine($"public sealed partial class {_generatorSettings.ClassName}");
                        using (sw.BeginBlock())
                        {
                            // Write constructor
                            sw.WriteLine($"static {_generatorSettings.ClassName}()");
                            using (sw.BeginBlock())
                            {
                                var nativeEntrypointsWithPrefix = _profile.NativeSignatures
                                                                  .Select
                                                                  (
                                    ns => $"{_generatorSettings.FunctionPrefix}{ns.Name}"
                                                                  )
                                                                  .ToList();

                                // Write entry point names.
                                // Instead of strings, which are costly to construct,
                                // we use a 1d array of ASCII bytes. Names are laid out
                                // sequentially, with a nul-terminator between them.
                                sw.WriteLine("EntryPointNames = new byte[]");
                                using (sw.BeginBlock(true))
                                {
                                    foreach (var nativeEntrypoint in nativeEntrypointsWithPrefix)
                                    {
                                        var byteString = string.Join
                                                         (
                                            ", ",
                                            Encoding.ASCII.GetBytes(nativeEntrypoint).Select(b => b.ToString()).ToArray()
                                                         );

                                        sw.WriteLine($"{byteString}, 0,");
                                    }
                                }

                                sw.WriteLineNoTabs();

                                // Write entry point name offsets.
                                // This is an array of offsets into the EntryPointNames[] array above.
                                sw.WriteLine("EntryPointNameOffsets = new int[]");
                                using (sw.BeginBlock(true))
                                {
                                    var offset = 0;
                                    foreach (var nativeEntrypoint in nativeEntrypointsWithPrefix)
                                    {
                                        sw.WriteLine($"{offset.ToString()},");
                                        offset += nativeEntrypoint.Length + 1;
                                    }
                                }

                                sw.WriteLineNoTabs();

                                sw.WriteLine("EntryPoints = new IntPtr[EntryPointNameOffsets.Length];");
                            }
                        }
                    }
                }
            }

            var outputFilePath = Path.Combine(wrappersOutputDirectory, $"{_generatorSettings.ClassName}.cs");

            if (File.Exists(outputFilePath))
            {
                File.Delete(outputFilePath);
            }

            File.Move(tempInteropFilePath, outputFilePath);
        }
Exemple #4
0
        private void WriteCategoryWrapperFile
        (
            [NotNull] string extensionOutputDirectory,
            [NotNull] string extensionName,
            [NotNull] string category
        )
        {
            var translatedExtensionName = _identifierTranslator.Translate(extensionName);

            var nativeSignatures = _profile.NativeSignatures
                                   .Where(ns => ns.Extension == extensionName && ns.Categories.First() == category)
                                   .OrderBy(s => s.Name)
                                   .ThenBy(s => s.Parameters.Count)
                                   .ToList();

            var overloads = _profile.Overloads
                            .Where(o => o.Extension == extensionName && o.Categories.First() == category)
                            .ToList();

            var categorySignatures = nativeSignatures
                                     .Concat(overloads)
                                     .OrderBy(s => s.Name)
                                     .ThenBy(s => s.Parameters.Count)
                                     .ThenBy(s => s.ToString())
                                     .ToList();

            if (categorySignatures.Count == 0)
            {
                return;
            }

            var translatedCategoryName = _identifierTranslator.Translate(category);

            // Create the category file
            var tempWrapperOutputPath = Path.GetTempFileName();

            using (var outputFile = File.Open(tempWrapperOutputPath, FileMode.OpenOrCreate))
            {
                using (var sw = new SourceWriter(new StreamWriter(outputFile)))
                {
                    sw.WriteLine(EmbeddedResources.LicenseText);
                    sw.WriteLineNoTabs();

                    sw.WriteLine("using System;");
                    sw.WriteLine("using System.Runtime.InteropServices;");
                    sw.WriteLine("using System.Text;");
                    sw.WriteLineNoTabs();

                    sw.WriteLine($"namespace {_generatorSettings.Namespace}");
                    using (sw.BeginBlock())
                    {
                        SourceWriterBlock?outerBlock = null;
                        if (extensionName == "Core")
                        {
                            sw.WriteLine($"public sealed partial class {_generatorSettings.ClassName}");
                        }
                        else
                        {
                            sw.WriteLine($"public sealed partial class {_generatorSettings.ClassName}");

                            outerBlock = sw.BeginBlock();

                            sw.WriteLine("/// <summary>");
                            sw.WriteLine
                            (
                                $"/// Contains native bindings to functions in the category" +
                                $" \"{translatedCategoryName}\" in the extension " +
                                $"\"{translatedExtensionName}\"."
                            );
                            sw.WriteLine("/// </summary>");

                            // Identifiers can't begin with numbers
                            var safeExtensionName = char.IsDigit(extensionName[0])
                                ? $"{_generatorSettings.ConstantPrefix}{extensionName}"
                                : extensionName;

                            sw.WriteLine($"public static partial class {safeExtensionName}");
                        }

                        // Write the native signature methods
                        // Write the overload methods
                        using (sw.BeginBlock())
                        {
                            var last = categorySignatures[categorySignatures.Count - 1];
                            foreach (var signature in categorySignatures)
                            {
                                WriteMethod(sw, signature);

                                if (signature != last)
                                {
                                    sw.WriteLineNoTabs();
                                }
                            }

                            sw.WriteLineNoTabs();

                            sw.WriteLine(
                                "#pragma warning disable SA1300 // Element should begin with an upper-case letter");
                            sw.WriteLineNoTabs();

                            // Write the native signature externs
                            // These are required by the patcher.
                            foreach (var signature in nativeSignatures)
                            {
                                sw.WriteLine(
                                    $"[Slot({_entrypointSlots[signature.NativeEntrypoint].ToString()})]");
                                sw.WriteLine(
                                    "[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]");
                                sw.WriteLine
                                (
                                    $"private static extern {GetNativeDeclarationString(signature)};"
                                );

                                if (signature != nativeSignatures.Last())
                                {
                                    sw.WriteLineNoTabs();
                                }
                            }
                        }

                        // We've got a nested class to close
                        outerBlock?.Dispose();
                    }
                }
            }

            var outputCategorySubPath = Path.Combine(extensionOutputDirectory, $"{translatedCategoryName}.cs");

            if (File.Exists(outputCategorySubPath))
            {
                File.Delete(outputCategorySubPath);
            }

            File.Move(tempWrapperOutputPath, outputCategorySubPath);
        }