singrdk/base/Windows/AppReader/ReaderMain.cs

654 lines
24 KiB
C#
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
// ----------------------------------------------------------------------------
2008-03-05 09:52:00 -05:00
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
2008-11-17 18:29:00 -05:00
// ----------------------------------------------------------------------------
2008-03-05 09:52:00 -05:00
using System;
using ManifestReader;
using System.Collections;
using System.Diagnostics;
using System.IO;
namespace AppReader
{
class ReaderMain
{
static void Usage()
{
Console.WriteLine("AppReader.exe <manifestfile | (-d | -s) manifestdirectory | -r appdirectory>");
return;
}
static double computeSpread(int[] directoryCounts)
{
double count = 0;
2008-11-17 18:29:00 -05:00
for (int i = 0; i < directoryCounts.Length; i++) {
2008-03-05 09:52:00 -05:00
int curLevelCount = directoryCounts[i];
count += Math.Pow(100, -i)*(curLevelCount - 1);
}
return count;
}
static int getAppNumber(string name, Hashtable appNameTable, ref int nameCount)
{
if (!appNameTable.ContainsKey(name))
{
appNameTable[name] = nameCount++;
}
return (int)appNameTable[name];
}
static void parseFile(string appName, string file)
{
ManifestParser mp;
// get the suffix
string[] components = file.Split(new char[] {'.'}, 50);
string suffix = components[components.Length - 1];
if (suffix.Equals("wxs"))
{
mp = new WiXParser();
}
else if (suffix.ToLower().Equals("man") ||
suffix.ToLower().Equals("manifest"))
{
mp = new CMIParser();
}
2008-11-17 18:29:00 -05:00
else if (suffix.Equals("inf")) {
2008-03-05 09:52:00 -05:00
mp = new INFParser();
}
2008-11-17 18:29:00 -05:00
else if (suffix.Equals("inft")) {
2008-03-05 09:52:00 -05:00
mp = new RegINFParser();
}
2008-11-17 18:29:00 -05:00
else {
2008-03-05 09:52:00 -05:00
//Console.WriteLine("Unknown manifest suffix " + suffix);
return;
}
// otherwise, try to parse it
2008-11-17 18:29:00 -05:00
try {
2008-03-05 09:52:00 -05:00
mp.Parse(appName, file, new Hashtable());
}
2008-11-17 18:29:00 -05:00
catch (System.Xml.XmlException) {
2008-03-05 09:52:00 -05:00
Console.WriteLine("Could not parse " + file);
}
// catch(System.Exception e)
// {
// Console.WriteLine("Failed to parse " + file + " : " + e.Message);
// }
return;
}
static Hashtable parseFile(string appName, string file, Hashtable wxsvals, Hashtable cmivals)
{
Hashtable whash = new Hashtable();;
ManifestParser mp;
Hashtable inHash;
// get the suffix
string[] components = file.Split(new char[] {'.'}, 50);
string suffix = components[components.Length - 1];
if (suffix.Equals("wxs"))
{
inHash = wxsvals;
mp = new WiXParser();
}
else if (suffix.ToLower().Equals("man") ||
suffix.ToLower().Equals("manifest"))
{
inHash = cmivals;
mp = new CMIParser();
}
2008-11-17 18:29:00 -05:00
else if (suffix.Equals("inf")) {
2008-03-05 09:52:00 -05:00
inHash = null;
mp = new INFParser();
}
2008-11-17 18:29:00 -05:00
else if (suffix.Equals("inft")) {
2008-03-05 09:52:00 -05:00
inHash = null;
mp = new RegINFParser();
}
2008-11-17 18:29:00 -05:00
else {
2008-03-05 09:52:00 -05:00
Console.WriteLine("Unknown manifest suffix " + suffix);
return whash;
}
// otherwise, try to parse it
try
{
whash = mp.Parse(appName, file, inHash);
}
2008-11-17 18:29:00 -05:00
catch (System.Xml.XmlException) {
2008-03-05 09:52:00 -05:00
Console.WriteLine("Could not parse " + file);
}
return whash;
}
static bool sameApp(string first, string second)
{
// we'll compute a heuristic measure of similarity by checking
// the number of elements they have in common in
// their strings. Any difference of 2 or less and
// we will say that they are the same
string[] firstArray = first.Split(new char[] {'.', '_'}, 40);
string[] secondArray = second.Split(new char[] {'.', '_'}, 40);
Hashtable firstHash = new Hashtable();
2008-11-17 18:29:00 -05:00
for (int i = 0; i < firstArray.Length; i++)
2008-03-05 09:52:00 -05:00
{
if (!firstHash.ContainsKey(firstArray[i]))
{
firstHash[firstArray[i]] = 0;
}
firstHash[firstArray[i]] = (int)firstHash[firstArray[i]] + 1;
}
2008-11-17 18:29:00 -05:00
for (int i = 0; i < secondArray.Length; i++)
2008-03-05 09:52:00 -05:00
{
if (firstHash.ContainsKey(secondArray[i]))
{
firstHash[secondArray[i]] = (int)firstHash[secondArray[i]] - 1;
}
}
ICollection vcol = firstHash.Values;
IEnumerator ienum = vcol.GetEnumerator();
int sum = 0;
2008-11-17 18:29:00 -05:00
while (ienum.MoveNext())
2008-03-05 09:52:00 -05:00
{
sum += (int)ienum.Current;
}
return System.Math.Abs(sum) <= 2;
}
[STAThread]
static void Main(string[] args)
{
if (args.Length < 1)
{
Usage();
return;
}
#region Setup Variables
// grab a new app tree
//AppTree tempat = AppTree.CreateAppTree(args[0]);
//ArrayList tempar = tempat.Flatten();
// ... that we can spit out for clustering
//for(int j = 0; j < tempar.Count; j++)
//{
// Console.Write(((AppNode)tempar[j]).Name + "\t");
//}
//Console.WriteLine();
// get the mapping from WiX elements to app tree paths
//Hashtable wxvals = WiXParser.GetManifestHashtable(args[1]);
// get the mapping from CMI elements to app tree paths
//Hashtable cmivals = CMIParser.GetManifestHashtable(args[2]);
#endregion
bool doConflictsAndDependencies = true;
2008-11-17 18:29:00 -05:00
if (args[0].Equals("-s")) {
2008-03-05 09:52:00 -05:00
doConflictsAndDependencies = false;
}
#region Parse Directory
2008-11-17 18:29:00 -05:00
if (args[0].Equals("-r")) {
2008-03-05 09:52:00 -05:00
// the next argument must be a directory that
// we can parse to get a list of directories that map to apps
2008-11-17 18:29:00 -05:00
if (args.Length != 2) {
2008-03-05 09:52:00 -05:00
Usage();
return;
}
string dir = args[1];
DirectoryInfo di = new DirectoryInfo(dir);
2008-11-17 18:29:00 -05:00
if (!di.Exists) {
2008-03-05 09:52:00 -05:00
Console.WriteLine("Directory " + dir + " does not exist");
return;
}
DirectoryInfo[] dis = di.GetDirectories();
2008-11-17 18:29:00 -05:00
for (int i = 0; i < dis.Length; i++) {
2008-03-05 09:52:00 -05:00
DirectoryInfo tempDi = dis[i];
// if this directory itself contains directories,
// step into them to get each app
DirectoryInfo[] subDirs = tempDi.GetDirectories();
if (subDirs.Length > 0)
{
2008-11-17 18:29:00 -05:00
for (int j = 0; j < subDirs.Length; j++)
2008-03-05 09:52:00 -05:00
{
DirectoryInfo subDir = subDirs[j];
string appName = tempDi.Name + " " + subDir.Name;
FileInfo[] fis = subDir.GetFiles();
2008-11-17 18:29:00 -05:00
for (int k = 0; k < fis.Length; k++)
2008-03-05 09:52:00 -05:00
{
parseFile(appName, subDir.FullName + "\\" + fis[k].Name);
}
}
}
2008-11-17 18:29:00 -05:00
else {
2008-03-05 09:52:00 -05:00
string appName = tempDi.Name;
FileInfo[] fis = tempDi.GetFiles();
2008-11-17 18:29:00 -05:00
for (int j = 0; j < fis.Length; j++)
2008-03-05 09:52:00 -05:00
{
parseFile(appName, tempDi.FullName + "\\" + fis[j].Name);
}
}
}
}
2008-11-17 18:29:00 -05:00
else if (args[0].Equals("-d") || args[0].Equals("-s")) {
2008-03-05 09:52:00 -05:00
// the next argument must be a directory that
// contains a set of .wxs files for us to parse
if (args.Length != 2)
{
Usage();
return;
}
Console.WriteLine("About to parse " + args[1]);
int count = 0;
string dir = args[1];
DirectoryInfo di = new DirectoryInfo(dir);
if (!di.Exists)
{
Console.WriteLine("Directory " + dir + " does not exist");
return;
}
FileInfo[] fis = di.GetFiles();
// Console.WriteLine("Got here with size " + fis.Length);
// for each manifest file
2008-11-17 18:29:00 -05:00
for (int i = 0; i < fis.Length; i++)
2008-03-05 09:52:00 -05:00
{
Console.WriteLine(++count);
// grab a new app tree
//AppTree at = AppTree.CreateAppTree(args[0]);
//Hashtable whash = parseFile(fis[i].DirectoryName + "\\" + fis[i].Name, wxvals, cmivals);
parseFile(fis[i].DirectoryName + "\\" + fis[i].Name, fis[i].DirectoryName + "\\" + fis[i].Name);
// then set up the app tree
//at.IncrementWithHashtable(whash);
// and flatten it to a point in R^n
//ArrayList ar = at.Flatten();
//Console.Write(fis[i].Name + "\t");
// ... that we can spit out for clustering
//for(int j = 0; j < ar.Count; j++)
//{
// Console.Write(((AppNode)ar[j]).Weight() + "\t");
//}
//Console.WriteLine();
}
}
#endregion
#region Parse Single File
2008-11-17 18:29:00 -05:00
else {
2008-03-05 09:52:00 -05:00
if (args.Length != 1)
{
Usage();
return;
}
// grab a new app tree
//AppTree at = AppTree.CreateAppTree(args[0]);
Console.WriteLine("about to parse file");
//Hashtable whash = parseFile(args[3], wxvals, cmivals);
parseFile(args[0], args[0]);
//at.IncrementWithHashtable(whash);
//at.Dump();
}
#endregion
#region Enumerate Registry Dependencies
Console.WriteLine("---Registry Conflicts---");
// this Hashtable will contain all the names found in the conflict table
// and the other apps with which they conflict on registry key/value pairs.
Hashtable appConflicts = new Hashtable();
// this table will be used to reduce the size of the generated file
Hashtable appNameTable = new Hashtable();
int nameCount = 0;
2008-11-17 18:29:00 -05:00
if (doConflictsAndDependencies) {
2008-03-05 09:52:00 -05:00
// now walk the Hashtable and dump any conflicts
Hashtable conflictTable = ManifestParser.registryConflictTable;
IDictionaryEnumerator iDictEnum = conflictTable.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (iDictEnum.MoveNext()) {
if (((ArrayList)iDictEnum.Value).Count > 1) {
2008-03-05 09:52:00 -05:00
// then we might have a conflict
ArrayList confs = ((ArrayList)iDictEnum.Value);
string val = (string)((Pair)confs[1]).First;
string appname = (string)((Pair)confs[1]).Second;
bool founddifference = false;
bool foundtwoapps = false;
2008-11-17 18:29:00 -05:00
for (int i = 0; i < confs.Count; i++) {
2008-03-05 09:52:00 -05:00
Pair outp = (Pair)confs[i];
string newval = (string)((Pair)confs[i]).First;
string newappname = (string)((Pair)confs[i]).Second;
if ((val == null && newval == null) ||
(val != null && newval != null && val.ToLower().Equals(newval.ToLower())))
{
continue;
}
// heuristic (may give some false negatives, but then we're just underestimating a bit)
// if one of these starts with a '[' in the first two characters,
// then it's probably just a substitution that we didn't notice.
// In that case, claim that it is not a conflict
if ((val != null && val.Length > 1 && val[0] == '[') ||
(val != null && val.Length > 2 && val[1] == '[') ||
(newval != null && newval.Length > 1 && newval[0] == '[') ||
(newval != null && newval.Length > 2 && newval[1] == '['))
{
continue;
}
founddifference = true;
if (newappname.Equals(appname)) continue;
foundtwoapps = true;
}
if (!founddifference || !foundtwoapps) continue;
Console.WriteLine("C: " + ((string)iDictEnum.Key) + " : " + ((ArrayList)iDictEnum.Value).Count);
Hashtable confHash = new Hashtable();
2008-11-17 18:29:00 -05:00
for (int i = 0; i < confs.Count; i++) {
2008-03-05 09:52:00 -05:00
Pair outp = (Pair)confs[i];
string confAppName = (string)outp.Second;
2008-11-17 18:29:00 -05:00
if (!appConflicts.ContainsKey(confAppName)) {
2008-03-05 09:52:00 -05:00
appConflicts[confAppName] = new Hashtable();
}
// write the conflicting app into the hash with its value
confHash[confAppName] = (string)outp.First;
Console.WriteLine("\t " +
getAppNumber((string)outp.Second, appNameTable, ref nameCount)
+ " writes " + (string)outp.First);
}
IDictionaryEnumerator iconf1 = confHash.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (iconf1.MoveNext()) {
2008-03-05 09:52:00 -05:00
string confAppName = (string)iconf1.Key;
string confVal1 = (string)iconf1.Value;
Hashtable htable = (Hashtable)appConflicts[confAppName];
IDictionaryEnumerator iconf2 = confHash.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (iconf2.MoveNext()) {
2008-03-05 09:52:00 -05:00
string curAppName = (string)iconf2.Key;
string confVal2 = (string)iconf2.Value;
// don't add this conflict if they are the same app
if (curAppName.Equals(confAppName)) continue;
// don't add this conflict if they have the same value on this key
2008-11-17 18:29:00 -05:00
if (confVal2 == null && confVal1 == null) {
2008-03-05 09:52:00 -05:00
continue;
}
2008-11-17 18:29:00 -05:00
else if (confVal2 != null && confVal1 != null && confVal2.ToLower().Equals(confVal1.ToLower())) {
2008-03-05 09:52:00 -05:00
continue;
}
2008-11-17 18:29:00 -05:00
if (!htable.ContainsKey(curAppName)) {
2008-03-05 09:52:00 -05:00
htable[curAppName] = 0;
}
htable[curAppName] = (int)htable[curAppName] + 1;
}
}
}
}
IDictionaryEnumerator iDE = appConflicts.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (iDE.MoveNext()) {
2008-03-05 09:52:00 -05:00
string firstName = (string)iDE.Key;
Hashtable confvals = (Hashtable)iDE.Value;
IDictionaryEnumerator iDEInner = confvals.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (iDEInner.MoveNext()) {
2008-03-05 09:52:00 -05:00
string secondName = (string)iDEInner.Key;
int strength = (int)iDEInner.Value;
Console.WriteLine(getAppNumber(firstName, appNameTable, ref nameCount)
+ "\t" + getAppNumber(secondName, appNameTable, ref nameCount)
+ "\t" + strength);
}
}
#endregion
#region Enumerate File Dependencies
Console.WriteLine("---File Dependencies---");
// now let's display all the file dependencies.
// We'll walk through the ManifestParser.provideFileTable
// and ManifestParser.requireFileTable
IDictionaryEnumerator ireq = ManifestParser.requiresFileTable.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (ireq.MoveNext()) {
2008-03-05 09:52:00 -05:00
string requiredFile = (string)ireq.Key;
ArrayList reqArray = (ArrayList)ireq.Value;
2008-11-17 18:29:00 -05:00
for (int i = 0; i < reqArray.Count; i++) {
2008-03-05 09:52:00 -05:00
string requiringAppName = (string)reqArray[i];
2008-11-17 18:29:00 -05:00
if (!ManifestParser.provideFileTable.ContainsKey(requiredFile)) {
2008-03-05 09:52:00 -05:00
// do nothing about it for now
//throw new Exception("File " + requiredFile + " is required but not provided!");
}
2008-11-17 18:29:00 -05:00
else {
2008-03-05 09:52:00 -05:00
// otherwise, we'll walk through all the apps that provide
// this file and print a dependency between them
ArrayList provArray = (ArrayList)ManifestParser.provideFileTable[requiredFile];
2008-11-17 18:29:00 -05:00
for (int j = 0; j < provArray.Count; j++) {
2008-03-05 09:52:00 -05:00
string providingAppName = (string)provArray[j];
Console.WriteLine(getAppNumber(requiringAppName, appNameTable, ref nameCount) + "\t" +
getAppNumber(providingAppName, appNameTable, ref nameCount));
}
}
}
}
#endregion
}
#region Evaluate File Spread
Console.WriteLine("\n---File Spread---\n");
// we use the appFileTable for each app to compute this
IDictionaryEnumerator appFileEnum = ManifestParser.appFileTable.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (appFileEnum.MoveNext()) {
2008-03-05 09:52:00 -05:00
string appName = (string)appFileEnum.Key;
Hashtable appFiles = (Hashtable)appFileEnum.Value;
// walk through the list and figure out how many unique prefixes there are of each length
IDictionaryEnumerator lengthEnum = appFiles.GetEnumerator();
int max = 0;
2008-11-17 18:29:00 -05:00
while (lengthEnum.MoveNext()) {
2008-03-05 09:52:00 -05:00
string path = (string)lengthEnum.Key;
string[] pathElts = path.Split(new char[] {'\\'}, 40);
// since the paths all start with \ and
// we don't want to count the empty first pathElt
int length = pathElts.Length - 1;
2008-11-17 18:29:00 -05:00
if (length > max) {
2008-03-05 09:52:00 -05:00
max = length;
}
}
int[] lengths = new int[max];
2008-11-17 18:29:00 -05:00
for (int i = 0; i < lengths.Length; i++) {
2008-03-05 09:52:00 -05:00
lengths[i] = 0;
}
lengthEnum.Reset();
2008-11-17 18:29:00 -05:00
while (lengthEnum.MoveNext()) {
2008-03-05 09:52:00 -05:00
string path = (string)lengthEnum.Key;
string[] pathElts = path.Split(new char[] {'\\'}, 40);
// since the paths all start with \ and
// we don't want to count the empty first pathElt
int length = pathElts.Length - 1;
// this -1 is because the lengths array is 0-based
lengths[length - 1]++;
}
2008-11-17 18:29:00 -05:00
for (int i = 0; i < lengths.Length; i++)
2008-03-05 09:52:00 -05:00
{
if (lengths[i] == 0)
{
lengths[i] = 1;
}
}
double spread = computeSpread(lengths);
// look up the real name
2008-11-17 18:29:00 -05:00
if (ManifestParser.nameTable.ContainsKey(appName)) {
2008-03-05 09:52:00 -05:00
appName = (string)ManifestParser.nameTable[appName];
}
string strSpread = "";
2008-11-17 18:29:00 -05:00
for (int i = 0; i < lengths.Length; i++) {
if (i != 0) {
2008-03-05 09:52:00 -05:00
strSpread += " ";
}
strSpread += lengths[i];
}
Console.WriteLine(appName + " : " + spread + " : " + strSpread);
}
#endregion
#region Evaluate Registry Spread
Console.WriteLine("\n---Registry Spread---\n");
// we use the appFileTable for each app to compute this
IDictionaryEnumerator appRegistryEnum = ManifestParser.appRegistryTable.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (appRegistryEnum.MoveNext()) {
2008-03-05 09:52:00 -05:00
string appName = (string)appRegistryEnum.Key;
Hashtable appRegs = (Hashtable)appRegistryEnum.Value;
// walk through the list and figure out how many unique prefixes there are of each length
IDictionaryEnumerator lengthEnum = appRegs.GetEnumerator();
int max = 0;
2008-11-17 18:29:00 -05:00
while (lengthEnum.MoveNext()) {
2008-03-05 09:52:00 -05:00
string path = (string)lengthEnum.Key;
string[] pathElts = path.Split(new char[] {'\\'}, 40);
// since the paths all start with \ and
// we don't want to count the empty first pathElt
int length = pathElts.Length - 1;
2008-11-17 18:29:00 -05:00
if (length > max) {
2008-03-05 09:52:00 -05:00
max = length;
}
}
int[] lengths = new int[max];
2008-11-17 18:29:00 -05:00
for (int i = 0; i < lengths.Length; i++) {
2008-03-05 09:52:00 -05:00
lengths[i] = 0;
}
lengthEnum.Reset();
2008-11-17 18:29:00 -05:00
while (lengthEnum.MoveNext()) {
2008-03-05 09:52:00 -05:00
string path = (string)lengthEnum.Key;
string[] pathElts = path.Split(new char[] {'\\'}, 40);
// since the paths all start with \ and
// we don't want to count the empty first pathElt
int length = pathElts.Length - 1;
// this -1 is because the lengths array is 0-based
lengths[length - 1]++;
}
2008-11-17 18:29:00 -05:00
for (int i = 0; i < lengths.Length; i++)
2008-03-05 09:52:00 -05:00
{
if (lengths[i] == 0)
{
lengths[i] = 1;
}
}
double spread = computeSpread(lengths);
// look up the real name
2008-11-17 18:29:00 -05:00
if (ManifestParser.nameTable.ContainsKey(appName)) {
2008-03-05 09:52:00 -05:00
appName = (string)ManifestParser.nameTable[appName];
}
string strSpread = "";
2008-11-17 18:29:00 -05:00
for (int i = 0; i < lengths.Length; i++) {
if (i != 0) {
2008-03-05 09:52:00 -05:00
strSpread += " ";
}
strSpread += lengths[i];
}
Console.WriteLine(appName + " : " + spread + " : " + strSpread);
}
#endregion
#region Print Custom Actions
Console.WriteLine("---Custom Actions---");
// walk through the ManifestParser.customActionsTable
IDictionaryEnumerator customEnum = ManifestParser.customActionsTable.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (customEnum.MoveNext())
2008-03-05 09:52:00 -05:00
{
string appName = (string)customEnum.Key;
int customCount = (int)customEnum.Value;
Console.WriteLine(appName + " : " + customCount);
}
#endregion
#region Print File Extensions and Counts
Console.WriteLine("---File Extensions---");
// walk through the ManifestParser.fileTypeTable
IDictionaryEnumerator fileEnum = ManifestParser.fileTypeTable.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (fileEnum.MoveNext())
2008-03-05 09:52:00 -05:00
{
int uniqueFileTypes = 0;
string appName = (string)fileEnum.Key;
Hashtable exts = (Hashtable)fileEnum.Value;
IDictionaryEnumerator extEnum = exts.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (extEnum.MoveNext())
2008-03-05 09:52:00 -05:00
{
uniqueFileTypes++;
string extension = (string)extEnum.Key;
int extCount = (int)extEnum.Value;
Console.WriteLine(appName + " : " + extension + " : " + extCount);
}
Console.WriteLine(appName + " : " + uniqueFileTypes);
}
#endregion
#region Print Name Table
Console.WriteLine("\n---Name Table---\n");
// now write out the name table
IDictionaryEnumerator iDENT = appNameTable.GetEnumerator();
2008-11-17 18:29:00 -05:00
while (iDENT.MoveNext())
2008-03-05 09:52:00 -05:00
{
string appName = "";
// look up the real name
2008-11-17 18:29:00 -05:00
if (ManifestParser.nameTable.ContainsKey((string)iDENT.Key)) {
2008-03-05 09:52:00 -05:00
appName = (string)ManifestParser.nameTable[(string)iDENT.Key];
}
2008-11-17 18:29:00 -05:00
if (appName.Equals("")) {
2008-03-05 09:52:00 -05:00
Console.WriteLine((string)iDENT.Key + " " + (int)iDENT.Value);
}
2008-11-17 18:29:00 -05:00
else {
2008-03-05 09:52:00 -05:00
Console.WriteLine((string)iDENT.Key + " " + appName + " " + (int)iDENT.Value);
}
}
#endregion
return;
}
}
}