I want to convert a packet (byte[]) into a hex dump view on a text file but it got messy.
Here is a picture.
I was looping on the main byte[] until I reach mod of 16 (excluding 0) but then if the last line isn't a factor of 16 then ill end up with ASCII representation shifted to the left
I did try several solutions but non is really decent, so I considered it a blind spot and thought I could use some help :)
Also I could use some help on how to check if that character has an ascii representation or should I just replace it with '.'
using (var sw = File.AppendText(Path))
{
sw.WriteLine("[Packet Logged at {0} with direction {1}] with length {2} and type {3}",
DateTime.Now.ToLongTimeString().Replace("PM", string.Empty).Replace("AM", string.Empty).Replace(" ", string.Empty),
ReadWrite.ReadString(Packet,Packet.Length-8,8) == "removed for privacy" ? "Server->Client" : "Client -> Server",
BitConverter.ToUInt16(Packet, 0), BitConverter.ToUInt16(Packet, 2));
for (int i = 0; i < Packet.Length; i++)
{
if (i%16 == 0 && i != 0)
{
}
else
{
sw.Write(Packet[i]);
}
}
}
Taken from http://www.codeproject.com/Articles/36747/Quick-and-Dirty-HexDump-of-a-Byte-Array:
using System.Text;
namespace HexDump
{
class Utils
{
public static string HexDump(byte[] bytes, int bytesPerLine = 16)
{
if (bytes == null) return "<null>";
int bytesLength = bytes.Length;
char[] HexChars = "0123456789ABCDEF".ToCharArray();
int firstHexColumn =
8 // 8 characters for the address
+ 3; // 3 spaces
int firstCharColumn = firstHexColumn
+ bytesPerLine * 3 // - 2 digit for the hexadecimal value and 1 space
+ (bytesPerLine - 1) / 8 // - 1 extra space every 8 characters from the 9th
+ 2; // 2 spaces
int lineLength = firstCharColumn
+ bytesPerLine // - characters to show the ascii value
+ Environment.NewLine.Length; // Carriage return and line feed (should normally be 2)
char[] line = (new String(' ', lineLength - 2) + Environment.NewLine).ToCharArray();
int expectedLines = (bytesLength + bytesPerLine - 1) / bytesPerLine;
StringBuilder result = new StringBuilder(expectedLines * lineLength);
for (int i = 0; i < bytesLength; i += bytesPerLine)
{
line[0] = HexChars[(i >> 28) & 0xF];
line[1] = HexChars[(i >> 24) & 0xF];
line[2] = HexChars[(i >> 20) & 0xF];
line[3] = HexChars[(i >> 16) & 0xF];
line[4] = HexChars[(i >> 12) & 0xF];
line[5] = HexChars[(i >> 8) & 0xF];
line[6] = HexChars[(i >> 4) & 0xF];
line[7] = HexChars[(i >> 0) & 0xF];
int hexColumn = firstHexColumn;
int charColumn = firstCharColumn;
for (int j = 0; j < bytesPerLine; j++)
{
if (j > 0 && (j & 7) == 0) hexColumn++;
if (i + j >= bytesLength)
{
line[hexColumn] = ' ';
line[hexColumn + 1] = ' ';
line[charColumn] = ' ';
}
else
{
byte b = bytes[i + j];
line[hexColumn] = HexChars[(b >> 4) & 0xF];
line[hexColumn + 1] = HexChars[b & 0xF];
line[charColumn] = asciiSymbol( b );
}
hexColumn += 3;
charColumn++;
}
result.Append(line);
}
return result.ToString();
}
static char asciiSymbol( byte val )
{
if( val < 32 ) return '.'; // Non-printable ASCII
if( val < 127 ) return (char)val; // Normal ASCII
// Handle the hole in Latin-1
if( val == 127 ) return '.';
if( val < 0x90 ) return "€.‚ƒ„…†‡ˆ‰Š‹Œ.Ž."[ val & 0xF ];
if( val < 0xA0 ) return ".‘’“”•–—˜™š›œ.žŸ"[ val & 0xF ];
if( val == 0xAD ) return '.'; // Soft hyphen: this symbol is zero-width even in monospace fonts
return (char)val; // Normal Latin-1
}
}
}
I wrote this solution for dumping binary data:
public static class BinaryVisualiser
{
public static string FormatAsHex(ReadOnlySpan<byte> data)
{
byte ReplaceControlCharacterWithDot(byte character)
=> character < 31 || character >= 127 ? (byte)46 /* dot */ : character;
byte[] ReplaceControlCharactersWithDots(byte[] characters)
=> characters.Select(ReplaceControlCharacterWithDot).ToArray();
var result = new StringBuilder();
const int lineWidth = 16;
for (var pos = 0; pos < data.Length;)
{
var line = data.Slice(pos, Math.Min(lineWidth, data.Length - pos)).ToArray();
var asHex = string.Join(" ", line.Select(v => v.ToString("X2", CultureInfo.InvariantCulture)));
asHex += new string(' ', lineWidth * 3 - 1 - asHex.Length);
var asCharacters = Encoding.ASCII.GetString(ReplaceControlCharactersWithDots(line));
result.Append(FormattableString.Invariant($"{pos:X4} {asHex} {asCharacters}\n"));
pos += line.Length;
}
return result.ToString();
}
}
Note that this implementation leverages Span from C# 7.2 and requires the System.Memory NuGet package from Microsoft.
The output is formatted like this:
0000 EF BB BF 48 65 6C 6C 6F 2C 20 53 74 61 63 6B 20 ...Hello, Stack
0010 4F 76 65 72 66 6C 6F 77 21 Overflow!
Update: configurable byte width.
public static string FormatAsHex(ReadOnlySpan<byte> data, int lineWidth = 16, int byteWidth = 1)
{
byte ReplaceControlCharacterWithDot(byte character) => character < 31 || character >= 127 ? (byte)46 /* dot */ : character;
byte[] ReplaceControlCharactersWithDots(byte[] characters) => characters.Select(ReplaceControlCharacterWithDot).ToArray();
IEnumerable<BigInteger> Chunk(IReadOnlyList<byte> source, int size) => source.Select((item, index) => source.Skip(size * index).Take(size).ToArray()).TakeWhile(bucket => bucket.Any()).Select(e => new BigInteger(e));
var result = new StringBuilder();
for(var pos = 0; pos < data.Length;)
{
var line = data.Slice(pos, Math.Min(lineWidth * byteWidth, data.Length - pos)).ToArray();
var asHex = string.Join(" ", Chunk(line, byteWidth).Select(v => v.ToString("X" + byteWidth * 2, CultureInfo.InvariantCulture)));
asHex += new string(' ', lineWidth * (byteWidth * 2 + 1) - 1 - asHex.Length);
var asCharacters = Encoding.ASCII.GetString(ReplaceControlCharactersWithDots(line));
result.Append(Invariant($"{pos:X4} {asHex} {asCharacters}\n"));
pos += line.Length;
}
return result.ToString();
}
Which allows (encoded as big-endian UTF-16):
0000 4800 6500 6C00 6C00 6F00 2C00 .H.e.l.l.o.,
000C 2000 5300 7400 6100 6300 6B00 . .S.t.a.c.k
0018 2000 4F00 7600 6500 7200 6600 . .O.v.e.r.f
0024 6C00 6F00 7700 .l.o.w
Yes partition 2 is the bootable partition with 80
The size of partition for the image above is 2056237 bytes
dd if=/dev/zero of=/dev/sdx bs=512 skip=2265165 count=1028160
The alignment doesn't matter for the end sector , at least not for performance reasons . Alignment of the start sectors affects in the partition; alignmengt of the last sectore only afftets the last few sectors of the partition , if at all. So sectors are numberes from 0 and the fdisk is suggesting the last sector on your disk which has above results.
hope this was helpful.
Related
I'm trying to create a sequence of numbers in string format, once I reach "99999" I want to continue the sequence using leading letters.
Example:
"00000" -> "00100" -> "99999" -> "A0001" -> "A9999" -> "B0001" -> "ZZZZZ"
Is there an easy way to achieve this ?
So far I tried to split my string in numbers and letters and then I have some code cheking if numbers reach maximum, if it reach the maximum available I add a letter. Doesn't look really elegant to me.
Let's implement GetNextValue method: for a given value (e.g. "A9999") we compute the next ("B0001"):
private static string GetNextValue(string value) {
StringBuilder sb = new StringBuilder(value);
// Digits only: 1239 -> 1240
for (int i = value.Length - 1; i >= 0; --i) {
if (sb[i] < '9') {
sb[i] = (char)(sb[i] + 1);
return sb.ToString();
}
else if (sb[i] >= 'A')
break;
else
sb[i] = '0';
}
// 1st letter: 9999 -> A001
if (sb[0] == '0') {
sb[0] = 'A';
if (sb[sb.Length - 1] == '0')
sb[sb.Length - 1] = '1';
return sb.ToString();
}
// Leading letters AZ999 -> BA001
for (int i = value.Length - 1; i >= 0; --i) {
if (sb[i] >= 'A') {
if (sb[i] < 'Z') {
sb[i] = (char)(sb[i] + 1);
if (sb[sb.Length - 1] == '0')
sb[sb.Length - 1] = '1';
return sb.ToString();
}
else
sb[i] = 'A';
}
}
// All letters increment: ABCDZ -> ABCEA
for (int i = 0; i < value.Length; ++i) {
if (sb[i] == '0') {
sb[i] = 'A';
if (sb[sb.Length - 1] == '0')
sb[sb.Length - 1] = '1';
return sb.ToString();
}
}
// Exhausting: ZZZZZ -> 00000
return new string('0', value.Length);
}
If you want to enumerate these values:
private static IEnumerable<string> Generator(int length = 5) {
string item = new string('0', length);
do {
yield return item;
item = GetNextValue(item);
}
while (!item.All(c => c == '0'));
}
Demo: (let's use a string of length 3)
Console.Write(string.Join(Environment.NewLine, Generator(3)));
Outcome: (27234 items in total; 18769482 items if length == 5)
000
001
002
...
009
010
...
999
A01
...
A99
B01
...
Z99
AA1
...
AA9
AB1
...
AZ9
BA1
...
ZZ9
AAA
AAB
AAC
...
AAZ
ABA
...
ZZY
ZZZ
Here is an extension method which formats integer values to your format (with leading letters):
public static string ToZormat(this int value, int length = 5)
{
string map = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] result = new char[length];
var x = value;
for(int i = 0; i < length; i++)
{
int threshold = (int)Math.Pow(10, length - i - 1);
var index = Math.Min(map.Length - 1, x / threshold);
result[i] = map[index];
x -= threshold * index;
}
return new String(result);
}
When you have number formatted to a string of length 5, leading letters appear after value 99,999, next go A0,000, ... A9,999, B0,000 etc. As you can see the first character changes every 10,000 numbers. The second character changes every 1,000 numbers. And last, the fifth character will change for every number. We just need to implement that algorithm.
Basic steps:
Define map of characters which are used in your format
Calculate character change threshold for the current position (i) - it will be power of 10: 10,000, 1,000, 100, 10, 1.
Get the index of character from map. Its simply number of thresholds which fits the value, but not more than the number of characters in your map.
Calculate what's left from input value and go to next postion
You should add validation for the max value which fits the given length of the formatted string.
Sample for length 3:
Enumerable.Range(0, 3886).Select(x => x.ToZormat(3))
Output:
000
001
002
...
999
A00
A01
...
A99
B00
B01
...
Z99
ZA0
ZA1
...
ZZ9
ZZA
...
ZZZ
I have a string which is alphanumeric. From this string I created a byte array:
var endoding = Encoding.ASCII.GetBytes("123abcABC");
The length of the string is equal to the length of the ASCII byte array encoding.Length , that is 9.
I want to squeeze this encoded array length to less than 9. So I am looking for
Six-bit corrector code techniques
I wrote a sample (row) function based on the my understanding but it is failing for cap letters.
test case 1.
string input = "ABCDEFGH"; // length = 8
var Bytes1 = ConvertToEightBitCode(input ); // length = 6
var output = GetRxString(Bytes1); // input == output
test case 2
string input = "ABCDEFGH123"; // length = 11
var rxBytes1 = ConvertToEightBitCode(input ); // length = 9
var output = GetRxString(Bytes1); // input == output
test case 3 (failed)
string input = "abcABC123"; // length = 9
var rxBytes1 = ConvertToEightBitCode(input ); // length = 8
var output = GetRxString(Bytes1); // input != output
This function needs much improvement.
public static byte[] ConvertToEightBitCode(string rxNumber)
{
var asciiBytes = Encoding.ASCII.GetBytes(rxNumber);
//Console.WriteLine("Actual ASCII rx bytes [{0}]", string.Join(", ", asciiBytes));
byte[] newasciiByte = new byte[asciiBytes.Length];
byte tt = 32;
for (int i = 0; i < asciiBytes.Length; i++)
{
newasciiByte[i] = (byte)(asciiBytes[i] - tt);
}
//Console.WriteLine("Converted ASCII rx bytes [{0}]", string.Join(", ", newasciiByte));
string datastring = "";
foreach (var item in newasciiByte)
{
var e = Convert.ToString(item, 2);
var pe = e.Length == 6 ? e : e.PadLeft(6, '0');
datastring += pe;
}
//Console.WriteLine("Binary string [{0}]", datastring);
int factor = GetDevideNum(datastring.Length, 8);
List<string> new8Binary = new List<string>();
for (int i = 0; i < factor; i++)
{
var s = GetCharString(datastring.ToCharArray(), i * 8, 8);
if (!string.IsNullOrEmpty(s))
{
new8Binary.Add(s);
}
}
//Console.WriteLine("New eight block binary string array [{0}]", string.Join(", ", new8Binary));
List<byte> new8bytes = new List<byte>();
foreach (var item in new8Binary)
{
var ii = Convert.ToByte(item, 2);
new8bytes.Add(ii);
}
//Console.WriteLine("New Ascii bytes values for rx [{0}]", string.Join(", ", new8bytes));
return new8bytes.ToArray();
}
public static string GetRxString(byte[] rxarray)
{
//Console.WriteLine("Input Ascii rx array values for rx [{0}]", string.Join(", ", rxarray));
List<string> eightpadBinarystringArray = new List<string>();
for (int i = 0; i < rxarray.Length; i++)
{
var ss = Convert.ToString(rxarray[i], 2);
if (i == rxarray.Length - 1 && ss != "0")
eightpadBinarystringArray.Add(GetExactBinary(ss));
else
eightpadBinarystringArray.Add(ss.PadLeft(8, '0'));
}
//Console.WriteLine("Converted eight block binary string array [{0}]", string.Join(", ", eightpadBinarystringArray));
string eightpadBinarystring = string.Join("", eightpadBinarystringArray);
//Console.WriteLine("Converted binary string array [{0}]", string.Join(", ", eightpadBinarystring));
int factor = GetDevideNum(eightpadBinarystring.Length, 6);
//eightpadBinarystring = 100001100010100011100100100101100110100111
List<string> sixpadBinarystringArray = new List<string>();
for (int i = 0; i < factor; i++)
{
var sixxx = GetCharString(eightpadBinarystring.ToCharArray(), i * 6, 6);
if (!string.IsNullOrEmpty(sixxx))
{
sixpadBinarystringArray.Add(sixxx);
}
}
//Console.WriteLine("Converted six pad block binary string array [{0}]", string.Join(", ", sixpadBinarystringArray));
List<byte> result = new List<byte>();
foreach (var item in sixpadBinarystringArray)
{
var rr = Convert.ToByte(item, 2);
var bbr = (byte)(rr + 32);
result.Add(bbr);
}
//Console.WriteLine("Converted ascii array [{0}]", string.Join(", ", result));
StringBuilder rxNumber = new StringBuilder();
foreach (var item in result)
{
if (item != 32)
{
char c = (char)item;
rxNumber.Append(c);
}
}
//Console.WriteLine("Converted char array [{0}]", string.Join(", ", clist));
return rxNumber.ToString();
}
private static int GetDevideNum(int length, int f)
{
if (length % f == 0)
{
return length / f;
}
else
{
return length / f + 1;
}
}
private static string GetExactBinary(string ss)
{
return ss.TrimStart(new char[] { '0' });
}
private static string GetCharString(char[] array, int start, int length)
{
int e = start + length;
char[] dd = new char[length];
for (int i = 0; i < length; i++)
{
dd[i] = ' ';
}
if (e <= array.Length)
{
Array.Copy(array, start, dd, 0, length);
return string.Join("", dd);
}
else
{
int ne = array.Length - start;
if (ne == 0)
{
return "";
}
Array.Copy(array, start, dd, 0, ne);
var data = string.Join("", dd).Trim();
string rdata = data.PadLeft(length, '0');
return rdata;
}
}
I use six bit encoding from wiki
table CDC 1612 printer codes (business applications)
input is ABC1234
A - 31 = hex to binary = 0011 0001 - six bit - 110001 -- six bit padding
B - 32 = hex to binary = 0011 0010 - six bit - 110010
C - 33 = hex to binary = 0011 0011 - six bit - 110011
1- 01 = hex to binary = 0000 0001 - six bit - 000001
2-02 = hex to binary = 0000 0010 - six bit - 000010
3- 03 = hex to binary = 0000 0011 - six bit - 000011
4 -03 = hex to binary = 0000 0100 - six bit - 000100
New six bit
110001110010110011000001000010000011000100
New eight bit pading
000000110001110010110011000001000010000011000100
Eight bit array
00000011 - binary to dec - 3
00011100 - binary to dec - 28
10110011 - binary to dec - 179
00000100 - binary to dec - 4
00100000 - binary to dec - 32
11000100 - binary to dec - 196
New aaray
3 -- dec to binary - 00000011 -- eight bit padding
28 -- dec to binary - 00011100
179 -- dec to binary - 10110011
4 -- dec to binary - 00000100
32 -- dec to binary - 00100000
196 -- dec to binary - 11000100
8 bit String
000000110001110010110011000001000010000011000100
Six bit padding
000000110001110010110011000001000010000011000100
000000 -- binary to hex -- 0 -- first ignore
110001 -- binary to hex -- 31 -- A
110010 -- binary to hex -- 32 -- B
110011 -- binary to hex -- 33 -- C
000001 -- binary to hex -- 01 -- 1
000010 -- binary to hex -- 02 -- 2
000011 -- binary to hex -- 03 -- 3
000100 -- binary to hex -- 04 -- 4
my c# code for this
namespace NewApproachSixBitEncodeApp
{
class Program
{
static int maxLength = 28;
static void Main(string[] args)
{
try
{
string input = args[0];//"::AB:C1234::AB:C1234::AB:C12";
if (args.Length <= 0
|| string.IsNullOrEmpty(args[0]))
{
throw new Exception("Input not correct please enter valid rx string.");
}
byte[] encode = Encode(input);
string output = Decode(encode);
Console.WriteLine("\ninput: [{0}] \ninput ecoded array [{1}] \ninput rx length: [{2}] \noutput encode array: [{3}] \noutput.encoded.length: [{4}] \noutput decoded: [{5}]",
input, string.Join(", ", Encoding.ASCII.GetBytes(input)), input.Length, string.Join(", ", encode), encode.Length, output);
}
catch (Exception ex)
{
Console.WriteLine("Error : " + ex.Message);
}
Console.ReadLine();
}
static ReferenceTable referenceTable = ReferenceTableValue.Create();
public static string Decode(byte[] encode)
{
string binary = "";
foreach (var item in encode)
{
binary += Convert.ToString(item, 2).PadLeft(8, '0');
}
while (binary.Length % 6 != 0)
binary = "0" + binary;
var sixPadBitbinaryArray = Enumerable.Range(0, binary.Length / 6).
Select(pos => binary.Substring(pos * 6, 6)
).ToArray();
StringBuilder result = new StringBuilder();
int count = 0;
foreach (var item in sixPadBitbinaryArray)
{
string element = Convert.ToInt32(item, 2).ToString("X").PadLeft(2, '0');
if (element == "00" && count == 0)
{
count++;
continue;
}
count++;
result.Append(referenceTable.GetChar(element[0].ToString(), element[1].ToString()));
}
return result.ToString();
}
public static byte[] Encode(string input)
{
if (!referenceTable.IsValidString(input))
{
throw new Exception("invalid string. use char from table" + input);
}
string eightPadBitbinary = "";
foreach (var item in input.ToCharArray())
eightPadBitbinary += hex2binaryWithSixPadding(referenceTable[item]);
while (eightPadBitbinary.Length % 8 != 0)
eightPadBitbinary = "0" + eightPadBitbinary;
var eightPadBitbinaryArray = Enumerable.Range(0, eightPadBitbinary.Length / 8).
Select(pos => Convert.ToByte(eightPadBitbinary.Substring(pos * 8, 8),
2)
).ToArray();
return eightPadBitbinaryArray;
}
static string hex2binaryWithSixPadding(string hexvalue)
{
var hexToBin = String.Join(String.Empty, hexvalue.Select(c => Convert.ToString(Convert.ToUInt32(c.ToString(), 16), 2).PadLeft(4, '0')));
string result = hexToBin;
while (result.Length > 6 && result.StartsWith("0"))
result = hexToBin.TrimStart(new char[] { '0' }); ;
if (result.Length > 6)
throw new Exception("hex to bin length error HexValue = " + hexvalue);
else
result = result.PadLeft(6, '0');
return result;
}
}
public class ReferenceTableValue
{
//CDC 1612 printer codes (business applications)
private ReferenceTableValue()
{
}
public string GetAllChar()
{
return string.Join("", list);
}
static List<string> list = new List<string>();
public static ReferenceTable Create()
{
ReferenceTable t = new ReferenceTable();
t.ReferenceTableValues = new List<ReferenceTableValue>();
list.Add(":1234567890=≠≤![");
list.Add(" /STUVWXYZ],(→≡~");
list.Add("-JKLMNOPQR%$*↑↓>");
list.Add("+ABCDEFGHI<.)≥?;");
for (int row = 0; row <= 3; row++)
{
for (int col = 0; col <= 15; col++)
{
char cc = list[row].Substring(col, 1).ToCharArray()[0];
ReferenceTableValue rf = new ReferenceTableValue(
String.Format("{0:X}", row),
String.Format("{0:X}", col),
cc);
t.ReferenceTableValues.Add(rf);
}
}
return t;
}
public ReferenceTableValue(string x, string y, char charector)
{
this.X = x;
this.Y = y;
this.Charector = charector;
}
public string X { get; set; }
public string Y { get; set; }
public char Charector { get; set; }
}
public class ReferenceTable
{
public List<ReferenceTableValue> ReferenceTableValues { get; set; }
public bool IsValidString(string input)
{
if (string.IsNullOrWhiteSpace(input)
|| ReferenceTableValues == null
|| ReferenceTableValues.Count == 0)
return false;
var refval = ReferenceTableValues[0];
string allStringChar = refval.GetAllChar();
foreach (var item in input.ToCharArray())
{
if (!allStringChar.Contains(item))
{
return false;
}
}
return true;
}
public string this[char val]
{
get
{
if (ReferenceTableValues == null) return null;
foreach (var item in ReferenceTableValues)
{
if ((int)item.Charector == (int)val)
{
return item.X + item.Y;
}
}
throw new Exception(string.Format("Value not found for char [{0}]", val.ToString()));
}
}
public char GetChar(string _x, string _y)
{
if (ReferenceTableValues == null)
return '\0';
foreach (var item in ReferenceTableValues)
{
if (item.X == _x && item.Y == _y)
return item.Charector;
}
throw new Exception(string.Format("value not found."));
}
}
}
I need to calculate a CRC checksum for a CAN BUS.
Scenario:
My input looks always like the following (where x is either 1 or 0, * marks multiple times x, | marks a section and - is a change of input method, lbis Label, tb is TextBox, cb is ComboBox):
lb: 0
tb: 11x
cb: x
cb: x
lb: 1
tb: 4x => Convert.ToString(8-64 / 8, 2).PadLeft(4, '0');
tb: 8-64x, => 8-64 % 8 == 0
tb: 15x => CRC of above
lb: 1
lb: 11
lb: 1111111
lb: 111
Which returns this layout:
0|11*x-x|x-1-4*x|64*x|15*x-1|11|1111111|111
Example:
00101010101000100100101010100101010(missing 15*x CRC sum)1111111111111
This string will be processed by the following string extension, so maximal 5 equal digits follow each other:
public static string Correct4CRC(this string s)
{
return s.Replace("00000", "000001").Replace("11111", "111110");
}
After that following method returns the divisor:
public static BigInteger CreateDivisor(string s)
{
var i = BigInteger.Parse(s);
var d = BigInteger.Pow(i, 15) + BigInteger.Pow(i, 14) + BigInteger.Pow(i, 10) + BigInteger.Pow(i, 8) + BigInteger.Pow(i, 7) + BigInteger.Pow(i, 4) + BigInteger.Pow(i, 3) + 1;
return d;
}
The only problem I've got is the part with ^:
public static string CRC(this string s)
{
var dd = s.Correct4CRC();
var dr = dd.CreateDivisor().ToString();
int drl = dr.Length;
var d = dd.Substring(0, drl).CreateDivisor();
var f = d ^ dr.CreateDivisor();
var p = true;
while (p)
{
d = dd.Substring(0, drl).CreateDivisor();
f = d ^ dr.CreateDivisor();
p = d > dd.CreateDivisor();
}
return f.ToString();
}
I know this might be closed as asking for code, but please bear with me as I really don't get it. Another problem is, that there is no real documentation which helped me figuring it out.
Anyway, if you know one good doc, which solves my problem please add it as a comment. I'll check it out and close the answer by myself if I get it.
I think your bitstuffing is wrong (the replacement of 00000 with 000001 and of 11111 with 111110), because it doesn't handle avalanche replacements... 0000011110000 that becomes 0000011111000001.
Here http://blog.qartis.com/can-bus/ there seems to be an example. The page is then linked to http://ghsi.de/CRC/index.php?Polynom=1100010110011001&Message=2AA80 that generates some C code for calculating the CRC-15.
// 0000011110000 becomes 0000011111000001
public static string BitStuff(string bits)
{
StringBuilder sb = null;
char last = ' ';
int count = 0;
for (int i = 0; i < bits.Length; i++)
{
char ch = bits[i];
if (ch == last)
{
count++;
if (count == 5)
{
if (sb == null)
{
// The maximum length is equal to the length of bits
// plus 1 for length 5, 2 for length 9, 3 for length 13...
// This because the maximum expanion is for
// 00000111100001111... or 11111000011110000...
sb = new StringBuilder(bits.Length + (bits.Length - 1) / 4);
sb.Append(bits, 0, i);
}
sb.Append(ch);
last = ch == '0' ? '1' : '0';
sb.Append(last);
count = 1;
continue;
}
}
else
{
last = ch;
count = 1;
}
if (sb != null)
{
sb.Append(ch);
}
}
return sb != null ? sb.ToString() : bits;
}
// Taken from http://ghsi.de/CRC/index.php?Polynom=1100010110011001&Message=2AA80
public static string Crc15(string bits)
{
var res = new char[15]; // CRC Result
var crc = new bool[15];
for (int i = 0; i < bits.Length; i++)
{
bool doInvert = (bits[i] == '1') ^ crc[14]; // XOR required?
crc[14] = crc[13] ^ doInvert;
crc[13] = crc[12];
crc[12] = crc[11];
crc[11] = crc[10];
crc[10] = crc[9] ^ doInvert;
crc[9] = crc[8];
crc[8] = crc[7] ^ doInvert;
crc[7] = crc[6] ^ doInvert;
crc[6] = crc[5];
crc[5] = crc[4];
crc[4] = crc[3] ^ doInvert;
crc[3] = crc[2] ^ doInvert;
crc[2] = crc[1];
crc[1] = crc[0];
crc[0] = doInvert;
}
// Convert binary to ASCII
for (int i = 0; i < 15; i++)
{
res[14 - i] = crc[i] ? '1' : '0';
}
return new string(res);
}
and then:
string bits = "0101010101010000000"; // Example data
string crc = Crc15(bits);
bits = bits + crc;
bits = BitStuff(bits);
bits += '1'; // CRC delimiter
bits += 'x'; // ACK slot TODO
bits += '1'; // ACK delimiter
bits += "1111111"; // EOF
Note that you have to put the value for the ACK slot
I'm trying to write function that converts an arbitrary large array of bytes (larger than 64-bit) into a decimal number represented as string in c# and I simply can't figure out how to do it.
For example the following code ...
Console.WriteLine(ConvertToString(
new byte[]
{
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00
}));
.. should print out
22774453838368691933757882222884355840
I don't want to just use an extra library like biginteger for that, because I want it to be simple and like to understand how it works.
Some guidelines:
You will need to save the digits of the number in a matrix, one space for each digit. The matrix starts empty.
Then you need a matrix to save the multiplication of the matrix. It too starts empty.
Now for each byte you have:
First multiply each digit of the current number matrix by 256, save the 10 modulus in the corresponding temporary digit and add the the number divided by 10 to the next digits multiplication.
Assign the temporary multiplication matrix to the current digit matrix.
Then add the byte to the first digit.
Correct the current matrix, saving only the 10 modulus in each index and passing the value divided by 10 to the next index.
Then you need to concatenate each digit in a string.
Return the string.
Don't forget to expand each matrix as needed, or determine the maximum size needed from the number of bytes been passed.
Edit, example following the third step above:
Values = [0xAA, 0xBB]
Initial Current = []
Initial Temp = []
With 0xAA
Nothing to multiply.
No change on assignment.
We add 0xAA to the first value in current: Current = [170]
We correct current to save only the modulus, passing the value divided by ten to the next value:
1st digit: Current = [0] pass 17.
2nd digit: Current = [0, 7] pass 1.
3rd digit: Current = [0, 7, 1] no value to pass so process ends.
Now with 0xBB
Multipli by 256, save in temp and correct, do for each digit:
1st digit: Temp = [0], 0 to save to the next digit.
2nd digit: Temp = [0, 1792] before correction, Temp = [0, 2], 179 to pass after correction.
3rd digit: Temp = [0, 2, 1 * 256 + 179 = 435] before correction, Temp = [0, 2, 5], 43 to pass after correction.
4th digit: Temp = [0, 2, 5, 43] before, Temp = [0, 2, 5, 3], 3 to pass after
5th digit: Temp = [0, 2, 5, 3, 4] before and after correction, no digit to save, so the multiplication ends.
Assing temp to current: Current = [0, 2, 5, 3, 4]; Temp = []
Add the current value to the first digit: Current = [187, 2, 5, 3, 4]
Correct the values:
1st digit: Current = [7, 2, 5, 3, 4], 18 to pass.
2nd digit: Current = [7, 0, 5, 3, 4], 2 to pass.
3rd digit: Current = [7, 0, 7, 3, 4], nothing to pass so the addition ends.
Now we only need to concatenate for the result 43707.
Based on #Wilheim's answer:
static string BytesToString(byte[] data) {
// Minimum length 1.
if (data.Length == 0) return "0";
// length <= digits.Length.
var digits = new byte[(data.Length * 0x00026882/* (int)(Math.Log(2, 10) * 0x80000) */ + 0xFFFF) >> 16];
int length = 1;
// For each byte:
for (int j = 0; j != data.Length; ++j) {
// digits = digits * 256 + data[j].
int i, carry = data[j];
for (i = 0; i < length || carry != 0; ++i) {
int value = digits[i] * 256 + carry;
carry = Math.DivRem(value, 10, out value);
digits[i] = (byte)value;
}
// digits got longer.
if (i > length) length = i;
}
// Return string.
var result = new StringBuilder(length);
while (0 != length) result.Append((char)('0' + digits[--length]));
return result.ToString();
}
You want to understand the workings so take a look at super cool
C# BigInteger Class # CodeProject.
Also, I have stripped that class to bare essentials for this question. It can be optimized further. :)
Try copy and paste following code it works!!
using System;
public class BigInteger
{
// maximum length of the BigInteger in uint (4 bytes)
// change this to suit the required level of precision.
private const int maxLength = 70;
private uint[] data = null; // stores bytes from the Big Integer
public int dataLength; // number of actual chars used
public BigInteger()
{
data = new uint[maxLength];
dataLength = 1;
}
public BigInteger(long value)
{
data = new uint[maxLength];
long tempVal = value;
dataLength = 0;
while (value != 0 && dataLength < maxLength)
{
data[dataLength] = (uint)(value & 0xFFFFFFFF);
value >>= 32;
dataLength++;
}
if (tempVal > 0) // overflow check for +ve value
{
if (value != 0 || (data[maxLength - 1] & 0x80000000) != 0)
throw (new ArithmeticException("Positive overflow in constructor."));
}
else if (tempVal < 0) // underflow check for -ve value
{
if (value != -1 || (data[dataLength - 1] & 0x80000000) == 0)
throw (new ArithmeticException("Negative underflow in constructor."));
}
if (dataLength == 0)
dataLength = 1;
}
public BigInteger(ulong value)
{
data = new uint[maxLength];
// copy bytes from ulong to BigInteger without any assumption of
// the length of the ulong datatype
dataLength = 0;
while (value != 0 && dataLength < maxLength)
{
data[dataLength] = (uint)(value & 0xFFFFFFFF);
value >>= 32;
dataLength++;
}
if (value != 0 || (data[maxLength - 1] & 0x80000000) != 0)
throw (new ArithmeticException("Positive overflow in constructor."));
if (dataLength == 0)
dataLength = 1;
}
public BigInteger(BigInteger bi)
{
data = new uint[maxLength];
dataLength = bi.dataLength;
for (int i = 0; i < dataLength; i++)
data[i] = bi.data[i];
}
public BigInteger(byte[] inData)
{
dataLength = inData.Length >> 2;
int leftOver = inData.Length & 0x3;
if (leftOver != 0) // length not multiples of 4
dataLength++;
if (dataLength > maxLength)
throw (new ArithmeticException("Byte overflow in constructor."));
data = new uint[maxLength];
for (int i = inData.Length - 1, j = 0; i >= 3; i -= 4, j++)
{
data[j] = (uint)((inData[i - 3] << 24) + (inData[i - 2] << 16) +
(inData[i - 1] << 8) + inData[i]);
}
if (leftOver == 1)
data[dataLength - 1] = (uint)inData[0];
else if (leftOver == 2)
data[dataLength - 1] = (uint)((inData[0] << 8) + inData[1]);
else if (leftOver == 3)
data[dataLength - 1] = (uint)((inData[0] << 16) + (inData[1] << 8) + inData[2]);
while (dataLength > 1 && data[dataLength - 1] == 0)
dataLength--;
//Console.WriteLine("Len = " + dataLength);
}
public override string ToString()
{
return ToString(10);
}
public string ToString(int radix)
{
string charSet = "ABCDEF";
string result = "";
BigInteger a = this;
BigInteger quotient = new BigInteger();
BigInteger remainder = new BigInteger();
BigInteger biRadix = new BigInteger(radix);
if (a.dataLength == 1 && a.data[0] == 0)
result = "0";
else
{
while (a.dataLength > 1 || (a.dataLength == 1 && a.data[0] != 0))
{
singleByteDivide(a, biRadix, quotient, remainder);
if (remainder.data[0] < 10)
result = remainder.data[0] + result;
else
result = charSet[(int)remainder.data[0] - 10] + result;
a = quotient;
}
}
return result;
}
private static void singleByteDivide(BigInteger bi1, BigInteger bi2,
BigInteger outQuotient, BigInteger outRemainder)
{
uint[] result = new uint[maxLength];
int resultPos = 0;
// copy dividend to reminder
for (int i = 0; i < maxLength; i++)
outRemainder.data[i] = bi1.data[i];
outRemainder.dataLength = bi1.dataLength;
while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0)
outRemainder.dataLength--;
ulong divisor = (ulong)bi2.data[0];
int pos = outRemainder.dataLength - 1;
ulong dividend = (ulong)outRemainder.data[pos];
if (dividend >= divisor)
{
ulong quotient = dividend / divisor;
result[resultPos++] = (uint)quotient;
outRemainder.data[pos] = (uint)(dividend % divisor);
}
pos--;
while (pos >= 0)
{
dividend = ((ulong)outRemainder.data[pos + 1] << 32) + (ulong)outRemainder.data[pos];
ulong quotient = dividend / divisor;
result[resultPos++] = (uint)quotient;
outRemainder.data[pos + 1] = 0;
outRemainder.data[pos--] = (uint)(dividend % divisor);
}
outQuotient.dataLength = resultPos;
int j = 0;
for (int i = outQuotient.dataLength - 1; i >= 0; i--, j++)
outQuotient.data[j] = result[i];
for (; j < maxLength; j++)
outQuotient.data[j] = 0;
while (outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength - 1] == 0)
outQuotient.dataLength--;
if (outQuotient.dataLength == 0)
outQuotient.dataLength = 1;
while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0)
outRemainder.dataLength--;
}
public static void Main(string[] args)
{
BigInteger big = new BigInteger( new byte[]
{
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00
});
Console.WriteLine(big);
}
}
Would System.Decimal meet your needs?
I'm trying to write a function that takes a revision number (int) and turns it into a revision name (string). The formula should produce outputs similar to this:
Number Name
1 A
2 B
3 C
... ...
25 Y
26 Z
27 AA
28 AB
29 AC
... ...
51 AY
52 AZ
53 BA
54 BB
55 BC
... ...
This seems simple, but I think it might involve recursion and I'm terrible at that. Any suggestions?
I think this is the same as working out the Excel column name from a column number:
private string GetExcelColumnName(int columnNumber)
{
int dividend = columnNumber;
string columnName = String.Empty;
int modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
dividend = (int)((dividend - modulo) / 26);
}
return columnName;
}
I think you basically need a transformation of a number in 10x numerical system to a number in 26x numerical system.
For example:
53 = 5*10^1 + 3*10^0 = [5][3]
53 = B*26^1 + A*26^0 = [B][A]
int value10 = 53;
int base10 = 10;
string value26 = "";
int base26 = 26;
int input = value10;
while (true)
{
int mod = input / base26;
if (mod > 0)
value26 += Map26SymbolByValue10 (mod); // Will map 2 to 'B'
else
value26 += Map26SymbolByValue10 (input); // Will map 1 to 'A'
int rest = input - mod * base26;
if (input < base26) break;
input = rest;
}
I really hope this isn't homework... (untested solution):
if(value == 1)
return "A";
StringBuilder result = new StringBuilder();
value--;
while(value > 0)
{
result.Insert(0, 'A' + (value % 26));
value /= 26;
}
Recursive version based on tanascius' original answer (also untested):
string ConvertToChar(int value)
{
char low = 'A' + (value - 1) % 26;
if(value > 26)
return ConvertToChar((value - 1) / 26 + 1) + low.ToString();
else
return low.ToString();
}
Tested solution:
private static string VersionName(int versionNum)
{
StringBuilder sb = new StringBuilder();
while (versionNum > 0)
{
versionNum--;
sb.Insert(0, (char)('A' + (versionNum % 26)));
versionNum /= 26;
}
return sb.ToString();
}
I wouldn't bother using recursion for this. Looping with a StringBuilder is more efficient than concatenating strings with each recursion, although you'd probably need a crazy number of revisions to notice the difference (4 letters is enough for over 400,000 revisions).
You can use the modulo operator and division to get your code.
Like 55 / 26 == 2 (that is B) and 55 % 26 = 3 (that is C). It works for two characters. When you have an unknown count of characters, you have to start looping:
[look at Aaron's solution, mine was wrong]