Convert ASCII Hex text to binary


Debugging sometimes means dumping a hex stream to the console, or to a log file, something like 0x0a 0xff…

I wrote a simple command line tool to convert that kind of hex data to binary. Users of Linux can resort to the fine xxd utility to do the same thing.

The following are all valid hex values (and produce the same binary sequence).

  • “0xDE 0xAD”
  • “0xDE0xAD”
  • “0xD E0xAD”
  • “0xD\r\nE0xAD”
  • “0xDE\r\n 0xAD”
  • “0xDE\n 0xAD”
  • “0xDE\r 0xAD”
  • “0xD\r\nE 0xAD”
  • “0x00DE 0xAD”
  • “DE AD”
  • “DEAD”
  • “DEA D”
  • “DEA\r\nD”

The following are invalid and will result in an error.

  • “0x01DE 0xAD”
  • “0xDExAD”
  • “0xDE AD”

The source code follows. You can also fork it at GitHub.

    public class HexToBin
    {
        /// <summary>
        /// Reads hex data from input file and writes corresponding binary to output file.
        /// </summary>
        /// <param name="infile">Input file name.</param>
        /// <param name="outfile">Output file name</param>
        /// <param name="encoding">Character encoding of data in input file.</param>
        /// <returns>Number of bytes written or a negative value on error.</returns>
        public static int Convert(string infile, string outfile, Encoding encoding)
        {
            StreamReader inf = new StreamReader(File.OpenRead(infile), encoding);
            FileStream outf = File.OpenWrite(outfile);

            int count = Convert(inf, outf);

            inf.Close();
            outf.Close();

            return count;
        }

        /// <summary>
        /// Reads hex data read from the specified reader, and writes corresponding binary
        /// to the specified output stream.
        /// </summary>
        /// <param name="input">Input text reader from where characters are read.</param>
        /// <param name="output">Output stream to where binary data is written.</param>
        /// <returns>Number of bytes written or a negative value on error.</returns>
        public static int Convert(TextReader input, Stream output)
        {
            int line = 1;
            int col = 1;
            int colStart = 0;
            int count = 0;
            bool parse = false;
            bool has0x = false;

            StringBuilder val = new StringBuilder();
            while (true)
            {
                int ch = input.Read();
                switch (ch)
                {
                    case '\n':
                    case '\r':
                        line++;
                        col = 0;
                        if (ch == '\r' && input.Peek() == '\n')
                        {
                            // just so we don't count the same line twice for dos/windows
                            input.Read();
                        }
                        if (!has0x && val.Length == 2)
                        {
                            parse = true;
                        }
                        break;

                    case ' ':
                        if (!has0x && val.Length == 2)
                        {
                            parse = true;
                        }
                        break;

                    case -1:
                        if (val.Length > 0)
                        {
                            parse = true;
                        }
                        break;

                    default:
                        if (colStart == 0)
                        {
                            colStart = col;
                        }
                        if (ch == '0')
                        {
                            // strip off 0x
                            int x = input.Peek();
                            if (x == 'x' || x == 'X')
                            {
                                has0x = true;
                                if (val.Length > 0)
                                {
                                    parse = true;
                                }

                                // skip
                                input.Read();
                                col++;
                                break;
                            }
                        }
                        val.Append((char)ch);
                        if (!has0x && val.Length == 2)
                        {
                            parse = true;
                        }
                        break;
                }

                if (parse)
                {
                    count++;
                    byte result;
                    if (byte.TryParse(val.ToString(), NumberStyles.HexNumber,
                        CultureInfo.InvariantCulture, out result))
                    {
                        output.WriteByte(result);
                    }
                    else
                    {
                        Console.Error.WriteLine("Bad data at line {0} column {1}: {2}",
                            line, colStart, val);
                        return -1;
                    }
                    val.Clear();
                    colStart = 0;
                    parse = false;
                }

                if (ch == -1)
                {
                    break;
                }

                col++;
            }
            return count;
        }
    }

    class MainClass
    {
        public static void Main (string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine("Usage: cmd <input filename> <output filename>");
                return;
            }

            try
            {
                int count = HexToBin.Convert(args[0], args[1], Encoding.ASCII);
                Console.WriteLine("{0} bytes written to output file", count);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine(e.StackTrace);
            }
        }
    }

One thought on “Convert ASCII Hex text to binary

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s