Reputation: 4114
I have a binary file that is created by an open source application that is written in C. Since it is open source I can see how the data is structured when it is written to the file. The problem is that I don't know C, but I can at least mostly tell what is going when the structs are being declared. But from what I've seen in other posts it isn't a simple as creating a struct in C# with the same data types as the ones in C.
I found this post https://stackoverflow.com/a/3863658/201021 which has a class for translating structs but (as far as I can tell) you need to declare the struct properly in C# for it to work.
I've read about the MarshalAs attribute and the StructLayout attribute. I mostly get how you would use them to control the physical structure of the data type. I think what I'm missing are the details.
I'm not asking for somebody to just convert the C data structures into C#. What I'd really like is some pointers to information that will help me figure out how to do it myself. I have another binary file in a slightly different format to read so some general knowledge around this topic would be really appreciated.
How do you convert a C data structure to a C# struct that will allow you to read the data type from a file?
Notes: Specifically I'm trying to read the rstats and cstats files that are output by the Tomato router firmware. This file contains bandwidth usage data and ip traffic data.
The C code for the data structure is (from rstats.c):
#define MAX_COUNTER 2
#define MAX_NSPEED ((24 * SHOUR) / INTERVAL)
#define MAX_NDAILY 62
#define MAX_NMONTHLY 25
typedef struct {
uint32_t xtime;
uint64_t counter[MAX_COUNTER];
} data_t;
typedef struct {
uint32_t id;
data_t daily[MAX_NDAILY];
int dailyp;
data_t monthly[MAX_NMONTHLY];
int monthlyp;
} history_t;
typedef struct {
char ifname[12];
long utime;
unsigned long speed[MAX_NSPEED][MAX_COUNTER];
unsigned long last[MAX_COUNTER];
int tail;
char sync;
} speed_t;
Upvotes: 1
Views: 1595
Reputation: 4804
I'm not an ANSI C programmer either but, at first glance at the source file, it appears to be saving data into a .gz file and then renaming it. The open function decompresses it with gzip. So, you might be looking at a compressed file at the top layer.
Once you know that you are dealing with the raw file, it looks like the best place to start is the load(int new)
function. You need to figure out how to reverse engineer whats going on. If you get lost, you may have to learn how some of the native C function calls work.
The first interesting line is:
if (f_read("/var/lib/misc/rstats-stime", &save_utime, sizeof(save_utime)) != sizeof(save_utime)) {
save_utime = 0;
}
In scanning the file save_time is declared as a long. In C, that is a 32-bit number so int is the C# equivalent. Given it's name, it seems to be a time-stamp. So, the first step appears to be to read in a 4-byte int.
The next interesting piece is
speed_count = decomp(hgz, speed, sizeof(speed[0]), MAX_SPEED_IF);
In the save
function it saves speed
as an array of size_t
structs with sizeof() * count
type behavior. But, it doesn't save
the actual count. Since it passes MAX_SPEED_IF
(which is defined as = 10) into decomp
from the load
function, it makes sense to see what it's doing in decomp
. In looking, it seems that it tries to read( ... size * max)
(a.k.a. size * MAX_SPEED_IF
) and depends on the return value from the read
library function to know how many size_t structures were actually saved.
From there, it's just a matter of reading in the correct number of bytes for the number of size_t structures written. Then, it goes on to load the history data.
This is the only approach I can think to reverse engineer a binary file while referencing the source code and porting it to a different language all at the same time.
BTW. I'm only offering my help. I could be totally wrong. Like I said, I'm not an ansi c guy. But, I do hope that this helps get you going.
Upvotes: 1
Reputation: 709
I think your first link https://stackoverflow.com/a/3863658/201021 is a good way to follow. So I guess the next thing would be constructing a C# struct to map C struct. Here is the map for different types from MSDN http://msdn.microsoft.com/en-us/library/ac7ay120(v=vs.110).aspx
Cheers!
Upvotes: 2
Reputation: 5697
The short answer is that you probably cannot do this automatically, at least at runtime. Knowing how many C programs are written, there's little chance of any meta-data being in the file. Even if there is, you need to address that as "a program that reads data with meta-data in this format". There are also all sorts of subtleties such as word length, packing etc.
Just because the two languages have "C" in the name does not make them magically compatible I am afraid. I fear you need to write a specific program for each file type and as part of that, re-declare your structures in C#
Upvotes: 0