Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Binary Inspector

0.00/5 (No votes)
24 Mar 2016 1  
A Windows Forms Application that can open, view and edit binary files in a simple way

Introduction

The Binary Inspector is a simple Windows Forms application that can open binary files and display its content in a clear way. It also allows to edit the binary file. It is limited to read files up to 10KB size, since it wasn't designed for larger files. I've seen similar tools doing this to find text and provide ways to do translations from ROMs files used by old videogames emulators. I thought that this application could turn out to be such a tool.

Download it! or get the source code.
Requirements: Windows Vista*, Seven, Eight, 10.
* Framework .NET 4.5 must be installed.

Background

Five years ago, I wrote an article about a multiple base number editor component. I developed this application soon after that. Back then, I was requested to open and read a binary file and I couldn't find a free tool that would do that in such a simple way. I also needed the address of every byte I wanted to inspect. At the end, if I could open and inspect the file in different views, why not allow to edit it too? I could add my multiple base number editor and put it to good use.

I regret that I haven't written this earlier. Recently, I decided to recover my old code and projects, and resurrect them. This project was originally developed with Visual Studio 2010 Express, Windows Forms and .NET Framework 3.5, now I'm updating using Visual Studio 2015 Community to .NET Framework 4.0. I'd like to pin point a few interesting snippets I used. The full source code is available for download. Figure 1 below presents how it looks like:

Figure 1: Main window

Figure 1

The initial idea was to keep it simple and easy to use. Now I see there are other tools that can do that, I'll mention the HexEdit. I think it is a complete tool with a lot of features.

Using the Code

The core function is displaying the list of bytes as numbers (decimal, hexadecimal, binary or octet base). To do that, the first thing to do is to open a file. Any type of file will do, it can be an image or a text file. The code snippet below depicts how the file was opened. The file content is stored in the array variable I called bytes and then a call to the method displayBytes(). Whenever the binary data needs to be rendered in the text box, there is a call to displayBytes().

if (dialogResult == DialogResult.OK) {
  if (File.Exists(openFileDialog1.FileName)) {
    fileStream = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read);
    // Limits the size of files this application can open and display.
    if (fileStream.Length < 10000) {
        bytes = ReadFully(fileStream);

        displayBytes();
        // ...
    }
    else
      txtBinary.Text = "File is too large";
  }
}

With the use of some math and logic, I present the binary data in the text box. Some options are set by the user, that are: display bytes as hexadecimal, display tips, use break lines, try to convert to ASCII Character, display information when mouse moves over and Auto select when mouse moves. To do the rendering, the code below does all the magic.

private void displayBytes() {
  char validChar;
  int padlef = cbHexadecimal.Checked ? 2 : 3;

  txtBinary.Clear();

  if (bytes == null)
    return;

  StringBuilder text = new StringBuilder();
  for (int i = 0; i < bytes.Length; i++) {

    if (UseBytesPerLine && i != 0 && (i % options.BytesPerLine == 0))
      text.AppendLine();

    if (options.ConvertCharacter)
      if (tryGetChar(bytes[i], out validChar)) {
        text.Append(validChar.ToString().PadLeft(padlef));
        text.Append(" ");
        continue;
      }

    if (cbHexadecimal.Checked) {
      text.Append(bytes[i].ToString("X").PadLeft(2, '0'));
    }
    else
      text.Append(bytes[i].ToString().PadLeft(3, ' '));

    text.Append(" ");
  }
  txtBinary.Text = text.ToString();

  updateAddress();
}

After that, the updateAddress() is called to fill the first byte address position for each line. That is all calculated based on the options set by the user. See how that is done in the code below.

private void updateAddress() {
    txtAddress.Clear();
    int height;
    height = 0;
    int charIndex = txtBinary.GetCharIndexFromPosition(new Point(0, height));
    int charIndexFromLastLine = txtBinary.GetCharIndexFromPosition
                    (new Point(0, txtBinary.Height - 2));
    int lastLine = txtBinary.GetLineFromCharIndex(charIndexFromLastLine);
    int breaklineCount = Environment.NewLine.Length;
    StringBuilder addresses = new StringBuilder();
    for(int i = 0; i < lastLine - 1; i++) {
      height = txtBinary.Font.Height * i + 1;
      charIndex = txtBinary.GetCharIndexFromPosition(new Point(1, height));
      if(options.UseBreakLine)
        charIndex -= breaklineCount * i; // Do not count the breakline characters
      int calculatedByteIndex = -1;
      if (options.DisplayHexadecimal) {
        // When displaying hexadecimal every byte occupy up to 2 characters 0 - FF.
        // Between every byte there is a space. Based on this information,
                    // the index on the byte array for the char index from the text area will be:
        calculatedByteIndex = charIndex / 3;
      }
      else {
        calculatedByteIndex = charIndex / 4;
      }
        addresses.AppendLine((calculatedByteIndex).ToString("X"));

    } // for
    txtAddress.Text = addresses.ToString();
}

The text box GetCharIndexFromPosition method is used to get the current character position given a screen relative point. Note that the GetCharIndexFromPosition method considers break lines as character and so the charIndex value needs to be adjusted. The text box font height is used to define each line height. The addresses are calculated only for the visible text. If Inspector is displaying hexadecimal values, it calculates considering each byte using 3 characters, otherwise 4 characters. Then the bytes can be counted, if I get the position of the first byte for each row (charIndex) and divide it by 3 or 4, depending on if it is displaying Decimal or Hexadecimal value, I get its addresses per row.

Besides all that, I used several resources to add features that improves the GUI. I consider it would be too extensive to go into details of all of them here. I'll just point them below. If you are a student and are trying to learn how to do any of these, please take a look into the source code to see how it was implemented. If you have any doubt, feel free to contact me.

Points of Interest

  • I've added the model.Options to use the DataBindings from the user controls. The options define how the applications behave and present its data. The user can change the options in the form called OptionsView.
  • The options are loaded and stored to a user settings file located at special folder Application.LocalUserAppDataPath.
  • Added tool tips to most of GUI components, and the user can turn it on or off.
  • There is an option to display the current byte info in the StatusTrip of the byte the mouse pointer is over at.
  • Double click over a byte position displays the EditByte form which uses the Multiple Base Number Editor component and allow the user to change that selected byte.
  • A documentation was generated using Doxygen tool.

Future Work

  • Upgrade to .NET Framework 4.6.1
  • Add user help tool (the question mark)
  • Add multiple language support using resource files
  • Create similar control for web-application

History

  • 2010 - This code was first written
  • 2016 - I decided to update, publish it and write about it

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here