From 5e4154fd28d400d9ea5ff18f8755e83c35ac5100 Mon Sep 17 00:00:00 2001 From: Aptivi Date: Sat, 30 Mar 2024 21:23:32 +0300 Subject: [PATCH] imp - Promoted Xml to PartsArray --- We've promoted Xml to PartsArray to make it more intuitive. --- Type: imp Breaking: False Doc Required: False Part: 1/1 --- .../TestFiles/fourVCard4.vcf | 1 + VisualCard/Parsers/VcardParser.cs | 2 +- VisualCard/Parsers/VcardParserTools.cs | 6 +- VisualCard/Parts/Enums/PartsArrayEnum.cs | 4 + VisualCard/Parts/Enums/StringsEnum.cs | 4 - VisualCard/Parts/Implementations/XmlInfo.cs | 161 ++++++++++++++++++ 6 files changed, 170 insertions(+), 8 deletions(-) create mode 100644 VisualCard/Parts/Implementations/XmlInfo.cs diff --git a/VisualCard.ShowContacts/TestFiles/fourVCard4.vcf b/VisualCard.ShowContacts/TestFiles/fourVCard4.vcf index e936f055..ad15ed4e 100644 --- a/VisualCard.ShowContacts/TestFiles/fourVCard4.vcf +++ b/VisualCard.ShowContacts/TestFiles/fourVCard4.vcf @@ -33,6 +33,7 @@ LANG;TYPE=home:en LANG;TYPE=work:de X-ANDROID-CUSTOM:vnd.android.cursor.item/nickname;NVL.N;1 ;;;;;;;;;;;;; +XML:Not an xCard XML element\nNot a second xCard XML element END:VCARD BEGIN:VCARD diff --git a/VisualCard/Parsers/VcardParser.cs b/VisualCard/Parsers/VcardParser.cs index cc0e3fa9..b6f65fa3 100644 --- a/VisualCard/Parsers/VcardParser.cs +++ b/VisualCard/Parsers/VcardParser.cs @@ -24,6 +24,7 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; +using System.Xml; using Textify.General; using VisualCard.Exceptions; using VisualCard.Parts; @@ -154,7 +155,6 @@ public Card Parse() case StringsEnum.ProductId: case StringsEnum.SortString: case StringsEnum.AccessClassification: - case StringsEnum.Xml: // Unescape the value finalValue = Regex.Unescape(value); break; diff --git a/VisualCard/Parsers/VcardParserTools.cs b/VisualCard/Parsers/VcardParserTools.cs index a1c8dcb2..f8261c03 100644 --- a/VisualCard/Parsers/VcardParserTools.cs +++ b/VisualCard/Parsers/VcardParserTools.cs @@ -99,7 +99,6 @@ internal static bool StringSupported(StringsEnum stringsEnum, Version cardVersio StringsEnum.ProductId => cardVersion.Major >= 3, StringsEnum.SortString => cardVersion.Major == 3 || cardVersion.Major == 5, StringsEnum.AccessClassification => cardVersion.Major != 2 || cardVersion.Major != 4, - StringsEnum.Xml => cardVersion.Major == 4, StringsEnum.FreeBusyUrl => cardVersion.Major >= 4, StringsEnum.CalendarUrl => cardVersion.Major >= 4, StringsEnum.CalendarSchedulingRequestUrl => cardVersion.Major >= 4, @@ -129,6 +128,7 @@ internal static bool EnumArrayTypeSupported(PartsArrayEnum partsArrayEnum, Versi PartsArrayEnum.Labels => cardVersion.Major != 4, PartsArrayEnum.Agents => cardVersion.Major != 4, PartsArrayEnum.Langs => cardVersion.Major >= 4, + PartsArrayEnum.Xml => cardVersion.Major == 4, _ => throw new InvalidOperationException("Invalid parts array enumeration type to get supported value"), }; @@ -159,7 +159,6 @@ internal static string GetPrefixFromStringsEnum(StringsEnum stringsEnum) => StringsEnum.SortString => VcardConstants._sortStringSpecifier, StringsEnum.Source => VcardConstants._sourceSpecifier, StringsEnum.Url => VcardConstants._urlSpecifier, - StringsEnum.Xml => VcardConstants._xmlSpecifier, _ => throw new NotImplementedException($"String enumeration {stringsEnum} is not implemented.") }; @@ -196,6 +195,7 @@ internal static string GetPrefixFromPartsArrayEnum(PartsArrayEnum partsArrayEnum PartsArrayEnum.Impps => VcardConstants._imppSpecifier, PartsArrayEnum.Categories => VcardConstants._categoriesSpecifier, PartsArrayEnum.Langs => VcardConstants._langSpecifier, + PartsArrayEnum.Xml => VcardConstants._xmlSpecifier, PartsArrayEnum.NonstandardNames => VcardConstants._xSpecifier, _ => throw new NotImplementedException($"String enumeration {partsArrayEnum} is not implemented.") @@ -222,6 +222,7 @@ internal static (PartType type, object enumeration, Type enumType, Func (PartType.PartsArray, PartsArrayEnum.Impps, typeof(ImppInfo), ImppInfo.FromStringVcardStatic, ImppInfo.FromStringVcardWithTypeStatic), VcardConstants._categoriesSpecifier => (PartType.PartsArray, PartsArrayEnum.Categories, typeof(CategoryInfo), CategoryInfo.FromStringVcardStatic, CategoryInfo.FromStringVcardWithTypeStatic), VcardConstants._langSpecifier => (PartType.PartsArray, PartsArrayEnum.Langs, typeof(LangInfo), LangInfo.FromStringVcardStatic, LangInfo.FromStringVcardWithTypeStatic), + VcardConstants._xmlSpecifier => (PartType.PartsArray, PartsArrayEnum.Xml, typeof(XmlInfo), XmlInfo.FromStringVcardStatic, XmlInfo.FromStringVcardWithTypeStatic), VcardConstants._xSpecifier => (PartType.PartsArray, PartsArrayEnum.NonstandardNames, typeof(XNameInfo), XNameInfo.FromStringVcardStatic, XNameInfo.FromStringVcardWithTypeStatic), VcardConstants._revSpecifier => (PartType.Parts, PartsEnum.Revision, typeof(RevisionInfo), RevisionInfo.FromStringVcardStatic, RevisionInfo.FromStringVcardWithTypeStatic), VcardConstants._birthSpecifier => (PartType.Parts, PartsEnum.Birthdate, typeof(BirthDateInfo), BirthDateInfo.FromStringVcardStatic, BirthDateInfo.FromStringVcardWithTypeStatic), @@ -236,7 +237,6 @@ internal static (PartType type, object enumeration, Type enumType, Func (PartType.Strings, StringsEnum.ProductId, null, null, null), VcardConstants._sortStringSpecifier => (PartType.Strings, StringsEnum.SortString, null, null, null), VcardConstants._classSpecifier => (PartType.Strings, StringsEnum.AccessClassification, null, null, null), - VcardConstants._xmlSpecifier => (PartType.Strings, StringsEnum.Xml, null, null, null), VcardConstants._fbUrlSpecifier => (PartType.Strings, StringsEnum.FreeBusyUrl, null, null, null), VcardConstants._calUriSpecifier => (PartType.Strings, StringsEnum.CalendarUrl, null, null, null), VcardConstants._caladrUriSpecifier => (PartType.Strings, StringsEnum.CalendarSchedulingRequestUrl, null, null, null), diff --git a/VisualCard/Parts/Enums/PartsArrayEnum.cs b/VisualCard/Parts/Enums/PartsArrayEnum.cs index d4de1de3..ba813f8f 100644 --- a/VisualCard/Parts/Enums/PartsArrayEnum.cs +++ b/VisualCard/Parts/Enums/PartsArrayEnum.cs @@ -97,6 +97,10 @@ public enum PartsArrayEnum /// Langs, /// + /// The contact's XML code + /// + Xml, + /// /// The contact's extended options (usually starts with X-SOMETHING:Value1;Value2...) /// NonstandardNames, diff --git a/VisualCard/Parts/Enums/StringsEnum.cs b/VisualCard/Parts/Enums/StringsEnum.cs index 9d2f9517..90bfc3bc 100644 --- a/VisualCard/Parts/Enums/StringsEnum.cs +++ b/VisualCard/Parts/Enums/StringsEnum.cs @@ -57,10 +57,6 @@ public enum StringsEnum /// Source, /// - /// The contact's XML code - /// - Xml, - /// /// The contact's free/busy indicator URL /// FreeBusyUrl, diff --git a/VisualCard/Parts/Implementations/XmlInfo.cs b/VisualCard/Parts/Implementations/XmlInfo.cs new file mode 100644 index 00000000..f5be469d --- /dev/null +++ b/VisualCard/Parts/Implementations/XmlInfo.cs @@ -0,0 +1,161 @@ +// +// VisualCard Copyright (C) 2021-2024 Aptivi +// +// This file is part of VisualCard +// +// VisualCard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// VisualCard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY, without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Xml; +using VisualCard.Parsers; + +namespace VisualCard.Parts.Implementations +{ + /// + /// Contact XML info + /// + [DebuggerDisplay("XML = {XML}")] + public class XmlInfo : BaseCardPartInfo, IEquatable + { + /// + /// The contact's XML field + /// + public XmlDocument Xml { get; } + + /// + /// The contact's XML string that generated the property + /// + public string XmlString { get; } + + internal static BaseCardPartInfo FromStringVcardStatic(string value, int altId, Version cardVersion) => + new XmlInfo().FromStringVcardInternal(value, altId, cardVersion); + + internal static BaseCardPartInfo FromStringVcardWithTypeStatic(string value, string[] finalArgs, int altId, Version cardVersion) => + new XmlInfo().FromStringVcardWithTypeInternal(value, finalArgs, altId, cardVersion); + + internal override string ToStringVcardInternal(Version cardVersion) + { + bool installAltId = AltId >= 0 && AltArguments.Length > 0; + return + $"{VcardConstants._xmlSpecifier}" + + $"{(installAltId ? VcardConstants._fieldDelimiter + VcardConstants._altIdArgumentSpecifier + AltId + VcardConstants._argumentDelimiter : VcardConstants._argumentDelimiter)}" + + $"{XmlString}"; + } + + internal override BaseCardPartInfo FromStringVcardInternal(string value, int altId, Version cardVersion) + { + // Get the value + string xmlValue = value.Substring(VcardConstants._xmlSpecifier.Length + 1); + + // Populate the fields + return InstallInfo(xmlValue, altId, cardVersion); + } + + internal override BaseCardPartInfo FromStringVcardWithTypeInternal(string value, string[] finalArgs, int altId, Version cardVersion) + { + // Get the value + string xmlValue = value.Substring(value.IndexOf(VcardConstants._argumentDelimiter) + 1); + + // Populate the fields + return InstallInfo(xmlValue, finalArgs, altId, cardVersion); + } + + private XmlInfo InstallInfo(string value, int altId, Version cardVersion) => + InstallInfo(value, [], altId, cardVersion); + + private XmlInfo InstallInfo(string value, string[] finalArgs, int altId, Version cardVersion) + { + // Check to see if the XML document is valid or not + string finalXml = + $""" + + + {value.Replace("\\n", "\n")} + + """; + XmlDocument doc = new(); + doc.LoadXml(finalXml); + + // Add the fetched information + bool altIdSupported = cardVersion.Major >= 4; + XmlInfo _xml = new(altIdSupported ? altId : 0, altIdSupported ? finalArgs : [], doc, value); + return _xml; + } + + /// + public override bool Equals(object obj) => + base.Equals(obj); + + /// + /// Checks to see if both the parts are equal + /// + /// The target instance to check to see if they equal + /// True if all the part elements are equal. Otherwise, false. + public bool Equals(XmlInfo other) => + Equals(this, other); + + /// + /// Checks to see if both the parts are equal + /// + /// The source instance to check to see if they equal + /// The target instance to check to see if they equal + /// True if all the part elements are equal. Otherwise, false. + public bool Equals(XmlInfo source, XmlInfo target) + { + // We can't perform this operation on null. + if (source is null) + return false; + + // Check all the properties + return + source.AltArguments.SequenceEqual(target.AltArguments) && + source.AltId == target.AltId && + source.Xml == target.Xml + ; + } + + /// + public override int GetHashCode() + { + int hashCode = -771740963; + hashCode = hashCode * -1521134295 + base.GetHashCode(); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(AltArguments); + hashCode = hashCode * -1521134295 + AltId.GetHashCode(); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Xml); + return hashCode; + } + + /// + public static bool operator ==(XmlInfo left, XmlInfo right) => + EqualityComparer.Default.Equals(left, right); + + /// + public static bool operator !=(XmlInfo left, XmlInfo right) => + !(left == right); + + internal XmlInfo() { } + + internal XmlInfo(int altId, string[] altArguments, XmlDocument xml, string xmlString) + { + AltId = altId; + AltArguments = altArguments; + Xml = xml; + XmlString = xmlString; + } + } +}