I am working on a project, using Qt 4.8.3 for an ARM platform. In my project, I use QGraphicsItems... one of which is a subclass of QGraphicsPixmapItem.
The code was tested with a 32 bit bitmap image - and it crashes.
The crash occurs not just when running on the ARM, but also in QVFB.
QPixmap p;
if (!p.load(filename)) // crashes here
return false;
I have tried to surround this with a try...catch, but it did not help.
I seem unable to step in the Qt code for this version... but the crash occurs inside QImageReader::read(QImage*).
The stack trace:
QImageReader::read(QImage*)
QImageReader::read()
QPixmapData::fromFile(QString const&*, QFlags<QT::ImageConversionFlag>)
QPixmap::load(QString const&, char const*, QFlags<QT::ImageConversionFlag>)
QPixmapItem::loadItemFromFile // mine, the code above
Any other type of image works... and the same 32 bit bitmap loads properly in windows, same Qt version. It fails to load (returning false) in the same Qt version, for Desktop.
I would be happy to exclude this type of file - but I don't know how.
Is there any way to check for the image type without loading the image and avoiding the crash ?
Is there a way to perhaps load the image header only, and verify its type ?
Since you want to exclude 32-bit BMP images, you have to read a BMP header. First two bytes are the characters "BM" and bytes 28, 29 contain bits per pixel.
Here is a small example where we read a file into QByteArray, check its format and load it to QPixmap if OK.
#include <QtCore>
#include <QtGui>
int main(int argc,char** argv)
{
QApplication app(argc,argv);
QFile file("./plot.bmp");
if (!file.open(QIODevice::ReadOnly)) return 1;
QByteArray ba=file.readAll();
if(ba[0]=='B' && ba[1]=='M' && ba[28] == 32) {
qDebug() << "Wrong format!";
return 1;
}
QPixmap pixmap;
pixmap.loadFromData(ba);
qDebug()<<"OK!";
return 0;
}
Or if you don't want to read everything into memory, you can open a file using QFile, ifstream etc, check these bytes and then close it.
Related
Here is the qt code that crash:
Writing the content of a 130MB binary file will crash, but writing a 2MB binary file will not.
Is there any solution for writeTextElement to write big file content? Thanks
env: qt opensource 4.8.7
Visual Studio 2010
Windows 10
big file: https://1drv.ms/u/s!Ap_EAuwC9QkXijOmXqxp9DEav3gm?e=iha0uI
test project: https://1drv.ms/u/s!Ap_EAuwC9QkXijWzOlpaWmtzOdtz?e=fDpo93
#include <QtCore/QCoreApplication>
#include <QFile>
#include <QXmlStreamWriter>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QByteArray mContentBuffer;
QFile file("C:\\Work\\bigfile.xar");
if(!file.open(QFile::ReadOnly))
{
return -1;
}
mContentBuffer = file.readAll();
file.close();
QFile profile("C:\\Work\\profile.xml");
if(!profile.open(QFile::WriteOnly|QFile::Truncate))
{
return -1;
}
QXmlStreamWriter stream(&profile);
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement("Profile");
stream.writeTextElement("Content", mContentBuffer.toBase64());
stream.writeEndElement(); // Profile
stream.writeEndDocument();
return a.exec();
}
The minimal reproducible example was a life saver.
Several things seem to be required to solve your issue in a clean way.
Mainly, the file must be read in chunks.To be precise and as mentioned in that other question, in chunks whose size is a multiple of 3 bytes (I have hardcoded 9000 below).You will need to look for the value that gives you the best performance while guaranteeing it never fails yourself.
Instead of writing in the XML in 1 go, I made it so the XML file is being written each chunk at a time.To achieve that, the code creates the node first, then uses the writeCharacters method to write text in it.
Note the if (mContentBuffer.isEmpty()) right before writing. It is indeed specified in Qt Assistant that the read function has no way of reporting errors; returning an empty QByteArray can mean either that no data was currently available for reading, or that an error occurred. Considering the while loop, it can only be an error, so we abort everything.BTW, I think but have not tested that you can just end the document, and the XML stream writer will close everything it needs to have a valid XML.
Just to make it clean, I reordered the lines of codes so that the XML file is opened before the xar file. I also added QtCore/ on every include. Not sure that last point is going to be useful on your real code.
This code implements all the above changes.It should not crash and while you will not be able to test the output on the 130MB file, you should be able to test your code vs mine on the 2MB file you has successfully read from before.
#include <QtCore/QCoreApplication>
#include <QtCore/QFile>
#include <QtCore/QXmlStreamWriter>
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
QFile profile("C:\\Work\\profile.xml");
if (!profile.open(QFile::WriteOnly | QFile::Truncate))
return -1;
QXmlStreamWriter stream(&profile);
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement("Profile");
stream.writeStartElement("Content");
QFile file("C:\\Work\\bigfile.xar");
if (!file.open(QFile::ReadOnly))
return -1;
while (!file.atEnd()) {
QByteArray mContentBuffer = file.read(9000);
if (mContentBuffer.isEmpty()) {
stream.writeEndDocument();
file.close();
profile.close();
return -1;
}
stream.writeCharacters(mContentBuffer.toBase64());
}
file.close();
stream.writeEndElement(); // </Content>
stream.writeEndElement(); // </Profile>
stream.writeEndDocument();
return a.exec();
}
Using console, I want to write the desired user's input into a file via getline function inside the wFile function and then read it. I face with logical error during Runtime; whatever I as user write doesn't type into the output terminal and it doesn't succeed more steps. Apparently fwrite function with this feature in the libraries exists, but I want to write my own code differently this way. I think I must have neglected a point. Here's the code:
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QString>
#include <QTextStream>
#include <String>
#include <cstdlib>
using namespace std;
void wFile(QString Filename)
{
QFile mFile(Filename);
QTextStream str(&mFile);
qDebug() << "what do you want to write in the desired file: ";
istream& getline (istream& is, string& str);
if (!mFile.open(QFile::WriteOnly | QFile::Text))
{
qDebug() << "could not open the file";
return;
}
mFile.flush();
mFile.close();
}
void read (QString Filename){
QFile nFile(Filename);
if(!nFile.open(QFile::ReadOnly | QFile::Text))
{
qDebug() << "could not open file for reading";
return;
}
QTextStream in(&nFile);
QString nText = in.readAll();
qDebug() << nText;
nFile.close();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString nFilename ="P:/DocumentArminV.txt";
wFile(nFilename);
read(nFilename);
return a.exec();
}
Spoiler alarm: At the very end of this answer, there is a very simple recommendation for a fix.
What OP did
Concerning istream& getline (istream& is, string& str); in wFile(QString Filename):
This declares function getline() in function wFile().
This is a valid declaration concerning C++.
Concerning the sample code, I missed the respective headers. IMHO,
#include <istream> and
#include <string>
are required to make this compiling.
However, it is possible that the existing #includes include them indirectly. So, OP's code may even compile without them.
Declaring functions, which are not used as well as re-declaring functions which are already declared is somehow useless but not wrong.
To demonstrate this, I made a small sample:
#include <cstdio>
#include <istream>
#include <string>
void func()
{
puts("in func()\n");
std::istream& getline(std::istream&, std::string&);
// Even duplicated prototyping is accepted without complaints:
std::istream& getline(std::istream&, std::string&);
}
int main ()
{
func();
return 0;
}
compiles and runs perfectly.
Output:
in func()
Live Demo on coliru
What OP (probably) wanted
Using console, I want to write the desired user's input into a file via getline function inside the wFile function and then read it.
This sounds a bit confusing to me. std::getline(std::cin, ) can be used to read user input from console. May be, it's a bit bad wording only.
Assuming, the OP wanted to read input from console, obviously, declaring a function is not sufficient – it must be called to become effective:
#include <iostream>
void func()
{
std::cout << "Enter file name: ";
std::string fileName; std::getline(std::cin, fileName);
std::cout << "Got file name '" << fileName << "'\n");
}
int main ()
{
func();
return 0;
}
Output:
Enter file name: test.txt↵
Got file name 'test.txt'
Live Demo on coliru
C++ std vs. Qt
Qt is undoubtly built on top of the C++ std library. However, though it's possible it is not recommended to mix both APIs when it can be prevented (or there aren't specific reasons to do so).
Both, Qt and C++ std, are a possibility to write portable software.
Qt covers a lot of things which are provided in the std library as well but a lot of other things additionally which are not or not yet part of std. In some cases, the Qt is a bit less generic but more convenient though this is my personal opinion. IMHO, the following explains how I came to this:
std::string vs. QString
std::string stores a sequence of chars. The meaning of chars when exposed as glyph (e.g. printing on console or displaying in a window) depends on the encoding which is used in this exposing. There are lot of encodings which interprete the numbers in the chars in distinct ways.
Example:
std::string text = "\xc3\xbc";
Decoded/displayed with
Windows-1252: ü
UTF-8: ü
Based on character type of std::string, it is not possible to determine the encoding. Hence, an additional hint must be provided to decode this properly.
(AFAIK, it is similar for std::wstring and wchar_t.)
QString stores a sequence of Unicode characters. So, one universal encoding was chosen by design to mitigate the "encoding hell".
As long as the program operates on QString, no encoding issues should be expected. The same is true when combining QString with other functions of Qt. However, it becomes a bit more complicated when "leaving the Qt universe" – e.g. storing contents of a std::string to QString.
This is the point where the programmer has to provide the additional hint for the encoding of the contents in std::string. QString provides a lot of from...() and to...() methods which can be used to re-encode contents but the application programmer is still responsible to chose the right one.
Assuming that the intended contents of text should have been the ü (i.e. UTF-8 encoding), this can be converted to QString (and back) by:
// std::string (UTF-8) -> QString
std::string text = "\xc3\xbc";
QString qText = QString::fromUtf8(text.c_str());
// QString -> std::string (UTF-8)
std::string text2 = qText.toUtf8();
This has to be considered when input from std::cin shall be passed to QString:
std::cout << "Enter file name: ";
std::string input; std::getline(std::cin, input);
QString qFileName = QString::fromLocal8Bit(input);
And even now, the code contains a little flaw – the locale of std::cin might have changed with std::ios::imbue(). I must admit that I cannot say much more about this. (In daily work, I try to prevent this topic at all e.g. by not relying on Console input which I consider especially critical on Windows – the OS on which we usually deploy to customers.)
Instead, a last note about OP's code:
How to fix it
Remembering my above recommendation (not to mix std and Qt if not necessary), this can be done in Qt exclusively:
QTextStream qtin(stdin);
qtin.readline();
I must admit that I never did it by myself but found this in the Qt forum: Re: stdin reading.
I have no idea why, but i can´t get the simplest example of QTemporaryFile to run... My real intent is to write data from QAudioInput into a temporary file before it is processed later.
After trying several times I realized that neither .read(), .readLine(), .readAll() or .write() would have any effect... The error string is always "Unknown Error" and it neither works for QFile or QTemporaryFile.
#include <QCoreApplication>
#include <QTemporaryFile>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTemporaryFile tf;
tf.open();
tf.write("Test");
QTextStream in(&tf);
qDebug() << "Testprogramm";
qDebug() << tf.isOpen();
qDebug() << tf.errorString();
qDebug() << in.readLine();
qDebug() << tf.readAll();
tf.close();
return a.exec();
}
The debug posts:
Testprogramm
true
"Unknown error"
""
""
Thank you in advance!
You need to move the file pointer back to the beginning of the file. This has to be done on the file itself when there's no stream on the file, or using the stream when one exists. Also - QFile is a proper C++ class that manages the file resource. There's no need to manually close the file. QFile::~QFile does that job.
The following works just fine:
#include <QtCore>
int main() {
auto line = QLatin1String("Test");
QTemporaryFile tf;
tf.open();
Q_ASSERT(tf.isOpen());
tf.write(line.data());
tf.reset(); // or tf.seek(0)
QTextStream in(&tf);
Q_ASSERT(in.readLine() == line);
in.seek(0); // not in.reset() nor tf.reset()!
Q_ASSERT(in.readLine() == line);
}
The above also demonstrates the following techniques applicable to sscce-style code:
Inclusion of entire Qt module(s). Remember that modules include their dependencies, i.e. #include <QtWidgets> is sufficient by itself.
Absence of main() arguments where unnecessary.
Absence of QCoreApplication instance where unnecessary. You will get clear runtime errors if you need the application instance but don't have one.
Use of asserts to indicate conditions that are expected to be true - that way you don't need to look at the output to verify that it is correct.
Use of QLatin1String over QStringLiteral where ASCII strings need to be compared to both C strings and QStrings. Implicit ASCII casts can be a source of bugs and are discouraged.
QLatin1String is a constant (read-only) wrapper, designed to wrap C string literals - thus there's no need to make line additionally const, although in real projects you'd want to follow the project's style guide here.
I'm having a problem writing directly to a disk, I'm trying to write a Qt version of the old PARTCOPY (now obsolete on systems incompatible with 16-bit)
I'm using Windows 10, and have my program elevated to Administrator privileges.
Every time I try to open "\\.\A:" in with QIODevice::WriteOnly, I get an error message "The parameter is incorrect".
Using Visual Studio step-wise debugging, I think I've found the problem occurs in QFSEnginePrivate::nativeOpen() when tring to execute CreateFile().
The line:
// WriteOnly can create files, ReadOnly cannot.
DWORD creationDisp = (openMode & QIODevice::WriteOnly) ? OPEN_ALWAYS : OPEN_EXISTING;
seems to be the cause. If I force the value of creationDisp to be OPEN_EXISTING, then I can get the file opened and I can write to the disk without any further problems. The issue is that I don't know what way I can get this working without using the debugger.
Has anyone found a solution to this?
UPDATE: (test case)
#include <QtCore/qcoreapplication.h>
#include <QtCore/qtextstream.h>
#include <QtCore/qfile.h>
int main(int argc, char **argv) {
QCoreApplication a(argc, argv);
QTextStream cout(stdout, QIODevice::WriteOnly);
QFile f("\\\\.\\A:");
if (!f.open(QIODevice::WriteOnly)) {
cout << f.errorString();
return -1;
}
return 0;
}
You can try these two functions, I write successfully by (1).
bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags = DontCloseHandle)
bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags = DontCloseHandle)
I am using the qUncompress of Qt and head to a problem I cant find more information to solve it.
Here is my code:
#include <QCoreApplication>
#include <QByteArray>
#include <QFile>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QFile f("/user/XXXXX/home/AgeRegression"); // hided
if (f.exists())
qDebug() << "File exists";
else
qDebug() << "Missing file";
f.open(QIODevice::ReadOnly);
QByteArray qb = f.readAll();
qb = qUncompress(qb);
qDebug()<<"Successfully";
const char *qt_version = qVersion();
qDebug()<< QString(qt_version);
return a.exec();
}
Here is the output:
File exists
qUncompress: Z_DATA_ERROR: Input data is corrupted
Successfully
"5.3.2"
From the documentation of Qt(you can find here):
Note: If you want to use this function to uncompress external data that was compressed using zlib, you first need to prepend a four byte header to the byte array containing the data. The header must contain the expected length (in bytes) of the uncompressed data, expressed as an unsigned, big-endian, 32-bit integer.
So what exactly should I do here? Do I have to find the length of uncompressed data (is there a way? I just have compressed data.)? An example would be appreciated.
qUncompress is not a general-purpose decompression function. It should only be used with data compressed with qCompress.
If your data was compressed using something other than qCompress, you must decompress it in the same way - using zlib directly, using an external utility, etc.
By using qUncompress like you do, you're relying on an implementation detail that may change at any moment. Don't do that. Simply assume that qCompress is a black box and uses an alien compressor implementation that nobody else does.