problem with char* block[5000] and binary reading

I

ishmael4

hello everyone!
i have a problem with reading from binary file. i was googling and
searching, but i just cant understand, why isnt this code working. i could
use any help. here's the source code:

--cut here--

typedef struct pkg_ {
short int info;
char* data[5000];
} pkg;

TFileStream* File;

void SendFile(char* FName, int status)
{
File=new TFileStream(FName,fmOpenRead);

while(File->Position<File->Size)
{
char *block[5000];
pkg* newPkg=new pkg;
File->Read(block,5000);
memcpy(*(newPkg->data),*(block),5000); //this line
newPkg->info=0;
Form1->SS1->Socket->Connections[0]->SendBuf((void*)newPkg,sizeof(newPkg));
delete newPkg;
}
pkg* newPkg=new pkg;
newPkg->info=status;
Form1->SS1->Socket->Connections[0]->SendBuf((void*)newPkg,sizeof(newPkg));
delete newPkg;
delete File;
return;
}

--cut here--

i was trying
memcpy(*(newPkg->data),*(block),5000); //this line

and getting "access violation" message, as well as
memcpy(newPkg->data,block,5000); //this line
but in this case "newPkg->data" appears to be a simple pointer, not an array
of pointers, as "block". And during debugging the following information
about contents of these variables are shown:
newPkg->data:=0090568C
block={:57200A0D, :6D756C6F, etc. etc. (the actual content of a binary
file)}
juest after instruction "memcpy(newPkg->data,block,5000); //this line".
Please help me.
 
M

mlimber

ishmael4 said:
hello everyone!
i have a problem with reading from binary file. i was googling and
searching, but i just cant understand, why isnt this code working. i could
use any help. here's the source code:

--cut here--

typedef struct pkg_ {
short int info;
char* data[5000];

You realize this is an array of 5000 pointers-to-char, not 5000 bytes,
right?
} pkg;

TFileStream* File;

void SendFile(char* FName, int status)
{
File=new TFileStream(FName,fmOpenRead);

while(File->Position<File->Size)
{
char *block[5000];

Same thing here.
pkg* newPkg=new pkg;
File->Read(block,5000);
memcpy(*(newPkg->data),*(block),5000); //this line

newPkg has only 5000 pointers allocated, no data. Your dereferencing of
the pointer is certainly an error. Dereferencing block may also be an
error depending on what happens in TFileStream::Read().
newPkg->info=0;
Form1->SS1->Socket->Connections[0]->SendBuf((void*)newPkg,sizeof(newPkg));
delete newPkg;
}
pkg* newPkg=new pkg;
newPkg->info=status;
Form1->SS1->Socket->Connections[0]->SendBuf((void*)newPkg,sizeof(newPkg));
delete newPkg;
delete File;
return;
}

You may want to consider using a smart pointer like std::auto_ptr
instead of all your news and deletes. It gives you exception safety at
no performance cost, and it means less for you to remember.
--cut here--
[snip]

Done.

Cheers! --M
 
B

Bryan Donlan

ishmael4 said:
hello everyone!
i have a problem with reading from binary file. i was googling and
searching, but i just cant understand, why isnt this code working. i could
use any help. here's the source code:

--cut here--

typedef struct pkg_ {
short int info;
char* data[5000];

This creates an array of 5000 char pointers, not a buffer of 5000 chars.
Try: char data[5000];
 
M

mlimber

mlimber said:
ishmael4 wrote: [snip]
pkg* newPkg=new pkg;
File->Read(block,5000);
memcpy(*(newPkg->data),*(block),5000); //this line

newPkg has only 5000 pointers allocated, no data. Your dereferencing of
the pointer is certainly an error. Dereferencing block may also be an
error depending on what happens in TFileStream::Read().
[snip]

Allow me to clarify my statement. *(newPkg->data) is the same as
newPkg->data[0], but this location is not a char but a pointer-to-char
and that pointer is clearly uninitialized. Either you meant to have an
array of chars or you need to allocate some space for each of those
5000 pointers to point to, e.g.,

pkg::pkg()
{
for( int i=0; i < 5000; ++i )
data = new char[ 30 ];
}

pkg::~pkg()
{
for( int i=0; i < 5000; ++i )
delete data;
}

Cheers! --M
 
J

John Harrison

ishmael4 said:
hello everyone!
i have a problem with reading from binary file. i was googling and
searching, but i just cant understand, why isnt this code working. i could
use any help. here's the source code:

--cut here--

typedef struct pkg_ {
short int info;
char* data[5000];
} pkg;

TFileStream* File;

void SendFile(char* FName, int status)
{
File=new TFileStream(FName,fmOpenRead);

while(File->Position<File->Size)
{
char *block[5000];
pkg* newPkg=new pkg;
File->Read(block,5000);
memcpy(*(newPkg->data),*(block),5000); //this line
newPkg->info=0;
Form1->SS1->Socket->Connections[0]->SendBuf((void*)newPkg,sizeof(newPkg));
delete newPkg;
}
pkg* newPkg=new pkg;
newPkg->info=status;
Form1->SS1->Socket->Connections[0]->SendBuf((void*)newPkg,sizeof(newPkg));
delete newPkg;
delete File;
return;
}

--cut here--

i was trying
memcpy(*(newPkg->data),*(block),5000); //this line

and getting "access violation" message, as well as
memcpy(newPkg->data,block,5000); //this line
but in this case "newPkg->data" appears to be a simple pointer, not an array
of pointers, as "block". And during debugging the following information
about contents of these variables are shown:
newPkg->data:=0090568C
block={:57200A0D, :6D756C6F, etc. etc. (the actual content of a binary
file)}
juest after instruction "memcpy(newPkg->data,block,5000); //this line".
Please help me.

Almost certainly you want

char block[5000];

not

char *block[5000];

and

typedef struct pkg_ {
short int info;
char data[5000];
} pkg;

not

typedef struct pkg_ {
short int info;
char* data[5000];
} pkg;

john
 
I

ishmael4

Almost certainly you want
char block[5000];

not

char *block[5000];

and

typedef struct pkg_ {
short int info;
char data[5000];
} pkg;

not

typedef struct pkg_ {
short int info;
char* data[5000];
} pkg;

john

fixed sourcecode:

--cut here--

typedef struct pkg_ {
short int info;
char data[5000];
} pkg;

void SendFile(char* FName, int status)
{
File=new TFileStream(FName,fmOpenRead);

while(File->Position<File->Size)
{
pkg* newPkg=new pkg;
File->Read(newPkg->data,5000);
newPkg->info=0;
Form1->SS1->Socket->Connections[0]->SendBuf((void*)newPkg,sizeof(pkg));
delete newPkg;
}
pkg* newPkg=new pkg;
newPkg->info=status;
Form1->SS1->Socket->Connections[0]->SendBuf((void*)newPkg,sizeof(pkg));
delete newPkg;
delete File;
return;
}

--cut here--

this one works correctly with txt files, but not with binary. For some
reason,
File->Read(newPkg->data,5000); reads data from binary only when data is
char* data[5000]; (but not inside the structure[?!?]). Here's info about
File->Read():

--begin here--

virtual int __fastcall Read(void *Buffer, int Count);

Description

Use Read to read data from the resource associated with the handle stream
when the number of bytes in the file is not known. Read transfers up to
Count bytes from the resource, starting at the current position, and then
advances the current position in the resource by the number of bytes
actually transferred. Read returns the number of bytes actually transferred,
which may be less than Count if the end of file marker is encountered.

All other data-reading methods of a handle stream (ReadBuffer,
ReadComponent) call Read to do the actual reading.

--end here--

I've read a few times, but i can't figure out, why Buffer has to be char*
buffer[count], and for some reason it has to be outside the structure (see
the previous code). But maybe my english isnt well enough to understand the
description of this function. Summing up, i need to load a block of binary
data and it works only with char* bufer[5000] that is outside the structure.
i cant copy it to similar variable inside the structure. char buffer[5000]
works with textfiles (debug info: newPkg->data:="blahblahblah"), but doesnt
with binary. sorry if it seems a bit messed up, but i am working on this
project since a week 10 hours a day and i grow depressed about it. thanks in
advance for any help.

ishmael4
 
M

mlimber

ishmael4 said:
fixed sourcecode:

--cut here--

typedef struct pkg_ {
short int info;
char data[5000];
} pkg;

This typedef method is C-style and unnecessary in C++. Just write:

struct pkg {
short int info;
char data[5000];
} pkg;
void SendFile(char* FName, int status)
{
File=new TFileStream(FName,fmOpenRead);

Why is File a file-scope variable if you always new and delete it here.
Why not just create an object on the stack like this:

TFileStream File( FName, fmOpenRead );

[snip]
this one works correctly with txt files, but not with binary. For some
reason,
File->Read(newPkg->data,5000); reads data from binary only when data is
char* data[5000]; (but not inside the structure[?!?]). Here's info about
File->Read():

--begin here--

virtual int __fastcall Read(void *Buffer, int Count);

Description

Use Read to read data from the resource associated with the handle stream
when the number of bytes in the file is not known. Read transfers up to
Count bytes from the resource, starting at the current position, and then
advances the current position in the resource by the number of bytes
actually transferred. Read returns the number of bytes actually transferred,
which may be less than Count if the end of file marker is encountered.

All other data-reading methods of a handle stream (ReadBuffer,
ReadComponent) call Read to do the actual reading.

--end here--

I've read a few times, but i can't figure out, why Buffer has to be char*
buffer[count], and for some reason it has to be outside the structure (see
the previous code). But maybe my english isnt well enough to understand the
description of this function. Summing up, i need to load a block of binary
data and it works only with char* bufer[5000] that is outside the structure.
i cant copy it to similar variable inside the structure. char buffer[5000]
works with textfiles (debug info: newPkg->data:="blahblahblah"), but doesnt
with binary. sorry if it seems a bit messed up, but i am working on this
project since a week 10 hours a day and i grow depressed about it. thanks in
advance for any help.

You might need to pass a flag into the TFileStream constructor to tell
it to operate in binary mode, but this class isn't standard C++, is
unfamiliar to me, and is, strictly speaking, off-topic in this forum.
Could you dump that TFileStream and use the standard <fstream> instead.
It would be much easier for us to help you get it to work in binary or
text mode.

Cheers! --M
 
M

mlimber

mlimber said:
This typedef method is C-style and unnecessary in C++. Just write:

struct pkg {
short int info;
char data[5000];
} pkg;

Correction: delete the "pkg" after the "}".
 
G

Guest

ishmael4 said:
typedef struct pkg_ {
short int info;
char data[5000];

Don't use magical constants define the buffer size somewhere before the
definition of pkg. For example:

size_t const bufferSize = 5000;

Use only bufferSize in the code.

Also, you don't need the 'typedef struct' idiom in C++. Just do

struct pkg { /* ... */};
void SendFile(char* FName, int status)
{
File=new TFileStream(FName,fmOpenRead);

while(File->Position<File->Size)

Himmm... You are not incrementing File->Position by one in the loop. Your
test above is not safe. There is a danger of attempting to read more than
there is in the file.
{
pkg* newPkg=new pkg;
File->Read(newPkg->data,5000);

There you go! What if File->Position was one less than File->Size? You would
attempt to read more. The documentation below for Read says that what it
returns is the number of bytes actually transfered. Don't ignore that value.

Also, chances are, if 0-based, Position will probably never equal Size. It's
range will be [0,Size-1].
newPkg->info=0;
Form1->SS1->Socket->Connections[0]->SendBuf((void*)newPkg,sizeof(pkg));
delete newPkg;
}
pkg* newPkg=new pkg;
newPkg->info=status;
Form1->SS1->Socket->Connections[0]->SendBuf((void*)newPkg,sizeof(pkg));
delete newPkg;
delete File;
return;
}

--cut here--

this one works correctly with txt files, but not with binary. For some
reason,
File->Read(newPkg->data,5000); reads data from binary only when data is
char* data[5000]; (but not inside the structure[?!?]). Here's info about

char vs. char* has nothing directly related to the problem. It seems to work
for you probably because sizeof(char*) is likely 4 times sizeof(char) on
your system. Allocating more than what you need is hiding the bug.

Here is the bit about the return value of Read:
Read returns the number of bytes actually transferred, which may be less
than Count if the end of file marker is encountered.

Ali
 
I

ishmael4

You might need to pass a flag into the TFileStream constructor to tell
it to operate in binary mode, but this class isn't standard C++, is
unfamiliar to me, and is, strictly speaking, off-topic in this forum.
Could you dump that TFileStream and use the standard <fstream> instead.
It would be much easier for us to help you get it to work in binary or
text mode.

Cheers! --M

well, could you give me an example, how to read binary block into
char[count] variable using fstream?
 
I

ishmael4

An example can be found here:
http://www.cplusplus.com/ref/iostream/istream/read.html

I would use std::vector<char> instead of a raw array of chars, but that
could obscure the example.

Here we go:

--cut here--

void __fastcall TForm1::Button1Click(TObject *Sender)
{
int length;
char * buffer;

ifstream is;
is.open (Edit1->Text.c_str(), ios::binary );

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

// allocate memory:
buffer = new char [length];

// read data as a block:
is.read (buffer,length);

is.close();

delete[] buffer; //somebody forgot?
return;
}

--cut here--

i have already tried this. well... it works perfectly with txt files. it may
be pretty shocking, but it doesnt with exe files, or even htm. i cant
understand this. debu info after is.read(buffer,length):

txt: length:=10333, buffer:="[KB888302.log]\r\n5.328: 2005/02/09
08:09:49.843 (local)..." (regular text,ok)
exe: length:=455680, buffer:="MZP"
html: ength:=117640, buffer:="a"

i am using BCB 6 Personal on WinXP.
what i need is a way to load _any_ type of file to send it through a socket.
 
K

Karl Heinz Buchegger

ishmael4 said:
i have already tried this. well... it works perfectly with txt files. it may
be pretty shocking, but it doesnt with exe files, or even htm. i cant
understand this. debu info after is.read(buffer,length):

txt: length:=10333, buffer:="[KB888302.log]\r\n5.328: 2005/02/09
08:09:49.843 (local)..." (regular text,ok)
exe: length:=455680, buffer:="MZP"

exe is binary data. Using your debugger to to interpret that as string
is futile.
html: ength:=117640, buffer:="a"

html data on the other hand is simple text, That should show some
results. But maybe your debugger can't handle text with a length
of ~110 kByte
 
I

ishmael4

Uzytkownik "Karl Heinz Buchegger said:
ishmael4 said:
i have already tried this. well... it works perfectly with txt files. it
may
be pretty shocking, but it doesnt with exe files, or even htm. i cant
understand this. debu info after is.read(buffer,length):

txt: length:=10333, buffer:="[KB888302.log]\r\n5.328: 2005/02/09
08:09:49.843 (local)..." (regular text,ok)
exe: length:=455680, buffer:="MZP"

exe is binary data. Using your debugger to to interpret that as string
is futile.

well... my thinking is: i load binary data into char array. so every
mnemonic (or assembler) command of exe, which actually is a hex value, is
casted to a char. and what it follows, it should be shown as a text. it may
not be sensful, but it is a text, which has certain length. am i right?
html data on the other hand is simple text, That should show some
results. But maybe your debugger can't handle text with a length
of ~110 kByte

It can. It shortens it. I wont explain it, but i am absolutly sure that it
handles any text data.
 
K

Karl Heinz Buchegger

ishmael4 said:
Uzytkownik "Karl Heinz Buchegger said:
ishmael4 said:
i have already tried this. well... it works perfectly with txt files. it
may
be pretty shocking, but it doesnt with exe files, or even htm. i cant
understand this. debu info after is.read(buffer,length):

txt: length:=10333, buffer:="[KB888302.log]\r\n5.328: 2005/02/09
08:09:49.843 (local)..." (regular text,ok)
exe: length:=455680, buffer:="MZP"

exe is binary data. Using your debugger to to interpret that as string
is futile.

well... my thinking is: i load binary data into char array.

By the way: when working with raw bytes always use 'unsigned char'. Less
pain in the long run.
so every
mnemonic (or assembler) command of exe, which actually is a hex value,

every opcode is a number. That's all that computers do: dealing with numbers.
Depending on context that numbers have different meanings. Sometimes those
numbers are opcodes (instructions to the CPU), sometimes they are simply that:
numbers and sometimes they are codes, where each code denotes a specific 'character'.
But everything is just a number in a computer.

However you usually don't see mnemonic's in an executable. The executable already
holds the 'numbers', where each number denotes a CPU instruction.
is
casted to a char. and what it follows, it should be shown as a text.

There is no text.

eg. the executable may hold the hex values:

00 c3 00 00

That's a program, in a more readable form (your disassembler translates the
byte sequence in the more readable form) this hex codes reads eg. for a 8080 CPU:

0000 00 NOP
0001 c3 00 00 JMP 0000H

Your dump tool can only show you the byte stream 00 c3 00 00
but it won't show you the disassembly listing.

Now remember that C-style strings stop with a '\0' character. Usually the '\0'
has code 0. So when you instruct your dump tool to show you that byte sequence
as a string, it will stop immediatly, since the very first byte already contains
the '\0' value.
it may
not be sensful, but it is a text, which has certain length. am i right?

It may be text. Yes. But since in C the 'length' of the text is encoded inside
the string by the use of a special charater, every occourence of that character
premature termintes that 'string'.
 
A

Arndt Muehlenfeld

ishmael4 said:
Uzytkownik "Karl Heinz Buchegger said:
ishmael4 said:
i have already tried this. well... it works perfectly with txt files. it
may
be pretty shocking, but it doesnt with exe files, or even htm. i cant
understand this. debu info after is.read(buffer,length):

txt: length:=10333, buffer:="[KB888302.log]\r\n5.328: 2005/02/09
08:09:49.843 (local)..." (regular text,ok)
exe: length:=455680, buffer:="MZP"

exe is binary data. Using your debugger to to interpret that as string
is futile.

well... my thinking is: i load binary data into char array. so every
mnemonic (or assembler) command of exe, which actually is a hex value, is
casted to a char. and what it follows, it should be shown as a text. it
may not be sensful, but it is a text, which has certain length. am i
right?

Partially.
You see the text in your example, it's "MZP".
Probably the next char is 0 thereby terminating the string.
(C-strings are 0 terminated strings, remember?)

Furthermore, not every possible value for char gives a printable character.
(cf. isprint() in ctype.h)

Here again, the second character might be 0.
HTML-pages contain text, but that may be encoded in UNICODE, e.g.
UCS-2, where each character is represented by two bytes instead of one.

Or something else is wrong with your program.

Happy debugging,
Arndt
 
I

ishmael4

Uzytkownik "Karl Heinz Buchegger said:
ishmael4 said:
Uzytkownik "Karl Heinz Buchegger" <[email protected]> napisal w
wiadomosci
ishmael4 wrote:

i have already tried this. well... it works perfectly with txt files.
it
may
be pretty shocking, but it doesnt with exe files, or even htm. i cant
understand this. debu info after is.read(buffer,length):

txt: length:=10333, buffer:="[KB888302.log]\r\n5.328: 2005/02/09
08:09:49.843 (local)..." (regular text,ok)
exe: length:=455680, buffer:="MZP"

exe is binary data. Using your debugger to to interpret that as string
is futile.

well... my thinking is: i load binary data into char array.

By the way: when working with raw bytes always use 'unsigned char'. Less
pain in the long run.
so every
mnemonic (or assembler) command of exe, which actually is a hex value,

every opcode is a number. That's all that computers do: dealing with
numbers.
Depending on context that numbers have different meanings. Sometimes those
numbers are opcodes (instructions to the CPU), sometimes they are simply
that:
numbers and sometimes they are codes, where each code denotes a specific
'character'.
But everything is just a number in a computer.

However you usually don't see mnemonic's in an executable. The executable
already
holds the 'numbers', where each number denotes a CPU instruction.
is
casted to a char. and what it follows, it should be shown as a text.

There is no text.

eg. the executable may hold the hex values:

00 c3 00 00

That's a program, in a more readable form (your disassembler translates
the
byte sequence in the more readable form) this hex codes reads eg. for a
8080 CPU:

0000 00 NOP
0001 c3 00 00 JMP 0000H

Your dump tool can only show you the byte stream 00 c3 00 00
but it won't show you the disassembly listing.

Now remember that C-style strings stop with a '\0' character. Usually the
'\0'
has code 0. So when you instruct your dump tool to show you that byte
sequence
as a string, it will stop immediatly, since the very first byte already
contains
the '\0' value.
it may
not be sensful, but it is a text, which has certain length. am i right?

It may be text. Yes. But since in C the 'length' of the text is encoded
inside
the string by the use of a special charater, every occourence of that
character
premature termintes that 'string'.

okay. then if i want to send an binary(executable) through socket i need an
array o bytes or sth? i need some rest :D. i'll consider this, thanks!
 
M

mlimber

ishmael4 said:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int length;
char * buffer;

ifstream is;
is.open (Edit1->Text.c_str(), ios::binary );

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

// allocate memory:
buffer = new char [length];

// read data as a block:
is.read (buffer,length);

is.close();

delete[] buffer; //somebody forgot?
return;
}

Now that you got that, consider this simpler version:

#include <fstream>
#include <vector>
#include <string>
using namespace std;

void ReadFile( string const& filename, vector<char>& buffer )
{
ifstream is( filename.c_str(), ios::binary );
if( !is ) return;

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

// allocate memory:
buffer.resize( length );

// read data as a block:
is.read( &buffer[0], buffer.size() );
}

int main()
{
string const filename = "file.bin";
vector<char> buffer;
ReadFile( filename, buffer );
return 0;
}

Note that no call to open or close is required and the vector manages
its own memory without explicit news and deletes.

Cheers! --M
 
K

Karl Heinz Buchegger

ishmael4 said:
okay. then if i want to send an binary(executable) through socket i need an
array o bytes or sth?

What's sth?
Array of bytes is fine. If there were a data type 'byte' in C. There is
none. But 'unsigned char' serves the same purpose.
i need some rest :D. i'll consider this, thanks!

What I am aiming at is:

Don't let yourself fool you with your tests so far. That your debugger
doesn't show you what you expect is in this case a problem of not using
your debugger correctly. The data in the array should be fine. Just send
it through the socket, write it to a file and you should have an exact copy
if the input file. If you want to verify that you read the file correctly,
you can write the read data to a file at the server side und use a hex dump tool
or a file difference tool to verify that it is identical to the source. That
would be better anyway, because in doing a manual check you *will* make errors.
(I already have spent hours staring at hex dumps and comparing them. That's no joy).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top