Reading offsets from a predefined text file

Jun 5, 2008 at 5:58pm
I want to know how to read an offset from a header file that is NOT included in the source code. For example if the header file was..

1
2
3
#define               Offset1           0x183A3C
#define               Offset2           0x382DA4
#define               Offset3           0x442AAB 


I would want to know how to copy the 0x183A3C from Offset1, the 0x382DA4 from Offset2 and the 0x442AAB from Offset3. So I could do something like this..

1
2
3
4
5
6
7
VOID ConvertToINI() {
char Offset1;
//code I need to make Offset1 = to how it is defined in the header file (0x183A3C)

WritePrivateProfileString( "Updates", "Offset One", Offset1, "C:/OffsetUpdates.ini" );
system("pause");
}


I would want that to make C:/OffsetUpdates.ini look like this..

1
2
[Updates]
Offset One = 0x183A3C


Again, I want to be able to read these offsets without having to INCLUDE the header file.
Last edited on Jun 5, 2008 at 6:05pm
Jun 5, 2008 at 6:32pm
Just read it using the hex manipulator.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
...
ifstream inf( ... );
...
string pp_define, offset_n;
unsigned offset_value, offset_number;

inf >> pp_define;
if (pp_define == "#") inf >> pp_define;

inf offset_n >> hex >> offset_value;
{
stringstream ss( offset_n.substr( offset_n.find_first_of( "0123456789" ) ) );
ss >> offset_number;
}

cout << "Offset number " << offset_number
     << " is at " << hex << offset_value
     << " (" << offset_value << " decimal)\n";


The extra stuff with the pp_define is for the case that the file uses
# define Offset1 0xABCDEF

as some people are wont to do (note the space between '#' and 'define').

Hope this helps.
Last edited on Jun 5, 2008 at 6:33pm
Jun 5, 2008 at 9:37pm
Sent you a PM.
Jun 5, 2008 at 9:42pm
Got it. I assumed you were using C++, but it looks like you are using C, which is what is causing the compile problems.

I'll look it over and PM you back with the results.

(For those reading, Sever3 wants to keep his proprietary code offline. I'll post the basic solution here when done, but nothing of Sever3's.)
Jun 5, 2008 at 10:13pm
Thanks Duoas, appreciate the support and I'll be waiting for your PM.
Jun 6, 2008 at 1:19am
Alrighty, now for the stuff you want to know.

I will assume that your file may contain any data, but that the following
conditions hold:

1. The offset has a unique name.
2. The offset is found on a line of the form:
" # define NAME 0xN..N [...]"

(Sorry, I had to put those double-quotes in there to preserve spaces)

So we will need to assume one thing:

1. The name of the desired offset is known beforehand

This isn't a big deal because you have to know the name of the offset anyway...

Now for some structure. Let's keep the offsets in an enumerated array:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* The following enumeration is ALPHABETIZED, and MUST match the following
   array.
 */
typedef enum  {
  AFewMountSkills,
  ARandomOffsetName,
  ...
  NUMBER_OF_OFFSETS
  }
  offset_names_t;

typedef struct {
  char* const name;   /* everything about name is immutable */
  long        value;  /* the value to get from the file     */
  }
  offset_t;

offset_t offsets[ NUMBER_OF_OFFSETS ] = {
  { "AFewMountSkills",   -1 },
  { "ARandomOffsetName", -1 },
  ...
  };

What this does for us is allow us to access offset data by name.

1
2
3
4
5
6
WritePrivateProfileString(
  "Updates",
  offsets[ AFewMountSkills ].name,
  offsets[ AFewMountSkills ].value,
  "C:/OffsetUpdates.ini"
  );


OK, now to find specific offsets in the file. Going on the (rather loose) conditions on the structure of the .h that I listed above, we cannot scan the file sequentially for offset values. Rather, we must ask for them by name, and test each line for a match.

Since random file access is rather slow, I would normally just load the whole thing into memory and analyze it there. However, since that complicates things a little and there are so few offsets to process, we'll just access it directly on disk. This adds one requirement:

2. The file must be random access.

This isn't a big deal either.

First, since we're getting lines again, let's move that line-getting stuff with fgets() into a more convenient little function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* Get the next line from the file, maximum 80 characters.
   Extra characters are ignored.

   Returns a constant, static char buffer which is overwritten with each
   call (so if you want to save the result, strcpy() it to your own char
   array before using this function again).
 */
const char *getline( FILE* f )
  {
  static char line[ 81 ];
  unsigned    last_index;
  int         c;

  fgets( line, sizeof( line ), f );

  last_index = strlen( line ) -1;
  if (line[ last_index ] != '\n')
    while (((c = fgetc( stdin )) != EOF) && (c != '\n'));
  else
    line[ last_index ] = '\0';

  return line;
  }


Now to the dirty work. Search for a specificly-named offset. We must account for the possibility that it is not found. A simple routine to do just that:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* Find and return the named offset.
 * If not found, returns -1.
 * The argument name must not exceed 65 characters plus null terminator.
 */
long findoffset( FILE* f, const char* name )
  {
  const char* line;
  long        result              = -1;
  char        format_string[ 80 ] = " # define ";
  strncat( format_string, name, 65 );
  strcat(  format_string, " %lx" );

  fseek( f, 0, SEEK_SET );
  while (!feof( f ))
    {
    line = getline( f );
    if (sscanf( line, format_string, &result ) == 1)
      return result;
    }

  return (-1);  
  }


Now at last, you can fill your offsets tree. Again, a little function to do the job:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* Endeavors to load the named offsets from the file.
 * Accesses global data directly.
 *
 * Returns the number of offsets found.
 * If the file could not be opened, returns -1;
 */
int load_offsets( const char* filename )
  {
  FILE*    f;
  unsigned i;
  int      result = 0;
  long     n;

  f = fopen( filename, "r" );
  if (f == NULL) return -1;

  for (i = 0; i < NUMBER_OF_OFFSETS; i++)
    {
    n = offsets[ i ].value = findoffset( f, offsets[ i ].name )
    if (n >= 0)
      result++;
    }

  fclose( f );

  return result;
  }


Whew. I hope this has been helpful and instructive.

--Michael
Last edited on Jun 6, 2008 at 12:51pm
Topic archived. No new replies allowed.