diff --git a/.vscode/launch.json b/.vscode/launch.json index e0a6b34..c2439bd 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceFolder}/test/bin/Debug/net6.0/HL7Test.dll", + "program": "${workspaceFolder}/test/bin/Debug/net8.0/HL7Test.dll", "args": [], "cwd": "${workspaceFolder}/test", "console": "internalConsole", diff --git a/src/HL7-V2.csproj b/src/HL7-V2.csproj index 53037f9..4f65d33 100755 --- a/src/HL7-V2.csproj +++ b/src/HL7-V2.csproj @@ -2,11 +2,11 @@ Lightweight HL7 V2 library (c) Efferent Health, LLC - 3.0.2 + 3.0.3 netstandard2.0;net8.0 HL7-V2 HL7-V2 - hl7;hl7-v2;dotnet + hl7;hl7-v2;hl7-parser https://github.com/Efferent-Health/HL7-V2 false git diff --git a/src/Encoding.cs b/src/HL7Encoding.cs similarity index 91% rename from src/Encoding.cs rename to src/HL7Encoding.cs index 438fd94..8ac8121 100644 --- a/src/Encoding.cs +++ b/src/HL7Encoding.cs @@ -233,23 +233,36 @@ public string Decode(string encodedValue) result.Append("
"); break; default: - if (seq.StartsWith("X", StringComparison.Ordinal)) - { - byte[] bytes = Enumerable.Range(0, seq.Length - 1) - .Where(x => x % 2 == 0) - .Select(x => Convert.ToByte(seq.Substring(x + 1, 2), 16)) - .ToArray(); - result.Append(Encoding.UTF8.GetString(bytes)); - } + if (seq[0]=='X') + result.Append(DecodeHexString(seq.Substring(1))); else - { result.Append(seq); - } break; } } return result.ToString(); } + + public static string DecodeHexString(string hex) + { + int numberChars = hex.Length; + byte[] bytes = new byte[numberChars / 2]; + + for (int i = 0; i < numberChars; i += 2) + bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); + + string str; + + if (bytes.Length == 1) + // str = Encoding.ASCII.GetString(bytes); + str = char.ConvertFromUtf32(bytes[0]); + else if (bytes.Length == 2 && bytes[0] == 0) + str = char.ConvertFromUtf32(bytes[1]); + else + str = Encoding.UTF8.GetString(bytes); + + return str; + } } } diff --git a/src/Message.cs b/src/Message.cs index 4779d71..0a71063 100644 --- a/src/Message.cs +++ b/src/Message.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -46,6 +47,8 @@ public override bool Equals(object obj) var arr1 = this.HL7Message.Split(this.Encoding.SegmentDelimiter.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); var arr2 = (obj as string).Split(this.Encoding.SegmentDelimiter.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); + DecodeHexaSequences(arr1); + return arr1.SequenceEqual(arr2); } @@ -976,5 +979,32 @@ private static bool validateValueFormat(string[] allComponents) return isValid; } + + /// + /// Decodes hexadecimal escape sequences from all message lines for comparison purposes + /// + /// Array of message lines + private void DecodeHexaSequences(string[] message) + { + var esc = "\\x" + ((int)this.Encoding.EscapeCharacter).ToString("X2", CultureInfo.InvariantCulture); + var regex = new Regex(esc + "X([0-9A-Fa-f]*)" + esc); + + for (int i=0; i + { + string hexValue = match.Groups[1].Value; + + // Does not decode CR or LF + if (hexValue != "0D" && hexValue != "0A") + return HL7Encoding.DecodeHexString(hexValue); + else + return match.Value; + }); + } + } } } diff --git a/test/HL7test.csproj b/test/HL7test.csproj index 8eb3188..87ca40b 100644 --- a/test/HL7test.csproj +++ b/test/HL7test.csproj @@ -1,8 +1,8 @@ (c) Efferent Health, LLC - 3.0.2 - net7.0 + 3.0.3 + net8.0 HL7Test HL7Test exe diff --git a/test/Program.cs b/test/Program.cs index 79c4874..d21bcc3 100644 --- a/test/Program.cs +++ b/test/Program.cs @@ -3,8 +3,6 @@ using System.Reflection; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Efferent.HL7.V2; - namespace Efferent.HL7.V2.Test { [TestClass] @@ -16,7 +14,7 @@ public class HL7Test public static void Main(string[] args) { // var test = new HL7Test(); - // test.DecodedValue1(); + // test.ParseTest1(); // test.AddRepeatingField(); // test.GenerateAckShortSeparatorListTest(); // test.CustomDelimiterTest(); @@ -45,6 +43,7 @@ public void ParseTest1() var message = new Message(this.HL7_ORM); var isParsed = message.ParseMessage(); + Assert.IsTrue(isParsed); } @@ -1006,7 +1005,7 @@ public void ParseBrokenCharMessage() Assert.IsTrue(isParsed); } -[TestMethod] + [TestMethod] public void BypassValidationParseMessage_ShouldReturnTrue() { string sampleMessage = @"MSH|^~\&|SCA|SCA|LIS|LIS|202107300000||ORU^R01||P|2.4||||||| @@ -1030,5 +1029,20 @@ public void BypassValidationParseMessage_ShouldReturnTrue() Assert.Fail("Unexpected exception", ex); } } + + [TestMethod] + public void SpecialCharacter() + { + string sampleMessage = @"MSH|^~\&|HELIOS|DEDALUS|||20240609213244||ADT^A01|HL7Gtw018FFE7D23AC00|P|2.5|||AL|AL|D|8859/1 +EVN|A01|||RO||20240609213200 +PID|1||5928948^^^X1V1_MPI^PI~1053251221^^^HELIOS^ANT~757HA514^^^SS^SS~WLMHLP81R56Z209U^^^NNITA^NNITA||ANONYMIZED ANONYMIZED^ANONYMIZED ANONYMIZED^^^^^^^^^^^^3||19811016|F|||V. ANTONIO BAZZINI 9&V. ANTONIO BAZZINI&9^^ANONYMIZED^^20125^^H^^015146~V. ANTONIO ANONYMIZED 9&V. ANTONIO BAZZINI&9^^ANONYMIZED^^12345^^L^^015146^030~^^SRI LANKA^^^^BDL^^999311||^PRN^PH^^^^^^^^^3279945913|||2||ANONYMIZED^MEF^NNITA|757HA514|||||||^^311^SRI LANKA (gi\X00E0\ CEYLON)||||N +PV1|1|I|XOSTPIO^^^ICHPIO^^^^^ANONYMIZED|4|P2024126713||ANONYMIZED^ANONYMIZED^TOMMASO||||1HB^602^D02|||3|||ANONYMIZED^ANONYMIZED^ANONYMIZED||G2024005887^^^PRZ^VN|1||||||||||||||||||||||||20240609213200"; + + var message = new Message(sampleMessage); + + var isParsed = message.ParseMessage(); + + Assert.IsTrue(isParsed); + } } }