From e67a9522d24d4b58ab9cb47b815369f1e4914999 Mon Sep 17 00:00:00 2001 From: Aptivi Date: Tue, 1 Oct 2024 17:29:21 +0300 Subject: [PATCH] imp - Improved support for GEO in calendars --- We've improved parsing the GEO values. --- Type: imp Breaking: False Doc Required: False Backport Required: False Part: 1/1 --- .../Parsers/VCalendarParser.cs | 2 +- .../Parts/Implementations/GeoInfo.cs | 4 +- VisualCard.ShowCalendars/TestFiles/vevent.vcs | 1 + .../TestFiles/vevent1.vcs | 1 + VisualCard/Parsers/VcardParserTools.cs | 153 +++++++++--------- 5 files changed, 84 insertions(+), 77 deletions(-) diff --git a/VisualCard.Calendar/Parsers/VCalendarParser.cs b/VisualCard.Calendar/Parsers/VCalendarParser.cs index 70dea56e..a504613a 100644 --- a/VisualCard.Calendar/Parsers/VCalendarParser.cs +++ b/VisualCard.Calendar/Parsers/VCalendarParser.cs @@ -169,7 +169,7 @@ public Parts.Calendar Parse() // Handle the part type Type calendarType = subPart is not null ? subPart.GetType() : calendar.GetType(); string valueType = VcardCommonTools.GetFirstValue(splitArgs, defaultValueType, VCalendarConstants._valueArgumentSpecifier); - string finalValue = VcardParserTools.ProcessStringValue(value, valueType); + string finalValue = VcardParserTools.ProcessStringValue(value, valueType, calendarVersion.Major == 1 ? ';' : ','); switch (type) { case PartType.Strings: diff --git a/VisualCard.Calendar/Parts/Implementations/GeoInfo.cs b/VisualCard.Calendar/Parts/Implementations/GeoInfo.cs index b9510937..c751a117 100644 --- a/VisualCard.Calendar/Parts/Implementations/GeoInfo.cs +++ b/VisualCard.Calendar/Parts/Implementations/GeoInfo.cs @@ -42,12 +42,12 @@ internal static BaseCalendarPartInfo FromStringVcalendarStatic(string value, str new GeoInfo().FromStringVcalendarInternal(value, finalArgs, elementTypes, valueType, calendarVersion); internal override string ToStringVcalendarInternal(Version calendarVersion) => - $"{Latitude}{(calendarVersion.Major == 1 ? ';' : ',')}{Longitude}"; + $"{Latitude}{(calendarVersion.Major == 1 ? ',' : ';')}{Longitude}"; internal override BaseCalendarPartInfo FromStringVcalendarInternal(string value, string[] finalArgs, string[] elementTypes, string valueType, Version calendarVersion) { // Get the value - string[] _geoSplit = value.Split(calendarVersion.Major == 1 ? ';' : ','); + string[] _geoSplit = value.Split(calendarVersion.Major == 1 ? ',' : ';'); if (_geoSplit.Length != 2) throw new ArgumentException($"When splitting geography, the split value is {_geoSplit.Length} instead of 2."); if (!double.TryParse(_geoSplit[0], out double lat)) diff --git a/VisualCard.ShowCalendars/TestFiles/vevent.vcs b/VisualCard.ShowCalendars/TestFiles/vevent.vcs index 853ec74e..ae632aa2 100644 --- a/VisualCard.ShowCalendars/TestFiles/vevent.vcs +++ b/VisualCard.ShowCalendars/TestFiles/vevent.vcs @@ -16,5 +16,6 @@ DESCRIPTION:Networld+Interop Conference Atlanta\, Georgia POPULAR:True X-TRENDING:True +GEO:37.24;-17.87 END:VEVENT END:VCALENDAR diff --git a/VisualCard.ShowCalendars/TestFiles/vevent1.vcs b/VisualCard.ShowCalendars/TestFiles/vevent1.vcs index 073e4946..34de111c 100644 --- a/VisualCard.ShowCalendars/TestFiles/vevent1.vcs +++ b/VisualCard.ShowCalendars/TestFiles/vevent1.vcs @@ -9,6 +9,7 @@ DTEND:19960401T083000Z SUMMARY:Steve's Proposal Review DESCRIPTION:Steve and John to review newest proposal material CLASS:PRIVATE +GEO:37.24,-17.87 END:VEVENT BEGIN:VTODO SUMMARY:John to pay for lunch diff --git a/VisualCard/Parsers/VcardParserTools.cs b/VisualCard/Parsers/VcardParserTools.cs index 847a21bf..ad4816ca 100644 --- a/VisualCard/Parsers/VcardParserTools.cs +++ b/VisualCard/Parsers/VcardParserTools.cs @@ -252,85 +252,90 @@ internal static (PartType type, object enumeration, Type? enumType, Func (PartType.PartsArray, PartsArrayEnum.IanaNames, typeof(ExtraInfo), ExtraInfo.FromStringVcardStatic, "", "", "", []), }; - internal static string ProcessStringValue(string value, string valueType) + internal static string ProcessStringValue(string value, string valueType, char split = ';') { // Now, handle each type individually string finalValue; finalValue = Regex.Unescape(value); - switch (valueType.ToUpper()) + foreach (string finalValuePart in finalValue.Split(split)) { - case "URI": - case "URL": - // Check the URI - if (!Uri.TryCreate(finalValue, UriKind.Absolute, out Uri uri)) - throw new InvalidDataException($"URL {finalValue} is invalid"); - finalValue = uri is not null ? uri.ToString() : finalValue; - break; - case "UTC-OFFSET": - // Check the UTC offset - VcardCommonTools.ParseUtcOffset(finalValue); - break; - case "DATE": - // Check the date - if (!VcardCommonTools.TryParsePosixDate(finalValue, out _)) - throw new InvalidDataException($"Date {finalValue} is invalid"); - break; - case "TIME": - // Check the time - if (!VcardCommonTools.TryParsePosixTime(finalValue, out _)) - throw new InvalidDataException($"Time {finalValue} is invalid"); - break; - case "DATE-TIME": - // Check the date and time - if (!VcardCommonTools.TryParsePosixDateTime(finalValue, out _)) - throw new InvalidDataException($"Date and time {finalValue} is invalid"); - break; - case "DATE-AND-OR-TIME": - // Check the date and/or time - if (!VcardCommonTools.TryParsePosixDateTime(finalValue, out _) && - !VcardCommonTools.TryParsePosixTime(finalValue, out _)) - throw new InvalidDataException($"Date and/or time {finalValue} is invalid"); - break; - case "TIMESTAMP": - // Check the timestamp - if (!VcardCommonTools.TryParsePosixTimestamp(finalValue, out _)) - throw new InvalidDataException($"Timestamp {finalValue} is invalid"); - break; - case "BOOLEAN": - // Check the boolean - if (!finalValue.Equals("true", StringComparison.OrdinalIgnoreCase) && - !finalValue.Equals("false", StringComparison.OrdinalIgnoreCase)) - throw new InvalidDataException($"Boolean {finalValue} is invalid"); - break; - case "INTEGER": - // Check the integer - if (!int.TryParse(finalValue, out _)) - throw new InvalidDataException($"Integer {finalValue} is invalid"); - break; - case "FLOAT": - // Check the float - if (!double.TryParse(finalValue, out _)) - throw new InvalidDataException($"Float {finalValue} is invalid"); - break; - case "DURATION": - // Check the duration - VcardCommonTools.GetDurationSpan(finalValue); - break; - case "PERIOD": - // Check the period - VcardCommonTools.GetTimePeriod(finalValue); - break; - case "RECUR": - // Check the recursion rules - try - { - RecurrenceParser.ParseRuleV1(finalValue); - } - catch - { - RecurrenceParser.ParseRuleV2(finalValue); - } - break; + switch (valueType.ToUpper()) + { + case "URI": + case "URL": + // Check the URI + if (!Uri.TryCreate(finalValue, UriKind.Absolute, out Uri uri)) + throw new InvalidDataException($"URL {finalValue} is invalid"); + finalValue = uri is not null ? uri.ToString() : finalValue; + break; + case "UTC-OFFSET": + // Check the UTC offset + VcardCommonTools.ParseUtcOffset(finalValue); + break; + case "DATE": + // Check the date + if (!VcardCommonTools.TryParsePosixDate(finalValue, out _)) + throw new InvalidDataException($"Date {finalValue} is invalid"); + break; + case "TIME": + // Check the time + if (!VcardCommonTools.TryParsePosixTime(finalValue, out _)) + throw new InvalidDataException($"Time {finalValue} is invalid"); + break; + case "DATE-TIME": + // Check the date and time + if (!VcardCommonTools.TryParsePosixDateTime(finalValue, out _)) + throw new InvalidDataException($"Date and time {finalValue} is invalid"); + break; + case "DATE-AND-OR-TIME": + // Check the date and/or time + if (!VcardCommonTools.TryParsePosixDateTime(finalValue, out _) && + !VcardCommonTools.TryParsePosixTime(finalValue, out _)) + throw new InvalidDataException($"Date and/or time {finalValue} is invalid"); + break; + case "TIMESTAMP": + // Check the timestamp + if (!VcardCommonTools.TryParsePosixTimestamp(finalValue, out _)) + throw new InvalidDataException($"Timestamp {finalValue} is invalid"); + break; + case "BOOLEAN": + // Check the boolean + if (!finalValue.Equals("true", StringComparison.OrdinalIgnoreCase) && + !finalValue.Equals("false", StringComparison.OrdinalIgnoreCase)) + throw new InvalidDataException($"Boolean {finalValue} is invalid"); + break; + case "INTEGER": + // Check the integer + if (!int.TryParse(finalValue, out _)) + throw new InvalidDataException($"Integer {finalValue} is invalid"); + break; + case "FLOAT": + // Check the float + string[] floatParts = finalValuePart.Split(split == ';' ? ',' : ';'); + foreach (var floatPart in floatParts) + if (!double.TryParse(floatPart, out _)) + throw new InvalidDataException($"Float {floatPart} in {finalValue} is invalid"); + break; + case "DURATION": + // Check the duration + VcardCommonTools.GetDurationSpan(finalValue); + break; + case "PERIOD": + // Check the period + VcardCommonTools.GetTimePeriod(finalValue); + break; + case "RECUR": + // Check the recursion rules + try + { + RecurrenceParser.ParseRuleV1(finalValue); + } + catch + { + RecurrenceParser.ParseRuleV2(finalValue); + } + break; + } } // Return the result