How to receive a JPEG image over serial port - c++

So I am trying to send a jpeg image (4Kb) from a raspberry pi to my Mac wirelessly using Xbee Series 1. I have an image on the raspberry pi and can read it into binary format. I've used this binary format to save it into another image file and it creates a copy of the image correctly. That tells me that I am reading it correctly. So I am trying to send that data over a serial port (to be transferred by the xbee's) to my Mac. Side note, Xbee's can only transmit I think 80 bytes of data per packet or something. I don't know how that affects what I'm doing though.
My problem is, I do not know how to read the data and properly store it into a jpeg file itself. Most of the Read() functions I have found require you to enter a length to read and I don't know how to tell how long it is since its just a serial stream coming in.
Here is my code to send the jpeg.
#include "xSerial.hpp"
#include <iostream>
#include <cstdlib>
using namespace std;
int copy_file( const char* srcfilename, const char* dstfilename );
int main(){
copy_file("tylerUseThisImage.jpeg", "copyImage.jpeg");
return 0;
}
int copy_file( const char* srcfilename, const char* dstfilename )
{
long len;
char* buf = NULL;
FILE* fp = NULL;
// Open the source file
fp = fopen( srcfilename, "rb" );
if (!fp) return 0;
// Get its length (in bytes)
if (fseek( fp, 0, SEEK_END ) != 0) // This should typically succeed
{ // (beware the 2Gb limitation, though)
fclose( fp );
return 0;
}
len = ftell( fp );
std::cout << len;
rewind( fp );
// Get a buffer big enough to hold it entirely
buf = (char*)malloc( len );
if (!buf)
{
fclose( fp );
return 0;
}
// Read the entire file into the buffer
if (!fread( buf, len, 1, fp ))
{
free( buf );
fclose( fp );
return 0;
}
fclose( fp );
// Open the destination file
fp = fopen( dstfilename, "wb" );
if (!fp)
{
free( buf );
return 0;
}
// this is where I send data in but over serial port.
//serialWrite() is just the standard write() being used
int fd;
fd = xserialOpen("/dev/ttyUSB0", 9600);
serialWrite(fd, buf, len);
//This is where the file gets copied to another file as a test
// Write the entire buffer to file
if (!fwrite( buf, len, 1, fp ))
{
free( buf );
fclose( fp );
return 0;
}
// All done -- return success
fclose( fp );
free( buf );
return 1;
}
On the receive side I know I need to open up the serial port to read and use some sort of read() but I don't know how that is done. Using a serial library it has some functions to check if serial data is available and return the number of characters available to read.
One question about the number of characters available to read, will that number grow as the serial stream comes over or will it immediately tell the entire length of the data to be read?
But finally, I know after I open the serial port, I need read the data into a buffer and then write that buffer to a file but I have not had any luck. This is what I have tried thus far.
// Loop, getting and printing characters
char temp;
bool readComplete = false;
int bytesRead = 0;
fp = fopen("copyImage11.jpeg", "rwb");
for (;;)
{
if(xserialDataAvail(fd) > 0)
{
bytesRead = serialRead(fd, buf, len);
readComplete = true;
}
if (readComplete)
{
if (!fwrite(buf, bytesRead, 1, fp))
{
free(buf);
fclose(fp);
return 0;
}
fclose(fp);
free(buf);
return 1;
}
}
I don't get errors with my code, it just doesnt create the jpeg file correctly. Maybe I'm not transmitting it right, or maybe I'm not reading/writing to file correctly. Any help would be appreciated. Thanks everyone you rock!

If you are defining your own protocol, then you need to have a method for sending the length first.
I would recommend testing your code by sending short blocks of ascii text to confirm your i/o. Once that is working you can use the ascii to set up the transfer; ie send the length, and have your receiver ready for an expected block.

Related

Mounting memory buffer as a file without writing to disk

I have a server and needs to feed data from clients to a library; however, that library only supports reading files (it uses open to access the file).
Since the data can get pretty big, I rather not write it out to a temporary file, read it in with the library then delete it afterwards. Instead I would like to do something similar to a ramdisk where there's a file in which the content is actually in memory.
However, there can be multiple clients sending over large data, I don't think constantly calling mount and umount to create a ramdisk for each client is efficient. Is there a way for me to mount an existing memory buffer as a file without writing to disk?
The library does not support taking in a file descriptor nor FILE*. It will only accept a path which it feeds directly to open
I do have the library's source code and attempted to add in a function that uses fmemopen; however, fmemopen returns a FILE* with no file descriptor. The internals of the library works only with file descriptors and it is too complex to change/add support to use FILE*
I looked at mmap, but it appears to be no different than writing out the data to a file
Using mount requires sudo access and I prefer not to run the application as sudo
bool IS_EXITING = false;
ssize_t getDataSize( int clientFD ) { /* ... */}
void handleClient( int clientFD ) {
// Read in messages to get actual data size
ssize_t dataSize = getDataSize( clientFD );
auto* buffer = new char[ dataSize ];
// Read in all the data from the client
ssize_t bytesRead = 0;
while( bytesRead < dataSize ) {
int numRead = read( clientFD, buffer + bytesRead, dataSize - bytesRead );
bytesRead += numRead;
// Error handle if numRead is <= 0
if ( numRead <= 0 ) { /* ... */ }
}
// Mount the buffer and get a file path... How to do this
std::string filePath = mountBuffer( buffer );
// Library call to read the data
readData( filePath );
delete[ ] buffer;
}
void runServer( int socket )
while( !IS_EXITING ) {
auto clientFD = accept( socket, nullptr, nullptr );
// Error handle if clientFD <= 0
if ( clientFD <= 0 ) { /* ... */ }
std::thread clientThread( handleClient, clientFD );
clientThread.detach( );
}
}
Use /dev/fd. Get the file descriptor of the socket, and append that to /dev/fd/ to get the filename.
If the data is in a memory buffer, you could create a thread that writes to a pipe. Use the file descriptor of the read end of the pipe with /dev/fd.

creating/opening file on disk returns EAGAIN

As title says I'm getting this error while trying to open file for binary writing(mode doesnt seem matter).
My app uses libev to handle sockets(non blocking/epoll backend) and while parsing client packets i want at some point where i receive fileupload message to start writing down to disk data i get from server.
I couldn't google anything about EAGAIN(Resource temporarily unavailable) message and file opening..
These are methods I've tried:
fopen( ... ) returns EAGAIN
using ofstream/fstream's open(...) by creating them on heap(new) returns EAGAIN
using ofstream/fstream's open(...) staticly as class member (ofstream m_ofFile;) works, but strangly compiler generates code which calls ofstream destructor and closes file before exiting class method im calling .open from. Now that contradicts with my C++ knowledge where for class members which are class types, destructors are called right before class owner's..
edit:
#Joachim
You're right, I'm not acually getting this error..(method #1. gonna test method #2 again soon). File opens regulary and i get regular FILE*. That happens in Init(...) function of my class, but then when I call OnFileChunk later on m_hFile is 0 and therefor i cant write to it. Here is complete class code:
class CFileTransferCS
{
wstring m_wszfile;
wstring m_wszLocalUserFolderPath;
int m_nChunkIndex;
int m_nWrittenBytes;
int m_nFileSize;
FILE* m_hFile;
CFileTransferCS( const CFileTransferCS& c ){}
CFileTransferCS& operator=( const CFileTransferCS& c ){}
public:
CFileTransferCS( );
CFileTransferCS( wstring file, uint32_t size );
void OnFileChunk( char* FileChunk, int size );
void Init( wstring file, uint32_t size );
void SetLocalUserLocalPath( wstring path );
};
CFileTransferCS::CFileTransferCS( )
{
m_hFile = NULL;
m_wszLocalUserFolderPath = L"";
m_nChunkIndex = 0;
m_nWrittenBytes = 0;
}
CFileTransferCS::CFileTransferCS( wstring file, uint32_t size )
{
m_nChunkIndex = 0;
m_nWrittenBytes = 0;
m_wszfile = file;
m_nFileSize = size;
wstring wszFullFilePath = m_wszLocalUserFolderPath + m_wszfile.substr( m_wszfile.find_last_of(L"\\") + 1 );
// string fp = string( file.begin(),file.end() );
string fp ="test.bin"; //for testing purposes
this->m_hFile = fopen(fp.c_str(),"wb");
printf("fp: %s hFile %d\n",fp.c_str(),this->m_hFile); //everything's fine here...
if(!this->m_hFile)
{
perror ("cant open file ");
}
}
void CFileTransferCS::SetLocalUserLocalPath( wstring path )
{
m_wszLocalUserFolderPath = path;
}
void CFileTransferCS::Init( wstring file, uint32_t size )
{
// If previous transfer session got interrupted for whatever reason
// close and delete old file and open new one
if( this->m_hFile )
{
printf("init CS transfer: deleting old file///\n");
fclose( this->m_hFile );
string fp = string( file.begin(),file.end() );
if( remove( fp.c_str() ))
{
//cant delete file...
}
}
CFileTransferCS( file, size );
}
void CFileTransferCS::OnFileChunk( char* FileChunk, int size )
{
for (;;)
{
printf("ofc: hFile %d\n",this->m_hFile); //m_hFile is 0 here...
if( !this->m_hFile )
{
// m_pofFile->open("kurac.txt",fstream::out);
printf("file not opened!\n");
break;
}
int nBytesWritten = fwrite( FileChunk, 1, size, this->m_hFile );
if( !nBytesWritten )
{
perror("file write!!\n");
break;
}
m_nWrittenBytes+=size;
if( m_nWrittenBytes == m_nFileSize )
{
fclose( m_hFile );
printf("file uplaod transfer finished!!!\n");
}
break;
}
printf("CFileTransferCS::OnFileChunk size: %d m_nWrittenBytes: %d m_nFileSize: %d\n",size,m_nWrittenBytes,m_nFileSize);
}
final edit:
I got it.. Calling explicitly CFileTransferCS( wstring file, uint32_t size ) constructor made problems.. Calling constructor like this explicitly caused that this pointer in it wasnt original one(that Init function was using) so when i was opening file from it and saving handle to m_hFile, i was doing it in some other object(now im not sure if CFileTransferCS(..) call allocated memory for CFileTransferCS object or it corrupted some other part of memory randomly.. will check it out with IDA later on )
Thanks to everyone and my apologies.
Regards, Mike –
#MikeJacksons answer:
Calling explicitly CFileTransferCS( wstring file, uint32_t size ) constructor made problems. Calling constructor like this explicitly caused that this pointer in it wasnt original one(that Init function was using) so when i was opening file from it and saving handle to m_hFile, i was doing it in some other object(now im not sure if CFileTransferCS(..) call allocated memory for CFileTransferCS object or it corrupted some other part of memory randomly.. will check it out with IDA later on ) Thanks everyone and my apologies.
Removed: CFileTransferCS( file, size );
(No need to appologize Mike, looks like you did a great job hunting down the bug).

Libzip - read file contents from zip

I using libzip to work with zip files and everything goes fine, until i need to read file from zip
I need to read just a whole text files, so it will be great to achieve something like PHP "file_get_contents" function.
To read file from zip there is a function "int
zip_fread(struct zip_file *file, void *buf, zip_uint64_t nbytes)".
Main problem what i don't know what size of buf must be and how many nbytes i must read (well i need to read whole file, but files have different size). I can just do a big buffer to fit them all and read all it's size, or do a while loop until fread return -1 but i don't think it's rational option.
You can try using zip_stat to get file size.
http://linux.die.net/man/3/zip_stat
I haven't used the libzip interface but from what you write it seems to look very similar to a file interface: once you got a handle to the stream you keep calling zip_fread() until this function return an error (ir, possibly, less than requested bytes). The buffer you pass in us just a reasonably size temporary buffer where the data is communicated.
Personally I would probably create a stream buffer for this so once the file in the zip archive is set up it can be read using the conventional I/O stream methods. This would look something like this:
struct zipbuf: std::streambuf {
zipbuf(???): file_(???) {}
private:
zip_file* file_;
enum { s_size = 8196 };
char buffer_[s_size];
int underflow() {
int rc(zip_fread(this->file_, this->buffer_, s_size));
this->setg(this->buffer_, this->buffer_,
this->buffer_ + std::max(0, rc));
return this->gptr() == this->egptr()
? traits_type::eof()
: traits_type::to_int_type(*this->gptr());
}
};
With this stream buffer you should be able to create an std::istream and read the file into whatever structure you need:
zipbuf buf(???);
std::istream in(&buf);
...
Obviously, this code isn't tested or compiled. However, when you replace the ??? with whatever is needed to open the zip file, I'd think this should pretty much work.
Here is a routine I wrote that extracts data from a zip-stream and prints out a line at a time. This uses zlib, not libzip, but if this code is useful to you, feel free to use it:
#
# compile with -lz option in order to link in the zlib library
#
#include <zlib.h>
#define Z_CHUNK 2097152
int unzipFile(const char *fName)
{
z_stream zStream;
char *zRemainderBuf = malloc(1);
unsigned char zInBuf[Z_CHUNK];
unsigned char zOutBuf[Z_CHUNK];
char zLineBuf[Z_CHUNK];
unsigned int zHave, zBufIdx, zBufOffset, zOutBufIdx;
int zError;
FILE *inFp = fopen(fName, "rbR");
if (!inFp) { fprintf(stderr, "could not open file: %s\n", fName); return EXIT_FAILURE; }
zStream.zalloc = Z_NULL;
zStream.zfree = Z_NULL;
zStream.opaque = Z_NULL;
zStream.avail_in = 0;
zStream.next_in = Z_NULL;
zError = inflateInit2(&zStream, (15+32)); /* cf. http://www.zlib.net/manual.html */
if (zError != Z_OK) { fprintf(stderr, "could not initialize z-stream\n"); return EXIT_FAILURE; }
*zRemainderBuf = '\0';
do {
zStream.avail_in = fread(zInBuf, 1, Z_CHUNK, inFp);
if (zStream.avail_in == 0)
break;
zStream.next_in = zInBuf;
do {
zStream.avail_out = Z_CHUNK;
zStream.next_out = zOutBuf;
zError = inflate(&zStream, Z_NO_FLUSH);
switch (zError) {
case Z_NEED_DICT: { fprintf(stderr, "Z-stream needs dictionary!\n"); return EXIT_FAILURE; }
case Z_DATA_ERROR: { fprintf(stderr, "Z-stream suffered data error!\n"); return EXIT_FAILURE; }
case Z_MEM_ERROR: { fprintf(stderr, "Z-stream suffered memory error!\n"); return EXIT_FAILURE; }
}
zHave = Z_CHUNK - zStream.avail_out;
zOutBuf[zHave] = '\0';
/* copy remainder buffer onto line buffer, if not NULL */
if (zRemainderBuf) {
strncpy(zLineBuf, zRemainderBuf, strlen(zRemainderBuf));
zBufOffset = strlen(zRemainderBuf);
}
else
zBufOffset = 0;
/* read through zOutBuf for newlines */
for (zBufIdx = zBufOffset, zOutBufIdx = 0; zOutBufIdx < zHave; zBufIdx++, zOutBufIdx++) {
zLineBuf[zBufIdx] = zOutBuf[zOutBufIdx];
if (zLineBuf[zBufIdx] == '\n') {
zLineBuf[zBufIdx] = '\0';
zBufIdx = -1;
fprintf(stdout, "%s\n", zLineBuf);
}
}
/* copy some of line buffer onto the remainder buffer, if there are remnants from the z-stream */
if (strlen(zLineBuf) > 0) {
if (strlen(zLineBuf) > strlen(zRemainderBuf)) {
/* to minimize the chance of doing another (expensive) malloc, we double the length of zRemainderBuf */
free(zRemainderBuf);
zRemainderBuf = malloc(strlen(zLineBuf) * 2);
}
strncpy(zRemainderBuf, zLineBuf, zBufIdx);
zRemainderBuf[zBufIdx] = '\0';
}
} while (zStream.avail_out == 0);
} while (zError != Z_STREAM_END);
/* close gzip stream */
zError = inflateEnd(&zStream);
if (zError != Z_OK) {
fprintf(stderr, "could not close z-stream!\n");
return EXIT_FAILURE;
}
if (zRemainderBuf)
free(zRemainderBuf);
fclose(inFp);
return EXIT_SUCCESS;
}
With any streaming you should consider the memory requirements of your app.
A good buffer size is large, but you do not want to have too much memory in use depending on your RAM usage requirements. A small buffer size will require you call your read and write operations more times which are expensive in terms of time performance. So, you need to find a buffer in the middle of those two extremes.
Typically I use a size of 4096 (4KB) which is sufficiently large for many purposes. If you want, you can go larger. But at the worst case size of 1 byte, you will be waiting a long time for you read to complete.
So to answer your question, there is no "right" size to pick. It is a choice you should make so that the speed of your app and the memory it requires are what you need.

C++ fwrite doesn't write to text file, have no idea why?

I have this code that basically reads from file and creates new file and write the content from the source to the destination file. It reads the buffer and creates the file, but fwrite
doesn't write the content to the newly created file, I have no idea why.
here is the code. (I have to use only this with _sopen, its part of legacy code)
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>
#include <string>
#include <share.h>
#include <sys\stat.h>
int main () {
std::string szSource = "H:\\cpp\\test1.txt";
FILE* pfFile;
int iFileId = _sopen(szSource.c_str(),_O_RDONLY, _SH_DENYNO, _S_IREAD);
if (iFileId >= 0)
pfFile = fdopen(iFileId, "r");
//read file content to buffer
char * buffer;
size_t result;
long lSize;
// obtain file size:
fseek (pfFile , 0 , SEEK_END);
lSize = ftell (pfFile);
fseek(pfFile, 0, SEEK_SET);
// buffer = (char*) malloc (sizeof(char)*lSize);
buffer = (char*) malloc (sizeof(char)*lSize);
if (buffer == NULL)
{
return false;
}
// copy the file into the buffer:
result = fread (buffer,lSize,1,pfFile);
std::string szdes = "H:\\cpp\\test_des.txt";
FILE* pDesfFile;
int iFileId2 = _sopen(szdes.c_str(),_O_CREAT,_SH_DENYNO,_S_IREAD | _S_IWRITE);
if (iFileId2 >= 0)
pDesfFile = fdopen(iFileId2, "w+");
size_t f = fwrite (buffer , 1, sizeof(buffer),pDesfFile );
printf("Error code: %d\n",ferror(pDesfFile));
fclose (pDesfFile);
return 0;
}
You can make main file and try it see if its working for you .
Thanks
Change your code to the following and then report your results:
int main () {
std::string szSource = "H:\\cpp\\test1.txt";
int iFileId = _sopen(szSource.c_str(),_O_RDONLY, _SH_DENYNO, _S_IREAD);
if (iFileId >= 0)
{
FILE* pfFile;
if ((pfFile = fdopen(iFileId, "r")) != (FILE *)NULL)
{
//read file content to buffer
char * buffer;
size_t result;
long lSize;
// obtain file size:
fseek (pfFile , 0 , SEEK_END);
lSize = ftell (pfFile);
fseek(pfFile, 0, SEEK_SET);
if ((buffer = (char*) malloc (lSize)) == NULL)
return false;
// copy the file into the buffer:
result = fread (buffer,(size_t)lSize,1,pfFile);
fclose(pfFile);
std::string szdes = "H:\\cpp\\test_des.txt";
FILE* pDesfFile;
int iFileId2 = _sopen(szdes.c_str(),_O_CREAT,_SH_DENYNO,_S_IREAD | _S_IWRITE);
if (iFileId2 >= 0)
{
if ((pDesfFile = fdopen(iFileId2, "w+")) != (FILE *)NULL)
{
size_t f = fwrite (buffer, (size_t)lSize, 1, pDesfFile);
printf ("elements written <%d>\n", f);
if (f == 0)
printf("Error code: %d\n",ferror(pDesfFile));
fclose (pDesfFile);
}
}
}
}
return 0;
}
[edit]
for other posters, to show the usage/results of fwrite - what is the output of the following?
#include <stdio.h>
int main (int argc, char **argv) {
FILE *fp = fopen ("f.kdt", "w+");
printf ("wrote %d\n", fwrite ("asdf", 4, 1, fp));
fclose (fp);
}
[/edit]
sizeof(buffer) is the size of the pointer, i.e. 4 and not the number of items in the buffer
If buffer is an array then sizeof(buffer) would potentially work as it returns the number of bytes in the array.
The third parameter to fwrite is sizeof(buffer) which is 4 bytes (a pointer). You need to pass in the number of bytes to write instead (lSize).
Update: It also looks like you're missing the flag indicating the file should be Read/Write: _O_RDWR
This is working for me...
std::string szdes = "C:\\temp\\test_des.txt";
FILE* pDesfFile;
int iFileId2;
err = _sopen_s(&iFileId2, szdes.c_str(), _O_CREAT|_O_BINARY|_O_RDWR, _SH_DENYNO, _S_IREAD | _S_IWRITE);
if (iFileId2 >= 0)
pDesfFile = _fdopen(iFileId2, "w+");
size_t f = fwrite (buffer , 1, lSize, pDesfFile );
fclose (pDesfFile);
Since I can't find info about _sopen, I can only look at man open. It reports:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
Your call _sopen(szdes.c_str(),_O_CREAT,_SH_DENYNO,_S_IREAD | _S_IWRITE); doesn't match either one of those, you seem to have flags and 'something' and modes / what is SH_DENY?
What is the result of man _sopen?
Finally, shouldn't you close the file descriptor from _sopen after you fclose the file pointer?
Your final lines should look like this, btw :
if (iFileId2 >= 0)
{
pDesfFile = fdopen(iFileId2, "w+");
size_t f = fwrite (buffer , 1, sizeof(buffer),pDesfFile ); //<-- the f returns me 4
fclose (pDesfFile);
}
Since you currently write the file regardless of whether or not the fdopen after the O_CREAT succeeded. You also do the same thing at the top, you process the read (and the write) regardless of the success of the fdopen of the RDONLY file :(
You are using a mixture of C and C++. That is confusing.
The sizeof operator does not do what you expect it to do.
Looks like #PJL and #jschroedl found the real problem, but also in general:
Documentation for fwrite states:
fwrite returns the number of full items actually written, which may be less than count if an error occurs. Also, if an error occurs, the file-position indicator cannot be determined.
So if the return value is less than the count passed, use ferror to find out what happened.
The ferror routine (implemented both as a function and as a macro) tests for a reading or writing error on the file associated with stream. If an error has occurred, the error indicator for the stream remains set until the stream is closed or rewound, or until clearerr is called against it.

How do I extract a user stream from a WinDbg extension?

I have embedded a custom stream in a dump (i.e. passed the UserStreamParam argument to MiniDumpWriteDump function). Now, I'm trying to extract the stream from a WinDbg extension. (Note that I have verified that I can retrieve the stream using the MiniDumpReadDumpStream function).
I'm using the IDebugAdvanced2::Request method with DEBUG_REQUEST_READ_USER_MINIDUMP_STREAM request. I am able to retrieve data from standard streams. For example, the following snippet will correctly retrieve the contents of the misc info stream.
DEBUG_READ_USER_MINIDUMP_STREAM rums = {};
rums.StreamType = MiscInfoStream;
rums.Buffer = &buf;
rums.BufferSize = sizeof buf;
hr = p->Request(DEBUG_REQUEST_READ_USER_MINIDUMP_STREAM,
&rums, sizeof rums, 0, 0, 0);
However, trying to retrieve my own stream will result in an error (0x80070570, ERROR_FILE_CORRUPT) and WinDbg outputs
Dir entry 11, ??? stream has unknown stream type 6381921
Note that the same message appears as a part of the .dumpdebug output.
Stream 11: type ??? (6381921), size 00000038, RVA 00033FA9
Dir entry 11, ??? stream has unknown stream type 6381921
What is the problem? How do I retrieve contents of my user stream?
very late answer
StreamType cannot be UserDefined StreamTypes
jen-lung chiu of ms posted so in osronline windbg lists long back
do not know if the latest dbgeng has this limitation eliminated
you either retrieve it with a dbghelp function independently
(using dbghelp functions inside windbg extensions are not recommended )
or parse the stream yourself with fopen() fread() like below
userstream:\>type ..\usrstr.cpp
#include <stdio.h>
#include <engextcpp.hpp>
#include <dbghelp.h>
const ULONG MBUFFSIZE = 0x1000;
PVOID Buff = 0;
int __cdecl ReadUserStream (char *dmpfile)
{
PMINIDUMP_HEADER MiniHeader = 0;
PMINIDUMP_DIRECTORY MiniDir = 0;
PMINIDUMP_USER_STREAM userstream = 0;
size_t result = 0;
ULONG Streams =0;
ULONG i = 0;
FILE * fp = fopen(dmpfile,"rb");
if (fp)
{
result = fread(Buff, 1, sizeof(MINIDUMP_HEADER), fp );
if ( result == sizeof(MINIDUMP_HEADER) )
{
MiniHeader = (PMINIDUMP_HEADER) Buff;
Streams = MiniHeader->NumberOfStreams;
for (i = 0; i < Streams; i++ )
{
result = fread( Buff, 1, sizeof(MINIDUMP_DIRECTORY), fp );
if ( result == sizeof(MINIDUMP_DIRECTORY) )
{
MiniDir = (PMINIDUMP_DIRECTORY) Buff;
if ( MiniDir->StreamType > LastReservedStream )
{
userstream = (PMINIDUMP_USER_STREAM)Buff;
ULONG savedbuffsize = userstream->BufferSize;
ULONG savedtype = userstream->Type;
PCHAR savedbufferptr = (PCHAR)userstream->Buffer;
long pos = ftell(fp);
fseek(fp, (long)savedbufferptr,SEEK_SET);
result = fread( Buff, 1, savedbuffsize, fp );
if ( result == savedbuffsize )
{
printf(
"\n"
"Datastream Type = %.8x\n"
"Buffer Size = %.8x\n"
"Buffer = %p\n"
"Buffer content = %s\n"
"\n",
savedtype,
savedbuffsize,
savedbufferptr,
Buff
);
fseek(fp,pos,SEEK_SET);
continue;
}
else
{
printf(
"failed to read buffer contents at offset %p of
user stream %x\n",
savedbufferptr,
savedtype);
fseek(fp,pos,SEEK_SET);
continue;
}
}
}
else
{
printf("failed to fread Minidump directory exiting \n");
goto getout;
}
}
}
else
{
printf("failed to fread Minidump header exiting \n");
goto getout;
}
}
else
{
printf("failed to open dmp file exiting \n");
goto getout;
}
getout:
if (fp)
fclose(fp);
return 0;
}
int __cdecl main (int argc, char * argv[])
{
if (argc !=2)
{
printf("Usage %s %s\n",argv[0],"somedump.dmp");
return 0;
}
Buff = malloc( MBUFFSIZE );
if (Buff)
{
ReadUserStream(argv[1]);
free(Buff);
return 0;
}
else
{
printf("malloc failed exiting\n");
return 0;
}
}
output from an userdump that has userStreams in it
(oleg staradumov debuginfo.com writeuserstream.cpp )
userstream:\>usrstr.exe
Usage usrstr.exe somedump.dmp
userstream:\>usrstr.exe test.dmp
Datastream Type = 00010000
Buffer Size = 00000021
Buffer = 000010B6
Buffer content = This is the first data stream...
Datastream Type = 00010001
Buffer Size = 00000023
Buffer = 000010D7
Buffer content = and this is the second data stream
I found this topic while looking for a method to read out user stream from the dbg file.
#blabb 's answer is correct in basics and helped me a lot, but it has a two flaws:
You should use the MINIDUMP_HEADER.StreamDirectoryRva to locate the MINIDUMP_DIRECTORY list.
You should not convert the MINIDUMP_DIRECTORY entry to MINIDUMP_USER_STREAM, because that's an error (MINIDUMP_USER_STREAM is a bigger struct than MINIDUMP_DIRECTORY, so you are reading uninitialized memory there) Use the MINIDUMP_DIRECTORY to locate the needed part of the stream.
Even if not tested, it should work if you fill StreamType with a custom value (greater than LastReservedStream = 0xFFFF) instead of MiscInfoStream.