Easiest way to read binary data from std :: vector <unsigned char>?
I have a piece of binary data in a form const std::vector<unsigned char>, and you want to be able to extract individual fields from it, such as 4 bytes for an integer, 1 for booleans, etc. It should be as effective and simple as possible. eg. It should be able to read data in place without the need for copying it (for example, to a string or array). And it should be able to read one field at a time, for example, a parser, since a piece of data does not have a fixed format. I already know how to determine which type of field to read in each case - the problem is that it uses a useful interface on top std::vector.
However, I cannot find an easy way to get this data in an easily accessible form that gives me useful reading functions. eg. std::basic_istringstream<unsigned char>gives me a read interface, but it seems to me that I need to copy the data to a temporary one first std::basic_string<unsigned char>, which is not an idea for large data blocks.
There may be some way to use streambuf in this situation to read data in place, but it seems I would need to create my own streambuf class for this.
It seems to me that I can probably just use sscanf for vector data (), and this will seem shorter and more efficient than alternatives to the standard C ++ library. EDIT: Having been reminded that sscanf is not doing what I mistakenly thought it was, I really don't know how to do this in C or C ++. But I'm missing something, and if so, then what?
You have access to the data in the vector through it operator[]. Vector data is stored in one continuous array, and []returns a link to an element of this array. You can use this link directly or through memcpy.
std::vector<unsigned char> v;
...
byteField = v[12];
memcpy(&intField, &v[13], sizeof intField);
memcpy(charArray, &v[20], lengthOfCharArray);
EDIT 1: If you want something “more convenient” that you can try:
template <class T>
ReadFromVector(T& t, std::size_t offset,
const std::vector<unsigned char>& v) {
memcpy(&t, &v[offset], sizeof(T));
}
Using:
std::vector<unsigned char> v;
...
char c;
int i;
uint64_t ull;
ReadFromVector(c, 17, v);
ReadFromVector(i, 99, v);
ReadFromVector(ull, 43, v);
EDIT 2:
struct Reader {
const std::vector<unsigned char>& v;
std::size_t offset;
Reader(const std::vector<unsigned char>& v) : v(v), offset() {}
template <class T>
Reader& operator>>(T&t) {
memcpy(&t, &v[offset], sizeof t);
offset += sizeof t;
return *this;
}
void operator+=(int i) { offset += i };
char *getStringPointer() { return &v[offset]; }
};
Using:
std::vector<unsigned char> v;
Reader r(v);
int i; uint64_t ull;
r >> i >> ull;
char *companyName = r.getStringPointer();
r += strlen(companyName);
, , . :
struct MyData {
int intVal;
bool boolVal;
char[15] stringVal;
} __attribute__((__packed__));
// assuming all extracted types are prefixed with a one byte indicator.
// Also assumes "vec" is your populated vector
int pos = 0;
while (pos < vec.size()-1) {
switch(vec[pos++]) {
case 0: { // handle int
int intValue;
memcpy(&vec[pos], &intValue, sizeof(int));
pos += sizeof(int);
// do something with handled value
break;
}
case 1: { // handle double
double doubleValue;
memcpy(&vec[pos], &doubleValue, sizeof(double));
pos += sizeof(double);
// do something with handled value
break;
}
case 2: { // handle MyData
struct MyData data;
memcpy(&vec[pos], &data, sizeof(struct MyData));
pos += sizeof(struct MyData);
// do something with handled value
break;
}
default: {
// ERROR: unknown type indicator
break;
}
}
}