From 3125b57cba350cb78961fb3e166309e2b70877ac Mon Sep 17 00:00:00 2001 From: Aptivi CEO Date: Sun, 29 Sep 2024 19:25:56 +0300 Subject: [PATCH] ref - Moved common internal parsing tools --- Type: ref Breaking: False Doc Required: False Backport Required: False Part: 1/1 --- .../Parsers/VCalendarParser.cs | 4 +- VisualCard.Calendar/Parts/Calendar.cs | 4 +- .../Parts/Implementations/AttachInfo.cs | 8 +- .../Parts/Implementations/DateCreatedInfo.cs | 4 +- .../Implementations/Event/DateEndInfo.cs | 4 +- .../Implementations/Event/DateStampInfo.cs | 4 +- .../Implementations/Event/DateStartInfo.cs | 4 +- .../Parts/Implementations/LastModifiedInfo.cs | 4 +- .../Implementations/Legacy/AudioAlarmInfo.cs | 4 +- .../Implementations/Legacy/DaylightInfo.cs | 12 +- .../Legacy/DisplayAlarmInfo.cs | 4 +- .../Implementations/Legacy/MailAlarmInfo.cs | 4 +- .../Legacy/ProcedureAlarmInfo.cs | 4 +- .../Parts/Implementations/RecDateInfo.cs | 6 +- .../TimeZone/TimeZoneOffsetFromInfo.cs | 4 +- .../TimeZone/TimeZoneOffsetToInfo.cs | 4 +- .../Implementations/Todo/DateCompletedInfo.cs | 4 +- .../Parts/Implementations/Todo/DueDateInfo.cs | 4 +- VisualCard/Parsers/VcardCommonTools.cs | 262 ++++++++++++++++++ VisualCard/Parsers/VcardParser.cs | 4 +- VisualCard/Parsers/VcardParserTools.cs | 247 ----------------- VisualCard/Parts/Card.cs | 6 +- .../Parts/Implementations/AnniversaryInfo.cs | 4 +- .../Parts/Implementations/BirthDateInfo.cs | 4 +- VisualCard/Parts/Implementations/KeyInfo.cs | 8 +- VisualCard/Parts/Implementations/LogoInfo.cs | 8 +- VisualCard/Parts/Implementations/PhotoInfo.cs | 8 +- .../Parts/Implementations/RevisionInfo.cs | 4 +- VisualCard/Parts/Implementations/SoundInfo.cs | 8 +- 29 files changed, 332 insertions(+), 317 deletions(-) create mode 100644 VisualCard/Parsers/VcardCommonTools.cs diff --git a/VisualCard.Calendar/Parsers/VCalendarParser.cs b/VisualCard.Calendar/Parsers/VCalendarParser.cs index 52cc1aba..7e01ee21 100644 --- a/VisualCard.Calendar/Parsers/VCalendarParser.cs +++ b/VisualCard.Calendar/Parsers/VCalendarParser.cs @@ -158,7 +158,7 @@ public Parts.Calendar Parse() } // Check the type for allowed types - string[] elementTypes = VcardParserTools.GetTypes(splitArgs, defaultType, specifierRequired); + string[] elementTypes = VcardCommonTools.GetTypes(splitArgs, defaultType, specifierRequired); foreach (string elementType in elementTypes) { string elementTypeUpper = elementType.ToUpper(); @@ -168,7 +168,7 @@ public Parts.Calendar Parse() // Handle the part type Type calendarType = subPart is not null ? subPart.GetType() : calendar.GetType(); - string values = VcardParserTools.GetValuesString(splitArgs, defaultValue, VCalendarConstants._valueArgumentSpecifier); + string values = VcardCommonTools.GetValuesString(splitArgs, defaultValue, VCalendarConstants._valueArgumentSpecifier); switch (type) { case PartType.Strings: diff --git a/VisualCard.Calendar/Parts/Calendar.cs b/VisualCard.Calendar/Parts/Calendar.cs index af028c09..0ce5c05f 100644 --- a/VisualCard.Calendar/Parts/Calendar.cs +++ b/VisualCard.Calendar/Parts/Calendar.cs @@ -277,7 +277,7 @@ internal string SaveToString(Version version, Dictionary /// Whether this attach is a blob or not /// public bool IsBlob => - VcardParserTools.IsEncodingBlob(Arguments, AttachEncoded); + VcardCommonTools.IsEncodingBlob(Arguments, AttachEncoded); internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, string[] finalArgs, string[] elementTypes, string valueType, Version calendarVersion) => new AttachInfo().FromStringVcalendarInternal(value, finalArgs, elementTypes, valueType, calendarVersion); @@ -55,8 +55,8 @@ internal override string ToStringVcalendarInternal(Version calendarVersion) => internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string[] finalArgs, string[] elementTypes, string valueType, Version calendarVersion) { // Check to see if the value is prepended by the ENCODING= argument - string attachEncoding = VcardParserTools.GetValuesString(finalArgs, "b", VCalendarConstants._encodingArgumentSpecifier); - if (!VcardParserTools.IsEncodingBlob(finalArgs, value)) + string attachEncoding = VcardCommonTools.GetValuesString(finalArgs, "b", VCalendarConstants._encodingArgumentSpecifier); + if (!VcardCommonTools.IsEncodingBlob(finalArgs, value)) { // Since we don't need embedded attachs, we need to check a URL. if (!Uri.TryCreate(value, UriKind.Absolute, out Uri uri)) @@ -74,7 +74,7 @@ internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, /// /// A stream that contains image data public Stream GetStream() => - VcardParserTools.GetBlobData(Arguments, AttachEncoded); + VcardCommonTools.GetBlobData(Arguments, AttachEncoded); /// public override bool Equals(object obj) => diff --git a/VisualCard.Calendar/Parts/Implementations/DateCreatedInfo.cs b/VisualCard.Calendar/Parts/Implementations/DateCreatedInfo.cs index 7887b804..9aad8c7f 100644 --- a/VisualCard.Calendar/Parts/Implementations/DateCreatedInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/DateCreatedInfo.cs @@ -38,12 +38,12 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str new DateCreatedInfo().FromStringVcalendarInternal(value, finalArgs, elementTypes, valueType, cardVersion); internal override string ToStringVcalendarInternal(Version cardVersion) => - $"{VcardParserTools.SavePosixDate(DateCreated)}"; + $"{VcardCommonTools.SavePosixDate(DateCreated)}"; internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string[] finalArgs, string[] elementTypes, string valueType, Version cardVersion) { // Populate the fields - DateTimeOffset created = VcardParserTools.ParsePosixDate(value); + DateTimeOffset created = VcardCommonTools.ParsePosixDate(value); // Add the fetched information DateCreatedInfo _time = new(finalArgs, elementTypes, valueType, created); diff --git a/VisualCard.Calendar/Parts/Implementations/Event/DateEndInfo.cs b/VisualCard.Calendar/Parts/Implementations/Event/DateEndInfo.cs index 85be9d78..d82712e6 100644 --- a/VisualCard.Calendar/Parts/Implementations/Event/DateEndInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/Event/DateEndInfo.cs @@ -38,12 +38,12 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str new DateEndInfo().FromStringVcalendarInternal(value, finalArgs, elementTypes, valueType, cardVersion); internal override string ToStringVcalendarInternal(Version cardVersion) => - $"{VcardParserTools.SavePosixDate(DateEnd)}"; + $"{VcardCommonTools.SavePosixDate(DateEnd)}"; internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string[] finalArgs, string[] elementTypes, string valueType, Version cardVersion) { // Populate the fields - DateTimeOffset end = VcardParserTools.ParsePosixDate(value); + DateTimeOffset end = VcardCommonTools.ParsePosixDate(value); // Add the fetched information DateEndInfo _time = new(finalArgs, elementTypes, valueType, end); diff --git a/VisualCard.Calendar/Parts/Implementations/Event/DateStampInfo.cs b/VisualCard.Calendar/Parts/Implementations/Event/DateStampInfo.cs index ab898795..08592857 100644 --- a/VisualCard.Calendar/Parts/Implementations/Event/DateStampInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/Event/DateStampInfo.cs @@ -38,12 +38,12 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str new DateStampInfo().FromStringVcalendarInternal(value, finalArgs, elementTypes, valueType, cardVersion); internal override string ToStringVcalendarInternal(Version cardVersion) => - $"{VcardParserTools.SavePosixDate(DateStamp)}"; + $"{VcardCommonTools.SavePosixDate(DateStamp)}"; internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string[] finalArgs, string[] elementTypes, string valueType, Version cardVersion) { // Populate the fields - DateTimeOffset stamp = VcardParserTools.ParsePosixDate(value); + DateTimeOffset stamp = VcardCommonTools.ParsePosixDate(value); // Add the fetched information DateStampInfo _time = new(finalArgs, elementTypes, valueType, stamp); diff --git a/VisualCard.Calendar/Parts/Implementations/Event/DateStartInfo.cs b/VisualCard.Calendar/Parts/Implementations/Event/DateStartInfo.cs index f4570a47..b9316afa 100644 --- a/VisualCard.Calendar/Parts/Implementations/Event/DateStartInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/Event/DateStartInfo.cs @@ -38,12 +38,12 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str new DateStartInfo().FromStringVcalendarInternal(value, finalArgs, elementTypes, valueType, cardVersion); internal override string ToStringVcalendarInternal(Version cardVersion) => - $"{VcardParserTools.SavePosixDate(DateStart)}"; + $"{VcardCommonTools.SavePosixDate(DateStart)}"; internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string[] finalArgs, string[] elementTypes, string valueType, Version cardVersion) { // Populate the fields - DateTimeOffset start = VcardParserTools.ParsePosixDate(value); + DateTimeOffset start = VcardCommonTools.ParsePosixDate(value); // Add the fetched information DateStartInfo _time = new(finalArgs, elementTypes, valueType, start); diff --git a/VisualCard.Calendar/Parts/Implementations/LastModifiedInfo.cs b/VisualCard.Calendar/Parts/Implementations/LastModifiedInfo.cs index 1b015593..acbbef7b 100644 --- a/VisualCard.Calendar/Parts/Implementations/LastModifiedInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/LastModifiedInfo.cs @@ -38,12 +38,12 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str new LastModifiedInfo().FromStringVcalendarInternal(value, finalArgs, elementTypes, valueType, cardVersion); internal override string ToStringVcalendarInternal(Version cardVersion) => - $"{VcardParserTools.SavePosixDate(LastModified)}"; + $"{VcardCommonTools.SavePosixDate(LastModified)}"; internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string[] finalArgs, string[] elementTypes, string valueType, Version cardVersion) { // Populate the fields - DateTimeOffset created = VcardParserTools.ParsePosixDate(value); + DateTimeOffset created = VcardCommonTools.ParsePosixDate(value); // Add the fetched information LastModifiedInfo _time = new(finalArgs, elementTypes, valueType, created); diff --git a/VisualCard.Calendar/Parts/Implementations/Legacy/AudioAlarmInfo.cs b/VisualCard.Calendar/Parts/Implementations/Legacy/AudioAlarmInfo.cs index 7845c4cb..5ea38a9a 100644 --- a/VisualCard.Calendar/Parts/Implementations/Legacy/AudioAlarmInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/Legacy/AudioAlarmInfo.cs @@ -55,7 +55,7 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str internal override string ToStringVcalendarInternal(Version calendarVersion) { - string posixRunTime = VcardParserTools.SavePosixDate(RunTime); + string posixRunTime = VcardCommonTools.SavePosixDate(RunTime); return $"{posixRunTime};{SnoozeTime};{RepeatCount};{AudioResource}"; } @@ -71,7 +71,7 @@ internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string audioResource = split[3]; // Process the run time and the repeat times - DateTimeOffset runTime = VcardParserTools.ParsePosixDate(unprocessedRunTime); + DateTimeOffset runTime = VcardCommonTools.ParsePosixDate(unprocessedRunTime); int repeat = 0; if (!string.IsNullOrWhiteSpace(unprocessedRepeat) && !int.TryParse(unprocessedRepeat, out repeat)) throw new ArgumentException("Invalid repeat times"); diff --git a/VisualCard.Calendar/Parts/Implementations/Legacy/DaylightInfo.cs b/VisualCard.Calendar/Parts/Implementations/Legacy/DaylightInfo.cs index 85905e8c..7e602eca 100644 --- a/VisualCard.Calendar/Parts/Implementations/Legacy/DaylightInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/Legacy/DaylightInfo.cs @@ -67,9 +67,9 @@ internal override string ToStringVcalendarInternal(Version calendarVersion) { if (!Flag) return "FALSE"; - string posixUtc = VcardParserTools.SaveUtcOffset(UtcOffset); - string posixStart = VcardParserTools.SavePosixDate(DaylightStart); - string posixEnd = VcardParserTools.SavePosixDate(DaylightEnd); + string posixUtc = VcardCommonTools.SaveUtcOffset(UtcOffset); + string posixStart = VcardCommonTools.SavePosixDate(DaylightStart); + string posixEnd = VcardCommonTools.SavePosixDate(DaylightEnd); return $"TRUE;{posixUtc};{posixStart};{posixEnd};{StandardDesignation};{DaylightDesignation}"; } @@ -88,9 +88,9 @@ internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string daylight = split[5]; // Process the UTC offset and start/end dates - TimeSpan utcOffset = VcardParserTools.ParseUtcOffset(unprocessedUtc); - DateTimeOffset startDate = VcardParserTools.ParsePosixDate(unprocessedStart); - DateTimeOffset endDate = VcardParserTools.ParsePosixDate(unprocessedEnd); + TimeSpan utcOffset = VcardCommonTools.ParseUtcOffset(unprocessedUtc); + DateTimeOffset startDate = VcardCommonTools.ParsePosixDate(unprocessedStart); + DateTimeOffset endDate = VcardCommonTools.ParsePosixDate(unprocessedEnd); // Populate the fields DaylightInfo _geo = new(finalArgs, elementTypes, valueType, true, utcOffset, startDate, endDate, standard, daylight); diff --git a/VisualCard.Calendar/Parts/Implementations/Legacy/DisplayAlarmInfo.cs b/VisualCard.Calendar/Parts/Implementations/Legacy/DisplayAlarmInfo.cs index e0f66755..3ed93cb5 100644 --- a/VisualCard.Calendar/Parts/Implementations/Legacy/DisplayAlarmInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/Legacy/DisplayAlarmInfo.cs @@ -55,7 +55,7 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str internal override string ToStringVcalendarInternal(Version calendarVersion) { - string posixRunTime = VcardParserTools.SavePosixDate(RunTime); + string posixRunTime = VcardCommonTools.SavePosixDate(RunTime); return $"{posixRunTime};{SnoozeTime};{RepeatCount};{Display}"; } @@ -71,7 +71,7 @@ internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string display = split[3]; // Process the run time and the repeat times - DateTimeOffset runTime = VcardParserTools.ParsePosixDate(unprocessedRunTime); + DateTimeOffset runTime = VcardCommonTools.ParsePosixDate(unprocessedRunTime); int repeat = 0; if (!string.IsNullOrWhiteSpace(unprocessedRepeat) && !int.TryParse(unprocessedRepeat, out repeat)) throw new ArgumentException("Invalid repeat times"); diff --git a/VisualCard.Calendar/Parts/Implementations/Legacy/MailAlarmInfo.cs b/VisualCard.Calendar/Parts/Implementations/Legacy/MailAlarmInfo.cs index 40412ba0..c18198a7 100644 --- a/VisualCard.Calendar/Parts/Implementations/Legacy/MailAlarmInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/Legacy/MailAlarmInfo.cs @@ -60,7 +60,7 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str internal override string ToStringVcalendarInternal(Version calendarVersion) { - string posixRunTime = VcardParserTools.SavePosixDate(RunTime); + string posixRunTime = VcardCommonTools.SavePosixDate(RunTime); return $"{posixRunTime};{SnoozeTime};{RepeatCount};{Address};{Note}"; } @@ -77,7 +77,7 @@ internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string note = split[4]; // Process the run time and the repeat times - DateTimeOffset runTime = VcardParserTools.ParsePosixDate(unprocessedRunTime); + DateTimeOffset runTime = VcardCommonTools.ParsePosixDate(unprocessedRunTime); int repeat = 0; if (!string.IsNullOrWhiteSpace(unprocessedRepeat) && !int.TryParse(unprocessedRepeat, out repeat)) throw new ArgumentException("Invalid repeat times"); diff --git a/VisualCard.Calendar/Parts/Implementations/Legacy/ProcedureAlarmInfo.cs b/VisualCard.Calendar/Parts/Implementations/Legacy/ProcedureAlarmInfo.cs index 2fa84698..18ab6293 100644 --- a/VisualCard.Calendar/Parts/Implementations/Legacy/ProcedureAlarmInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/Legacy/ProcedureAlarmInfo.cs @@ -55,7 +55,7 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str internal override string ToStringVcalendarInternal(Version calendarVersion) { - string posixRunTime = VcardParserTools.SavePosixDate(RunTime); + string posixRunTime = VcardCommonTools.SavePosixDate(RunTime); return $"{posixRunTime};{SnoozeTime};{RepeatCount};{Procedure}"; } @@ -71,7 +71,7 @@ internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string procedure = split[3]; // Process the run time and the repeat times - DateTimeOffset runTime = VcardParserTools.ParsePosixDate(unprocessedRunTime); + DateTimeOffset runTime = VcardCommonTools.ParsePosixDate(unprocessedRunTime); int repeat = 0; if (!string.IsNullOrWhiteSpace(unprocessedRepeat) && !int.TryParse(unprocessedRepeat, out repeat)) throw new ArgumentException("Invalid repeat times"); diff --git a/VisualCard.Calendar/Parts/Implementations/RecDateInfo.cs b/VisualCard.Calendar/Parts/Implementations/RecDateInfo.cs index cfb348ed..e27f3202 100644 --- a/VisualCard.Calendar/Parts/Implementations/RecDateInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/RecDateInfo.cs @@ -48,9 +48,9 @@ internal override string ToStringVcalendarInternal(Version cardVersion) var builder = new StringBuilder(); if (cardVersion.Major == 1) - builder.Append(string.Join(";", RecDates.Select((dt) => VcardParserTools.SavePosixDate(dt)))); + builder.Append(string.Join(";", RecDates.Select((dt) => VcardCommonTools.SavePosixDate(dt)))); else - builder.Append(VcardParserTools.SavePosixDate(RecDates[0])); + builder.Append(VcardCommonTools.SavePosixDate(RecDates[0])); return builder.ToString(); } @@ -61,7 +61,7 @@ internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, cardVersion.Major == 1 ? Regex.Unescape(value).Split(';') : [Regex.Unescape(value)]; - var recDates = recDateStrings.Select(VcardParserTools.ParsePosixDate).ToArray(); + var recDates = recDateStrings.Select(VcardCommonTools.ParsePosixDate).ToArray(); // Add the fetched information RecDateInfo _time = new([], elementTypes, valueType, recDates); diff --git a/VisualCard.Calendar/Parts/Implementations/TimeZone/TimeZoneOffsetFromInfo.cs b/VisualCard.Calendar/Parts/Implementations/TimeZone/TimeZoneOffsetFromInfo.cs index f5c2166a..c707ba0f 100644 --- a/VisualCard.Calendar/Parts/Implementations/TimeZone/TimeZoneOffsetFromInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/TimeZone/TimeZoneOffsetFromInfo.cs @@ -38,12 +38,12 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str new TimeZoneOffsetFromInfo().FromStringVcalendarInternal(value, finalArgs, elementTypes, valueType, cardVersion); internal override string ToStringVcalendarInternal(Version cardVersion) => - $"{VcardParserTools.SaveUtcOffset(Offset)}"; + $"{VcardCommonTools.SaveUtcOffset(Offset)}"; internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string[] finalArgs, string[] elementTypes, string valueType, Version cardVersion) { // Populate the fields - TimeSpan start = VcardParserTools.ParseUtcOffset(value); + TimeSpan start = VcardCommonTools.ParseUtcOffset(value); // Add the fetched information TimeZoneOffsetFromInfo _time = new(finalArgs, elementTypes, valueType, start); diff --git a/VisualCard.Calendar/Parts/Implementations/TimeZone/TimeZoneOffsetToInfo.cs b/VisualCard.Calendar/Parts/Implementations/TimeZone/TimeZoneOffsetToInfo.cs index 6e75cef5..72167d1b 100644 --- a/VisualCard.Calendar/Parts/Implementations/TimeZone/TimeZoneOffsetToInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/TimeZone/TimeZoneOffsetToInfo.cs @@ -38,12 +38,12 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str new TimeZoneOffsetToInfo().FromStringVcalendarInternal(value, finalArgs, elementTypes, valueType, cardVersion); internal override string ToStringVcalendarInternal(Version cardVersion) => - $"{VcardParserTools.SaveUtcOffset(Offset)}"; + $"{VcardCommonTools.SaveUtcOffset(Offset)}"; internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string[] finalArgs, string[] elementTypes, string valueType, Version cardVersion) { // Populate the fields - TimeSpan start = VcardParserTools.ParseUtcOffset(value); + TimeSpan start = VcardCommonTools.ParseUtcOffset(value); // Add the fetched information TimeZoneOffsetToInfo _time = new(finalArgs, elementTypes, valueType, start); diff --git a/VisualCard.Calendar/Parts/Implementations/Todo/DateCompletedInfo.cs b/VisualCard.Calendar/Parts/Implementations/Todo/DateCompletedInfo.cs index 19690de6..cc259e2d 100644 --- a/VisualCard.Calendar/Parts/Implementations/Todo/DateCompletedInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/Todo/DateCompletedInfo.cs @@ -38,12 +38,12 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str new DateCompletedInfo().FromStringVcalendarInternal(value, finalArgs, elementTypes, valueType, cardVersion); internal override string ToStringVcalendarInternal(Version cardVersion) => - $"{VcardParserTools.SavePosixDate(DateCompleted)}"; + $"{VcardCommonTools.SavePosixDate(DateCompleted)}"; internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string[] finalArgs, string[] elementTypes, string valueType, Version cardVersion) { // Populate the fields - DateTimeOffset completed = VcardParserTools.ParsePosixDate(value); + DateTimeOffset completed = VcardCommonTools.ParsePosixDate(value); // Add the fetched information DateCompletedInfo _time = new(finalArgs, elementTypes, valueType, completed); diff --git a/VisualCard.Calendar/Parts/Implementations/Todo/DueDateInfo.cs b/VisualCard.Calendar/Parts/Implementations/Todo/DueDateInfo.cs index d30a477c..089d026d 100644 --- a/VisualCard.Calendar/Parts/Implementations/Todo/DueDateInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/Todo/DueDateInfo.cs @@ -38,12 +38,12 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str new DueDateInfo().FromStringVcalendarInternal(value, finalArgs, elementTypes, valueType, cardVersion); internal override string ToStringVcalendarInternal(Version cardVersion) => - $"{VcardParserTools.SavePosixDate(DueDate)}"; + $"{VcardCommonTools.SavePosixDate(DueDate)}"; internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string[] finalArgs, string[] elementTypes, string valueType, Version cardVersion) { // Populate the fields - DateTimeOffset completed = VcardParserTools.ParsePosixDate(value); + DateTimeOffset completed = VcardCommonTools.ParsePosixDate(value); // Add the fetched information DueDateInfo _time = new(finalArgs, elementTypes, valueType, completed); diff --git a/VisualCard/Parsers/VcardCommonTools.cs b/VisualCard/Parsers/VcardCommonTools.cs new file mode 100644 index 00000000..9759d02a --- /dev/null +++ b/VisualCard/Parsers/VcardCommonTools.cs @@ -0,0 +1,262 @@ +// +// 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.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using VisualCard.Parts.Enums; + +namespace VisualCard.Parsers +{ + internal static class VcardCommonTools + { + internal static string GetTypesString(string[] args, string @default, bool isSpecifierRequired = true) + { + // We're given an array of split arguments of an element delimited by the colon, such as: "...TYPE=home..." + // Filter list of arguments with the arguments that start with the type argument specifier, or, if specifier is not required, + // that doesn't have an equals sign + var ArgType = args.Where((arg) => arg.StartsWith(VcardConstants._typeArgumentSpecifier) || !arg.Contains("=")).ToArray(); + + // Trying to specify type without TYPE= is illegal according to RFC2426 in vCard 3.0 and 4.0 + if (ArgType.Count() > 0 && !ArgType[0].StartsWith(VcardConstants._typeArgumentSpecifier) && isSpecifierRequired) + throw new InvalidDataException("Type must be prepended with TYPE="); + + // Get the type from the split argument + string Type = ""; + if (isSpecifierRequired) + // Attempt to get the value from the key strictly + Type = + ArgType.Count() > 0 ? + string.Join(VcardConstants._valueDelimiter.ToString(), ArgType.Select((arg) => arg.Substring(VcardConstants._typeArgumentSpecifier.Length))) : + @default; + else + // Attempt to get the value from the key + Type = + ArgType.Count() > 0 ? + string.Join(VcardConstants._valueDelimiter.ToString(), ArgType.Select((arg) => arg.StartsWith(VcardConstants._typeArgumentSpecifier) ? arg.Substring(VcardConstants._typeArgumentSpecifier.Length) : arg)) : + @default; + + // Return the type + return Type; + } + + internal static string[] GetTypes(string[] args, string @default, bool isSpecifierRequired = true) => + GetTypesString(args, @default, isSpecifierRequired).Split([VcardConstants._valueDelimiter], StringSplitOptions.RemoveEmptyEntries); + + internal static string GetValuesString(string[] args, string @default, string argSpecifier) + { + // We're given an array of split arguments of an element delimited by the colon, such as: "...TYPE=home..." + // Filter list of arguments with the arguments that start with the specified specifier (key) + var argFromSpecifier = args.Where((arg) => arg.StartsWith(argSpecifier)); + + // Attempt to get the value from the key + string argString = + argFromSpecifier.Count() > 0 ? + string.Join(VcardConstants._valueDelimiter.ToString(), argFromSpecifier.Select((arg) => arg.Substring(argSpecifier.Length))) : + @default; + return argString; + } + + internal static string[] GetValues(string[] args, string @default, string argSpecifier) => + GetValuesString(args, @default, argSpecifier).Split([VcardConstants._valueDelimiter], StringSplitOptions.RemoveEmptyEntries); + + internal static bool StringSupported(StringsEnum stringsEnum, Version cardVersion) => + stringsEnum switch + { + StringsEnum.Kind => cardVersion.Major >= 4, + StringsEnum.Mailer => cardVersion.Major != 4, + StringsEnum.ProductId => cardVersion.Major >= 3, + StringsEnum.SortString => cardVersion.Major == 3 || cardVersion.Major == 5, + StringsEnum.AccessClassification => cardVersion.Major != 2 || cardVersion.Major != 4, + StringsEnum.Uid => cardVersion.Major <= 4, + _ => + throw new InvalidOperationException("Invalid string enumeration type to get supported value"), + }; + + internal static string MakeStringBlock(string target, int firstLength) + { + const int maxChars = 74; + int maxCharsFirst = maxChars - firstLength + 1; + + // Construct the block + StringBuilder block = new(); + int selectedMax = maxCharsFirst; + int processed = 0; + for (int currCharNum = 0; currCharNum < target.Length; currCharNum++) + { + if (target[currCharNum] != '\n' && target[currCharNum] != '\r') + { + block.Append(target[currCharNum]); + processed++; + } + if (processed >= selectedMax || target[currCharNum] == '\n') + { + // Append a new line because we reached the maximum limit + selectedMax = maxChars; + processed = 0; + block.Append("\n "); + } + } + return block.ToString(); + } + + internal static bool IsEncodingBlob(string[]? args, string? keyEncoded) + { + args ??= []; + string encoding = GetValuesString(args, "b", VcardConstants._encodingArgumentSpecifier); + bool isValidUri = Uri.TryCreate(keyEncoded, UriKind.Absolute, out Uri uri); + if (isValidUri) + { + if (uri.Scheme == "data") + return true; + return false; + } + return + encoding.Equals("b", StringComparison.OrdinalIgnoreCase) || + encoding.Equals("BASE64", StringComparison.OrdinalIgnoreCase) || + encoding.Equals("BLOB", StringComparison.OrdinalIgnoreCase); + } + + internal static Stream GetBlobData(string[]? args, string? keyEncoded) + { + args ??= []; + if (IsEncodingBlob(args, keyEncoded)) + { + bool isValidUri = Uri.TryCreate(keyEncoded, UriKind.Absolute, out Uri uri); + string dataStr; + if (isValidUri) + { + if (uri.Scheme == "data") + dataStr = uri.AbsolutePath.Substring(uri.AbsolutePath.IndexOf(",") + 1); + else + throw new InvalidDataException("Contains a valid URL; you should fetch that URL manually and convert the response to the stream."); + } + else + dataStr = keyEncoded ?? + throw new InvalidDataException("There is no encoded data."); + byte[] dataBytes = Convert.FromBase64String(dataStr); + Stream blobStream = new MemoryStream(dataBytes); + return blobStream; + } + else + throw new InvalidOperationException("Not a blob. You should somehow handle it."); + } + + internal static DateTimeOffset ParsePosixDate(string posixDateRepresentation) + { + // Check to see if this date and time representation is supported by .NET + if (DateTimeOffset.TryParse(posixDateRepresentation, out DateTimeOffset date)) + return date; + + // Now, this date might be a POSIX date that follows the vCard specification, but check it + if (posixDateRepresentation.Length == 8) + { + // It might be yyyyMMdd, but check again + string yearStr = posixDateRepresentation.Substring(0, 4); + string monthStr = posixDateRepresentation.Substring(4, 2); + string dayStr = posixDateRepresentation.Substring(6, 2); + if (DateTimeOffset.TryParseExact($"{yearStr}/{monthStr}/{dayStr}", "yyyy/MM/dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out date)) + return date; + } + else if (posixDateRepresentation.Length == 15 || posixDateRepresentation.Length == 16) + { + // It might be yyyyMMdd + "T" + HHmmss + ["Z"], but check again + string yearStr = posixDateRepresentation.Substring(0, 4); + string monthStr = posixDateRepresentation.Substring(4, 2); + string dayStr = posixDateRepresentation.Substring(6, 2); + char timeIndicator = posixDateRepresentation[8]; + string hourStr = posixDateRepresentation.Substring(9, 2); + string minuteStr = posixDateRepresentation.Substring(11, 2); + string secondStr = posixDateRepresentation.Substring(13, 2); + if (timeIndicator != 'T') + throw new ArgumentException($"Time indicator is invalid."); + if (posixDateRepresentation.Length == 16 && posixDateRepresentation[15] != 'Z') + throw new ArgumentException($"UTC indicator is invalid."); + bool assumeUtc = posixDateRepresentation.Length == 16 && posixDateRepresentation[15] == 'Z'; + var utcOffset = assumeUtc ? DateTimeOffset.UtcNow.Offset : DateTimeOffset.Now.Offset; + string renderedOffset = SaveUtcOffset(utcOffset); + if (DateTimeOffset.TryParseExact($"{yearStr}/{monthStr}/{dayStr} {hourStr}:{minuteStr}:{secondStr} {renderedOffset}", "yyyy/MM/dd HH:mm:ss zzz", CultureInfo.InvariantCulture, assumeUtc ? DateTimeStyles.AssumeUniversal : DateTimeStyles.AssumeLocal, out date)) + return date; + } + throw new ArgumentException($"Can't parse date {posixDateRepresentation}"); + } + + internal static string SavePosixDate(DateTimeOffset posixDateRepresentation, bool dateOnly = false) + { + StringBuilder posixDateBuilder = new( + $"{posixDateRepresentation.Year:0000}" + + $"{posixDateRepresentation.Month:00}" + + $"{posixDateRepresentation.Day:00}" + ); + if (!dateOnly) + posixDateBuilder.Append( + $"T" + + $"{posixDateRepresentation.Hour:00}" + + $"{posixDateRepresentation.Minute:00}" + + $"{posixDateRepresentation.Second:00}" + + $"{(posixDateRepresentation.Offset == new TimeSpan() ? "Z" : "")}" + ); + return posixDateBuilder.ToString(); + } + + internal static TimeSpan ParseUtcOffset(string utcOffsetRepresentation) + { + // Check for sanity + if (utcOffsetRepresentation.Length != 3 && utcOffsetRepresentation.Length != 5 && utcOffsetRepresentation.Length != 7) + throw new ArgumentException($"UTC offset representation [{utcOffsetRepresentation}] is invalid."); + bool hasMinutes = utcOffsetRepresentation.Length >= 5; + bool hasSeconds = utcOffsetRepresentation.Length == 7; + + // Now, this representation might be a POSIX offset that follows the vCard specification, but check it, + // because it might be either <+/->HHmmss, <+/->HHmm, or <+/->HH. + string designatorStr = utcOffsetRepresentation.Substring(0, 1); + string hourStr = utcOffsetRepresentation.Substring(1, 2); + string minuteStr = hasMinutes ? utcOffsetRepresentation.Substring(3, 2) : ""; + string secondStr = hasSeconds ? utcOffsetRepresentation.Substring(5, 2) : ""; + if (designatorStr != "+" && designatorStr != "-") + throw new ArgumentException($"Designator {designatorStr} is invalid."); + if (hourStr == "00" && (!hasMinutes || (hasMinutes && minuteStr == "00")) && (!hasSeconds || (hasSeconds && secondStr == "00"))) + { + if (designatorStr == "-") + throw new ArgumentException($"Can't specify negative zero offset."); + return new(); + } + if (TimeSpan.TryParseExact($"{hourStr}:{(hasMinutes ? minuteStr : "00")}:{(hasSeconds ? secondStr : "00")}", "hh\\:mm\\:ss", CultureInfo.InvariantCulture, out TimeSpan offset)) + return designatorStr == "-" ? -offset : offset; + throw new ArgumentException($"Can't parse offset {utcOffsetRepresentation}"); + } + + internal static string SaveUtcOffset(TimeSpan utcOffsetRepresentation) + { + StringBuilder utcOffsetBuilder = new( + $"{(utcOffsetRepresentation < new TimeSpan() ? "-" : "+")}" + + $"{Math.Abs(utcOffsetRepresentation.Hours):00}" + + $"{Math.Abs(utcOffsetRepresentation.Minutes):00}" + ); + if (utcOffsetRepresentation.Seconds != 0) + utcOffsetBuilder.Append( + $"{Math.Abs(utcOffsetRepresentation.Seconds):00}" + ); + return utcOffsetBuilder.ToString(); + } + } +} diff --git a/VisualCard/Parsers/VcardParser.cs b/VisualCard/Parsers/VcardParser.cs index 068c16ac..1307b465 100644 --- a/VisualCard/Parsers/VcardParser.cs +++ b/VisualCard/Parsers/VcardParser.cs @@ -164,7 +164,7 @@ public Card Parse() } // Check the type for allowed types - string[] elementTypes = VcardParserTools.GetTypes(splitArgs, defaultType, specifierRequired); + string[] elementTypes = VcardCommonTools.GetTypes(splitArgs, defaultType, specifierRequired); foreach (string elementType in elementTypes) { string elementTypeUpper = elementType.ToUpper(); @@ -173,7 +173,7 @@ public Card Parse() } // Handle the part type - string values = VcardParserTools.GetValuesString(splitArgs, defaultValue, VcardConstants._valueArgumentSpecifier); + string values = VcardCommonTools.GetValuesString(splitArgs, defaultValue, VcardConstants._valueArgumentSpecifier); switch (type) { case PartType.Strings: diff --git a/VisualCard/Parsers/VcardParserTools.cs b/VisualCard/Parsers/VcardParserTools.cs index 002dda9d..234d042f 100644 --- a/VisualCard/Parsers/VcardParserTools.cs +++ b/VisualCard/Parsers/VcardParserTools.cs @@ -17,84 +17,17 @@ // along with this program. If not, see . // -using System.Collections.Generic; using System; using System.IO; -using System.Linq; using VisualCard.Parts.Enums; using VisualCard.Parts.Implementations; -using System.Text; using VisualCard.Parts; -using System.Globalization; using System.Text.RegularExpressions; namespace VisualCard.Parsers { internal class VcardParserTools { - internal static string GetTypesString(string[] args, string @default, bool isSpecifierRequired = true) - { - // We're given an array of split arguments of an element delimited by the colon, such as: "...TYPE=home..." - // Filter list of arguments with the arguments that start with the type argument specifier, or, if specifier is not required, - // that doesn't have an equals sign - var ArgType = args.Where((arg) => arg.StartsWith(VcardConstants._typeArgumentSpecifier) || !arg.Contains("=")).ToArray(); - - // Trying to specify type without TYPE= is illegal according to RFC2426 in vCard 3.0 and 4.0 - if (ArgType.Count() > 0 && !ArgType[0].StartsWith(VcardConstants._typeArgumentSpecifier) && isSpecifierRequired) - throw new InvalidDataException("Type must be prepended with TYPE="); - - // Get the type from the split argument - string Type = ""; - if (isSpecifierRequired) - // Attempt to get the value from the key strictly - Type = - ArgType.Count() > 0 ? - string.Join(VcardConstants._valueDelimiter.ToString(), ArgType.Select((arg) => arg.Substring(VcardConstants._typeArgumentSpecifier.Length))) : - @default; - else - // Attempt to get the value from the key - Type = - ArgType.Count() > 0 ? - string.Join(VcardConstants._valueDelimiter.ToString(), ArgType.Select((arg) => arg.StartsWith(VcardConstants._typeArgumentSpecifier) ? arg.Substring(VcardConstants._typeArgumentSpecifier.Length) : arg)) : - @default; - - // Return the type - return Type; - } - - internal static string[] GetTypes(string[] args, string @default, bool isSpecifierRequired = true) => - GetTypesString(args, @default, isSpecifierRequired).Split([VcardConstants._valueDelimiter], StringSplitOptions.RemoveEmptyEntries); - - internal static string GetValuesString(string[] args, string @default, string argSpecifier) - { - // We're given an array of split arguments of an element delimited by the colon, such as: "...TYPE=home..." - // Filter list of arguments with the arguments that start with the specified specifier (key) - var argFromSpecifier = args.Where((arg) => arg.StartsWith(argSpecifier)); - - // Attempt to get the value from the key - string argString = - argFromSpecifier.Count() > 0 ? - string.Join(VcardConstants._valueDelimiter.ToString(), argFromSpecifier.Select((arg) => arg.Substring(argSpecifier.Length))) : - @default; - return argString; - } - - internal static string[] GetValues(string[] args, string @default, string argSpecifier) => - GetValuesString(args, @default, argSpecifier).Split([VcardConstants._valueDelimiter], StringSplitOptions.RemoveEmptyEntries); - - internal static bool StringSupported(StringsEnum stringsEnum, Version cardVersion) => - stringsEnum switch - { - StringsEnum.Kind => cardVersion.Major >= 4, - StringsEnum.Mailer => cardVersion.Major != 4, - StringsEnum.ProductId => cardVersion.Major >= 3, - StringsEnum.SortString => cardVersion.Major == 3 || cardVersion.Major == 5, - StringsEnum.AccessClassification => cardVersion.Major != 2 || cardVersion.Major != 4, - StringsEnum.Uid => cardVersion.Major <= 4, - _ => - throw new InvalidOperationException("Invalid string enumeration type to get supported value"), - }; - internal static bool EnumArrayTypeSupported(PartsArrayEnum partsArrayEnum, Version cardVersion, string kind) => partsArrayEnum switch { @@ -318,186 +251,6 @@ internal static (PartType type, object enumeration, Type? enumType, Func (PartType.PartsArray, PartsArrayEnum.IanaNames, typeof(ExtraInfo), ExtraInfo.FromStringVcardStatic, "", "", []), }; - internal static string MakeStringBlock(string target, int firstLength) - { - const int maxChars = 74; - int maxCharsFirst = maxChars - firstLength + 1; - - // Construct the block - StringBuilder block = new(); - int selectedMax = maxCharsFirst; - int processed = 0; - for (int currCharNum = 0; currCharNum < target.Length; currCharNum++) - { - if (target[currCharNum] != '\n' && target[currCharNum] != '\r') - { - block.Append(target[currCharNum]); - processed++; - } - if (processed >= selectedMax || target[currCharNum] == '\n') - { - // Append a new line because we reached the maximum limit - selectedMax = maxChars; - processed = 0; - block.Append("\n "); - } - } - return block.ToString(); - } - - internal static IEnumerable GetDigits(int num) - { - int individualFactor = 0; - int tennerFactor = Convert.ToInt32(Math.Pow(10, num.ToString().Length)); - while (tennerFactor > 1) - { - num -= tennerFactor * individualFactor; - tennerFactor /= 10; - individualFactor = num / tennerFactor; - yield return individualFactor; - } - } - - internal static bool IsEncodingBlob(string[]? args, string? keyEncoded) - { - args ??= []; - string encoding = GetValuesString(args, "b", VcardConstants._encodingArgumentSpecifier); - bool isValidUri = Uri.TryCreate(keyEncoded, UriKind.Absolute, out Uri uri); - if (isValidUri) - { - if (uri.Scheme == "data") - return true; - return false; - } - return - encoding.Equals("b", StringComparison.OrdinalIgnoreCase) || - encoding.Equals("BASE64", StringComparison.OrdinalIgnoreCase) || - encoding.Equals("BLOB", StringComparison.OrdinalIgnoreCase); - } - - internal static Stream GetBlobData(string[]? args, string? keyEncoded) - { - args ??= []; - if (IsEncodingBlob(args, keyEncoded)) - { - bool isValidUri = Uri.TryCreate(keyEncoded, UriKind.Absolute, out Uri uri); - string dataStr; - if (isValidUri) - { - if (uri.Scheme == "data") - dataStr = uri.AbsolutePath.Substring(uri.AbsolutePath.IndexOf(",") + 1); - else - throw new InvalidDataException("Contains a valid URL; you should fetch that URL manually and convert the response to the stream."); - } - else - dataStr = keyEncoded ?? - throw new InvalidDataException("There is no encoded data."); - byte[] dataBytes = Convert.FromBase64String(dataStr); - Stream blobStream = new MemoryStream(dataBytes); - return blobStream; - } - else - throw new InvalidOperationException("Not a blob. You should somehow handle it."); - } - - internal static DateTimeOffset ParsePosixDate(string posixDateRepresentation) - { - // Check to see if this date and time representation is supported by .NET - if (DateTimeOffset.TryParse(posixDateRepresentation, out DateTimeOffset date)) - return date; - - // Now, this date might be a POSIX date that follows the vCard specification, but check it - if (posixDateRepresentation.Length == 8) - { - // It might be yyyyMMdd, but check again - string yearStr = posixDateRepresentation.Substring(0, 4); - string monthStr = posixDateRepresentation.Substring(4, 2); - string dayStr = posixDateRepresentation.Substring(6, 2); - if (DateTimeOffset.TryParseExact($"{yearStr}/{monthStr}/{dayStr}", "yyyy/MM/dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out date)) - return date; - } - else if (posixDateRepresentation.Length == 15 || posixDateRepresentation.Length == 16) - { - // It might be yyyyMMdd + "T" + HHmmss + ["Z"], but check again - string yearStr = posixDateRepresentation.Substring(0, 4); - string monthStr = posixDateRepresentation.Substring(4, 2); - string dayStr = posixDateRepresentation.Substring(6, 2); - char timeIndicator = posixDateRepresentation[8]; - string hourStr = posixDateRepresentation.Substring(9, 2); - string minuteStr = posixDateRepresentation.Substring(11, 2); - string secondStr = posixDateRepresentation.Substring(13, 2); - if (timeIndicator != 'T') - throw new ArgumentException($"Time indicator is invalid."); - if (posixDateRepresentation.Length == 16 && posixDateRepresentation[15] != 'Z') - throw new ArgumentException($"UTC indicator is invalid."); - bool assumeUtc = posixDateRepresentation.Length == 16 && posixDateRepresentation[15] == 'Z'; - var utcOffset = assumeUtc ? DateTimeOffset.UtcNow.Offset : DateTimeOffset.Now.Offset; - string renderedOffset = SaveUtcOffset(utcOffset); - if (DateTimeOffset.TryParseExact($"{yearStr}/{monthStr}/{dayStr} {hourStr}:{minuteStr}:{secondStr} {renderedOffset}", "yyyy/MM/dd HH:mm:ss zzz", CultureInfo.InvariantCulture, assumeUtc ? DateTimeStyles.AssumeUniversal : DateTimeStyles.AssumeLocal, out date)) - return date; - } - throw new ArgumentException($"Can't parse date {posixDateRepresentation}"); - } - - internal static string SavePosixDate(DateTimeOffset posixDateRepresentation, bool dateOnly = false) - { - StringBuilder posixDateBuilder = new( - $"{posixDateRepresentation.Year:0000}" + - $"{posixDateRepresentation.Month:00}" + - $"{posixDateRepresentation.Day:00}" - ); - if (!dateOnly) - posixDateBuilder.Append( - $"T" + - $"{posixDateRepresentation.Hour:00}" + - $"{posixDateRepresentation.Minute:00}" + - $"{posixDateRepresentation.Second:00}" + - $"{(posixDateRepresentation.Offset == new TimeSpan() ? "Z" : "")}" - ); - return posixDateBuilder.ToString(); - } - - internal static TimeSpan ParseUtcOffset(string utcOffsetRepresentation) - { - // Check for sanity - if (utcOffsetRepresentation.Length != 3 && utcOffsetRepresentation.Length != 5 && utcOffsetRepresentation.Length != 7) - throw new ArgumentException($"UTC offset representation [{utcOffsetRepresentation}] is invalid."); - bool hasMinutes = utcOffsetRepresentation.Length >= 5; - bool hasSeconds = utcOffsetRepresentation.Length == 7; - - // Now, this representation might be a POSIX offset that follows the vCard specification, but check it, - // because it might be either <+/->HHmmss, <+/->HHmm, or <+/->HH. - string designatorStr = utcOffsetRepresentation.Substring(0, 1); - string hourStr = utcOffsetRepresentation.Substring(1, 2); - string minuteStr = hasMinutes ? utcOffsetRepresentation.Substring(3, 2) : ""; - string secondStr = hasSeconds ? utcOffsetRepresentation.Substring(5, 2) : ""; - if (designatorStr != "+" && designatorStr != "-") - throw new ArgumentException($"Designator {designatorStr} is invalid."); - if (hourStr == "00" && (!hasMinutes || (hasMinutes && minuteStr == "00")) && (!hasSeconds || (hasSeconds && secondStr == "00"))) - { - if (designatorStr == "-") - throw new ArgumentException($"Can't specify negative zero offset."); - return new(); - } - if (TimeSpan.TryParseExact($"{hourStr}:{(hasMinutes ? minuteStr : "00")}:{(hasSeconds ? secondStr : "00")}", "hh\\:mm\\:ss", CultureInfo.InvariantCulture, out TimeSpan offset)) - return designatorStr == "-" ? -offset : offset; - throw new ArgumentException($"Can't parse offset {utcOffsetRepresentation}"); - } - - internal static string SaveUtcOffset(TimeSpan utcOffsetRepresentation) - { - StringBuilder utcOffsetBuilder = new( - $"{(utcOffsetRepresentation < new TimeSpan() ? "-" : "+")}" + - $"{Math.Abs(utcOffsetRepresentation.Hours):00}" + - $"{Math.Abs(utcOffsetRepresentation.Minutes):00}" - ); - if (utcOffsetRepresentation.Seconds != 0) - utcOffsetBuilder.Append( - $"{Math.Abs(utcOffsetRepresentation.Seconds):00}" - ); - return utcOffsetBuilder.ToString(); - } - internal static string ProcessStringValue(string value, string values, StringsEnum stringType) { // Now, handle each type individually diff --git a/VisualCard/Parts/Card.cs b/VisualCard/Parts/Card.cs index 658bdf0f..e32650db 100644 --- a/VisualCard/Parts/Card.cs +++ b/VisualCard/Parts/Card.cs @@ -156,7 +156,7 @@ public BaseCardPartInfo[] GetPartsArray(Type partType, PartsArrayEnum key) public string GetString(StringsEnum key) { // Check for version support - if (!VcardParserTools.StringSupported(key, CardVersion)) + if (!VcardCommonTools.StringSupported(key, CardVersion)) return ""; // Get the fallback value @@ -201,7 +201,7 @@ public string SaveToString() // Now, locate the prefix and assemble the line string prefix = VcardParserTools.GetPrefixFromStringsEnum(stringEnum); cardBuilder.Append($"{prefix}{VcardConstants._argumentDelimiter}"); - cardBuilder.AppendLine($"{VcardParserTools.MakeStringBlock(stringValue, prefix.Length)}"); + cardBuilder.AppendLine($"{VcardCommonTools.MakeStringBlock(stringValue, prefix.Length)}"); } // Then, enumerate all the arrays @@ -228,7 +228,7 @@ public string SaveToString() string[] partArgumentsLines = partArguments.SplitNewLines(); partBuilder.Append($"{prefix}"); partBuilder.Append($"{partArguments}"); - partBuilder.Append($"{VcardParserTools.MakeStringBlock(partRepresentation, partArgumentsLines[partArgumentsLines.Length - 1].Length + prefix.Length)}"); + partBuilder.Append($"{VcardCommonTools.MakeStringBlock(partRepresentation, partArgumentsLines[partArgumentsLines.Length - 1].Length + prefix.Length)}"); cardBuilder.AppendLine($"{partBuilder}"); } } diff --git a/VisualCard/Parts/Implementations/AnniversaryInfo.cs b/VisualCard/Parts/Implementations/AnniversaryInfo.cs index c408737b..03c7c842 100644 --- a/VisualCard/Parts/Implementations/AnniversaryInfo.cs +++ b/VisualCard/Parts/Implementations/AnniversaryInfo.cs @@ -38,12 +38,12 @@ internal static BaseCardPartInfo FromStringVcardStatic(string value, string[] fi new AnniversaryInfo().FromStringVcardInternal(value, finalArgs, altId, elementTypes, valueType, cardVersion); internal override string ToStringVcardInternal(Version cardVersion) => - $"{VcardParserTools.SavePosixDate(Anniversary, true)}"; + $"{VcardCommonTools.SavePosixDate(Anniversary, true)}"; internal override BaseCardPartInfo FromStringVcardInternal(string value, string[] finalArgs, int altId, string[] elementTypes, string valueType, Version cardVersion) { // Populate the fields - DateTimeOffset anniversary = VcardParserTools.ParsePosixDate(value); + DateTimeOffset anniversary = VcardCommonTools.ParsePosixDate(value); // Add the fetched information AnniversaryInfo _time = new(-1, [], [], valueType, anniversary); diff --git a/VisualCard/Parts/Implementations/BirthDateInfo.cs b/VisualCard/Parts/Implementations/BirthDateInfo.cs index 669b764b..dad19ac0 100644 --- a/VisualCard/Parts/Implementations/BirthDateInfo.cs +++ b/VisualCard/Parts/Implementations/BirthDateInfo.cs @@ -38,12 +38,12 @@ internal static BaseCardPartInfo FromStringVcardStatic(string value, string[] fi new BirthDateInfo().FromStringVcardInternal(value, finalArgs, altId, elementTypes, valueType, cardVersion); internal override string ToStringVcardInternal(Version cardVersion) => - $"{VcardParserTools.SavePosixDate(BirthDate, true)}"; + $"{VcardCommonTools.SavePosixDate(BirthDate, true)}"; internal override BaseCardPartInfo FromStringVcardInternal(string value, string[] finalArgs, int altId, string[] elementTypes, string valueType, Version cardVersion) { // Populate field - DateTimeOffset bday = VcardParserTools.ParsePosixDate(value); + DateTimeOffset bday = VcardCommonTools.ParsePosixDate(value); // Add the fetched information BirthDateInfo _time = new(altId, finalArgs, elementTypes, valueType, bday); diff --git a/VisualCard/Parts/Implementations/KeyInfo.cs b/VisualCard/Parts/Implementations/KeyInfo.cs index dda2ecb6..56a46b4b 100644 --- a/VisualCard/Parts/Implementations/KeyInfo.cs +++ b/VisualCard/Parts/Implementations/KeyInfo.cs @@ -43,7 +43,7 @@ public class KeyInfo : BaseCardPartInfo, IEquatable /// Whether this key is a blob or not /// public bool IsBlob => - VcardParserTools.IsEncodingBlob(Arguments, KeyEncoded); + VcardCommonTools.IsEncodingBlob(Arguments, KeyEncoded); internal static BaseCardPartInfo FromStringVcardStatic(string value, string[] finalArgs, int altId, string[] elementTypes, string valueType, Version cardVersion) => new KeyInfo().FromStringVcardInternal(value, finalArgs, altId, elementTypes, valueType, cardVersion); @@ -67,8 +67,8 @@ internal override BaseCardPartInfo FromStringVcardInternal(string value, string[ else { // vCard 3.0 handles this in a different way - keyEncoding = VcardParserTools.GetValuesString(finalArgs, "b", VcardConstants._encodingArgumentSpecifier); - if (!VcardParserTools.IsEncodingBlob(finalArgs, value)) + keyEncoding = VcardCommonTools.GetValuesString(finalArgs, "b", VcardConstants._encodingArgumentSpecifier); + if (!VcardCommonTools.IsEncodingBlob(finalArgs, value)) { // Since we don't need embedded keys, we need to check a URL. if (!Uri.TryCreate(value, UriKind.Absolute, out Uri uri)) @@ -87,7 +87,7 @@ internal override BaseCardPartInfo FromStringVcardInternal(string value, string[ /// /// A stream that contains key data public Stream GetStream() => - VcardParserTools.GetBlobData(Arguments, KeyEncoded); + VcardCommonTools.GetBlobData(Arguments, KeyEncoded); /// public override bool Equals(object obj) => diff --git a/VisualCard/Parts/Implementations/LogoInfo.cs b/VisualCard/Parts/Implementations/LogoInfo.cs index 3d6035c8..d8ec28d1 100644 --- a/VisualCard/Parts/Implementations/LogoInfo.cs +++ b/VisualCard/Parts/Implementations/LogoInfo.cs @@ -43,7 +43,7 @@ public class LogoInfo : BaseCardPartInfo, IEquatable /// Whether this logo is a blob or not /// public bool IsBlob => - VcardParserTools.IsEncodingBlob(Arguments, LogoEncoded); + VcardCommonTools.IsEncodingBlob(Arguments, LogoEncoded); internal static BaseCardPartInfo FromStringVcardStatic(string value, string[] finalArgs, int altId, string[] elementTypes, string valueType, Version cardVersion) => new LogoInfo().FromStringVcardInternal(value, finalArgs, altId, elementTypes, valueType, cardVersion); @@ -67,8 +67,8 @@ internal override BaseCardPartInfo FromStringVcardInternal(string value, string[ else { // vCard 3.0 handles this in a different way - logoEncoding = VcardParserTools.GetValuesString(finalArgs, "b", VcardConstants._encodingArgumentSpecifier); - if (!VcardParserTools.IsEncodingBlob(finalArgs, value)) + logoEncoding = VcardCommonTools.GetValuesString(finalArgs, "b", VcardConstants._encodingArgumentSpecifier); + if (!VcardCommonTools.IsEncodingBlob(finalArgs, value)) { // Since we don't need embedded logos, we need to check a URL. if (!Uri.TryCreate(value, UriKind.Absolute, out Uri uri)) @@ -87,7 +87,7 @@ internal override BaseCardPartInfo FromStringVcardInternal(string value, string[ /// /// A stream that contains logo data public Stream GetStream() => - VcardParserTools.GetBlobData(Arguments, LogoEncoded); + VcardCommonTools.GetBlobData(Arguments, LogoEncoded); /// public override bool Equals(object obj) => diff --git a/VisualCard/Parts/Implementations/PhotoInfo.cs b/VisualCard/Parts/Implementations/PhotoInfo.cs index a06fd032..adfc588b 100644 --- a/VisualCard/Parts/Implementations/PhotoInfo.cs +++ b/VisualCard/Parts/Implementations/PhotoInfo.cs @@ -43,7 +43,7 @@ public class PhotoInfo : BaseCardPartInfo, IEquatable /// Whether this photo is a blob or not /// public bool IsBlob => - VcardParserTools.IsEncodingBlob(Arguments, PhotoEncoded); + VcardCommonTools.IsEncodingBlob(Arguments, PhotoEncoded); internal static BaseCardPartInfo FromStringVcardStatic(string value, string[] finalArgs, int altId, string[] elementTypes, string valueType, Version cardVersion) => new PhotoInfo().FromStringVcardInternal(value, finalArgs, altId, elementTypes, valueType, cardVersion); @@ -67,8 +67,8 @@ internal override BaseCardPartInfo FromStringVcardInternal(string value, string[ else { // vCard 3.0 handles this in a different way - photoEncoding = VcardParserTools.GetValuesString(finalArgs, "b", VcardConstants._encodingArgumentSpecifier); - if (!VcardParserTools.IsEncodingBlob(finalArgs, value)) + photoEncoding = VcardCommonTools.GetValuesString(finalArgs, "b", VcardConstants._encodingArgumentSpecifier); + if (!VcardCommonTools.IsEncodingBlob(finalArgs, value)) { // Since we don't need embedded photos, we need to check a URL. if (!Uri.TryCreate(value, UriKind.Absolute, out Uri uri)) @@ -87,7 +87,7 @@ internal override BaseCardPartInfo FromStringVcardInternal(string value, string[ /// /// A stream that contains image data public Stream GetStream() => - VcardParserTools.GetBlobData(Arguments, PhotoEncoded); + VcardCommonTools.GetBlobData(Arguments, PhotoEncoded); /// public override bool Equals(object obj) => diff --git a/VisualCard/Parts/Implementations/RevisionInfo.cs b/VisualCard/Parts/Implementations/RevisionInfo.cs index dc8f81ed..1558b8b1 100644 --- a/VisualCard/Parts/Implementations/RevisionInfo.cs +++ b/VisualCard/Parts/Implementations/RevisionInfo.cs @@ -38,7 +38,7 @@ internal static BaseCardPartInfo FromStringVcardStatic(string value, string[] fi new RevisionInfo().FromStringVcardInternal(value, finalArgs, altId, elementTypes, valueType, cardVersion); internal override string ToStringVcardInternal(Version cardVersion) => - $"{VcardParserTools.SavePosixDate(Revision)}"; + $"{VcardCommonTools.SavePosixDate(Revision)}"; internal override BaseCardPartInfo FromStringVcardInternal(string value, string[] finalArgs, int altId, string[] elementTypes, string valueType, Version cardVersion) { @@ -46,7 +46,7 @@ internal override BaseCardPartInfo FromStringVcardInternal(string value, string[ string revValue = value.Substring(VcardConstants._revSpecifier.Length + 1); // Populate the fields - DateTimeOffset rev = VcardParserTools.ParsePosixDate(revValue); + DateTimeOffset rev = VcardCommonTools.ParsePosixDate(revValue); // Add the fetched information RevisionInfo _time = new(altId, finalArgs, elementTypes, valueType, rev); diff --git a/VisualCard/Parts/Implementations/SoundInfo.cs b/VisualCard/Parts/Implementations/SoundInfo.cs index dddf7642..6532195e 100644 --- a/VisualCard/Parts/Implementations/SoundInfo.cs +++ b/VisualCard/Parts/Implementations/SoundInfo.cs @@ -43,7 +43,7 @@ public class SoundInfo : BaseCardPartInfo, IEquatable /// Whether this sound is a blob or not /// public bool IsBlob => - VcardParserTools.IsEncodingBlob(Arguments, SoundEncoded); + VcardCommonTools.IsEncodingBlob(Arguments, SoundEncoded); internal static BaseCardPartInfo FromStringVcardStatic(string value, string[] finalArgs, int altId, string[] elementTypes, string valueType, Version cardVersion) => new SoundInfo().FromStringVcardInternal(value, finalArgs, altId, elementTypes, valueType, cardVersion); @@ -67,8 +67,8 @@ internal override BaseCardPartInfo FromStringVcardInternal(string value, string[ else { // vCard 3.0 handles this in a different way - soundEncoding = VcardParserTools.GetValuesString(finalArgs, "b", VcardConstants._encodingArgumentSpecifier); - if (!VcardParserTools.IsEncodingBlob(finalArgs, value)) + soundEncoding = VcardCommonTools.GetValuesString(finalArgs, "b", VcardConstants._encodingArgumentSpecifier); + if (!VcardCommonTools.IsEncodingBlob(finalArgs, value)) { // Since we don't need embedded sounds, we need to check a URL. if (!Uri.TryCreate(value, UriKind.Absolute, out Uri uri)) @@ -87,7 +87,7 @@ internal override BaseCardPartInfo FromStringVcardInternal(string value, string[ /// /// A stream that contains sound data public Stream GetStream() => - VcardParserTools.GetBlobData(Arguments, SoundEncoded); + VcardCommonTools.GetBlobData(Arguments, SoundEncoded); /// public override bool Equals(object obj) =>