i have a function defined as follows:
void AddHeadCode(std::ofstream &ostream, size_t length){
ostream.write((char*)length, sizeof(length));
ostream.seekp(0x10L, std::ios::beg);
}
Now when this executes, it will fail obviously... as the char pointer will point nowhere.
But i want the actual pointervalue written into the file.
Like length = 19152
Then when I open up the file in an HEX Editor, I should find 0d4a there.
How can this be achieved in c++? Im kinda lost here...
Take the address of your length variable, and pass that address to .write:
void AddHeadCode(std::ofstream &ostream, size_t length){
// by popular demand, removed C-style cast
ostream.write(reinterpret_cast<char*>(&length), sizeof(length));
ostream.seekp(0x10L, std::ios::beg);
}
But, this is not usually refered to as writing an integer "as hex". This is sometimes referred to as writing an integer "as binary", or simply writing an integer.
Note that what you have done is not a portable practice. If you read the value back in on a different computer (or even on the same computer, but with a different compiler), you might not read in the same value.
Filestreams are tricky so I am uncertain about that but I use this for stringstreams:
std::basic_stringstream<wchar_t> oTmpStream;
oTmpStream << L"0x" << std::nouppercase << std::setfill( L'0' ) << std::hex << std::setw( 8 ) << iSomeValue
// or without fancy formatting;
oTmpStream << std::hex << iSomeValue
Related
So I'm trying to make use of zlib in C++ using Visual Studio 2019, to extract the contents from a specific file format. According to the documentation that I'm following, this file format is consisted mainly consisted of values that's consisted of "32-bit (4-byte) little-endian signed integers", and within several sections of the file there's also blocks of data that is compressed by zlib to save space.
But I believe that's not relevant to my problem, I'm having trouble with just simply using zlib.
I should note that I'm unfamiliar to using fstream and more specifically, zlib. I can guess uncompress() may be the function I'm looking since the number for the compressed bytes is read before I can even call it. It's not unlikely the issue could be related to the former library.
But I do believe I'm not putting in the buffer properly (or maybe not even reading it from the file properly), as I'm getting either syntax errors for incorrect types, the program crashing, and most importantly, unable to get the blocks of the uncompressed data. I can tell it's not working properly as it's returning Z_STREAM_ERROR (-2) or Z_DATA_ERROR (-3) from the call, not Z_OK (0). The program at least reads the 32-bit data correctly, at least.
#include <iostream>
#include <fstream>
#include "zlib.h"
using namespace std;
//Basically it works like this.
int main()
{
streampos size;
unsigned char memblock;
char* memblock2;
Bytef memblock3;
Bytef memblock_res;
int ret;
int res=0;
uint32_t a;
ifstream file("not_a_real_file.lol", ios::in | ios::binary | ios::ate);
if (file.is_open())
{
size = file.tellg();
file.seekg(0, ios::beg);
file.read(reinterpret_cast<char*>(&a), sizeof(a));
std::cout << "Format Identifier: " << a << "\n";
file.read(reinterpret_cast<char*>(&a), sizeof(a));
std::cout << "File Version: " << a << "\n";
//A bunch of other 32-bit values be here, would be redudent to put them all.
file.read(reinterpret_cast<char*>(&a), sizeof(a));
std::cout << "Length of Zlib Block: " << a << "\n";
//Anyways, this is where things get really weird. I'm using 'a' to determine the length of bytes, and I know it should be stored into it's own variable.
char* membuffer = new char[a];
file.read(membuffer, a);
uLongf zaz;
res=uncompress(&memblock_res, &zaz, (unsigned char*)(&membuffer), a);
if (res==Z_OK)
std::cout << "Good!\n";
std::cout << "This resulted in " << (int)res << ", it's got this many bytes: " << zaz << "\n";
//It should be Z_DATA_ERROR with 0 bytes returned; it's obviously not the desired results.
file.read(reinterpret_cast<char*>(&a), sizeof(a));
std::cout << "Value after Block: " << a << "\n";
//At least it seems the 32-bit value that comes after the block is correctly read.
file.close();
}
}
Either I'm using read() incorrectly, or don't know how to properly convert the data into the use for uncompress(). Or maybe I'm using the wrong functions; I honestly have no clue. I spent hours trying to figure this out from looking up things, but having no avail.
I need to read in an mp3 file so that I can run the hash(). I do not need to parse the mp3 tag data out of this so I can just read the whole thing all together.
Currently I am using ifstream() to open the file in binary mode. I then get the size of the file, allocate enough space with a char* and read it all at once.
I know that when I run cout on this data I can only see "ID3 and some gibberish." I opened the mp3 file up in a hex editor and ID3 and the gibberish was what was at the beginning of the file. The next binary data I believe is being interpreted as end of line/string and does not print.
This is okay because I don't need to print it. I need to get the data in a format that I can run the Hash function on. Any ideas on a type I can convert it to that will not interpret the end of the file being a couple bytes in?
Here is code of what I have so far.
bool Sender::openSoundFile(){
streampos size;
soundSampleStream.open(soundFilePath.c_str(), ios::in|ios::binary|ios::ate);
if(!soundSampleStream.is_open()){
return false;
}
size = soundSampleStream.tellg();
cout << "Size of MP3: " << size << endl;
soundFileInMemory = new char [size];
soundSampleStream.seekg (0, ios::beg);
soundSampleStream.read(soundFileInMemory, size);
cout << "Error is: " << strerror(errno) << endl;
cout << "gcount: " << soundSampleStream.gcount() << endl;
soundSampleStream.close();
cout << soundFileInMemory << endl;
return true;
}
I get no error on reading the file and gcount() comes back with the correct numbers of bytes for the file.
Edit 1:
To add some more on this. The hash() seems to hash the char* and not the data being pointed at because the hash value changes on different program runs. This is why I need to convert to some other thing. I also don't think that a vector is supported by the c++11 hash().
std::string has a constructor that takes a char * and a size_t. See the fourth item in http://en.cppreference.com/w/cpp/string/basic_string/basic_string.
std::string file_contents(soundFileInMemory, size);
That will convert your char array to a string.
As the title said, I'm curious if there is a way to read a C++ string with scanf.
I know that I can read each char and insert it in the deserved string, but I'd want something like:
string a;
scanf("%SOMETHING", &a);
gets() also doesn't work.
Thanks in advance!
this can work
char tmp[101];
scanf("%100s", tmp);
string a = tmp;
There is no situation under which gets() is to be used! It is always wrong to use gets() and it is removed from C11 and being removed from C++14.
scanf() doens't support any C++ classes. However, you can store the result from scanf() into a std::string:
Editor's note: The following code is wrong, as explained in the comments. See the answers by Patato, tom, and Daniel Trugman for correct approaches.
std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
// ...
}
I'm not entirely sure about the way to specify that buffer length in scanf() and in which order the parameters go (there is a chance that the parameters &str[0] and str.size() need to be reversed and I may be missing a . in the format string). Note that the resulting std::string will contain a terminating null character and it won't have changed its size.
Of course, I would just use if (std::cin >> str) { ... } but that's a different question.
Problem explained:
You CAN populate the underlying buffer of an std::string using scanf, but(!) the managed std::string object will NOT be aware of the change.
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.reserve(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: '" << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: (size = 0)
Underlying buffer: Daniel (size = 6)
So, what happened here?
The object std::string is not aware of changes not performed through the exported, official, API.
When we write to the object through the underlying buffer, the data changes, but the string object is not aware of that.
If we were to replace the original call: token.reseve(64) with token.resize(64), a call that changes the size of the managed string, the results would've been different:
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.resize(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: " << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: Daniel (size = 64)
Underlying buffer: Daniel (size = 6)
Once again, the result is sub-optimal. The output is correct, but the size isn't.
Solution:
If you really want to make do this, follow these steps:
Call resize to make sure your buffer is big enough. Use a #define for the maximal length (see step 2 to understand why):
std::string buffer;
buffer.resize(MAX_TOKEN_LENGTH);
Use scanf while limiting the size of the scanned string using "width modifiers" and check the return value (return value is the number of tokens scanned):
#define XSTR(__x) STR(__x)
#define STR(__x) #x
...
int rv = scanf("%" XSTR(MAX_TOKEN_LENGTH) "s", &buffer[0]);
Reset the managed string size to the actual size in a safe manner:
buffer.resize(strnlen(buffer.data(), MAX_TOKEN_LENGTH));
The below snippet works
string s(100, '\0');
scanf("%s", s.c_str());
Here a version without limit of length (in case of the length of the input is unknown).
std::string read_string() {
std::string s; unsigned int uc; int c;
// ASCII code of space is 32, and all code less or equal than 32 are invisible.
// For EOF, a negative, will be large than 32 after unsigned conversion
while ((uc = (unsigned int)getchar()) <= 32u);
if (uc < 256u) s.push_back((char)uc);
while ((c = getchar()) > 32) s.push_back((char)c);
return s;
}
For performance consideration, getchar is definitely faster than scanf, and std::string::reserve could pre-allocate buffers to prevent frequent reallocation.
You can construct an std::string of an appropriate size and read into its underlying character storage:
std::string str(100, ' ');
scanf("%100s", &str[0]);
str.resize(strlen(str.c_str()));
The call to str.resize() is critical, otherwise the length of the std::string object will not be updated. Thanks to Daniel Trugman for pointing this out.
(There is no off-by-one error with the size reserved for the string versus the width passed to scanf, because since C++11 it is guaranteed that the character data of std::string is followed by a null terminator so there is room for size+1 characters.)
int n=15; // you are going to scan no more than n symbols
std::string str(n+1); //you can't scan more than string contains minus 1
scanf("%s",str.begin()); // scanf only changes content of string like it's array
str=str.c_str() //make string normal, you'll have lots of problems without this string
I have a struct:
struct zipType{
int postalCode;
double longitude;
double latitude;
};
And I have a function called zipToCout:
void zipToCout(zipType zip){
cout << "Postal Code = " << zip.postalCode << "\tLongitude = " << zip.longitude << "\t\tLatitude = " << zip.latitude << endl;
}
now I need a function to read a binary file into a zipType struct. The function prototype is supposed to be void binRead(zipType *zip, fstream *input);. The only way I can get close to this is by changing the prototype to this void binRead(zipType &zip, fstream &input). With that, Here is what I currently have for the function:
void binRead(zipType &zip, fstream &input){
int temp;
double temp2;
zipType tempZip;
tempZip = zip;
//cout << "Reader at location " << input.tellg() << endl;
input.read((char*)&temp,sizeof(int));
tempZip.postalCode=temp;
input.read((char*)&temp2,sizeof(double));
tempZip.longitude=temp2;
input.read((char*)&temp2,sizeof(double));
tempZip.latitude=temp2;
zipToCout(tempZip);
}
This is the output I get when I run this on my sample.bin file:
Postal Code = 64501 Longitude = 2.61457e-261 Latitude = -7.13357e+288
What I need help with is reformatting the function to use *'s instead of &'s and fixing how to read the file into the three variables correctly. Thanks for looking! Also, I only have to read one zipType from the file at this point.
void binRead(zipType *zip, fstream *input)
{
input->read((char*)( &zip->postalCode ), sizeof(int ));
input->read((char*)( &zip->longitude ), sizeof(double));
input->read((char*)( &zip->latitude ), sizeof(double));
zipToCout(*zip);
}
Also, depending on the architecture (ie. 32-bit x86), the following may work:
void binRead(zipType *zip, fstream *input)
{
input->read((char*) zip, sizeof(zipType));
zipToCout(*zip);
}
That will only work on architectures where double only requires 4-byte alignment. I believe 32-bit x86 fits that. A quick test I wrote locally suggests that's the case.
A quick note on portable, maintainable code that goes beyond the immediate need above: Code such as the above works well enough when the machine saving the data is the same as the machine that later reads the data. It does, however, result in portability problems. If you really want to design a file format that's portable across machines and preserves data, the above techniques aren't really conducive to that.
I think the problem lies in while printing the values.
if you see the value is read in string and printed as other datatypes. I guess proper conversion function should work for you. and use see my comments below.
void binRead(zipType &zip, fstream &input){
char* temp = NULL
char* temp2 = NULL;
zipType tempZip;
tempZip = zip;
//cout << "Reader at location " << input.tellg() << endl;
input.read(temp,sizeof(int));
tempZip.postalCode=(atoi)temp; //use for proper conversion, or other function
input.read(temp2,sizeof(double));
tempZip.longitude=static_cast<double*>temp2; //use for proper conversion, or other function
input.read(temp2,sizeof(double));
tempZip.latitude=static_cast<double*>temp2;
zipToCout(tempZip);
}
Few comments on above code,
tempZip = zip; //why this, since you havn't declared any proper assignment
operator. Use memcpy instead.
tempZip.postalCode=(atoi)temp; //use for proper conversion, or other function
tempZip.longitude=static_cast<double*>temp2; //use for proper conversion, or other function
Let me know if this solves your problem.
I am in larval stage with Python and pre-egg stage in C++, but i am trying to do my best, specially with the "Don't Repeat Yourself" principle.
I have a multichannel raw file-format to open, with a main ascii header with fields representable as strings and integers (always coded as chars padded with white spaces). The second part is N headers, with N being a field of the main header, and each of those headers has itself a lot more of text and number fields (coded as ascii) refering to the length and size of the actual 16 bit multichannel streams that compose the rest of the file.
So far, I have this working code in C++:
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <map>
using namespace std;
struct Header {
string version;
string patinfo;
string recinfo;
string start_date;
string start_time;
int header_bytes;
string reserved;
int nrecs;
double rec_duration;
int nchannels;
};
struct Channel {
string label;
string transducertype;
string phys_dim;
int pmin;
int pmax;
int dmin;
int dmax;
string prefiltering;
int n_samples;
string reserved;
};
int main()
{
ifstream edf("/home/helton/Dropbox/01MIOTEC/06APNÉIA/Samples/Osas2002plusQRS.rec", ios::binary);
// prepare to read file header
Header header;
char buffer[80];
// reads header fields into the struct 'header'
edf.read(buffer, 8);
header.version = string(buffer, 8);
edf.read(buffer, 80);
header.patinfo = string(buffer, 80);
edf.read(buffer, 80);
header.recinfo = string(buffer, 80);
edf.read(buffer, 8);
header.start_date = string(buffer, 8);
edf.read(buffer, 8);
header.start_time = string(buffer, 8);
edf.read(buffer, 8);
stringstream(buffer) >> header.header_bytes;
edf.read(buffer, 44);
header.reserved = string(buffer, 44);
edf.read(buffer, 8);
stringstream(buffer) >> header.nrecs;
edf.read(buffer,8);
stringstream(buffer) >> header.rec_duration;
edf.read(buffer,4);
stringstream(buffer) >> header.nchannels;
/*
cout << "'" << header.version << "'" << endl;
cout << "'" << header.patinfo << "'" << endl;
cout << "'" << header.recinfo << "'" << endl;
cout << "'" << header.start_date << "'" << endl;
cout << "'" << header.start_time << "'" << endl;
cout << "'" << header.header_bytes << "'" << endl;
cout << "'" << header.reserved << "'" << endl;
cout << "'" << header.nrecs << "'" << endl;
cout << "'" << header.rec_duration << "'" << endl;
cout << "'" << header.nchannels << "'" << endl;
*/
// prepare to read channel headers
int ns = header.nchannels; // ns tells how much channels I have
char title[16]; // 16 is the specified length of the "label" field of each channel
for (int n = 0; n < ns; n++)
{
edf >> title;
cout << title << endl; // and this successfully echoes the label of each channel
}
return 0;
};
Some remarks I already have to make:
I opted to use struct because the format specification is very hardcoded;
I didn't iterate over the main header fields because the number of bytes and types to read seemed to me rather arbitrary;
Now that I successfully got each channel's label, I would actually create structs for each channel's fields, which by themselves would have to be stored perhaps in a map.
My (hopefully straightforward) question is:
"Should I worry about cutting corners to make this kind of code more 'Pythonic' (more abstract, less repetitive), or this is not the way things work in C++?"
Many Python evangelists (as I would be myself, because I love it) highlight its easyness to use and all that. So, I will wonder for some time if I am doing dumb things or only doing things right, but not so "automagical" because of the very nature of C++.
Thanks for reading
Helton
I'd say there's no such thing as Pythonic C++ code. The DRY principle applies in both languages, but much of what is considered "Pythonic" is simply the shortest, sweetest way of expressing logic in Python, using Python-specific constructs. Idiomatic C++ is quite different.
lambda, for example, is sometimes not considered very Pythonic and reserved for cases where no other solution exists, but is just being added to the C++ standard. C++ has no keyword arguments, which are very Pythonic. C++ programmers don't like constructing a map when not necessary, while a Python programmer might throw dict at a lot of problems where they just happen to make the intention clearer than the efficient alternative.
If you want to save typing, use the function I posted earlier, then:
header.version = read_field(edf, 8);
header.patinfo = read_field(edf, 80);
That should save you quite a few lines. But more important than those few lines is that you've achieved a small amount of modularity: how to read a field and what fields to read are now separate parts of your program.
You are correct: as written, the code is repetitive (and has no error checking). Each field that you read really requires you to take three or five steps, depending on the type of data being read:
Read the field from the stream
Ensure the read succeeded
Parse the data (if necessary)
Ensure the parse succeeded (if necessary)
Copy the data into the target location
You can wrap all three of these up into a function so that the code is less repetitive. For example, consider the following function templates:
template <typename TStream, typename TResult>
void ReadFixedWidthFieldFromStream(TStream& str, TResult& result, unsigned sz)
{
std::vector<char> data(sz);
if (!str.read(&data[0], sz))
throw std::runtime_error("Failed to read from stream");
std::stringstream ss(&data[0]);
if (!(ss >> result))
throw std::runtime_error("Failed to parse data from stream");
}
// Overload for std::string:
template <typename TStream>
void ReadFixedWidthFieldFromStream(TStream& str, std::string& result, unsigned sz)
{
std::vector<char> data(sz);
if (!str.read(&data[0], sz))
throw std::runtime_error("Failed to read from stream");
result = std::string(&data[0], sz);
}
Now your code can be much more succinct:
ReadFixedWidthFieldFromStream(edf, header.version, 8);
ReadFixedWidthFieldFromStream(edf, header.patinfo, 80);
ReadFixedWidthFieldFromStream(edf, header.recinfo, 80);
// etc.
This code is straightforward, simple, and easy to understand. If it's working, don't waste time changing it. I'm sure there's plenty of badly written, complex, and difficult to understand (and probably incorrect) code that should be fixed first :)
The Zen of Python doesn't mention DRY explicitly.
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
For reading from file directly in strings see this question The rest is wrong. but personally I think there's a better/cleaner way of doing this.
If you know the size of the structure don't use string, use primitive C types (and make sure the structure is packed). See these links: http://msdn.microsoft.com/en-us/library/2e70t5y1(v=vs.80).aspx & http://gcc.gnu.org/onlinedocs/gcc-3.2.3/gcc/Type-Attributes.html
I would do it this way for example (not sure about the size of each string but you get the idea):
struct Header {
char version[8];
char patinfo[80];
char recinfo[80];
char start_date[8];
char start_time[8];
int header_bytes;
char reserved[44];
int nrecs;
double rec_duration;
int nchannels;
};
Once you have a packed structure you can read it directly from the file:
struct Header h;
edf.read(&h,sizeof(struct Header));
For me this is the cleanest way to do it, but remember you must have your structure packed so that you have the guarantee that the structure in memory has the same size as the structure saved in the file - this is not very hard to see while testing.