Skip to main content
GameDev.net gamedev.net
🔒 Locked

Reading from byte array

Started by Calneon Nov 24, 2011 at 8:48 PM 9 replies 2.3k views
Original Post
Calneon
Calneon
I'm developing an app in Windows 8, there's an included function that reads a file into a byte array, and I'm trying to then read data from that byte array and I'm not sure how it's done. The data is plaintext (.obj file), is there a way to read in this data like you were reading from a file using ifstream? Thanks for any help.
rip-off
rip-off
You could dump the data into a stringstream.
the_edd
the_edd
Or write a custom stream buffer (possibly overkill when the stringstream option's on the table).

FWIW, I have literally been doing the exact same thing this last hour (reading OBJ data that's embedded inside my demo executables!) and I went with the stringstream approach. An extra copy of the data is needed, but it works just fine.
Calneon
Calneon

You could dump the data into a stringstream.


Ah, I didn't know that existed, thanks! I might try that.
SiCrane
SiCrane

An extra copy of the data is needed, but it works just fine.

If you want to avoid the extra copy you can try using strstream. It's deprecated, but allows you to work with an existing buffer.
BradBobak_68669
BradBobak_68669
This is what I've used and it seems to work ok.
Basically you do a charstream ch(your_array_ptr, your_array_size), then you can use whatever an istream allows for input (operator <<), etc. The array must be in scope until you are done with ch.


#include <streambuf>
#include <istream>

class charstreambuf : public std::streambuf
{
public:
charstreambuf(char const *data_, size_t size_)
{
char *data = const_cast< char * >(data_);
std::streambuf::setg(data, data, data + size_);
}
};

class charstream : public std::istream
{
private:
charstreambuf cs_buf;

public:
charstream(char const *data_, size_t size_)
: cs_buf(data_, size_), std::istream(0)
{
std::istream::rdbuf(&cs_buf);
}
};
Hodgman
Hodgman
Using streams seems like complete overkill to me (IMHO).
You can just cast the byte array to whatever type you want to "read" from it.
struct ObjHeader { .... };
byte* myArray = ...;
ObjHeader* myHeader = (ObjHeader*)myArray;//read a value from the "byte stream"
myArray += sizeof( ObjHeader );//increment my "byte iterator"
[edit]Oh, I missed the part where the bytes are actually text, oops unsure.gif
Calneon
Calneon
Just finished, this is the code I'm using at the moment, seems to work well. Haven't tested multiple vertex groups yet (.obj model file).

std::stringstream ss (std::stringstream::in | std::stringstream::out);
char input;
int i = 0;

// Create the vectors to hold the position, normal, and texture values.
std::vector<float3> Pos;
std::vector<float3> Norm;
std::vector<float2> Tex;

// Create the vector to hold the vertex groups.
std::vector<Group> Groups;

// Add the byte array data to the stringstream.
ss << meshData;
ss.unsetf(std::ios_base::skipws);

// Crawl through the array until we reach the end.
do {
// Get the character at the start of the line.
ss >> input;

switch (input)
{
case '#': // Comment, ignore.
ss.ignore(256, '\n');
break;
case 'v':
{
ss >> input;
switch (input)
{
case ' ': // Vertex position.
{
float3 pos;
ss >> input >> pos.x >> input >> pos.y >> input >> pos.z;
ss.ignore(256, '\n');
Pos.push_back(pos);
break;
}
case 'n': // Vertex normal.
{
float3 norm;
ss >> input >> norm.x >> input >> norm.y >> input >> norm.z;
ss.ignore(256, '\n');
Norm.push_back(norm);
break;
}
case 't': // Vertex uv.
{
float2 tex;
ss >> input >> tex.x >> input >> tex.y;
ss.ignore(256, '\n');
Tex.push_back(tex);
break;
}
default:
ss.ignore(256, '\n');
break;
}
break;
}
case 'g': // Vertex group.
{
Group group;
ss >> input >> group.name;
ss.ignore(256, '\n');
ss >> input;
do {
Triangle triangle;
for (i = 0; i < 3; i++)
{
int num;
ss >> input >> num;
triangle.vertex.pos = Pos[num-1];
ss >> input >> num;
triangle.vertex.tex = Tex[num-1];
ss >> input >> num;
triangle.vertex.norm = Norm[num-1];
}
group.triangles.push_back(triangle);
ss.ignore(256, '\n');
ss >> input;
} while (input == 'f');
ss.ignore(256, '\n');
Groups.push_back(group);
break;
}
default:
ss.ignore(256, '\n');
break;
}
} while (!ss.eof());

Antheus
Antheus
ss.ignore(256, '\n');[/quote]

Copy paste is bad...

What happens if comment is longer than 256 characters?

There's a similar issue in Java using skip(), which is used incorrectly in just about all code, including standard library, though some of it was probably fixed.

ignore() is effectively useless for intended purpose since it doesn't offer a useful signal on result of operation. It should return number of characters skipped, so one knows what happened.

Using std::getline would be better for intended purpose.
rip-off
rip-off
Well ignore(std::numeric_limits::max(), '\n') should work. You can also test gcount() for the number of characters ignored, if that is important.
Calneon
Calneon

ss.ignore(256, '\n');


Copy paste is bad...

What happens if comment is longer than 256 characters?

There's a similar issue in Java using skip(), which is used incorrectly in just about all code, including standard library, though some of it was probably fixed.

ignore() is effectively useless for intended purpose since it doesn't offer a useful signal on result of operation. It should return number of characters skipped, so one knows what happened.

Using std::getline would be better for intended purpose.
[/quote]
Thanks for pointing that out, I'm using getline now .

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.