예제 #1
0
        private static Boolean TryParsePublicKeyFullOrToken(CILAssemblyName assemblyName, String fullAssemblyName, ref Int32 nameIdx)
        {
            var aux     = NextSeparatorIdx(fullAssemblyName, ASSEMBLY_NAME_ELEMENTS_SEPARATOR, nameIdx);
            var success = aux > 0;

            if (success && !String.Equals("null", fullAssemblyName.Substring(nameIdx, aux), StringComparison.OrdinalIgnoreCase))
            {
                assemblyName._publicKey = StringConversions.HexStr2ByteArray(fullAssemblyName, nameIdx, 0, 0);
            }
            nameIdx += aux;
            return(success);
        }
        /// <summary>
        /// This method will generate the Qi4CS assemblies.
        /// </summary>
        /// <param name="projectDir">The project directory.</param>
        /// <param name="targetFWID">The target framework identifier.</param>
        /// <param name="targetFWVersion">The target framework version.</param>
        /// <param name="targetFWProfile">The target framework profile.</param>
        /// <param name="referenceAssembliesDir">The base directory where target framework assemblies reside. Should be the directory where target framework assemblies are found under subdirectory <c>&lt;framework-id&gt;\&lt;framework-version&gt;</c>, e.g. <c>".NETFramework\v4.0"</c>.</param>
        /// <param name="targetPlatform">The textual name of target platform.</param>
        /// <param name="path">The path where to store assemblies.</param>
        /// <param name="assemblySNInfo">The file containing strongname information about the assemblies to be emitted.</param>
        /// <param name="qi4CSDir">The directory where Qi4CS assemblies actually used by the application reside.</param>
        /// <param name="verify">Whether to run PEVerify on generated Qi4CS assemblies.</param>
        /// <param name="winSDKDir">The directory where the Windows SDK resides, needed to detect PEVerify executable.</param>
        public IDictionary <String, String> GenerateAssemblies(String projectDir, String targetFWID, String targetFWVersion, String targetFWProfile, String referenceAssembliesDir, String targetPlatform, String path, String assemblySNInfo, String qi4CSDir, Boolean verify, String winSDKDir)
        {
            qi4CSDir = Path.GetFullPath(qi4CSDir);
            path     = Path.GetFullPath(path);

            XElement assemblyInfo = null;

            if (!String.IsNullOrEmpty(assemblySNInfo))
            {
                try
                {
                    assemblyInfo = XElement.Load(new StringReader(assemblySNInfo));
                }
                catch (Exception exc)
                {
                    throw new Qi4CSBuildException("Invalid assembly info element " + assemblySNInfo + ".\n" + exc);
                }
            }
            Func <String, Stream> streamOpener = str => File.Open(str, FileMode.Open, FileAccess.Read, FileShare.Read);

            referenceAssembliesDir = Path.Combine(referenceAssembliesDir, targetFWID, targetFWVersion);
            if (!String.IsNullOrEmpty(targetFWProfile))
            {
                referenceAssembliesDir = Path.Combine(referenceAssembliesDir, "Profile", targetFWProfile);
            }

            String msCorLibName; String fwDisplayName; String targetFWDir;
            var    thisFWMoniker = new FrameworkMonikerInfo(targetFWID, targetFWVersion, targetFWProfile, DotNETReflectionContext.ReadAssemblyInformationFromRedistXMLFile(Path.Combine(referenceAssembliesDir, "RedistList", "FrameworkList.xml"), out msCorLibName, out fwDisplayName, out targetFWDir), msCorLibName, fwDisplayName);

            if (!String.IsNullOrEmpty(targetFWDir))
            {
                referenceAssembliesDir = targetFWDir;
            }

            if (!Directory.Exists(referenceAssembliesDir))
            {
                throw new Qi4CSBuildException("The reference assemblies directory " + referenceAssembliesDir + " does not exist.");
            }

            referenceAssembliesDir += Path.DirectorySeparatorChar;

            var isX86         = X86.Equals(targetPlatform, StringComparison.InvariantCultureIgnoreCase);
            var targetMachine = String.IsNullOrEmpty(targetPlatform) || ANYCPU.Equals(targetPlatform, StringComparison.InvariantCultureIgnoreCase) || isX86 ?
                                ImageFileMachine.I386 :
                                ImageFileMachine.AMD64; // TODO more machines
            var mFlags = ModuleFlags.ILOnly;

            if (isX86)
            {
                mFlags |= ModuleFlags.Required32Bit;
            }

            var snDic = new ConcurrentDictionary <String, Tuple <StrongNameKeyPair, AssemblyHashAlgorithm> >();

            if (assemblyInfo != null)
            {
                foreach (var elem in assemblyInfo.XPathSelectElements("assembly"))
                {
                    snDic[elem.Attribute("name").Value] = Tuple.Create(
                        SubElementTextOrFallback(elem, "sn", (XElement snElem, out StrongNameKeyPair sn) =>
                    {
                        var type = snElem.Attribute("type");
                        sn       = "container".Equals(type.Value, StringComparison.InvariantCultureIgnoreCase) ?
                                   new StrongNameKeyPair(snElem.Value) :
                                   new StrongNameKeyPair("inline".Equals(type.Value, StringComparison.InvariantCultureIgnoreCase) ? StringConversions.HexStr2ByteArray(snElem.Value) : ReadAllBytes(projectDir, snElem.Value));
                        return(true);
                    }, null),
                        SubElementAttributeOrFallback(elem, "hashAlgorithm", (String algoStr, out AssemblyHashAlgorithm algo) =>
                    {
                        return(Enum.TryParse <AssemblyHashAlgorithm>(algoStr, out algo));
                    }, AssemblyHashAlgorithm.SHA1));
                }
            }

            var runtimeRootDir = Path.GetDirectoryName(new Uri(typeof(Object).Assembly.CodeBase).LocalPath);


            var actualPath = path;
            var needToMove = verify && !String.Equals(actualPath, qi4CSDir);

            if (needToMove)
            {
                // When verifying strong-named assemblies in different location than application's out dir, the .dll.config file
                // should hold recursively all non-.NET references, which is quite complicated and maybe not even enough.
                // Instead, emit Qi4CS assemblies into out dir and move them after verifying
                actualPath = qi4CSDir;
            }

            IDictionary <System.Reflection.Assembly, String> genAssFilenames;

            try
            {
                genAssFilenames = this._modelFactory.Model.GenerateAndSaveAssemblies(
                    actualPath,
                    this.IsSilverlight,
                    (nAss, gAss) =>
                {
                    Tuple <StrongNameKeyPair, AssemblyHashAlgorithm> snTuple;
                    snDic.TryGetValue(nAss.GetName().Name, out snTuple);
                    var sn    = snTuple == null ? null : snTuple.Item1;
                    var eArgs = EmittingArguments.CreateForEmittingWithMoniker(gAss.ReflectionContext, targetMachine, TargetRuntime.Net_4_0, ModuleKind.Dll, null, runtimeRootDir, referenceAssembliesDir, streamOpener, sn, thisFWMoniker, String.Equals(thisFWMoniker.FrameworkName, PCL_FW_NAME), mFlags);

                    gAss.AddTargetFrameworkAttributeWithMonikerInfo(thisFWMoniker, eArgs.AssemblyMapper);
                    if (snTuple != null)
                    {
                        eArgs.SigningAlgorithm = snTuple.Item2;
                    }
                    return(eArgs);
                });
            }
            catch (InvalidApplicationModelException apme)
            {
                throw new Qi4CSBuildException("The Qi4CS model was not valid:\n" + apme.ValidationResult, apme);
            }

            if (verify)
            {
                try
                {
                    winSDKDir = FindWinSDKBinPath(winSDKDir);
                    foreach (var fn in genAssFilenames)
                    {
                        Verify(winSDKDir, fn.Value, snDic != null && snDic.ContainsKey(fn.Key.GetName().Name));
                    }
                }
                finally
                {
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }

                    foreach (var kvp in genAssFilenames.ToArray())
                    {
                        var fn = kvp.Value;
                        try
                        {
                            var targetFn = Path.Combine(path, Path.GetFileName(fn));
                            if (!String.Equals(fn, targetFn))
                            {
                                if (File.Exists(targetFn))
                                {
                                    try
                                    {
                                        File.Delete(targetFn);
                                    }
                                    catch
                                    {
                                        // Ignore
                                    }
                                }
                                File.Move(fn, targetFn);
                                genAssFilenames.Remove(kvp.Key);
                                genAssFilenames.Add(kvp.Key, targetFn);
                            }
                        }
                        catch
                        {
                            // Ignore
                        }
                    }
                }
            }

            return(genAssFilenames.ToDictionary(
                       kvp => kvp.Key.CodeBase,
                       kvp => kvp.Value
                       ));
        }
예제 #3
0
        /// <summary>
        /// This method reads assembly information from the <c>FrameworkList.xml</c> located in reference assemblies sud-directory <c>RedistList</c>.
        /// </summary>
        /// <param name="defaultTargetFWDir">This will be the default target framework directory if XML file does not define <c>TargetFrameworkDirectory</c> attribute.</param>
        /// <param name="stream">The opened file to <c>FrameworkList.xml</c>.</param>
        /// <param name="assemblyFilenameEnumerator">The callback to enumerate all assembly files in the directory. Will be used only if assembly file list is not present in XML file.</param>
        /// <param name="ctxFactory">The callback to create a new <see cref="CILReflectionContext"/>. Will be used only if assembly file list is not present in XML file.</param>
        /// <param name="streamOpener">The callback to open assemblies in the target framework directory. Will be used only if assembly file list is not present in XML file.</param>
        /// <param name="fileExistsCheck">The callback to check for file existence. Will be used only if assembly file list is present in XML file. The first argument is target framework directory, and second argument is assembly name.</param>
        /// <param name="msCorLibName">The detected name of the assembly which acts as <c>mscorlib</c> assembly of this framework.</param>
        /// <param name="frameworkDisplayName">The detected display name of the framework.</param>
        /// <param name="targetFWDir">The detected value of target framework directory, potentially relative.</param>
        /// <returns>Assembly information persisted in the file.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="assemblyFilenameEnumerator"/> or <paramref name="ctxFactory"/> is <c>null</c>.</exception>
        /// <exception cref="InvalidDataException">If the <c>FrameworkList.xml</c> is in malformed format.</exception>
        /// <exception cref="InvalidOperationException">If the <c>FrameworkList.xml</c> does not define <c>TargetFrameworkDirectory</c> attribute and <paramref name="defaultTargetFWDir"/> is <c>null</c> or empty.</exception>
        public static IDictionary <String, Tuple <Version, Byte[]> > ReadAssemblyInformationFromRedistXMLFile(
            String defaultTargetFWDir,
            Stream stream,
            Func <String, IEnumerable <String> > assemblyFilenameEnumerator,
            Func <CILReflectionContext> ctxFactory,
            Func <String, Stream> streamOpener,
            Func <String, String, Boolean> fileExistsCheck,
            out String msCorLibName,
            out String frameworkDisplayName,
            out String targetFWDir
            )
        {
            var xmlSettings = new System.Xml.XmlReaderSettings();

            xmlSettings.CloseInput = false;

            using (var xml = System.Xml.XmlReader.Create(stream, xmlSettings))
            {
                xml.Read();
                // Move to Root and then to File-listing
                if (!xml.ReadToNextSibling("FileList"))
                {
                    throw new InvalidDataException("FrameworkList.xml seems to be in invalid format (FileList).");
                }

                frameworkDisplayName = xml.GetAttribute("Name");

                var asses = new List <Tuple <String, Version, Byte[]> >();


                targetFWDir = xml.GetAttribute("TargetFrameworkDirectory");
                if (String.IsNullOrEmpty(targetFWDir))
                {
                    // Can't trust <FileList> element children, since they contain facade assemblies as well.
                    targetFWDir = defaultTargetFWDir;
                    if (String.IsNullOrEmpty(targetFWDir))
                    {
                        throw new InvalidOperationException("Failed to resolve target framework moniker directory, as XML redistribution list file did not contain 'TargetFrameworkDirectory' attribute nor default target framework directory was specified.");
                    }
                }

                // If the <FileList> is present, we need to read the file information while checking that the file really exists
                if (xml.ReadToDescendant("File"))
                {
                    ArgumentValidator.ValidateNotNull("File existence checker", fileExistsCheck);

                    do
                    {
                        var simpleAssemblyName = xml.GetAttribute("AssemblyName");
                        if (fileExistsCheck(targetFWDir, simpleAssemblyName))
                        {
                            asses.Add(Tuple.Create(simpleAssemblyName, Version.Parse(xml.GetAttribute("Version")), StringConversions.HexStr2ByteArray(xml.GetAttribute("PublicKeyToken"))));
                        }
                    } while (xml.ReadToNextSibling("File"));
                }
                else
                {
                    // On Mono, .NETFramework assemblies are not enumerated in the FrameworkList.xml, making this process really slow
                    ArgumentValidator.ValidateNotNull("Assembly file name enumerator", assemblyFilenameEnumerator);
                    ArgumentValidator.ValidateNotNull("CIL Reflection Context factory", ctxFactory);
                    ArgumentValidator.ValidateNotNull("Stream opener", streamOpener);

                    using (var ctx = ctxFactory())
                    {
                        foreach (var fn in assemblyFilenameEnumerator(targetFWDir))
                        {
                            var eArgs = EmittingArguments.CreateForLoadingAssembly();
                            using (var curStream = streamOpener(fn))
                            {
                                try
                                {
                                    var ass = ctx.LoadAssembly(curStream, eArgs);
                                    var an  = ass.Name;
                                    asses.Add(Tuple.Create(an.Name, new Version(an.MajorVersion, an.MinorVersion, an.BuildNumber, an.Revision), ass.GetPublicKeyToken()));
                                }
                                catch
                                {
                                    // Ignore - some non-CLI files present sometimes as well here.
                                }
                            }
                        }
                    }
                }

                var result = asses.ToDictionary(t => t.Item1, t => Tuple.Create(t.Item2, t.Item3));
                msCorLibName = result.ContainsKey(Consts.NEW_MSCORLIB_NAME) ? Consts.NEW_MSCORLIB_NAME : Consts.MSCORLIB_NAME;
                return(result);
            }
        }