using MultiTerm.Core.Types; using System.Text; namespace MultiTerm.Core.Model; public class MultiFormatString { public List> FormatValuePairs { get; private set; } = new(); public void Add(FormatType format, string value) { // check if value is valid, if yes add to FormatValuePairs if (ValidateValue(format, value)) { this.FormatValuePairs.Add(Tuple.Create(format, value)); } } public void Remove(int amount) { // guard amount <= 0 if (amount <= 0) throw new ArgumentException($"{nameof(amount)} cannot be <= 0"); // limit amount to maximum int listCount = this.FormatValuePairs.Count; if (amount > listCount) { amount = listCount; } // remove range this.FormatValuePairs.RemoveRange( (listCount - amount) , amount); } // TODO Setup Unit Tests public override string ToString() { StringBuilder stringBuilder = new(); string hexConversionCharacters = String.Empty, binaryConversionCharacters = String.Empty; // parameter == null will force ending void finalizeHexConversion(Tuple? formatValuePair) { // hex conversion ongoing? if (String.IsNullOrEmpty(hexConversionCharacters) == false) { // ending conversion or reached limit of characters? if (formatValuePair == null || formatValuePair.Item1 != FormatType.Hexadecimal || hexConversionCharacters.Count() == 4) { // finalize conversion stringBuilder.Append(FromHexString(hexConversionCharacters)); // reset ongoing conversion hexConversionCharacters = String.Empty; } } } // parameter == null will force ending void finalizeBinaryConversion(Tuple? formatValuePair) { // binary conversion ongoing? if (String.IsNullOrEmpty(binaryConversionCharacters) == false) { // ending conversion or reached limit of characters? if (formatValuePair == null || formatValuePair.Item1 != FormatType.Binary || binaryConversionCharacters.Count() == 16) { // finalize conversion stringBuilder.Append(FromBinaryString(binaryConversionCharacters)); // reset ongoing conversion binaryConversionCharacters = String.Empty; } } } foreach (var formatValuePair in this.FormatValuePairs) { finalizeHexConversion(formatValuePair); finalizeBinaryConversion(formatValuePair); switch (formatValuePair.Item1) // switch by format { case FormatType.Character: stringBuilder.Append(formatValuePair.Item2); break; case FormatType.Hexadecimal: hexConversionCharacters += formatValuePair.Item2; break; case FormatType.Binary: binaryConversionCharacters += formatValuePair.Item2; break; default: throw new NotImplementedException($"'{nameof(ToString)}()' does not implement conversion for format {formatValuePair.Item1}"); } } finalizeHexConversion(null); finalizeBinaryConversion(null); return stringBuilder.ToString(); } public static bool ValidateValue(FormatType format, string value) { // invalid if more than one character if(value.Count() > 1) { return false; } // extract character var character = value.First(); switch (format) { case FormatType.Character: return true; case FormatType.Hexadecimal: if (character >= '0' && character <= '9' || character >= 'A' && character <= 'F' || character >= 'a' && character <= 'f') { return true; } else { return false; }; case FormatType.Binary: if (character == '0' || character == '1') { return true; } else { return false; }; default: throw new NotImplementedException($"'{nameof(ValidateValue)}()' does not implement validation for format {format}"); } } // from: https://stackoverflow.com/questions/724862/converting-from-hex-to-string // test with: returns: "Hello world" for "48656C6C6F20776F726C64" // see https://www.fileformat.info/info/charset/UTF-16/list.htm public static string FromHexString(string hexString) { // Added PadLeft so strings with one character do not get ignored string internalHexString = hexString.PadLeft(4, '0'); var bytes = new byte[internalHexString.Length / 2]; for (var i = 0; i < bytes.Length; i++) { bytes[i] = Convert.ToByte(internalHexString.Substring(i * 2, 2), 16); } return Encoding.BigEndianUnicode.GetString(bytes); } public static string FromBinaryString(string binaryString) { string internalBinaryString = binaryString.PadLeft(16, '0'); var bytes = new byte[internalBinaryString.Length / 8]; for (var i = 0; i < bytes.Length; i++) { bytes[i] = Convert.ToByte(internalBinaryString.Substring(i * 8, 8), 2); } return Encoding.BigEndianUnicode.GetString(bytes); } }