817 lines
30 KiB
C#
817 lines
30 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using JD.Kernel.StaticHelpers;
|
|
using JD.Kernel.Structs;
|
|
using JD.LogService;
|
|
using JD.Serializers.Xml;
|
|
using JD.TeaBoxAddinSystem.Addins.Description;
|
|
using JD.TeaBoxAddinSystem.Addins.Description.Conditions;
|
|
using JD.TeaBoxAddinSystem.Addins.Description.FileReferences;
|
|
|
|
namespace JD.TeaBoxAddinSystem.Addins.Management
|
|
{
|
|
/// <summary>
|
|
/// An object that serializes an <see cref="Addin"/> from an <see cref="XmlSerializerReader"/>
|
|
/// </summary>
|
|
internal class AddinXmlSerializerReaderSerializer : AddinXmlSerializer
|
|
{
|
|
#region Variables
|
|
|
|
private readonly XmlSerializerReader m_reader;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
internal AddinXmlSerializerReaderSerializer(XmlSerializerReader reader, ILogger logger)
|
|
: base(logger)
|
|
{
|
|
Throw.IfNull(reader, "reader");
|
|
m_reader = reader;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
/// <summary>
|
|
/// Overriden.
|
|
/// </summary>
|
|
protected override FileLocation CurrentFileLocation
|
|
{
|
|
get { return new FileLocation(m_reader.FileName, m_reader.LineNumber, m_reader.ColumnNumber); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
/// <summary>
|
|
/// Overriden.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
protected override Addin Serialize()
|
|
{
|
|
if (!string.IsNullOrEmpty(m_reader.FileName))
|
|
{
|
|
LogMessage("Reading addin from " + m_reader.FileName, MessageImportance.Low);
|
|
}
|
|
|
|
FileLocation fileLocation = CurrentFileLocation;
|
|
|
|
Addin addin = new Addin(m_reader.Serialize(IdAttribute));
|
|
addin.FileLocation = fileLocation;
|
|
addin.MainModule.FileLocation = null; // Override the debug file location.
|
|
|
|
// Read manifest
|
|
if (m_reader.AttributeExists(NameAttribute))
|
|
{
|
|
addin.Manifest.Name = m_reader.Serialize(NameAttribute);
|
|
}
|
|
else
|
|
{
|
|
addin.Manifest.Name = addin.Manifest.Id;
|
|
}
|
|
|
|
Version version = ParseVersion(m_reader.Serialize(VersionAttribute));
|
|
if (version != null)
|
|
{
|
|
addin.Manifest.Version = version;
|
|
}
|
|
|
|
addin.Manifest.Author = m_reader.Serialize(AuthorAttribute);
|
|
addin.Manifest.Url = m_reader.Serialize(UrlAttribute);
|
|
addin.Manifest.Description = m_reader.Serialize(DescriptionAttribute);
|
|
addin.Manifest.Category = m_reader.Serialize(CategoryAttribute);
|
|
addin.Manifest.X86Only = m_reader.Serialize<bool>(X86OnlyAttribute);
|
|
|
|
ReadModule(addin.MainModule);
|
|
|
|
return addin;
|
|
}
|
|
|
|
private void ReadModule(Module module)
|
|
{
|
|
System.Diagnostics.Debug.Assert(module != null);
|
|
System.Diagnostics.Debug.Assert(module.Addin != null);
|
|
|
|
bool isMainModule = module.IsMainModule;
|
|
Addin addin = module.Addin;
|
|
|
|
foreach (string element in m_reader)
|
|
{
|
|
if (isMainModule && string.Equals(element, IncludeNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Include(addin);
|
|
}
|
|
else if (isMainModule && string.Equals(element, ExtensionNodeSetNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
ExtensionTypeSet typeSet = ReadExtensionTypeSet();
|
|
|
|
if (typeSet != null)
|
|
{
|
|
if (addin.ExtensionTypeSets.Contains(typeSet.Name))
|
|
{
|
|
LogDuplicateElement("extension node set", typeSet.Name, addin.ExtensionTypeSets[typeSet.Name].FileLocation);
|
|
}
|
|
else
|
|
{
|
|
addin.ExtensionTypeSets.Add(typeSet);
|
|
}
|
|
}
|
|
}
|
|
else if (isMainModule && string.Equals(element, ExtensionPointNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
ExtensionPoint point = ReadExtensionPoint();
|
|
|
|
if (point != null)
|
|
{
|
|
if (addin.ExtensionPoints.Contains(point.Path))
|
|
{
|
|
LogDuplicateElement("extension point", point.Path, addin.ExtensionPoints[point.Path].FileLocation);
|
|
}
|
|
else
|
|
{
|
|
addin.ExtensionPoints.Add(point);
|
|
}
|
|
}
|
|
}
|
|
else if (isMainModule && string.Equals(element, ConditionNodeNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
ConditionType conditionType = ReadConditionType();
|
|
|
|
if (conditionType != null)
|
|
{
|
|
if (addin.ConditionTypes.Contains(conditionType.Name))
|
|
{
|
|
LogDuplicateElement("condition node", conditionType.Name, addin.ConditionTypes[conditionType.Name].FileLocation);
|
|
}
|
|
else
|
|
{
|
|
addin.ConditionTypes.Add(conditionType);
|
|
}
|
|
}
|
|
}
|
|
else if (string.Equals(element, FilesNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
ReadFiles(module);
|
|
}
|
|
else if (string.Equals(element, DependenciesNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
ReadDependencies(module);
|
|
}
|
|
else if (string.Equals(element, ExtensionNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
ReadExtension(module);
|
|
}
|
|
else if (string.Equals(element, ModuleNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
if (isMainModule)
|
|
{
|
|
Module newModule = new Module();
|
|
newModule.FileLocation = CurrentFileLocation;
|
|
addin.Modules.Add(newModule);
|
|
ReadModule(newModule);
|
|
}
|
|
else
|
|
{
|
|
LogError("Nested modules are not supported");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogUnexpectedXmlElement(element);
|
|
}
|
|
}
|
|
}
|
|
|
|
private ExtensionPoint ReadExtensionPoint()
|
|
{
|
|
string path = m_reader.Serialize(PathAttribute);
|
|
|
|
if (string.IsNullOrEmpty(path))
|
|
{
|
|
LogInvalidAttributeElement(PathAttribute, ExtensionPointNode);
|
|
return null;
|
|
}
|
|
|
|
ExtensionPoint point = new ExtensionPoint(path);
|
|
point.FileLocation = CurrentFileLocation;
|
|
point.Name = m_reader.Serialize(NameAttribute);
|
|
point.DeprecationMessage = m_reader.Serialize(DeprecatedAttribute);
|
|
|
|
// Read children
|
|
ReadExtensionTypeSetBase(point.ExtensionTypeSet, ExtensionPointNode);
|
|
point.Description = point.ExtensionTypeSet.Description;
|
|
|
|
return point;
|
|
}
|
|
|
|
private ExtensionTypeSet ReadExtensionTypeSet()
|
|
{
|
|
string name = m_reader.Serialize(NameAttribute);
|
|
|
|
if (string.IsNullOrEmpty(name))
|
|
{
|
|
LogInvalidAttributeElement(NameAttribute, ExtensionNodeSetNode);
|
|
return null;
|
|
}
|
|
|
|
ExtensionTypeSet extensionTypeSet = new ExtensionTypeSet(name);
|
|
extensionTypeSet.FileLocation = CurrentFileLocation;
|
|
|
|
// Read children
|
|
ReadExtensionTypeSetBase(extensionTypeSet, ExtensionNodeSetNode);
|
|
|
|
return extensionTypeSet;
|
|
}
|
|
|
|
private void ReadExtensionTypeSetBase(ExtensionTypeSet extensionTypeSet, string nodeName)
|
|
{
|
|
System.Diagnostics.Debug.Assert(extensionTypeSet != null);
|
|
System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(nodeName));
|
|
|
|
FileLocation? descriptionLocation = null;
|
|
|
|
if (m_reader.AttributeExists(DescriptionAttribute))
|
|
{
|
|
extensionTypeSet.Description = m_reader.Serialize(DescriptionAttribute);
|
|
descriptionLocation = CurrentFileLocation;
|
|
}
|
|
|
|
foreach (string element in m_reader)
|
|
{
|
|
if (string.Equals(element, ExtensionNodeNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
ExtensionType extensionType = ReadExtensionType();
|
|
|
|
if (extensionType != null)
|
|
{
|
|
if (extensionTypeSet.ExtensionTypes.Contains(extensionType.Name))
|
|
{
|
|
LogDuplicateElement("extension node", extensionType.Name, extensionTypeSet.ExtensionTypes[extensionType.Name].FileLocation);
|
|
}
|
|
else
|
|
{
|
|
ReadExtensionTypeSetBase(extensionType.ExtensionTypeSet, ExtensionNodeNode);
|
|
extensionType.Description = extensionType.ExtensionTypeSet.Description;
|
|
extensionTypeSet.ExtensionTypes.Add(extensionType);
|
|
}
|
|
}
|
|
}
|
|
else if (string.Equals(element, ExtensionNodeSetNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
CheckIsEmpty(ExtensionNodeSetNode);
|
|
|
|
string nameReference = m_reader.Serialize(NameAttribute);
|
|
|
|
if (string.IsNullOrEmpty(nameReference))
|
|
{
|
|
LogInvalidAttributeElement(NameAttribute, ExtensionNodeSetNode);
|
|
}
|
|
else
|
|
{
|
|
extensionTypeSet.ExtensionTypeSets.Add(nameReference);
|
|
}
|
|
}
|
|
else if (string.Equals(element, DescriptionNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
if (descriptionLocation != null)
|
|
{
|
|
LogDescriptionAlreadyDefined(nodeName, descriptionLocation);
|
|
}
|
|
else
|
|
{
|
|
descriptionLocation = CurrentFileLocation;
|
|
extensionTypeSet.Description = m_reader.ReadInnerData();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogUnexpectedXmlElement(element);
|
|
}
|
|
}
|
|
}
|
|
|
|
private ExtensionType ReadExtensionType()
|
|
{
|
|
string name = m_reader.Serialize(NameAttribute);
|
|
|
|
if (string.IsNullOrEmpty(name))
|
|
{
|
|
LogInvalidAttributeElement(NameAttribute, ExtensionNodeNode);
|
|
return null;
|
|
}
|
|
|
|
// Validate name
|
|
if (name.StartsWith(ConditionPrefix, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
LogError($"Extension nodes cannot have a name that starts with \"{ConditionPrefix}\" because it is reserved for condition nodes");
|
|
return null;
|
|
}
|
|
|
|
ExtensionType extensionType = new ExtensionType(name);
|
|
extensionType.FileLocation = CurrentFileLocation;
|
|
|
|
extensionType.TypeName = m_reader.Serialize(TypeAttribute);
|
|
extensionType.ObjectTypeName = m_reader.Serialize(ObjectTypeAttribute);
|
|
|
|
return extensionType;
|
|
}
|
|
|
|
private ConditionType ReadConditionType()
|
|
{
|
|
string name = m_reader.Serialize(NameAttribute);
|
|
|
|
if (string.IsNullOrEmpty(name))
|
|
{
|
|
LogInvalidAttributeElement(NameAttribute, ConditionNodeNode);
|
|
return null;
|
|
}
|
|
|
|
string typename = m_reader.Serialize(TypeAttribute);
|
|
|
|
if (string.IsNullOrEmpty(typename))
|
|
{
|
|
LogInvalidAttributeElement(TypeAttribute, ConditionNodeNode);
|
|
return null;
|
|
}
|
|
|
|
ConditionType conditionType = new ConditionType(name, typename);
|
|
conditionType.FileLocation = CurrentFileLocation;
|
|
|
|
FileLocation? descriptionLocation = null;
|
|
if (m_reader.AttributeExists(DescriptionAttribute))
|
|
{
|
|
conditionType.Description = m_reader.Serialize(DescriptionAttribute);
|
|
descriptionLocation = CurrentFileLocation;
|
|
}
|
|
|
|
if (m_reader.StartElement(DescriptionNode, false, false) != null)
|
|
{
|
|
if (descriptionLocation != null)
|
|
{
|
|
LogDescriptionAlreadyDefined(ConditionNodeNode, descriptionLocation);
|
|
}
|
|
else
|
|
{
|
|
conditionType.Description = m_reader.ReadInnerData();
|
|
descriptionLocation = CurrentFileLocation;
|
|
}
|
|
}
|
|
|
|
return conditionType;
|
|
}
|
|
|
|
private void ReadFiles(Module module)
|
|
{
|
|
System.Diagnostics.Debug.Assert(module != null);
|
|
|
|
foreach (string element in m_reader)
|
|
{
|
|
if (string.Equals(element, ImportNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
ReadImportNode(module);
|
|
}
|
|
else
|
|
{
|
|
LogUnexpectedXmlElement(element);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ReadImportNode(Module module)
|
|
{
|
|
System.Diagnostics.Debug.Assert(module != null);
|
|
|
|
if (m_reader.AttributeCount > 1)
|
|
{
|
|
// Oops, more than one specified
|
|
LogError($"Cannot specify more than one attribute in a \"{ImportNode}\" element");
|
|
}
|
|
|
|
if (m_reader.AttributeExists(AssemblyAttribute))
|
|
{
|
|
string assemblyFile = m_reader.Serialize(AssemblyAttribute);
|
|
|
|
if (string.IsNullOrEmpty(assemblyFile))
|
|
{
|
|
LogInvalidAttributeElement(AssemblyAttribute, ImportNode);
|
|
}
|
|
else
|
|
{
|
|
AssemblyFileReference assembly = new AssemblyFileReference(assemblyFile, System.IO.Path.GetDirectoryName(m_reader.FileName));
|
|
assembly.FileLocation = CurrentFileLocation;
|
|
ReadImportAssemblyNode(assembly);
|
|
module.Assemblies.Add(assembly);
|
|
}
|
|
}
|
|
else if (m_reader.AttributeExists(FileAttribute))
|
|
{
|
|
CheckIsEmpty(ImportNode);
|
|
string file = m_reader.Serialize(FileAttribute);
|
|
|
|
if (string.IsNullOrEmpty(file))
|
|
{
|
|
LogInvalidAttributeElement(FileAttribute, ImportNode);
|
|
}
|
|
else
|
|
{
|
|
FileReference fileReference = new FileReference(file);
|
|
fileReference.FileLocation = CurrentFileLocation;
|
|
module.OtherFiles.Add(fileReference);
|
|
}
|
|
}
|
|
else if (m_reader.AttributeExists(ResourceAttribute))
|
|
{
|
|
CheckIsEmpty(ImportNode);
|
|
string resource = m_reader.Serialize(ResourceAttribute);
|
|
|
|
if (string.IsNullOrEmpty(resource))
|
|
{
|
|
LogInvalidAttributeElement(ResourceAttribute, ImportNode);
|
|
}
|
|
else
|
|
{
|
|
ResourceFileReference resourceReference = new ResourceFileReference(resource);
|
|
resourceReference.FileLocation = CurrentFileLocation;
|
|
module.ResourceFiles.Add(resourceReference);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No attribute!
|
|
LogInvalidAttributeElement($"{AssemblyAttribute}\", \"{ResourceAttribute}\" or \"{FileAttribute}", ImportNode);
|
|
}
|
|
}
|
|
|
|
private void ReadImportAssemblyNode(AssemblyFileReference reference)
|
|
{
|
|
System.Diagnostics.Debug.Assert(reference != null);
|
|
|
|
foreach (string element in m_reader)
|
|
{
|
|
if (string.Equals(element, ImportNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
CheckIsEmpty(ImportNode);
|
|
|
|
string resource = m_reader.Serialize(ResourceAttribute);
|
|
|
|
if (m_reader.AttributeCount != 1 || string.IsNullOrEmpty(resource))
|
|
{
|
|
LogError($"Only {ResourceAttribute} imports are allowed in {AssemblyAttribute} imports");
|
|
}
|
|
else
|
|
{
|
|
AssemblyResourceFileReference resourceReference = new AssemblyResourceFileReference(resource);
|
|
resourceReference.FileLocation = CurrentFileLocation;
|
|
reference.ResourceFiles.Add(resourceReference);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogUnexpectedXmlElement(element);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ReadDependencies(Module module)
|
|
{
|
|
System.Diagnostics.Debug.Assert(module != null);
|
|
|
|
foreach (string element in m_reader)
|
|
{
|
|
if (string.Equals(element, AddinNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
AddinReference reference = ReadAddinNode();
|
|
if (reference != null)
|
|
{
|
|
module.Dependencies.Add(reference);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogUnexpectedXmlElement(element);
|
|
}
|
|
}
|
|
}
|
|
|
|
private AddinReference ReadAddinNode()
|
|
{
|
|
CheckIsEmpty(AddinNode);
|
|
|
|
string id = m_reader.Serialize(IdAttribute);
|
|
|
|
if (string.IsNullOrEmpty(id))
|
|
{
|
|
LogInvalidAttributeElement(IdAttribute, AddinNode);
|
|
return null;
|
|
}
|
|
|
|
string versionString = m_reader.Serialize(VersionAttribute);
|
|
|
|
if (string.IsNullOrEmpty(versionString))
|
|
{
|
|
return new AddinReference(id);
|
|
}
|
|
|
|
// Try to split the version into a version range
|
|
int indexOfHyphen = versionString.IndexOf('-');
|
|
|
|
if (indexOfHyphen != -1)
|
|
{
|
|
string minVersionString = versionString.Substring(0, indexOfHyphen);
|
|
Version minVersion = string.IsNullOrEmpty(minVersionString) ? AddinReference.ZeroVersion : ParseVersion(minVersionString);
|
|
|
|
string maxVersionString = versionString.Substring(indexOfHyphen + 1);
|
|
Version maxVersion = string.IsNullOrEmpty(maxVersionString) ? AddinReference.InfiniteVersion : ParseVersion(maxVersionString);
|
|
|
|
if (minVersion == null || maxVersion == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (AddinReference.Compare(minVersion, maxVersion) > 0)
|
|
{
|
|
LogError("Invalid version range: min version is larger than max version");
|
|
return null;
|
|
}
|
|
|
|
return new AddinReference(id, minVersion, maxVersion);
|
|
}
|
|
else
|
|
{
|
|
Version version = ParseVersion(versionString);
|
|
return version == null ? null : new AddinReference(id, version);
|
|
}
|
|
}
|
|
|
|
private void ReadExtension(Module module)
|
|
{
|
|
System.Diagnostics.Debug.Assert(module != null);
|
|
|
|
string path = m_reader.Serialize(PathAttribute);
|
|
|
|
if (string.IsNullOrEmpty(path))
|
|
{
|
|
LogInvalidAttributeElement(PathAttribute, ExtensionNode);
|
|
return;
|
|
}
|
|
|
|
Extension extension = new Extension(path);
|
|
extension.FileLocation = CurrentFileLocation;
|
|
module.Extensions.Add(extension);
|
|
|
|
ReadExtensionNodes(extension.ExtensionNodes, new Stack<ConditionInfo>());
|
|
}
|
|
|
|
private void ReadExtensionNodes(ICollection<ExtensionNodeDescription> nodes, Stack<ConditionInfo> conditionStack)
|
|
{
|
|
System.Diagnostics.Debug.Assert(nodes != null);
|
|
System.Diagnostics.Debug.Assert(!nodes.IsReadOnly);
|
|
|
|
foreach (string element in m_reader)
|
|
{
|
|
if (string.Equals(element, ConditionPrefix, StringComparison.OrdinalIgnoreCase) || element.StartsWith(ConditionPrefix + ".", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
string target = m_reader.Serialize(TargetAttribute);
|
|
|
|
Condition condition = null;
|
|
if (string.Equals(element, ConditionPrefix, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// Complex condition
|
|
|
|
// First element must be a conditional operator
|
|
using (IXmlElement conditionElement = m_reader.StartElement())
|
|
{
|
|
if (conditionElement != null)
|
|
{
|
|
condition = ReadConditionalOperator(conditionElement.Name, false);
|
|
}
|
|
|
|
if (condition == null)
|
|
{
|
|
LogError("First element of a complex condition must be a condition operator (And, Or, Not, Xor)");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
System.Diagnostics.Debug.Assert(element.StartsWith(ConditionPrefix + ".", StringComparison.OrdinalIgnoreCase));
|
|
|
|
// Simple condition
|
|
condition = ReadConditionalOperator(element, true);
|
|
}
|
|
|
|
System.Diagnostics.Debug.Assert(condition != null);
|
|
conditionStack.Push(new ConditionInfo(condition, target));
|
|
ReadExtensionNodes(nodes, conditionStack);
|
|
conditionStack.Pop();
|
|
}
|
|
else
|
|
{
|
|
ExtensionNodeDescription extensionNodeDescription = new ExtensionNodeDescription(element);
|
|
extensionNodeDescription.FileLocation = CurrentFileLocation;
|
|
ReadNodeDescription(extensionNodeDescription);
|
|
|
|
// Add current conditions
|
|
foreach (ConditionInfo conditionInfo in conditionStack)
|
|
{
|
|
extensionNodeDescription.Conditions.Add(conditionInfo);
|
|
}
|
|
|
|
nodes.Add(extensionNodeDescription);
|
|
ReadExtensionNodes(extensionNodeDescription.ChildNodes, new Stack<ConditionInfo>());
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ReadNodeDescription(NodeDescription nodeDescription)
|
|
{
|
|
System.Diagnostics.Debug.Assert(nodeDescription != null);
|
|
|
|
foreach (KeyValuePair<string, string> attribute in m_reader.GetAttributes())
|
|
{
|
|
nodeDescription.Attributes[attribute.Key] = attribute.Value;
|
|
}
|
|
}
|
|
|
|
private void Include(Addin addin)
|
|
{
|
|
System.Diagnostics.Debug.Assert(addin != null);
|
|
|
|
string filename = m_reader.Serialize(FileAttribute);
|
|
|
|
if (string.IsNullOrEmpty(filename))
|
|
{
|
|
LogInvalidAttributeElement(FileAttribute, IncludeNode);
|
|
return;
|
|
}
|
|
|
|
if (!FileUtility.IsAbsolutePath(filename))
|
|
{
|
|
// Transform to absolute
|
|
|
|
filename = FileUtility.FormatPath(Path.GetDirectoryName(m_reader.FileName) + Path.DirectorySeparatorChar + filename);
|
|
}
|
|
|
|
if (!File.Exists(filename))
|
|
{
|
|
LogError("Cannot find filename " + filename);
|
|
return;
|
|
}
|
|
|
|
using (XmlSerializerReader reader = new XmlSerializerReader(filename))
|
|
{
|
|
LogMessage("Including partial addin from " + filename, MessageImportance.Low);
|
|
addin.AddPartialAddinFilename(filename);
|
|
new AddinXmlSerializerReaderSerializer(reader, m_logger).ReadPartialAddin(addin);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Entry point for partial addin reader.
|
|
/// </summary>
|
|
/// <param name="addin"></param>
|
|
private void ReadPartialAddin(Addin addin)
|
|
{
|
|
using (IXmlElement element = m_reader.StartElement(AddinNode, false, false))
|
|
{
|
|
if (element == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_reader.AttributeCount != 1 || !m_reader.AttributeExists(IdAttribute))
|
|
{
|
|
LogError($"Partial addin declaration must include only the {IdAttribute} attribute.");
|
|
}
|
|
|
|
string id = m_reader.Serialize(IdAttribute);
|
|
|
|
if (addin.FullId != id)
|
|
{
|
|
LogError($"Partial addin id {id} does not correspond to addin {addin.FullId}");
|
|
return;
|
|
}
|
|
|
|
ReadModule(addin.MainModule);
|
|
}
|
|
}
|
|
|
|
#region Complex conditions
|
|
|
|
private Condition ReadConditionalOperator(string name, bool allowBasicCondition)
|
|
{
|
|
System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(name));
|
|
|
|
FileLocation fileLocation = CurrentFileLocation;
|
|
Condition condition = null;
|
|
|
|
if (allowBasicCondition && name.StartsWith(ConditionPrefix + ".", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// Simple condition
|
|
ConditionNodeDescription conditionNodeDescription = new ConditionNodeDescription(name.Substring(ConditionPrefix.Length + 1));
|
|
conditionNodeDescription.FileLocation = CurrentFileLocation;
|
|
ReadNodeDescription(conditionNodeDescription);
|
|
conditionNodeDescription.Attributes.Remove(TargetAttribute);
|
|
condition = new BasicCondition(conditionNodeDescription);
|
|
}
|
|
else if (string.Equals(name, AndNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
condition = Condition.And(ReadInnerConditionList().ToArray());
|
|
}
|
|
else if (string.Equals(name, OrNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
condition = Condition.Or(ReadInnerConditionList().ToArray());
|
|
}
|
|
else if (string.Equals(name, XorNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
condition = Condition.Xor(ReadInnerConditionList().ToArray());
|
|
}
|
|
else if (string.Equals(name, NotNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Condition notCondition = null;
|
|
bool noElements = true;
|
|
foreach (string element in m_reader)
|
|
{
|
|
noElements = false;
|
|
if (notCondition != null)
|
|
{
|
|
LogError($"{NotNode} conditional operator must contain one and only one child element");
|
|
break;
|
|
}
|
|
|
|
notCondition = ReadConditionalOperator(element, true);
|
|
|
|
if (notCondition == null)
|
|
{
|
|
LogUnexpectedXmlElement(element);
|
|
}
|
|
}
|
|
|
|
if (notCondition == null)
|
|
{
|
|
if (noElements)
|
|
{
|
|
LogError($"{NotNode} conditional operator must contain one and only one child element");
|
|
}
|
|
condition = Condition.False;
|
|
}
|
|
else
|
|
{
|
|
condition = Condition.Not(notCondition);
|
|
}
|
|
}
|
|
else if (string.Equals(name, FalseNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
condition = Condition.False;
|
|
}
|
|
else if (string.Equals(name, TrueNode, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
condition = Condition.True;
|
|
}
|
|
|
|
if (condition != null)
|
|
{
|
|
condition.FileLocation = fileLocation;
|
|
}
|
|
|
|
return condition;
|
|
}
|
|
|
|
private List<Condition> ReadInnerConditionList()
|
|
{
|
|
List<Condition> conditionList = new List<Condition>();
|
|
|
|
foreach (string element in m_reader)
|
|
{
|
|
Condition readCondition = ReadConditionalOperator(element, true);
|
|
if (readCondition == null)
|
|
{
|
|
LogUnexpectedXmlElement(element);
|
|
continue;
|
|
}
|
|
conditionList.Add(readCondition);
|
|
}
|
|
|
|
return conditionList;
|
|
}
|
|
|
|
#endregion
|
|
|
|
private void CheckIsEmpty(string currentNodeName)
|
|
{
|
|
System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(currentNodeName));
|
|
|
|
if (!m_reader.IsEmptyElement)
|
|
{
|
|
LogError(string.Format(ElementMustBeEmpty, currentNodeName));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|