Qt Writing mouse position to file - c++

I'm writing a simple application using QT that should write the mouse position inside certain widget to a file (the writing is on user double click).
The situation is as follows:
The user performs double click inside the widget.
In the Debug window i can see the current mouse position.
The mouse position is written to the file as expected.
The issue when the mouse position (X or Y) is less then 100. In case that the position is less then 100 the number that is written to the file is always 3 digits number.
For example: Mouse position in the debug window is: 34, 251 and in the file the position is 344, 251. So i can't predict if the actual X position was 34 or 344 because both of them are valid values.
This is the part that responsible on writing the data to the file.
QByteArray temp1;
char buf[2];
::sprintf(buf, "%d", X); // X is the mouse x position
temp1.append(buf);
temp1.append(",");
::sprintf(buf, "%d", Y); // Y is the mouse y position
temp1.append(buf);
...
if (tempFile.open(QIODevice::ReadWrite)) {
QTextStream stream(&tempFile);
stream << temp1;
}
tempFile.close();
This code works good only for positions larger then 100 for some reason.
Thanks

Problem 1
The buffer is too small.
char buf[2];
There needs to be place for multiple digits and a terminating NUL byte, since your are using sprintf here:
::sprintf(buf, "%d", X);
Writing over the end of the array results in undefined behavior.
So you need to increase the size of the array to fix it.
Problem 2
the file is opened in ReadWrite mode
the X and Y value are written
the file is closed
The next time the values are written the same operations are called. ReadWrite mode does not delete the existing contents of the file. For example if you write once
128,1024
and then the next time you write the position: 60,30 it would look like this:
60,3024
One possible solution for this problem would be to apply Truncate mode.
if (tempFile.open(QIODevice::ReadWrite | QIODevice::Truncate)) {

Related

C++ ifstream will read some values then stop

I am trying to write a program that reads 940 4-byte long values of binary data [hex] from a bin file, and output the values to console. I have ifstream::read, cout and seekg operations in a loop.
It will work for the first 10 or so iterations, and then in one iteration skip the read and write operations, preform the seekg operation, and continue on reading and writing. Also the last 200 lines or so are coming out the same value.
It will work properly for 12 iterations, then it will start outputting the wrong numbers. At this point it goes from address 0x230 to 0x28B when it should be at 0x260. It looks like read and cout are not called in this particular iteration.
The last correct value reads 3f4fc938. The next value should be 3ef646c1.
Does anyone know why this would fail? Any help is appreciated.
This is the program:
int main(int argc, char* argv[]) {
fstream in;
uint32_t buffer;
in.open(argv[1]);
in.seekg(0x6500,in.beg);
for(int i = 0; i < 940; i++) {
in.read(reinterpret_cast<char*> (&buffer),4);
cout << hex << buffer << endl;
in.seekg(0x2c,in.cur);
}
}
You have opened your file in text mode. Text mode means that operations on the file will interpret a Byte sequence that matches the platform-specific representation of a newline as a single '\n' character. If you're on Windows, for example, newlines are represented as the Byte sequence 0D 0A. So on Windows, whatever you do in your file will work well up to the point where your file happens to have a Byte with value 13 followed by a Byte with value 10. Once you reach that point, that 13 followed by 10 will be interpreted as a single character. Essentially, text mode will just swallow any Byte with value 13 if it happens to appear right before a Byte with value 10. Your application will never see the 13 and anything beyond the point where the 13 appeared will end up "shifted" by one Byte. On other platforms, other newline representations are common. If you wanna work with binary data, you will generally want to open your file in binary mode, for example
fstream in(argv[1], std::ios::binary);
or
in.open(argv[1], std::ios::binary);

MIDI Note Counting Program producing incorrect results

I wrote a program in c++ that counts the number of notes in a .mid file, outputs the number of each note (A to G#), then outputs that to a file. It doesn't find enough notes, but I can't figure out why. I've built it based on the MIDI file documentation from midi.org.
While reading the file, all it does is look for the status byte for note on, 1001nnnn, and then reads the next byte as a note. I used Anvil Studio to make a MIDI file with only 1 note, and used the program to analyze it and it found that it only had 1 note which is correct, however when I use it on much larger files (2000+ notes), it won't find nearly all of them, and sometimes it will find that 90%+ of the notes are one or two pitches.
This is the segment of the program that searches for notes. The file is open in byte mode with ios::binary
//Loop through every byte of the file
for (int i = 0; i <= size; i++) {
//Read next byte of file to tempblock
myfile.read(tempblock, 1);
//Put int value of byte in b
int b = tempblock[0];
//x = first 4 binary digits of b, appended with 0000
unsigned int x = b & 0xF0;
//If note is next, set the next empty space of notearray to the notes value, and then set notenext to 0
if (notenext) {
myfile.read(tempblock, 1);
int c = tempblock[0];
i++;
//Add the note to notearray if the velocity data byte is not set to 0
if (c != 0) {
notearray[notecount] = b;
notenext = 0;
notecount++;
}
}
//If note is not next, and x is 144 (int of 10010000, status byte for MIDI "Note on" message), set note next to true
else if (x == 144) {
notenext = 1;
}
}
Does anyone know whats going on? Am I just missing a component of the file type, or could it be a problem with the files I'm using? I am primarily looking at classical piano pieces, downloaded from midi repositories
Channel message status bytes can be omitted when they are identical with the last one; this is called running status.
Furthermore, 1001nnnn bytes can occur inside delta time values.
You have to correctly parse all messages to be able to detect notes.
The problem is very likely to be how your MIDI editor is creating the files. Many MIDI editors do not actually switch notes off - they just set their velocities to 0. This can make them a royal pain to parse.
Have a look at the raw MIDI messages contained in the file and you should see a lot of velocity messages.

Binary file not holding data properly

Im currently trying to replace a text based file in my application with a binary one. Im just doing some early tests so the code isn't exactly safe but I'm having problems with the data.
When trying to read out the data it gets about half way before it starts coming back with incorrect results.
Im creating the file in c++ and my client application is c#. I think the problem is in my c++ (which I haven't used very much)
Where the problem is at the moment is I have a vector of a struct that is called DoubleVector3 which consists of 3 doubles
struct DoubleVector3 {
double x, y, z;
DoubleVector3(std::string line);
};
Im currently writing the variables individually to the file
void ObjElement::WriteToFile(std::string file) {
std::ofstream fileStream;
fileStream.open(file); //, ios::out | ios::binary);
// ^^problem was this line. it should be
// fileStream.open(file, std::ios_base::out | std::ios_base::binary);
fileStream << this->name << '\0';
fileStream << this->materialName << '\0';
int size = this->vertices.size();
fileStream.write((char*)&size,sizeof(size));
//i have another int written here
for (int i=0; i<this->vertices.size(); i++) {
fileStream.write((char*)&this->vertices[i].x, 8);
fileStream.write((char*)&this->vertices[i].y, 8);
fileStream.write((char*)&this->vertices[i].z, 8);
}
fileStream.close();
}
When I read the file in c# the first 6 sets of 3 doubles are all correct but then I start getting 0s and minus infinities
Am I doing anything obviously wrong in my WriteToFile code?
I have the file uploaded on mega if anyone needs to look at it
https://mega.co.nz/#!XEpHTSYR!87ihtCfnGXJJNn13iE6GIpeRhlhbabQHFfN88kr_BAk
(im writing the name and material in first then the number of vertices before the actual list of vertices)
Small side question - Should I delimit these doubles or just add them in one after the other?
To store binary data in a stream, you must add std::ios_base::binary to the stream's flags when opening it. Without this, the stream is opened in text mode and line-ending conversions can happen.
On Windows, line-ending conversions mean inserting a byte 0x0D (ASCII for carriage-return) before each 0x0A byte (ASCII for line-feed). Needless to say, this corrupts binary data.

Reading integers from files in Qt

I have a text file, with many lines that goes like this:
1,1
2
7,7
11,11
13,13
0,0
I would like to take every integer and assign it to a variable, using the text file system that Qt provides. I've thought about reading every line, then using QString::split(), but I think that there are easier methods to do this.
Use QFile::readAll, pass it to QString in constructor, split it to QStringList, iterate through it with toInt function.
Edited to suit better your purpose, this is simple console test app (i would assume, that line with only number 2 is a mistake and every line should have at least two numbers).
main.cpp:
QFile f("file.txt");
f.open(QIODevice::ReadOnly);
foreach (QString i,QString(f.readAll()).split(QRegExp("[\r\n]"),QString::SkipEmptyParts)){
QPoint pos;
pos.setX(i.section(",",0,0).toInt());
pos.setY(i.section(",",1,1).toInt());
// draw something here, pos holds your coords in x as first valur and in y second (pos.x(), pos.y() )
qDebug()<<pos;
}
f.close();
your coords will hold QPoint pos, it will have one line of coords at a time, so you can draw points or do whatever you want with them. file.txt should be in a dir with a binary file or you can change as it suit you.

Binary file only overwrites first line C++

So I have a binary file that I create and initialize. If I set my pointer to seekg = 0 or seekp = 0, then I can overwrite the line of text fine. However if I jump ahead 26 bytes (the size of one line of my file and something I have certainly confirmed), it refuses to overwrite. Instead it just adds it before the binary data and pushes the old data further onto the line. I want the data completely overwritten.
char space1[2] = { ',' , ' '};
int main()
{
CarHashFile lead;
lead.createFile(8, cout);
fstream in;
char* tempS;
tempS = new char[25];
in.open("CarHash.dat", ios::binary | ios::in | ios::out);
int x = 2000;
for(int i = 0; i < 6; i++)
tempS[i] = 'a';
int T = 30;
in.seekp(26); //Start of second line
in.write(tempS, 6); //Will not delete anything, will push
in.write(space1, sizeof(space1)); //contents back
in.write((char *)(&T), sizeof(T));
in.write(space1, sizeof(space1));
in.write(tempS,6);
in.write(space1, sizeof(space1));
in.write((char *)&x, sizeof(x));
//Now we will use seekp(0) and write to the first line
//it WILL overwrite the first line perfectly fine
in.seekp(0);
in.write(tempS, 6);
in.write((char*) &x, sizeof(x));
in.write(tempS, 6);
in.write((char *) &T, sizeof(T));
return 0;
}
The CarHashFile is an outside class that creates a binary file full of the following contents when create file is invoked: "Free, " 1900 ", Black, $" 0.00f.
Everything enclosed in quotes was added as a string, 1900 as an int, and 0.00f as a float obviously. I added all of these through write, so I'm pretty sure it's an actual binary file, I just don't know why it only chooses to write over the first line. I know the file size is correct because if I set seekp = 26 it will print at the beginning of the second line and push it down. space was created to easily add the ", " combo to the file, there is also a char dol[1] = '$' array for simplicity and a char nl[1] = '\n' that lets me add a new line to the binary file (just tried removing that binary add and it forced everything onto one row, so afaik, its needed).
EDIT: Ok so, it was erasing the line all along, it just wasn't putting in a new line (kind of embarrassing). But now I can't figure out how to insert a newline into the file. I tried writing it the way I originally did with char nl[1] = { '\n' }. That worked when I first created the file, but won't afterwards. Are there any other ways to add lines? I also tried in << endl and got nothing.
I suggest taking this one step at a time. the code looks OK to me, but lack of error checking will mean any behavior could be happening.
Add error checks and reporting to all operations on in.
If that shows no issues, do a simple seek then write
result = in.pseek(26);
//print result
result = in.write("Hello World",10);
// print result
in.close();
lets know what happens
The end problem wasn't my understand of file streams. It was my lack of understanding of binary files. The newline screwed everything up royally, and while it could be added fine at one point in time, dealing with it later was a huge hassle. Once I removed that, everything else fell into place just fine. And the reason a lot of error checking or lack of closing files is there is because its just driver code. Its as bare bones as possible, I really didn't care what happened to the file at that point in time and I knew it was being opened. Why waste my time? The final version has error checks, when the main program was rewritten. And like I said, what I didn't get was binary files, not file streams. So AJ's response wasn't very useful, at all. And I had to have 25 characters as part of the assignment, no name is 25 characters long, so it gets filled up with junk. Its a byproduct of the project, nothing I can do about it, other than try and fill it with spaces, which just takes more time than skipping ahead and writing from there. So I chose to write what would probably be the average name (8 chars) and then just jump ahead 25 afterwards. The only real solution I could say that was given here was from Emile, who told me to get a Hex Editor. THAT really helped. Thanks for your time.