Sign in to follow this  
FunkyTune

Copying part of a file to istream buffer

Recommended Posts

Basically, I have an ifstream object representing an open file. I want to copy a part of the data from this stream to a buffer in local memory, and then access the buffer through an istream object. I've tried with different combinations of streambuf's and stringstreams, but I just can't get it to work properly. Surely there must be a way to accomplish this in a non-ugly manner? /John

Share this post


Link to post
Share on other sites
If you could elaborate some more maybe with some code, for instance when you say copy part of a file exactly how much or what value indicates when to stop reading in? what is it your hoping to achieve (like parsing a string in memory to some particular type then stringstreams etc)? and what exactly was it you tried that didn't work? then we can give you better advice and/or maybe a better alternative.

[Edited by - snk_kid on November 8, 2004 3:53:37 PM]

Share this post


Link to post
Share on other sites
Thank you for the help! I really appreciate it.

So, what I'm trying to do is parse a MIDI file. The file is made up of chunks, each representing a MIDI track. Each track chunk consists of a header, followed by a number of midi events. The header contains the byte length of the chunk.

Now, what I want to do is to read only the chunk that I'm currently working with into a separate buffer, that I want to access through another istream object.
The reason for this is, so I don't read past the end of the track chunk, since it is hard to keep track of how many bytes different functions extract from the stream. With a limited stream, there is an exception thrown if i read past the end of the chunk.

Something like this (though this code doesn't work, of course):

ifstream midiFileStream("test.mid");

//Once for every track do this
for (....)
{
//Number of bytes in the track chunk
DWORD chunkLength = midiFileStream.get();

//Create a temp buffer and read data from midiFile into it
istream tempBufferStream;
midiFileStream.read(tempBufferStream, chunkLength)

//Perform actions with tempBufferStream, instead of midiFileStream
ReadFromStreamFunction(tempBufferStream);
}







I tried to create a streambuf object from a char array, which I filled with the chunk data, and then use that streambuf to create an istream object, but it only gives me -1 instead of the correct byte values when I call get().

Hope this explanation made things easier to understand...
It's a bit hard to explain in a simple way...

Share this post


Link to post
Share on other sites
Try using an istringstream object:

static char tempBuffer[1024]; // Make sure this is big enough to hold the largest chunk size; if you're unsure, make this dynamic instead of static
midiFileStream.read(tempBuffer, 1024);

istringstream tempBufferStream(tempBuffer);

ReadFromStreamFunction(tempBufferStream); // tempBufferStream is derived from istream, so this is kosher

Share this post


Link to post
Share on other sites
Quote:
Original post by FunkyTune
Thank you for the help! I really appreciate it.

So, what I'm trying to do is parse a MIDI file. The file is made up of chunks, each representing a MIDI track. Each track chunk consists of a header, followed by a number of midi events. The header contains the byte length of the chunk.

Now, what I want to do is to read only the chunk that I'm currently working with into a separate buffer, that I want to access through another istream object.
The reason for this is, so I don't read past the end of the track chunk, since it is hard to keep track of how many bytes different functions extract from the stream. With a limited stream, there is an exception thrown if i read past the end of the chunk.


i don't think its nessercary to open another stream for this, this whole idea about "chunks" is way to represent data that has a hierarchical structure (think of trees) in a binary file, much like xml is used to represent data that has a hierarchical structure in a text file. i looked up the midi file format and there is only 2 offical levels the header and the tracks and would like something like this:


MThd //<--------------------------------------------
| ^ ^
| | sub-chunk |
| | level 1 |
| | |
+---+--- (MTrk chunk) track 1 //<--|
| ^ |
| | sub-chunk level 2 |
+--- track 2 |
| |
| |Main chunk, the whole file
+--- track 3 |level 0
| |
| |
+--- track N - 1 |
| |
| |
+--- track N //<----------------------------------


As you can see from the rubbbish ascii art a the whole file can be considered a chunk and each sub-chunk is also a chunk, the way you would normally handle reading this is to recursively go into each level read a new chunk (but not data just 8 bytes chunk) in then have a switch statemenet check the chunk type and do the appropriate action such as if a paritcular sub-chunk has sub-chunks with-in it then recusively call the function again, its like your "traversing a tree" and the chunks are your tree nodes.

You can easily find & keep track how much you've read in aswell, you can find out the size of the file with the I/O streams lib e.g.


// get length of file:
in.seekg (0, ios::end);
length = is.tellg();
in.seekg (0, ios::beg);


and to find out how much you've currently read in std::istream::gcount will say how many bytes you've read after the last unformatted operation.

With this in mind you need a generic midi chunk structure that has the chunk id & the length the chunk plus how many bytes have currently been read to keep track of where you are:


typedef unsigned long dword;

struct midi_chunk {
char ID[4];
dword length; //<------ this member is stored in the file in big-endian byte-order
std::streamsize bytes_read; //<--- this member is a derived value not from the file
};


i think you should read this this there are some useful structures & functions and info on midi file format, i read that the midi file format stores its data in binary and most data is in big endian format so you must convert the order for your platform (PCs generally being little-endian), note also from what you've shown me you haven't opened your stream in binary mode.

EDIT: You can use these to convert big-endian to little endian:


typedef unsigned long dword;
typedef unsigned short word;

inline dword byte_swap(dword n) {

return (((n & 0x000000FF) << 24) + ((n & 0x0000FF00) << 8) +
((n & 0x00FF0000) >> 8) + ((n & 0xFF000000) >> 24));
}

inline word byte_swap(word n) {
return (((n >> 8)) | (n << 8));
}


[Edited by - snk_kid on November 8, 2004 7:06:31 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this