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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
using namespace std;
struct Example
{
int index;
char name[16];
bool registered;
bool suspended;
};
void dumpExample(ostream& os, const char* var_name, const Example& ex)
{
os << "[Example : name = \"" << var_name << "\" size = " << sizeof(Example) << "]" << endl
<< "- index = " << ex.index << endl
<< "- name = " << ex.name << endl
<< "- registered = " << ex.registered << endl
<< "- suspended = " << ex.suspended << endl;
}
// wrap function with macro which uses stringizing operator
#define DUMP_EXPAMPLE(s, v) dumpExample(s, #v, v)
bool saveAsByteString(ostream& os, const unsigned char* pch, int size)
{
bool ret = true; // in real code, there would be error handling!
ostream::fmtflags old_flags = os.flags();
char old_fill = os.fill();
os << hex << setfill('0');
// could break line every 16/? bytes?
for(int idx = 0; size > idx; ++idx)
{
if(0 < idx)
os << ' ';
// force output to use hex version of ascii code
os << "0x" << setw(2) << static_cast<int>(pch[idx]);
}
os.flags(old_flags);
os.fill(old_fill);
return ret;
}
bool readAsByteString(istream& is, unsigned char* pch, int size)
{
bool ret = true; // in real code, there would be more error handling!
// get the line we want to process
// could handle multi-line easy enough
string line;
getline(is, line); // error not handled, etc
istringstream iss_convert(line);
iss_convert >> hex;
// read in unsigned ints, as wrote out hex version of ascii code rather
// than the actual char (some of which would have been control
// codes, etc)
unsigned int u = 0;
int idx = 0;
while((iss_convert >> u) && (idx < size) && ret)
{
if((0x00 <= u) && (0xff >= u))
pch[idx++] = static_cast<unsigned char>(u);
else
ret = false;
}
// if nothing went wrong in the loop, make sure we got the right
// number of bytes.
if(ret)
{
ret = iss_convert.eof() && (size == idx);
}
return ret;
}
// Test using stringstream as too lazy to code file reading...
void Test()
{
bool ret = false;
const Example ex = {
11, // index;
"Tintin", // name
true, // registered;
false // suspended;
};
cout << "Start:" << endl
<< endl;
DUMP_EXPAMPLE(cout, ex);
cout << endl;
ostringstream oss;
cout << "=> saveAsByteString()" << endl;
ret = saveAsByteString(oss, reinterpret_cast<const unsigned char*>(&ex), sizeof(Example));
cout << endl;
if(ret)
{
cout << "Ok!" << endl
<< endl;
string result = oss.str();
// to force failure
//result += " 0x66 0x60"; // too long
//result.resize(result.length() - 4); // too short
// Note: if you loose only a bit of the last byte
// e.g. 0xC cf 0xCC then error is not detected.
// Prob need to write the lenth of the string to file
// so can check it's all read back. Or use explicit
// markers for begin and end of data?
cout << "Result:" << endl
<< endl
<< result << endl
<< endl;
istringstream iss(result);
Example chk = {0};
cout << "=> readAsByteString()" << endl;
ret = readAsByteString(iss, reinterpret_cast<unsigned char*>(&chk), sizeof(Example));
cout << endl;
if(ret)
{
cout << "Ok!" << endl
<< endl;
cout << "Do structs match? = " << (0 == memcmp(&ex, &chk, sizeof(Example))) << endl
<< endl;
cout << "Check:" << endl
<< endl;
DUMP_EXPAMPLE(cout, chk);
cout << endl;
}
else
{
cerr << "Erk!" << endl
<< "readAsByteString failed?" << endl;
}
}
else
{
cerr << "Erk!" << endl
<< "saveAsByteString failed?" << endl;
}
cout << "Done." << endl;
}
int main()
{
cout << boolalpha;
Test();
return 0;
}
|