diff --git a/src/Id3.Net/Frames/String/CustomTextFrame.cs b/src/Id3.Net/Frames/String/CustomTextFrame.cs index ec5930a..5b193d8 100644 --- a/src/Id3.Net/Frames/String/CustomTextFrame.cs +++ b/src/Id3.Net/Frames/String/CustomTextFrame.cs @@ -31,6 +31,8 @@ public CustomTextFrame(string value) : base(value) { } + public string Description { get; set; } + public static implicit operator CustomTextFrame(string value) => new CustomTextFrame(value); } diff --git a/src/Id3.Net/Id3/v2/Id3v23Handler.Frames.cs b/src/Id3.Net/Id3/v2/Id3v23Handler.Frames.cs index f3f6df3..2fe8d55 100644 --- a/src/Id3.Net/Id3/v2/Id3v23Handler.Frames.cs +++ b/src/Id3.Net/Id3/v2/Id3v23Handler.Frames.cs @@ -26,6 +26,11 @@ namespace Id3.v2 { internal sealed partial class Id3V23Handler { + // from: https://id3.org/id3v2.3.0#Text_information_frames + //
+ // Text encoding $xx + // Information + private static TFrame DecodeText(byte[] data) where TFrame : TextFrameBase, new() { @@ -36,16 +41,13 @@ private static TFrame DecodeText(byte[] data) if (encodingByte == 0 || encodingByte == 1) { frame.EncodingType = (Id3TextEncoding) encodingByte; - Encoding encoding = TextEncodingHelper.GetEncoding(frame.EncodingType); - value = encoding.GetString(data, 1, data.Length - 1); - if (value.Length > 0 && frame.EncodingType == Id3TextEncoding.Unicode && - (value[0] == '\xFFFE' || value[0] == '\xFEFF')) - value = value.Remove(0, 1); + int currentPos = 1; + value = TextEncodingHelper.DecodeString(data, ref currentPos, frame.EncodingType); } else { frame.EncodingType = Id3TextEncoding.Iso8859_1; - Encoding encoding = TextEncodingHelper.GetEncoding(frame.EncodingType); - value = encoding.GetString(data, 0, data.Length); + int currentPos = 0; + value = TextEncodingHelper.DecodeString(data, ref currentPos, frame.EncodingType); } frame.TextValue = value; @@ -67,10 +69,54 @@ private static byte[] EncodeText(Id3Frame id3Frame) return data; } + + // from: https://id3.org/id3v2.3.0#User_defined_text_information_frame + //
+ // Text encoding $xx + // Description $00 (00) + // Value + + private static CustomTextFrame DecodeCustomText(byte[] data) + { + var frame = new CustomTextFrame { EncodingType = (Id3TextEncoding)data[0] }; + + int currentPos = 1; + frame.Description = TextEncodingHelper.DecodeString(data, ref currentPos, frame.EncodingType); + frame.TextValue = TextEncodingHelper.DecodeString(data, ref currentPos, frame.EncodingType); + + return frame; + } + + private static byte[] EncodeCustomText(Id3Frame id3Frame) + { + var frame = (CustomTextFrame)id3Frame; + + var bytes = new List { + (byte) frame.EncodingType + }; + + Encoding encoding = TextEncodingHelper.GetEncoding(frame.EncodingType); + bytes.AddRange(encoding.GetPreamble()); + if (!string.IsNullOrEmpty(frame.Description)) + bytes.AddRange(encoding.GetBytes(frame.Description)); + bytes.AddRange(TextEncodingHelper.GetTerminationBytes(frame.EncodingType)); + bytes.AddRange(encoding.GetPreamble()); + if (!string.IsNullOrEmpty(frame.TextValue)) + bytes.AddRange(encoding.GetBytes(frame.TextValue)); + + return bytes.ToArray(); + } + + + // from: https://id3.org/id3v2.3.0#URL_link_frames + //
+ // URL + private static TFrame DecodeUrlLink(byte[] data) where TFrame : UrlLinkFrame, new() { - var frame = new TFrame {Url = TextEncodingHelper.GetDefaultString(data, 0, data.Length)}; + int currentPos = 0; + var frame = new TFrame {Url = TextEncodingHelper.DecodeString(data, ref currentPos, Id3TextEncoding.Iso8859_1)}; return frame; } @@ -81,6 +127,14 @@ private static byte[] EncodeUrlLink(Id3Frame id3Frame) return frame.Url != null ? TextEncodingHelper.GetDefaultEncoding().GetBytes(frame.Url) : new byte[0]; } + + // from: https://id3.org/id3v2.3.0#Comments + //
+ // Text encoding $xx + // Language $xx xx xx + // Short content descrip. $00 (00) + // The actual text + private static Id3Frame DecodeComment(byte[] data) { var frame = new CommentFrame {EncodingType = (Id3TextEncoding) data[0]}; @@ -91,13 +145,9 @@ private static Id3Frame DecodeComment(byte[] data) else frame.Language = (Id3Language) Enum.Parse(typeof(Id3Language), language, true); - string[] splitStrings = TextEncodingHelper.GetSplitStrings(data, 4, data.Length - 4, frame.EncodingType); - if (splitStrings.Length > 1) - { - frame.Description = splitStrings[0]; - frame.Comment = splitStrings[1]; - } else if (splitStrings.Length == 1) - frame.Comment = splitStrings[0]; + int currentPos = 4; + frame.Description = TextEncodingHelper.DecodeString(data, ref currentPos, frame.EncodingType); + frame.Comment = TextEncodingHelper.DecodeString(data, ref currentPos, frame.EncodingType); return frame; } @@ -116,7 +166,7 @@ private static byte[] EncodeComment(Id3Frame id3Frame) bytes.AddRange(encoding.GetPreamble()); if (!string.IsNullOrEmpty(frame.Description)) bytes.AddRange(encoding.GetBytes(frame.Description)); - bytes.AddRange(TextEncodingHelper.GetSplitterBytes(frame.EncodingType)); + bytes.AddRange(TextEncodingHelper.GetTerminationBytes(frame.EncodingType)); bytes.AddRange(encoding.GetPreamble()); if (!string.IsNullOrEmpty(frame.Comment)) bytes.AddRange(encoding.GetBytes(frame.Comment)); @@ -124,22 +174,20 @@ private static byte[] EncodeComment(Id3Frame id3Frame) return bytes.ToArray(); } + + // from: https://id3.org/id3v2.3.0#User_defined_URL_link_frame + //
+ // Text encoding $xx + // Description $00 (00) + // URL + private static Id3Frame DecodeCustomUrlLink(byte[] data) { var frame = new CustomUrlLinkFrame {EncodingType = (Id3TextEncoding) data[0]}; - byte[][] splitBytes = ByteArrayHelper.SplitBySequence(data, 1, data.Length - 1, - TextEncodingHelper.GetSplitterBytes(frame.EncodingType)); - string url = null; - if (splitBytes.Length > 1) - { - frame.Description = - TextEncodingHelper.GetString(splitBytes[0], 0, splitBytes[0].Length, frame.EncodingType); - url = TextEncodingHelper.GetDefaultString(splitBytes[1], 0, splitBytes[1].Length); - } else if (splitBytes.Length == 1) - url = TextEncodingHelper.GetDefaultString(splitBytes[0], 0, splitBytes[0].Length); - - frame.Url = url; + int currentPos = 1; + frame.Description = TextEncodingHelper.DecodeString(data, ref currentPos, frame.EncodingType); + frame.Url = TextEncodingHelper.DecodeString(data, ref currentPos, Id3TextEncoding.Iso8859_1); return frame; } @@ -156,13 +204,21 @@ private static byte[] EncodeCustomUrlLink(Id3Frame id3Frame) bytes.AddRange(encoding.GetPreamble()); if (!string.IsNullOrEmpty(frame.Description)) bytes.AddRange(encoding.GetBytes(frame.Description)); - bytes.AddRange(TextEncodingHelper.GetSplitterBytes(frame.EncodingType)); + bytes.AddRange(TextEncodingHelper.GetTerminationBytes(frame.EncodingType)); if (frame.Url != null) bytes.AddRange(TextEncodingHelper.GetDefaultEncoding().GetBytes(frame.Url)); return bytes.ToArray(); } + + // from: https://id3.org/id3v2.3.0#Unsychronised_lyrics.2Ftext_transcription + //
+ // Text encoding $xx + // Language $xx xx xx + // Content descriptor $00 (00) + // Lyrics/text + private static Id3Frame DecodeLyrics(byte[] data) { var frame = new LyricsFrame {EncodingType = (Id3TextEncoding) data[0]}; @@ -173,48 +229,66 @@ private static Id3Frame DecodeLyrics(byte[] data) else frame.Language = (Id3Language) Enum.Parse(typeof(Id3Language), language, true); - string[] splitStrings = TextEncodingHelper.GetSplitStrings(data, 4, data.Length - 4, frame.EncodingType); - if (splitStrings.Length > 1) - { - frame.Description = splitStrings[0]; - frame.Lyrics = splitStrings[1]; - } else if (splitStrings.Length == 1) - frame.Lyrics = splitStrings[0]; + int currentPos = 4; + frame.Description = TextEncodingHelper.DecodeString(data, ref currentPos, frame.EncodingType); + frame.Lyrics = TextEncodingHelper.DecodeString(data, ref currentPos, frame.EncodingType); return frame; } private static byte[] EncodeLyrics(Id3Frame id3Frame) { - throw new NotImplementedException(); + var frame = (LyricsFrame)id3Frame; + + var bytes = new List { + (byte) frame.EncodingType + }; + + bytes.AddRange(TextEncodingHelper.GetDefaultEncoding().GetBytes(frame.Language.ToString())); + + Encoding encoding = TextEncodingHelper.GetEncoding(frame.EncodingType); + bytes.AddRange(encoding.GetPreamble()); + if (!string.IsNullOrEmpty(frame.Description)) + bytes.AddRange(encoding.GetBytes(frame.Description)); + bytes.AddRange(TextEncodingHelper.GetTerminationBytes(frame.EncodingType)); + bytes.AddRange(encoding.GetPreamble()); + if (!string.IsNullOrEmpty(frame.Lyrics)) + bytes.AddRange(encoding.GetBytes(frame.Lyrics)); + + return bytes.ToArray(); } + + // from: https://id3.org/id3v2.3.0#Attached_picture + //
+ // Text encoding $xx + // MIME type $00 + // Picture type $xx + // Description $00 (00) + // Picture data + private static Id3Frame DecodePicture(byte[] data) { var frame = new PictureFrame {EncodingType = (Id3TextEncoding) data[0]}; - byte[] mimeType = ByteArrayHelper.GetBytesUptoSequence(data, 1, new byte[] {0x00}); - if (mimeType == null) + int currentPos = 1; + frame.MimeType = TextEncodingHelper.DecodeString(data, ref currentPos, Id3TextEncoding.Iso8859_1); + if (frame.MimeType == null) { frame.MimeType = "image/"; return frame; } - frame.MimeType = TextEncodingHelper.GetDefaultString(mimeType, 0, mimeType.Length); - - int currentPos = mimeType.Length + 2; frame.PictureType = (PictureType) data[currentPos]; - currentPos++; - byte[] description = ByteArrayHelper.GetBytesUptoSequence(data, currentPos, - TextEncodingHelper.GetSplitterBytes(frame.EncodingType)); - if (description == null) - return frame; - frame.Description = TextEncodingHelper.GetString(description, 0, description.Length, frame.EncodingType); - currentPos += description.Length + TextEncodingHelper.GetSplitterBytes(frame.EncodingType).Length; - frame.PictureData = new byte[data.Length - currentPos]; - Array.Copy(data, currentPos, frame.PictureData, 0, frame.PictureData.Length); + frame.Description = TextEncodingHelper.DecodeString(data, ref currentPos, frame.EncodingType); + + if (currentPos < data.Length) + { + frame.PictureData = new byte[data.Length - currentPos]; + Array.Copy(data, currentPos, frame.PictureData, 0, frame.PictureData.Length); + } return frame; } @@ -239,7 +313,7 @@ private static byte[] EncodePicture(Id3Frame id3Frame) bytes.AddRange(descriptionEncoding.GetPreamble()); if (!string.IsNullOrEmpty(frame.Description)) bytes.AddRange(descriptionEncoding.GetBytes(frame.Description)); - bytes.AddRange(TextEncodingHelper.GetSplitterBytes(frame.EncodingType)); + bytes.AddRange(TextEncodingHelper.GetTerminationBytes(frame.EncodingType)); if (frame.PictureData != null && frame.PictureData.Length > 0) bytes.AddRange(frame.PictureData); @@ -247,15 +321,22 @@ private static byte[] EncodePicture(Id3Frame id3Frame) return bytes.ToArray(); } + + // from: https://id3.org/id3v2.3.0#Private_frame + //
+ // Owner identifier $00 + // The private data + private static Id3Frame DecodePrivate(byte[] data) { var frame = new PrivateFrame(); - byte[] splitterSequence = TextEncodingHelper.GetSplitterBytes(Id3TextEncoding.Iso8859_1); - byte[] ownerIdBytes = ByteArrayHelper.GetBytesUptoSequence(data, 0, splitterSequence); - frame.OwnerId = - TextEncodingHelper.GetString(ownerIdBytes, 0, ownerIdBytes.Length, Id3TextEncoding.Iso8859_1); - frame.Data = new byte[data.Length - ownerIdBytes.Length - splitterSequence.Length]; - Array.Copy(data, ownerIdBytes.Length + splitterSequence.Length, frame.Data, 0, frame.Data.Length); + + int currentPos = 0; + frame.OwnerId = TextEncodingHelper.DecodeString(data, ref currentPos, Id3TextEncoding.Iso8859_1); + + frame.Data = new byte[data.Length - currentPos]; + Array.Copy(data, currentPos, frame.Data, 0, frame.Data.Length); + return frame; } @@ -265,7 +346,7 @@ private static byte[] EncodePrivate(Id3Frame id3Frame) var bytes = new List(); bytes.AddRange(TextEncodingHelper.GetEncoding(Id3TextEncoding.Iso8859_1).GetBytes(frame.OwnerId)); - bytes.AddRange(TextEncodingHelper.GetSplitterBytes(Id3TextEncoding.Iso8859_1)); + bytes.AddRange(TextEncodingHelper.GetTerminationBytes(Id3TextEncoding.Iso8859_1)); bytes.AddRange(frame.Data ?? new byte[0]); return bytes.ToArray(); } diff --git a/src/Id3.Net/Id3/v2/Id3v23Handler.cs b/src/Id3.Net/Id3/v2/Id3v23Handler.cs index 40ecc24..1bec44e 100644 --- a/src/Id3.Net/Id3/v2/Id3v23Handler.cs +++ b/src/Id3.Net/Id3/v2/Id3v23Handler.cs @@ -195,7 +195,7 @@ protected override void BuildFrameHandlers(FrameHandlers mappings) mappings.Add("TIT1", EncodeText, DecodeText); mappings.Add("TCOP", EncodeText, DecodeText); mappings.Add("WCOP", EncodeUrlLink, DecodeUrlLink); - mappings.Add("TXXX", EncodeText, DecodeText); + mappings.Add("TXXX", EncodeCustomText, DecodeCustomText); mappings.Add("WXXX", EncodeCustomUrlLink, DecodeCustomUrlLink); mappings.Add("TENC", EncodeText, DecodeText); mappings.Add("TSSE", EncodeText, DecodeText); diff --git a/src/Id3.Net/Utils/ByteArrayHelper.cs b/src/Id3.Net/Utils/ByteArrayHelper.cs index 53aa43d..ba56fd5 100644 --- a/src/Id3.Net/Utils/ByteArrayHelper.cs +++ b/src/Id3.Net/Utils/ByteArrayHelper.cs @@ -40,21 +40,6 @@ internal static bool AreEqual(byte[] bytes1, byte[] bytes2) return true; } - internal static byte[] GetBytesUptoSequence(byte[] bytes, int start, byte[] sequence) - { - int sequenceIndex = LocateSequence(bytes, start, bytes.Length - start + 1, sequence); - if (sequenceIndex == -1) - return null; - var result = new byte[sequenceIndex - start]; - Array.Copy(bytes, start, result, 0, result.Length); - return result; - } - - internal static int LocateSequence(byte[] bytes, params byte[] sequence) - { - return LocateSequence(bytes, 0, bytes.Length, sequence); - } - internal static int LocateSequence(byte[] bytes, int start, int count, byte[] sequence) { int sequenceIndex = 0; @@ -72,66 +57,16 @@ internal static int LocateSequence(byte[] bytes, int start, int count, byte[] se return -1; } - internal static int[] LocateSequences(byte[] bytes, params byte[] sequence) + internal static bool CompareSequence(byte[] bytes, int start, byte[] sequence) { - return LocateSequences(bytes, 0, bytes.Length, sequence); - } - - internal static int[] LocateSequences(byte[] bytes, int start, int count, byte[] sequence) - { - var locations = new List(); - - int sequenceLocation = LocateSequence(bytes, start, count, sequence); - while (sequenceLocation >= 0) - { - locations.Add(sequenceLocation); - count -= sequenceLocation - start + 1; - start = sequenceLocation + sequence.Length; - sequenceLocation = LocateSequence(bytes, start, count, sequence); - } - - return locations.ToArray(); - } - - internal static byte[][] SplitBySequence(byte[] bytes, params byte[] sequence) - { - return SplitBySequence(bytes, 0, bytes.Length, sequence); - } - - internal static byte[][] SplitBySequence(byte[] bytes, int start, int count, byte[] sequence) - { - if (start + count > bytes.Length) - count = bytes.Length - start; - - int[] locations = LocateSequences(bytes, start, count, sequence); - if (locations.Length == 0) - return new[] { bytes }; - - var results = new List(locations.Length + 1); - for (var locationIdx = 0; locationIdx < locations.Length; locationIdx++) - { - int startIndex = locationIdx > 0 ? locations[locationIdx - 1] + sequence.Length : start; - int endIndex = locations[locationIdx] - 1; - if (endIndex < startIndex) - results.Add(new byte[0]); - else - { - var splitBytes = new byte[endIndex - startIndex + 1]; - Array.Copy(bytes, startIndex, splitBytes, 0, splitBytes.Length); - results.Add(splitBytes); - } - } - - if (locations[locations.Length - 1] + sequence.Length > start + count - 1) - results.Add(new byte[0]); - else + if ((start + sequence.Length) > bytes.Length) + return false; + for (int i = 0; i < sequence.Length; i++) { - var splitBytes = new byte[start + count - locations[locations.Length - 1] - sequence.Length]; - Array.Copy(bytes, locations[locations.Length - 1] + sequence.Length, splitBytes, 0, splitBytes.Length); - results.Add(splitBytes); + if (bytes[start + i] != sequence[i]) + return false; } - - return results.ToArray(); + return true; } } } \ No newline at end of file diff --git a/src/Id3.Net/Utils/TextEncodingHelper.cs b/src/Id3.Net/Utils/TextEncodingHelper.cs index 5d3096f..129f286 100644 --- a/src/Id3.Net/Utils/TextEncodingHelper.cs +++ b/src/Id3.Net/Utils/TextEncodingHelper.cs @@ -20,6 +20,21 @@ limitations under the License. using System.Diagnostics; using System.Text; +// from: https://id3.org/id3v2.3.0#ID3v2_frame_overview +// If nothing else is said a string is represented as ISO-8859-1 characters in the range $20 - $FF. +// Such strings are represented as , or if newlines are allowed, in the frame descriptions. +// All Unicode strings use 16-bit unicode 2.0 (ISO/IEC 10646-1:1993, UCS-2). +// Unicode strings must begin with the Unicode BOM($FF FE or $FE FF) to identify the byte order. +// +// All numeric strings and URLs are always encoded as ISO-8859-1. +// Terminated strings are terminated with $00 if encoded with ISO-8859-1 and $00 00 if encoded as unicode. +// If nothing else is said newline character is forbidden. +// In ISO-8859-1 a new line is represented, when allowed, with $0A only. +// Frames that allow different types of text encoding have a text encoding description byte directly after the frame size. +// If ISO-8859-1 is used this byte should be $00, if Unicode is used it should be $01. +// Strings dependent on encoding is represented as , or if newlines are allowed. +// Any empty Unicode strings which are NULL-terminated may have the Unicode BOM followed by a Unicode NULL ($FF FE 00 00 or $FE FF 00 00). + namespace Id3 { internal static class TextEncodingHelper @@ -27,7 +42,7 @@ internal static class TextEncodingHelper //Gets the default encoding, which is ISO-8859-1 internal static Encoding GetDefaultEncoding() { - return Encoding.GetEncoding("iso-8859-1"); + return GetEncoding(Id3TextEncoding.Iso8859_1); } internal static string GetDefaultString(byte[] bytes, int start, int count) @@ -45,39 +60,80 @@ internal static Encoding GetEncoding(Id3TextEncoding encodingType) return null; } - internal static string GetString(byte[] bytes, int start, int count, Id3TextEncoding encodingType) + // decode a string according to the encoding until a termination bytes $00 ($00) is found or end of buffer is reached. + // respect the byte count according the encoding so the correct termination bytes are recognized. + internal static string DecodeString(byte[] bytes, ref int currentPos, Id3TextEncoding encodingType) { - Encoding encoding = GetEncoding(encodingType); - string str = encoding.GetString(bytes, start, count); + int startIndex = currentPos; + int endIndex = currentPos; + int charBytes = GetBytesPerCharacter(encodingType); + if (charBytes < 1) + return null; // invalid encodingType, cannot process + + byte[] terminationBytes = GetTerminationBytes(encodingType); + while (endIndex < bytes.Length && !ByteArrayHelper.CompareSequence(bytes, endIndex, terminationBytes)) + endIndex += charBytes; + + //if (endIndex >= bytes.Length) + // return null; // termination sequence not found within remaining bytes + + // endIndex points to the first termination byte (or behind the last byte) + currentPos = endIndex + terminationBytes.Length; + int byteCount = endIndex - startIndex; + if (byteCount <= 0) + return null; // empty string, return as no-string + + Encoding encoding = GetEncoding(encodingType); + if (encodingType == Id3TextEncoding.Iso8859_1) + { + return encoding.GetString(bytes, startIndex, byteCount); + } if (encodingType == Id3TextEncoding.Unicode) { - if (str[0] == '\xFFFE' || str[0] == '\xFEFF') - str = str.Remove(0, 1); + string result; + // test BOM for little-endian-order + Debug.Assert(encoding == Encoding.Unicode, "Wrong encoding for little-endian-order"); + if (TryDecodeStringWithBom(bytes, startIndex, byteCount, encoding, out result)) + return result; + // test BOM for big-endian-order + if (TryDecodeStringWithBom(bytes, startIndex, byteCount, Encoding.BigEndianUnicode, out result)) + return result; + Debug.Assert(false, "Could not detect BOM for unicode decoding"); + return null; } - - return str; + Debug.Assert(false, "Invalid encoding type specified"); + return null; } - internal static string[] GetSplitStrings(byte[] bytes, int start, int count, Id3TextEncoding encodingType) + private static bool TryDecodeStringWithBom(byte[] bytes, int startIndex, int byteCount, Encoding encoding, out string result) { - byte[][] splitBytes = ByteArrayHelper.SplitBySequence(bytes, start, count, GetSplitterBytes(encodingType)); - if (splitBytes.Length == 0) - return new[] { string.Empty }; - - var strings = new string[splitBytes.Length]; - for (int splitByteIdx = 0; splitByteIdx < splitBytes.Length; splitByteIdx++) - strings[splitByteIdx] = GetString(splitBytes[splitByteIdx], 0, splitBytes[splitByteIdx].Length, encodingType); - return strings; + result = null; + byte[] preamble = encoding.GetPreamble(); + if (preamble.Length == 0 || ByteArrayHelper.CompareSequence(bytes, startIndex, preamble)) + { + // skip the preamble + startIndex += preamble.Length; + byteCount -= preamble.Length; + if (byteCount <= 0) + return true; + result = encoding.GetString(bytes, startIndex, byteCount); + return true; + } + return false; } - internal static byte[] GetSplitterBytes(Id3TextEncoding encodingType) + internal static byte[] GetTerminationBytes(Id3TextEncoding encodingType) { - var splitterBytes = new byte[GetSplitterLength(encodingType)]; - return splitterBytes; + if (encodingType == Id3TextEncoding.Iso8859_1) + return terminationBytesIso8859; + if (encodingType == Id3TextEncoding.Unicode) + return terminationBytesUnicode; + Debug.Assert(false, "Invalid encoding type specified"); + return null; } - private static int GetSplitterLength(Id3TextEncoding encodingType) + private static int GetBytesPerCharacter(Id3TextEncoding encodingType) { if (encodingType == Id3TextEncoding.Iso8859_1) return 1; @@ -86,5 +142,8 @@ private static int GetSplitterLength(Id3TextEncoding encodingType) Debug.Assert(false, "Invalid encoding type specified"); return -1; } + + private static readonly byte[] terminationBytesIso8859 = new byte[] { 0 }; + private static readonly byte[] terminationBytesUnicode = new byte[] { 0, 0 }; } } \ No newline at end of file