user2946437
user2946437

Reputation: 23

How to parse hex dump

I have a flash memory dump file that spits out addresses and data. I want to parse the data so that it will tell me the valid tags The '002F0900' column are the starting addresses. An example of a valid tag is "DC 08 00 06 00 00 07 26 01 25 05 09" where "DC 08" = tag number, "00 06" = tag data length, "00 00" = tag version. Tag data starts after the version and in this case would be "07 26 01 25 05 09" and the next tag would start "DC 33".

I'm able to print out the first tag up to the data length but I'm not sure how to print the data because I have to consider if the data will go onto the next line so I'd have to skip the address somehow. Each line contains 58 columns. Each address is 8 characters long plus a colon and 2 spaces until the next hex value starts.

I also will eventually have to consider when "DC" shows up in the address column. If anyone could give some advice because I know how I'm doing this isn't the best way to do this. I'm just trying to get it to work first.

The text file is thousands of lines that look like this:

002F0900:  09 FF DC 08 00 06 00 00 07 26 01 25 05 09 DC 33
002F0910:  00 07 00 00 1F A0 26 01 25 05 09 FF 9C 3E 00 08
002F0920:  00 01 07 DD 0A 0D 00 29 35 AD 9C 41 00 0A 00 01
002F0930:  07 DD 0A 0D 00 29 36 1C 1D 01 9C 40 00 02 00 01
002F0940:  01 00 9C 42 00 0A 00 01 07 DD 0A 0D 00 29 36 21
002F0950:  1D AD 9C 15 00 20 00 00 01 00 00 00 00 04 AD AE
002F0960:  C8 0B C0 8A 5B 52 01 00 00 00 00 00 FF 84 36 BA
002F0970:  4E 92 E4 16 28 86 75 C0 DC 10 00 05 00 00 00 00
002F0980:  00 00 01 FF DC 30 00 04 00 01 00 00 00 01 9C 41

Example output would be:

Tag Number: DC 08
Address: 002E0000    
Data Length: 06
Tag Data: 07 26 01 25 05 09

Source Code:

#include<stdio.h>
FILE *fp;

main()
{
    int i=0;
    char ch;
    char address[1024];
    char tag_number[5];
    char tag_length[4];
    int number_of_addresses = 0;
    long int length;

    fp = fopen(FILE_NAME,"rb");
    if(fp == NULL) {
        printf("error opening file");
    }
    else {
        printf("File opened\n");
        while(1){
            if((address[i]=fgetc(fp)) ==':')
                break;

            number_of_addresses++;
            i++;
        }

        printf("\nAddress:");
        for (i = 0; i < number_of_addresses;i++)
            printf("%c",address[i]);

        while((ch = fgetc(fp)) != 'D'){ //Search for valid tag
        }

        tag_number[0] = ch;
        if((ch = fgetc(fp)) == 'C')  //We have a valid TAG
        {
            tag_number[1] = ch;
            tag_number[2] = fgetc(fp);
            tag_number[3] = fgetc(fp);
            tag_number[4] = fgetc(fp);
        }

        printf("\nNumber:");
        for(i=0;i<5;i++)
            printf("%c",tag_number[i]);

        fgetc(fp);      //For space
        tag_length[0] = fgetc(fp);
        tag_length[1] = fgetc(fp);
        fgetc(fp);      //For space
        tag_length[2] = fgetc(fp);
        tag_length[3] = fgetc(fp);

        printf("\nLength:");

        for(i=0;i<4;i++)
            printf("%c",tag_length[i]);

        length = strtol(tag_length,&tag_length[4], 16);
        printf("\nThe decimal equilvant is: %ld",length);
        for (i = 0;i<165;i++)
            printf("\n%d:%c",i,fgetc(fp));
    }

    fclose(fp);
}

Update @ooga:The tags are written arbitrarily. If we also consider invalid tag in the logic then I should be able to figure out the rest if I spend some time. Thanks

Upvotes: 1

Views: 3113

Answers (1)

ooga
ooga

Reputation: 15501

This is just an idea to get you started since I'm not entirely sure what you need. The basic idea is that read_byte returns the next two-digit hex value as a byte and also returns its address.

#include <stdio.h>
#include <stdlib.h>

#define FILE_NAME "UA201_dump.txt"

void err(char *msg) {
  fprintf(stderr, "Error: %s\n", msg);
  exit(EXIT_FAILURE);
}

// read_byte
// Reads a single two-digit "byte" from the hex dump, also
// reads the address (if necessary).
// Returns the byte and current address through pointers.
// Returns 1 if it was able to read a byte, 0 otherwise.

int read_byte(FILE *fp, unsigned *byte, unsigned *addr_ret) {

  // Save current column and address between calls.
  static int column = 0;
  static unsigned addr;

  // If it's the beginning of a line...
  if (column == 0)
    // ... read the address.
    if (fscanf(fp, "%x:", &addr) != 1)
      // Return 0 if no address could be read.
      return 0;

  // Read the next two-digit hex value into *byte.
  if (fscanf(fp, "%x", byte) != 1)
    // Return 0 if no byte could be read.
    return 0;

  // Set return address to current address.
  *addr_ret = addr;
  // Increment current address for next time.
  ++addr;

  // Increment column, wrapping back to 0 when it reaches 16.
  column = (column + 1) % 16;

  // Return 1 on success.
  return 1;
}


int main() {
  unsigned byte, addr, afterdc, length, version, i;

  FILE *fp = fopen(FILE_NAME,"r");
  if (!fp) {
    fprintf(stderr, "Can't open %s\n", FILE_NAME);
    exit(EXIT_FAILURE);
  }

  while (read_byte(fp, &byte, &addr)) {
    if (byte == 0xDC) {

      // Read additional bytes like this:
      if (!read_byte(fp, &afterdc, &addr)) err("EOF 1");

      if (!read_byte(fp, &length, &addr)) err("EOF 2");
      if (!read_byte(fp, &byte, &addr)) err("EOF 3");
      length = (length << 8) | byte;

      if (!read_byte(fp, &version, &addr)) err("EOF 4");
      if (!read_byte(fp, &byte, &addr)) err("EOF 5");
      version = (version << 8) | byte;

      printf("DC: %02X, %u, %u\n  ", afterdc, length, version);
      for (i = 0; i < length; ++i) {
        if (!read_byte(fp, &byte, &addr)) err("EOF 6");
        printf("%02X ", byte);
      }
      putchar('\n');
    }
  }

  fclose(fp);
  return 0;
}

Some explanation:

Every time read_byte is called, it reads the next printed byte (the two-digit hex values) from the hex dump. It returns that byte and also the address of that byte.

There are 16 two-digit hex values on each line. The column number (0 to 15) is retained in a static variable between calls. The column is incremented after reading each byte and reset to 0 every time the column reaches 16.

Any time the column number is 0, it reads the printed address, retaining it between calls in a static variable. It also increments the static addr variable so it can tell you the address of a byte anywhere in the line (when the column number is not zero).

As an example, you could use read_bye like this, which prints each byte value and it's address on a separate line:

// after opening file as fp
while (read_byte(fp, &byte, &addr))
    printf("%08X- %02X\n", addr, byte);

(Not that it would be useful to do that, but to test it you could run it with the snippet you provided in your question.)

Upvotes: 2

Related Questions