private string GenerateBinaryString(byte[] requestedOrderBytes, NumberByteOrder byteOrder) { StringBuilder sb = new StringBuilder(BitsPerByte * requestedOrderBytes.Length); foreach (byte currentByte in requestedOrderBytes) { if (sb.Length > 0 && this.options.UseByteSpaceSeparators) { sb.Append(' '); } for (int i = BitsPerByte - 1; i >= 0; i--) { bool isBitSet = (currentByte & (1 << i)) != 0; sb.Append(isBitSet ? "1" : "0"); } } string result = sb.ToString(); if (this.ShouldTrimLeadingZeros(byteOrder)) { result = TrimLeadingZeros(result); } return(result); }
private static byte[] EnsureRequestedByteOrder(byte[] machineValueBytes, NumberByteOrder byteOrder) { if (!MachineOrderMatchesByteOrder(byteOrder)) { Array.Reverse(machineValueBytes); } return(machineValueBytes); }
private static bool MachineOrderMatchesByteOrder(NumberByteOrder byteOrder) { // As far as this function is concerned, numeric and big endian are the same because they // both order from most significant down to least significant. bool result = (BitConverter.IsLittleEndian && byteOrder == NumberByteOrder.LittleEndian) || (!BitConverter.IsLittleEndian && byteOrder != NumberByteOrder.LittleEndian); return(result); }
private void InitializeFromHex(string textValue, NumberByteOrder byteOrder, NumberType numberType) { int requiredNumBytes = GetNumBytesForNumberType(numberType); byte[] machineValueBytes = GetMachineBytesFromText(textValue, byteOrder, NumberBase.Hex, requiredNumBytes); object convertedValue = GetConvertedValueForBytes(machineValueBytes, numberType); if (convertedValue != null) { this.decimalValue = this.FormatDecimalValue(convertedValue); this.hexValue = textValue; byte[] requestedOrderBytes = EnsureRequestedByteOrder(machineValueBytes, byteOrder); this.binaryValue = this.GenerateBinaryString(requestedOrderBytes, byteOrder); } }
private static bool ValidateAndNormalizeByteText(ref string textValue, NumberByteOrder byteOrder, NumberBase numBase, int numRequiredBytes) { // Ignore whitespace (leading, trailing, and between digit groups) and non-printable control characters. textValue = new string(textValue.Where(ch => !char.IsWhiteSpace(ch) && !char.IsControl(ch)).ToArray()); // Ignore 0x prefix for hex if (numBase == NumberBase.Hex && textValue.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { textValue = textValue.Substring(2); } int numCharsPerByte = numBase == NumberBase.Binary ? BitsPerByte : 2; int numCharsTotal = textValue.Length; // I'm depending on the truncation of integer division here. int numWholeBytes = numCharsTotal / numCharsPerByte; int numLeftoverCharacters = numCharsTotal % numCharsPerByte; bool validLength = numWholeBytes == numRequiredBytes && numLeftoverCharacters == 0; // If necessary, we can pad up to the number of required bytes, but we can never truncate. if (!validLength && numWholeBytes < numRequiredBytes) { int numRequiredChars = numCharsPerByte * numRequiredBytes; if (byteOrder == NumberByteOrder.Numeric) { textValue = new string('0', numRequiredChars - numCharsTotal) + textValue; validLength = true; } else { // For big and little endian, we'll left pad up to the next full byte, then we'll right pad the rest of the data. // This seems the most reasonable strategy since entering a single byte's data is a "Numeric" entry, which // normally zero pads on the left. But since Endianness deals with storage and we enter data from left to // right, it seems reasonable to zero pad on the right to fill up the remaining unspecified bytes. For example, // if "F" is entered for a Hex Int32, we'll left pad that up to "0F" and then right pad it to "0F000000". int numLeftPadChars = numLeftoverCharacters == 0 ? 0 : numCharsPerByte - numLeftoverCharacters; textValue = new string('0', numLeftPadChars) + textValue + new string('0', numRequiredChars - numCharsTotal - numLeftPadChars); validLength = true; } } return(validLength); }
public BaseConverter(string textValue, Options options, NumberBase numBase, NumberByteOrder byteOrder, NumberType numberType) { this.options = options; if (!string.IsNullOrEmpty(textValue)) { switch (numBase) { case NumberBase.Binary: this.InitializeFromBinary(textValue, byteOrder, numberType); break; case NumberBase.Decimal: this.InitializeFromDecimal(textValue, byteOrder, numberType); break; case NumberBase.Hex: this.InitializeFromHex(textValue, byteOrder, numberType); break; } } }
private string GenerateHexString(byte[] requestedOrderBytes, NumberByteOrder byteOrder) { StringBuilder sb = new StringBuilder(2 * requestedOrderBytes.Length); foreach (byte b in requestedOrderBytes) { if (sb.Length > 0 && this.options.UseByteSpaceSeparators) { sb.Append(' '); } sb.AppendFormat("{0:X2}", b); } string result = sb.ToString(); if (this.ShouldTrimLeadingZeros(byteOrder)) { result = TrimLeadingZeros(result); } return(result); }
private static byte[] GetMachineBytesFromText(string textValue, NumberByteOrder byteOrder, NumberBase numBase, int requiredNumBytes) { Debug.Assert(numBase == NumberBase.Binary || numBase == NumberBase.Hex, "GetMachineBytesFromText is only for binary and hex values."); byte[] result = null; bool validLength = ValidateAndNormalizeByteText(ref textValue, byteOrder, numBase, requiredNumBytes); if (validLength) { bool valid = true; string[] byteStrings = SplitIntoByteStrings(textValue, numBase == NumberBase.Binary ? BitsPerByte : 2); List <byte> byteList = new List <byte>(requiredNumBytes); foreach (string byteString in byteStrings) { if (TryParse(byteString, numBase, out byte byteValue)) { byteList.Add(byteValue); } else { valid = false; break; } } if (valid) { result = byteList.ToArray(); // Regardless of input byte order we must return bytes that match machine byte order // (i.e., BitConverter.IsLittleEndian) because our output will be passed to BitConverter. result = EnsureRequestedByteOrder(result, byteOrder); } } return(result); }
private bool ShouldTrimLeadingZeros(NumberByteOrder byteOrder) { bool result = byteOrder == NumberByteOrder.Numeric ? this.options.TrimLeadingZerosNumeric : this.options.TrimLeadingZerosEndian; return(result); }
private void InitializeFromDecimal(string textValue, NumberByteOrder byteOrder, NumberType numberType) { const NumberStyles IntegerStyles = NumberStyles.Integer | NumberStyles.AllowThousands; byte[] machineValueBytes = null; switch (numberType) { case NumberType.Byte: byte byteValue; if (byte.TryParse(textValue, IntegerStyles, null, out byteValue)) { machineValueBytes = new byte[1] { byteValue }; } break; case NumberType.Int16: short shortValue; if (short.TryParse(textValue, IntegerStyles, null, out shortValue)) { machineValueBytes = BitConverter.GetBytes(shortValue); } break; case NumberType.Int32: int intValue; if (int.TryParse(textValue, IntegerStyles, null, out intValue)) { machineValueBytes = BitConverter.GetBytes(intValue); } break; case NumberType.Int64: long longValue; if (long.TryParse(textValue, IntegerStyles, null, out longValue)) { machineValueBytes = BitConverter.GetBytes(longValue); } break; case NumberType.Single: float singleValue; if (float.TryParse(textValue, out singleValue)) { machineValueBytes = BitConverter.GetBytes(singleValue); } break; case NumberType.Double: double doubleValue; if (double.TryParse(textValue, out doubleValue)) { machineValueBytes = BitConverter.GetBytes(doubleValue); } break; case NumberType.Decimal: decimal decimalValue; if (decimal.TryParse(textValue, out decimalValue)) { machineValueBytes = GetBytes(decimalValue); } break; case NumberType.SByte: sbyte sbyteValue; if (sbyte.TryParse(textValue, IntegerStyles, null, out sbyteValue)) { unchecked { byte castValue = (byte)sbyteValue; machineValueBytes = new byte[1] { castValue }; } } break; case NumberType.UInt16: ushort ushortValue; if (ushort.TryParse(textValue, IntegerStyles, null, out ushortValue)) { machineValueBytes = BitConverter.GetBytes(ushortValue); } break; case NumberType.UInt32: uint uintValue; if (uint.TryParse(textValue, IntegerStyles, null, out uintValue)) { machineValueBytes = BitConverter.GetBytes(uintValue); } break; case NumberType.UInt64: ulong ulongValue; if (ulong.TryParse(textValue, IntegerStyles, null, out ulongValue)) { machineValueBytes = BitConverter.GetBytes(ulongValue); } break; } if (machineValueBytes != null) { this.decimalValue = textValue; byte[] requestedOrderBytes = EnsureRequestedByteOrder(machineValueBytes, byteOrder); this.hexValue = this.GenerateHexString(requestedOrderBytes, byteOrder); this.binaryValue = this.GenerateBinaryString(requestedOrderBytes, byteOrder); } }