in src/tools/MakePIAPortableTool/MakePIAPortableTool.cs [117:283]
private static int TransformIL(string inputFilePath, string outputFile)
{
bool isInterface = false;
Regex mscorlibType = new Regex(@"\[mscorlib\][A-Za-z][A-Za-z\.]+");
Regex paramCustomAttributeRegex = new Regex(@"^ *.param \[[0-9]+\]$");
HashSet<string> emittedUnknownTypes = new HashSet<string>();
using (InputFile inputFile = new InputFile(inputFilePath))
using (StreamWriter output = new StreamWriter(File.OpenWrite(outputFile)))
{
while (true)
{
string inputLine = inputFile.ReadLine();
if (inputLine == null)
break;
if (isInterface)
{
if (inputLine.Contains(" internalcall"))
{
inputLine = inputLine.Replace(" internalcall", "");
}
if (inputLine.Contains(" runtime "))
{
inputLine = inputLine.Replace(" runtime ", " ");
}
}
if (inputLine == ".assembly extern mscorlib")
{
if (!IsAssemblyReferenceBody(inputFile))
{
Error.Emit(Error.Code.BadMscorlibReference, inputFile, "Unexpected text near '.assembly extern mscorlib'. Unable to transform.");
return -1;
}
foreach (var assembly in s_contractAssemblies)
{
output.Write(".assembly extern ");
output.WriteLine(assembly.Item1);
output.WriteLine("{");
output.WriteLine(" .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )");
output.Write(" .ver ");
output.WriteLine(assembly.Item2);
output.WriteLine("}");
}
continue;
}
else if (inputLine == ".assembly extern stdole")
{
if (!IsAssemblyReferenceBody(inputFile))
{
Error.Emit(Error.Code.BadStdoleReference, inputFile, "Unexpected text near '.assembly extern stdole'. Unable to transform.");
return -1;
}
// Drop the stdole reference on the floor. It wasn't actually used.
continue;
}
else if (inputLine.StartsWith(" .publickey = (00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00", StringComparison.Ordinal))
{
output.WriteLine(" .custom instance void [System.Runtime]System.Reflection.AssemblyDelaySignAttribute::.ctor(bool)");
output.WriteLine(" = { bool(true)}");
output.WriteLine(" .custom instance void [System.Runtime]System.Reflection.AssemblySignatureKeyAttribute::.ctor(string, string)");
output.WriteLine(" = {string('002400000c800000140100000602000000240000525341310008000001000100613399aff18ef1a2c2514a273a42d9042b72321f1757102df9ebada69923e2738406c21e5b801552ab8d200a65a235e001ac9adc25f2d811eb09496a4c6a59d4619589c69f5baf0c4179a47311d92555cd006acc8b5959f2bd6e10e360c34537a1d266da8085856583c85d81da7f3ec01ed9564c58d93d713cd0172c8e23a10f0239b80c96b07736f5d8b022542a4e74251a5f432824318b3539a5a087f8e53d2f135f9ca47f3bb2e10aff0af0849504fb7cea3ff192dc8de0edad64c68efde34c56d302ad55fd6e80f302d5efcdeae953658d3452561b5f36c542efdbdd9f888538d374cef106acf7d93a4445c3c73cd911f0571aaf3d54da12b11ddec375b3')");
output.WriteLine(" string('a5a866e1ee186f807668209f3b11236ace5e21f117803a3143abb126dd035d7d2f876b6938aaf2ee3414d5420d753621400db44a49c486ce134300a2106adb6bdb433590fef8ad5c43cba82290dc49530effd86523d9483c00f458af46890036b0e2c61d077d7fbac467a506eba29e467a87198b053c749aa2a4d2840c784e6d')}");
// fall through to outputting the input line
}
else if (inputLine.Contains("[mscorlib]"))
{
if (IsIgnoredCustomAttributeLine(inputLine))
{
SkipCustomAttribute(inputLine, inputFile);
continue;
}
StringBuilder lineBuilder = new StringBuilder();
Match match = mscorlibType.Match(inputLine);
int nextStartPos = 0;
while (match.Success)
{
lineBuilder.Append(inputLine, nextStartPos, match.Index - nextStartPos);
nextStartPos = match.Index + match.Length;
string typeName = match.Value.Substring("[mscorlib]".Length);
string assemblyName;
if (!s_typeToContractAssemblyMap.TryGetValue(typeName, out assemblyName))
{
if (!emittedUnknownTypes.Contains(typeName))
{
emittedUnknownTypes.Add(typeName);
Error.Emit(Error.Code.UnknownType, inputFile, "Unknown type '{0}'. Unable to map to contract assembly.", typeName);
}
assemblyName = "unknown_assembly";
}
lineBuilder.Append('[');
lineBuilder.Append(assemblyName);
lineBuilder.Append(']');
lineBuilder.Append(typeName);
match = match.NextMatch();
}
lineBuilder.Append(inputLine, nextStartPos, inputLine.Length - nextStartPos);
output.WriteLine(lineBuilder);
continue;
}
else if (paramCustomAttributeRegex.IsMatch(inputLine))
{
string customAttributeLine = inputFile.TestNextLine(IsIgnoredCustomAttributeLine);
if (customAttributeLine != null)
{
SkipCustomAttribute(customAttributeLine, inputFile);
inputFile.SkipBlankLines();
// The '.param' directive contains an integer with the custom attribute index. We currently don't have code to rewrite that index, so
// error out if we detect we need such code. If we need to implement this in the future, we could do so by getting a bunch of lines, rewriting them
// and then unreading them (InputFile.UnreadLine)
string[] problemLines = inputFile.TestNextLines(
l1 => paramCustomAttributeRegex.IsMatch(l1),
l2 => !IsIgnoredCustomAttributeLine(l2));
if (problemLines != null)
{
Error.Emit(Error.Code.UnsupportedCustomAttribute, inputFile, "Non-ignored custom attribute found after ignored custom attribute. This is not currently supported by this script.");
}
continue;
}
}
else if (inputLine.StartsWith("// Metadata version: v", StringComparison.Ordinal))
{
// This line doesn't hurt, but it is slightly confusing since this isn't the metadata version we will use, so strip it.
continue;
}
// Remove 'import' from the interfaces
else if (inputLine.StartsWith(".class ", StringComparison.Ordinal))
{
// Remove '_EventProvider' classes from MS.VS.Interop since they
// use ArrayList which is not in netstandard 1.3
if (inputLine.Contains("_EventProvider"))
{
inputLine = "";
SkipClass(inputFile);
}
else
{
isInterface = inputLine.Contains(" interface");
if (inputLine.Contains(" import "))
{
inputLine = inputLine.Replace(" import ", " ");
}
}
}
output.WriteLine(inputLine);
}
}
return Error.HasError ? 1 : 0;
}