I am working on an emulation tool in windows.
On intercepting an application I landed up with a situation.
I have a c++ structure which has the following format
typedef struct node {
int open;
int version;
const unsigned long long * data;
char* flags;
} _node;
It is a handle to a binary file. I am doing API interception and I get this pointer from an internal API call being made by the application.
Also The data field in the structure above is a pointer to instances of two structures laid out contiguously. The two structures are as follows.
typedef struct header{
unsigned int open;
unsigned int version;
unsigned long long int length;
} _header;
typedef struct body{
unsigned int v1, v2, v3, v4, v5, v6, v7, v8, v9, v10;
unsigned long long int ll1, ll2;
} _body;
I am able to access and print the data field as follows.
_node* First=(node *)address;//Address is a pointer that i get from intercepting an application
_header* nodeHeader=(_header*)First->data;
char *bodyPtr=(char *)(nodeHeader+1);
_body* nodeBody=(_body *)(bodyPtr);
unsigned long long int offset=0;
while(!(nodeBody->v1 & 1) && offset< nodeHeader->length)
{
nodeBody=(_body*)(bodyPtr+offset);
offset=nodeBody->v2+nodeBody->v3;
}
I want to write the struct node instance into a text file and be able to read it back into a struct instance later. What is the best way to do it? I want an answer in c++
I want a c++ code because the code I am working on is in c++. The code i posted here has typedef because people who wrote the structure has written it in C.
If it would help, I need this data in the structure so I could emulate an application with my tool.Since some aspects of the structure are internal and are hidden from me, my best bet is to store the structure members and reconstruct it at a later time (emulation time)
I'm not sure I'm not getting the entire question context right, but here is a setup based on boost serialization:
Of course I opted for the C++ way
- using a std::pair or std::tuple to model a contiguously stored pair of structs (see
element_t
). 2
- I would actually prefer using a list of
element_t
instead of element_t*
. Regardless, it works both ways with this library
- I chose XML for clarity: the sample clearly shows what gets serialized and how duplicate (aliased) pointers get correctly treated and restored.
simple drop-in replacement for binary serialization instead of XML if preferred: s/xml_/binary_/g
does the trick! 1
You could also drop the NVL()
macros because binary serialization doesn't need named elements:
ar & NVP(version) & NVP(open) & NVP(length);
would become
ar & version & open & length;
as written, the sample leaks the data elements (just a demo, and I was trying several things; I decided on using pointers only to match your question more closely)
1 oops, almost forgot about std::ios:binary on opening you fstreams!
2Note that for particular in-memory layout you may need to tinker with a struct using #pragma
to achieve proper aligment/padding. That is beyond the scope of my answer
Oh, compile with
g++ -O2 -g test.cpp -lboost_serialization
Tested with boost v.1_42 through boost v.1_47
#include <boost/serialization/list.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <fstream>
#include <string>
#define NVP BOOST_SERIALIZATION_NVP // name-value pairs
struct header
{
unsigned int open;
unsigned int version;
unsigned long long int length;
header() : open(1), version(2), length(3) {}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int archversion)
{
ar & NVP(version) & NVP(open) & NVP(length);
}
};
struct body
{
unsigned int iv[20];
unsigned long long int ll1, ll2;
body() : ll1(1), ll2(2)
{
for (int i=0; i<20; i++)
iv[i] = i;
}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int archversion)
{
ar & NVP(ll1) & NVP(ll2) & NVP(iv);
}
};
typedef std::pair<header, body> element_t;
struct node
{
int open;
int version;
std::list<element_t*> data;
std::string flags;
node() : open(1), version(2), flags("hello") { }
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int archversion)
{
ar & NVP(version) & NVP(open) & NVP(flags) & NVP(data);
}
};
int main()
{
node anode;
anode.data.push_back(new element_t(header(), body()));
element_t* duplicated = new element_t(header(), body());
anode.data.push_back(duplicated);
anode.data.push_back(new element_t(header(), body()));
anode.data.push_back(duplicated);
{
std::ofstream ofs("/tmp/test.xml");
boost::archive::xml_oarchive archive(ofs);
archive << NVP(anode);
ofs.flush();
ofs.close();
}
return 0;
{
std::ifstream ifs("/tmp/test.xml");
boost::archive::xml_iarchive archive(ifs);
node deserialized;
archive >> NVP(deserialized);
}
return 0;
}
Here is the sample output (test.xml)
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="9">
<anode class_id="0" tracking_level="0" version="0">
<version>2</version>
<open>1</open>
<flags>hello</flags>
<data class_id="1" tracking_level="0" version="0">
<count>4</count>
<item_version>0</item_version>
<item class_id="2" tracking_level="1" version="0" object_id="_0">
<first class_id="3" tracking_level="0" version="0">
<version>2</version>
<open>1</open>
<length>3</length>
</first>
<second class_id="4" tracking_level="0" version="0">
<ll1>1</ll1>
<ll2>2</ll2>
<iv>
<count>20</count>
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
</iv>
</second>
</item>
<item class_id_reference="2" object_id="_1">
<first>
<version>2</version>
<open>1</open>
<length>3</length>
</first>
<second>
<ll1>1</ll1>
<ll2>2</ll2>
<iv>
<count>20</count>
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
</iv>
</second>
</item>
<item class_id_reference="2" object_id="_2">
<first>
<version>2</version>
<open>1</open>
<length>3</length>
</first>
<second>
<ll1>1</ll1>
<ll2>2</ll2>
<iv>
<count>20</count>
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
</iv>
</second>
</item>
<item class_id_reference="2" object_id_reference="_1"></item>
</data>
</anode>