using System; using System.Collections.Generic; using ANXStatusComparer.Data; // This file is part of the ANX.Framework created by the // "ANX.Framework developer group" and released under the Ms-PL license. // For details see: http://anxframework.codeplex.com/license namespace ANXStatusComparer { /// /// The assembly comparer is the main logic component of the tool. /// public static class AssemblyComparer { #region Private /// /// Private caches of assemblies, so we don't need to pass them over /// as parameters all the time. /// private static AssembliesData xnaAssemblies; private static AssembliesData anxAssemblies; private static ResultData result; #endregion #region Compare /// /// Compare the assemblies of xna and anx and create a result data instance. /// /// XNA assemblies. /// ANX assemblies. /// The type of check to do. /// Generated result data. public static ResultData Compare(AssembliesData setXnaAssemblies, AssembliesData setAnxAssemblies, CheckType checkType) { xnaAssemblies = setXnaAssemblies; anxAssemblies = setAnxAssemblies; result = new ResultData(); if (checkType == CheckType.All || (checkType | CheckType.Namespaces) == checkType) { CheckNamespaces(); } if (checkType == CheckType.All || (checkType | CheckType.Structs) == checkType) { CheckStructs(); } if (checkType == CheckType.All || (checkType | CheckType.Interfaces) == checkType) { CheckInterfaces(); } if (checkType == CheckType.All || (checkType | CheckType.Classes) == checkType) { CheckClasses(); } if (checkType == CheckType.All || (checkType | CheckType.Enumerations) == checkType) { CheckEnums(); } return result; } #endregion #region CheckNamespaces /// /// Check all the namespaces. /// private static void CheckNamespaces() { foreach (string name in xnaAssemblies.Namespaces.Keys) { if (xnaAssemblies.Namespaces[name].IsPublic == false) { continue; } string compareName = TranslateNamespaceName(name); if (anxAssemblies.Namespaces.ContainsKey(compareName) == false) { if (result.MissingNamespaces.Contains(name) == false) { result.MissingNamespaces.Add(name); } } else { if (result.ImplementedNamespaces.Contains(name) == false) { result.ImplementedNamespaces.Add(name); } } } } #endregion #region CheckInterfaces private static void CheckInterfaces() { foreach (string key in xnaAssemblies.Namespaces.Keys) { NamespaceData namespaceData = xnaAssemblies.Namespaces[key]; string compareName = TranslateNamespaceName(key); foreach (string classKey in namespaceData.Interfaces.Keys) { CheckInterface(compareName, namespaceData.Interfaces[classKey]); } } } private static void CheckInterface(string namespaceKey, BaseObject xnaInterface) { // If the namespace is already missing, we can abort directly. if (anxAssemblies.Namespaces.ContainsKey(namespaceKey) == false) { result.MissingInterfaces.Add(xnaInterface); return; } NamespaceData anxNamespace = anxAssemblies.Namespaces[namespaceKey]; // Now check if we got this enum in the anx namespace. if (anxNamespace.Interfaces.ContainsKey(xnaInterface.Handle.Name) == false) { result.MissingInterfaces.Add(xnaInterface); return; } BaseObject anxInterface = anxNamespace.Interfaces[xnaInterface.Handle.Name]; ResultData.WrongObjectPair pair = new ResultData.WrongObjectPair() { XnaObject = xnaInterface, AnxObject = anxInterface, }; // Everything is present, so we do the in-depth checks. if (xnaInterface.IsCorrect(anxInterface, pair) == false) { result.WrongInterfaces.Add(pair); } else { result.ImplementedInterfaces.Add(anxInterface); } } #endregion #region CheckClasses private static void CheckClasses() { foreach (string key in xnaAssemblies.Namespaces.Keys) { NamespaceData namespaceData = xnaAssemblies.Namespaces[key]; string compareName = TranslateNamespaceName(key); foreach (string classKey in namespaceData.Classes.Keys) { CheckClass(compareName, namespaceData.Classes[classKey]); } } } private static void CheckClass(string namespaceKey, BaseObject xnaClass) { // If the namespace is already missing, we can abort directly. if (anxAssemblies.Namespaces.ContainsKey(namespaceKey) == false) { result.MissingClasses.Add(xnaClass); return; } NamespaceData anxNamespace = anxAssemblies.Namespaces[namespaceKey]; // Now check if we got this enum in the anx namespace. if (anxNamespace.Classes.ContainsKey(xnaClass.Handle.Name) == false) { result.MissingClasses.Add(xnaClass); return; } BaseObject anxClass = anxNamespace.Classes[xnaClass.Handle.Name]; ResultData.WrongObjectPair pair = new ResultData.WrongObjectPair() { XnaObject = xnaClass, AnxObject = anxClass, }; // Everything is present, so we do the in-depth checks. if (xnaClass.IsCorrect(anxClass, pair) == false) { result.WrongClasses.Add(pair); } else { result.ImplementedClasses.Add(anxClass); } } #endregion #region CheckStructs private static void CheckStructs() { foreach (string key in xnaAssemblies.Namespaces.Keys) { NamespaceData namespaceData = xnaAssemblies.Namespaces[key]; string compareName = TranslateNamespaceName(key); foreach (string classKey in namespaceData.Structs.Keys) { CheckStruct(compareName, namespaceData.Structs[classKey]); } } } private static void CheckStruct(string namespaceKey, BaseObject xnaStruct) { // If the namespace is already missing, we can abort directly. if (anxAssemblies.Namespaces.ContainsKey(namespaceKey) == false) { result.MissingStructs.Add(xnaStruct); return; } NamespaceData anxNamespace = anxAssemblies.Namespaces[namespaceKey]; // Now check if we got this enum in the anx namespace. if (anxNamespace.Structs.ContainsKey(xnaStruct.Handle.Name) == false) { result.MissingStructs.Add(xnaStruct); return; } BaseObject anxStruct = anxNamespace.Structs[xnaStruct.Handle.Name]; ResultData.WrongObjectPair pair = new ResultData.WrongObjectPair() { XnaObject = xnaStruct, AnxObject = anxStruct, }; // Everything is present, so we do the in-depth checks. if (xnaStruct.IsCorrect(anxStruct, pair) == false) { result.WrongStructs.Add(pair); } else { result.ImplementedStructs.Add(anxStruct); } } #endregion #region CheckEnums /// /// Compare all enumerations. /// private static void CheckEnums() { foreach (string key in xnaAssemblies.Namespaces.Keys) { NamespaceData namespaceData = xnaAssemblies.Namespaces[key]; string compareName = TranslateNamespaceName(key); foreach(string enumKey in namespaceData.Enums.Keys) { CheckEnum(compareName, namespaceData.Enums[enumKey]); } } } /// /// Compare a specific xna enumeration. /// /// The name of the namespace this enum is in. /// /// XNA enumeration to compare. private static void CheckEnum(string namespaceKey, EnumData xnaEnum) { // If the namespace is already missing, we can abort directly. if (anxAssemblies.Namespaces.ContainsKey(namespaceKey) == false) { result.MissingEnums.Add(xnaEnum); return; } NamespaceData anxNamespace = anxAssemblies.Namespaces[namespaceKey]; // Now check if we got this enum in the anx namespace. if (anxNamespace.Enums.ContainsKey(xnaEnum.Handle.Name) == false) { result.MissingEnums.Add(xnaEnum); return; } EnumData anxEnum = anxNamespace.Enums[xnaEnum.Handle.Name]; // Everything is present, so we do the in-depth checks for names and // values contained in the enumeration. bool isWrong = false; for (int index = 0; index < xnaEnum.Names.Count; index++) { int indexOfAnxValue = anxEnum.Names.IndexOf(xnaEnum.Names[index]); if (indexOfAnxValue == -1) { isWrong = true; break; } object value1 = anxEnum.Values.GetValue(indexOfAnxValue); object value2 = xnaEnum.Values.GetValue(index); if (value1.Equals(value2) == false) { isWrong = true; break; } } if (isWrong) { result.WrongEnums.Add(new KeyValuePair( xnaEnum, anxEnum)); } else { result.ImplementedEnums.Add(anxEnum); } } #endregion #region TranslateNamespaceName /// /// Translate a namespace name if needed. /// Used to get the ANX equivalent to the XNA namespace names. /// /// XNA namespace name. /// ANX valid namespace name. public static string TranslateNamespaceName(string name) { name = name.Replace("Microsoft.Xna.", "ANX."); return name; } #endregion } }