Issues with variable used in reading binary file - c++

I'm writing some serial port code and need to read the contents of a file (in binary) to a variable.
Starting from the example for "Binary files" at http://www.cplusplus.com/doc/tutorial/files/ ,
I try opening a .jpg file:
#include <iostream>
#include <fstream>
using namespace std;
ifstream::pos_type size;
char * memblock;
int main () {
ifstream file ("example.jpg", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
cout << memblock << endl;
delete[] memblock;
}
else cout << "Unable to open file";
return 0;
}
However, only the first 4 characters (32 bits) are printed in the console.
What's particularly odd though is that using ostream::write() with that supposedly faulty variable "memblock" works perfectly:
ofstream fileOut ("writtenFile.jpg",ios::out|ios::binary);
fileOut.write(memblock,size);
fileOut.close();
ie it creates a new .jpg file.
So my question is why the memblock variable seems to only contain the first 4 characters.

There is probably a 0 in your binary data. cout is a text stream so looks at memblock as a string. If it reaches a null character then it thinks the string has finished.
See this for some help pin outputting binary data:
How to make cout behave as in binary mode?

Hmmm. A quick glance at the page you cite shows that the author doesn't
know much about IO in C++. Avoid it, since much of what it says is
wrong.
For the rest: .jpg is not a text format, and cannot be simply output
to cout. When you use <<, of course, the output stops at the first
'\0' character, but all sorts of binary data may cause wierd effects:
data may be interpreted as an escape sequence repositionning the cursor,
locking the keyboard (actually happened to me once), etc. These
problems will occur even if you use std::cout.write() (which will not
stop at the '\0' character). If you want to visualize the data,
your best bet is some sort of binary dump. (I use something like the
following for visualizing large blocks of data:
template <typename InputIterator>
void
process(
InputIterator begin,
InputIterator end,
std::ostream& output = std::cout )
{
IOSave saveAndRestore( output ) ;
output.setf( std::ios::hex, std::ios::basefield ) ;
output.setf( std::ios::uppercase ) ;
output.fill( '0' ) ;
static int const lineLength( 16 ) ;
while ( begin != end ) {
int inLineCount = 0;
unsigned char buffer[ lineLength ] ;
while ( inLineCount != lineLength && begin != end ) {
buffer[inLineCount] = *begin;
++ begin;
++ inLineCount;
}
for ( int i = 0 ; i < lineLength ; ++ i ) {
static char const *const
separTbl [] =
{
" ", " ", " ", " ",
" ", " ", " ", " ",
" ", " ", " ", " ",
" ", " ", " ", " ",
} ;
output << separTbl[ i ] ;
if ( i < inLineCount ) {
output << std::setw( 2 )
<< static_cast< unsigned int >(buffer[ i ] & 0xFF) ) ;
} else {
output << " " ;
}
}
output << " |" ;
for ( int i = 0 ; i != inLineCount ; ++ i ) {
output << (i < lengthRead && isprint( buffer[ i ] )
? static_cast< char >( buffer[ i ] )
: ' ') ;
}
output << '|' << std::endl ;
}
}
(You'll also want to read into an std::vector<char>, so you don't have
to worry about freeing the memory.)

Related

C++ equivalent of C fgets

I am looking to find a C++ fstream equivalent function of C fgets. I tried with get function of fstream but did not get what I wanted. The get function does not extract the delim character whereas the fgets function used to extract it. So, I wrote a code to insert this delim character from my code itself. But it is giving strange behaviour. Please see my sample code below;
#include <stdio.h>
#include <fstream>
#include <iostream>
int main(int argc, char **argv)
{
char str[256];
int len = 10;
std::cout << "Using C fgets function" << std::endl;
FILE * file = fopen("C:\\cpp\\write.txt", "r");
if(file == NULL){
std::cout << " Error opening file" << std::endl;
}
int count = 0;
while(!feof(file)){
char *result = fgets(str, len, file);
std::cout << result << std::endl ;
count++;
}
std::cout << "\nCount = " << count << std::endl;
fclose(file);
std::fstream fp("C:\\cpp\\write.txt", std::ios_base::in);
int iter_count = 0;
while(!fp.eof() && iter_count < 10){
fp.get(str, len,'\n');
int count = fp.gcount();
std::cout << "\nCurrent Count = " << count << std::endl;
if(count == 0){
//only new line character encountered
//adding newline character
str[1] = '\0';
str[0] = '\n';
fp.ignore(1, '\n');
//std::cout << fp.get(); //ignore new line character from stream
}
else if(count != (len -1) ){
//adding newline character
str[count + 1] = '\0';
str[count ] = '\n';
//std::cout << fp.get(); //ignore new line character from stream
fp.ignore(1, '\n');
//std::cout << "Adding new line \n";
}
std::cout << str << std::endl;
std::cout << " Stream State : Good: " << fp.good() << " Fail: " << fp.fail() << std::endl;
iter_count++;
}
std::cout << "\nCount = " << iter_count << std::endl;
fp.close();
return 0;
}
The txt file that I am using is write.txt with following content:
This is a new lines.
Now writing second
line
DONE
If you observe my program, I am using fgets function first and then using the get function on same file. In case of get function, the stream state goes bad.
Can anyone please point me out what is going wrong here?
UPDATED: I am now posting a simplest code which does not work at my end. If I dont care about the delim character for now and just read the entire file 10 characters at a time using getline:
void read_file_getline_no_insert(){
char str[256];
int len =10;
std::cout << "\nREAD_GETLINE_NO_INSERT FUNCITON\n" << std::endl;
std::fstream fp("C:\\cpp\\write.txt", std::ios_base::in);
int iter_count = 0;
while(!fp.eof() && iter_count < 10){
fp.getline(str, len,'\n');
int count = fp.gcount();
std::cout << "\nCurrent Count = " << count << std::endl;
std::cout << str << std::endl;
std::cout << " Stream State : Good: " << fp.good() << " Fail: " << fp.fail() << std::endl;
iter_count++;
}
std::cout << "\nCount = " << iter_count << std::endl;
fp.close();
}
int main(int argc, char **argv)
{
read_file_getline_no_insert();
return 0;
}
If wee see the output of above code:
READ_GETLINE_NO_INSERT FUNCITON
Current Count = 9
This is a
Stream State : Good: 0 Fail: 1
Current Count = 0
Stream State : Good: 0 Fail: 1
You would see that the state of stream goes Bad and the fail bit is set. I am unable to understand this behavior.
Rgds
Sapan
std::getline() will read a string from a stream, until it encounters a delimiter (newline by default).
Unlike fgets(), std::getline() discards the delimiter. But, also unlike fgets(), it will read the whole line (available memory permitting) since it works with a std::string rather than a char *. That makes it somewhat easier to use in practice.
All types derived from std::istream (which is the base class for all input streams) also have a member function called getline() which works a little more like fgets() - accepting a char * and a buffer size. It still discards the delimiter though.
The C++-specific options are overloaded functions (i.e. available in more than one version) so you need to read documentation to decide which one is appropriate to your needs.

Reading a text file using a relative path

I'm looking to read a text file using a relative path in C++. The directory structure is as follows: source -> Resources -> Settings -> Video.txt.
The contents of the file (note: these are used for testing, of course):
somes*** = 1
mores*** = 2
evenmores*** = 3
According to my research, this is possible. Still, I find that this has yet to work. For example, when I step through my debugger, my char *line variable which is used to receive line-by-line text file input is always at a constant 8 value. As to my understanding, a char pointer can act as a dynamic array of characters which you may reassign to.
Why can't I read my file? When I try do an if ( !videoSettings ), it returns true, and I get an error message (created by myself).
Code
#ifdef WIN32
const char *filePath = "Resources\\Settings\\Video.txt";
#else
const char *filePath = "Resources/Settings/Video.txt";
#endif
std::ifstream videoSettings( filePath );
if ( !videoSettings )
{
cout << "ERROR: Failed opening file " << filePath << ". Switching to configure mode." << endl;
//return false;
}
int count = 0;
char *line;
while( !videoSettings.eof() )
{
videoSettings >> line;
cout << "LOADING: " << *line << "; ";
count = sizeof( line ) / sizeof( char );
cout << "VALUE: " << line[ count - 1 ];
/*
for ( int i = count; i > count; --i )
{
if ( i == count - 4 )
{
}
}
*/
}
delete line;
Wow ok- you cannot read a string of text into just a char * you need to preallocate the memory first.
2nd the size of a char* pointer is constant - but the size of the data it points to is not
I suggest using the std::string getline call and avoid all the dynamic memory allocation
So this would be
std::ifstream in("file.txt");
std::string line;
while(getline(in, line))
{
std::cout << line << std::endl;
}
Lastly relative paths are the last of your problems in you code example :-)

Put in a string the output of autoseed PNRG in Crypto++

I'm using Cryptopp to generate a random string.
This is the code:
const unsigned int BLOCKSIZE = 16 * 8;
byte pcbScratch[ BLOCKSIZE ];
// Construction
// Using a ANSI approved Cipher
CryptoPP::AutoSeededX917RNG<CryptoPP::DES_EDE3> rng;
rng.GenerateBlock( pcbScratch, BLOCKSIZE );
// Output
std::cout << "The generated random block is:" << std::endl;
string str = "";
for( unsigned int i = 0; i < BLOCKSIZE; i++ )
{
std::cout << "0x" << std::setbase(16) << std::setw(2) << std::setfill('0');
std::cout << static_cast<unsigned int>( pcbScratch[ i ] ) << " ";
str += pcbScratch[i];
}
std::cout << std::endl;
std::cout << str <<std::endl;
I've put int the code a new var: string str = "".
Then in the for append for each result, the part of the string.
But my output is dirty! I see only strange ASCII char.
How can I set well the string?
Thank you.
You will want to some output encoding, e.g.
base64
hex
because what you are seeing is the raw binary data, interpreted as if it were text. Random characters are the consequence
AFAICT (google) you should be able to use something like this
#include <base64.h>
string base64encoded;
StringSource(str, true, new Base64Encoder(new StringSink(base64encoded)));
Appending arbitrary bytes (chars) to the end of a string is going to result in that containing some non-printable characters:
http://en.wikipedia.org/wiki/Control_character
You don't mention what you wanted or expected. Did you want the string to be the same as what got sent to std::cout? If so, you can use a stringstream via #include <sstream>:
std::stringstream ss;
for( unsigned int i = 0; i < BLOCKSIZE; i++ )
{
ss << "0x" << std::setbase(16) << std::setw(2) << std::setfill('0');
ss << static_cast<unsigned int>(pcbScratch[i]);
}
str = ss.str();
You can also use Crypto++'s built in HexEncoder:
std::cout << "The generated random block is:" << std::endl;
string str = "0x";
StringSource ss(pcbScratch, BLOCKSIZE, true,
new HexEncoder(
new StringSink(str),
true, // uppercase
2, // grouping
" 0x" // separator
) // HexDecoder
); // StringSource
The StringSource 'owns' the HexEncoder, so there's no need to call delete.

How detect if file was overwrote?,

In my C/C++ program I need to check if the file from what I read have been overwrote (its inode was changed or some new lines were added). If I'm now wrong fstat and fstat64 can be usefull only when I use Linux but not for windows. Is there any universal (to work for complex OSes) way to do this? And also can you tell me how do this using fstat64?
You can keep track of when the file was last written to know if it has been modified. The cross platform solution is using boost::filesystem. Windows doesn't have fstat64 AFAIK.
http://www.boost.org/doc/libs/1_44_0/libs/filesystem/v2/doc/index.htm
http://rosettacode.org/wiki/File_modification_time#C.2B.2B
#include <boost/filesystem/operations.hpp>
#include <ctime>
#include <iostream>
int main( int argc , char *argv[ ] ) {
if ( argc != 2 ) {
std::cerr << "Error! Syntax: moditime <filename>!\n" ;
return 1 ;
}
boost::filesystem::path p( argv[ 1 ] ) ;
if ( boost::filesystem::exists( p ) ) {
std::time_t t = boost::filesystem::last_write_time( p ) ;
std::cout << "On " << std::ctime( &t ) << " the file " << argv[ 1 ]
<< " was modified the last time!\n" ;
std::cout << "Setting the modification time to now:\n" ;
std::time_t n = std::time( 0 ) ;
boost::filesystem::last_write_time( p , n ) ;
t = boost::filesystem::last_write_time( p ) ;
std::cout << "Now the modification time is " << std::ctime( &t ) << std::endl ;
return 0 ;
} else {
std::cout << "Could not find file " << argv[ 1 ] << '\n' ;
return 2 ;
}
}
I don't have a code sample for you, but can you check the last modified time of the file, against what it was when you first opened it?
Edit
Found a pretty good snippet that appears to do the trick
http://www.jb.man.ac.uk/~slowe/cpp/lastmod.html

C++ converting a mac id string into an array of uint8_t

I want to read a mac id from command line and convert it to an array of uint8_t values to use it in a struct. I can not get it to work. I have a vector of string for the mac id split about : and I want to use stringstream to convert them with no luck. What I am missing?
int parseHex(const string &num){
stringstream ss(num);
ss << std::hex;
int n;
ss >> n;
return n;
}
uint8_t tgt_mac[6] = {0, 0, 0, 0, 0, 0};
v = StringSplit( mac , ":" );
for( int j = 0 ; j < v.size() ; j++ ){
tgt_mac[j] = parseHex(v.at(j));
}
I hate to answer this in this fashion, but sscanf() is probably the most succinct way to parse out a MAC address. It handles zero/non-zero padding, width checking, case folding, and all of that other stuff that no one likes to deal with. Anyway, here's my not so C++ version:
void
parse_mac(std::vector<uint8_t>& out, std::string const& in) {
unsigned int bytes[6];
if (std::sscanf(in.c_str(),
"%02x:%02x:%02x:%02x:%02x:%02x",
&bytes[0], &bytes[1], &bytes[2],
&bytes[3], &bytes[4], &bytes[5]) != 6)
{
throw std::runtime_error(in+std::string(" is an invalid MAC address"));
}
out.assign(&bytes[0], &bytes[6]);
}
Your problem may be in the output of the parsed data. The "<<" operator makes decisions on how to display data based on the data type passed it, and uint8_t may be getting interpretted as a char. Make sure you cast the array values to ints when printing, or investigate in a debugger.
The sample program:
uint8_t tgt_mac[6] = {0};
std::stringstream ss( "AA:BB:CC:DD:EE:11" );
char trash;
for ( int i = 0; i < 6; i++ )
{
int foo;
ss >> std::hex >> foo >> trash;
tgt_mac[i] = foo;
std::cout << std::hex << "Reading: " << foo << std::endl;
}
std::cout << "As int array: " << std::hex
<< (int) tgt_mac[0]
<< ":"
<< (int) tgt_mac[1]
<< ":"
<< (int) tgt_mac[2]
<< ":"
<< (int) tgt_mac[3]
<< ":"
<< (int) tgt_mac[4]
<< ":"
<< (int) tgt_mac[5]
<< std::endl;
std::cout << "As unint8_t array: " << std::hex
<< tgt_mac[0]
<< ":"
<< tgt_mac[1]
<< ":"
<< tgt_mac[2]
<< ":"
<< tgt_mac[3]
<< ":"
<< tgt_mac[4]
<< ":"
<< tgt_mac[5]
<< std::endl;
Gives the following output ( cygwin g++ )
Reading: aa
Reading: bb
Reading: cc
Reading: dd
Reading: ee
Reading: 11
As int array: aa:bb:cc:dd:ee:11
As unint8_t array: ª:»:I:Y:î:◄
First I want to point out that I think #Steven's answer is a very good one - indeed I noticed the same: the values are correct, but the output looks awkward. This is due to ostream& operator<<( ostream&, unsigned char ) being used, since the uint8_t type you used is a typedef for unsigned char (as I found in the linux man pages). Note that on VC++, the typedef isn't there, and you have to use unsigned __int8 instead (which will also route you to the char specialization).
Next, you can test your code like this (output-independent):
assert( uint8_t( parseHex( "00" ) ) == uint8_t(0) );
assert( uint8_t( parseHex( "01" ) ) == uint8_t(1) );
//...
assert( uint8_t( parseHex( "ff" ) ) == uint8_t(255) );
In addition to Steven's answer, I just want to point out the existence of the transform algorithm, which could still simplify your code.
for( int j = 0 ; j < v.size() ; j++ ){
tgt_mac[j] = parseHex(v.at(j));
}
Writes in one line:
std::transform( v.begin(), v.end(), tgt_mac, &parseHex );
(And I know that hasn't to do with the question...)
(See codepad.org for what it then looks like)
I think you are using the std::hex in the wrong place:
#include <sstream>
#include <iostream>
int main()
{
std::string h("a5");
std::stringstream s(h);
int x;
s >> std::hex >> x;
std::cout << "X(" << x << ")\n";
}