QFile::open fails with unicode filename - c++

I want to open a file with QFile::Open where my file name is unicode:
QString fname(QFile::decodeName("D:/أحدالأنشطة.txt"));
QFile qFile(fname);
bool b=qFile.open(QIODevice::ReadOnly);
if(b)
{
FILE* filedesc = fdopen(qFile.handle(), "rb");
if(filedesc!=NULL)
{
char* nb=(char*)malloc(2*sizeof(char));
qDebug()<<"opened ";
size_t size=fread(nb,sizeof(char),2,filedesc);
fclose(filedesc);
qDebug()<<"filedesc closed size "<<size<<"nb "<<QString::fromAscii(nb,2);
nb=NULL;
free(nb);
}else qDebug()<<"filedesc failed error"<<strerror(errno);
}else
qDebug()<<"qFile failed error"<<strerror(errno);
It failed and I get:
qFile failed error No error
any help will be appreciated.

If the data is in WCHAR array than just use QString filename((QChar*) yourWcharData);

If your source file is UTF-8 encoded, then you might be able to do this:
QString fname(QString::fromUtf8("D:/أحدالأنشطة.txt"));
If it's UTF-16, then:
QString fname(QString::fromUtf16("D:/أحدالأنشطة.txt"));
If the source file is neither UTF-8 not UTF-16, try this instead:
QString fname(QString::fromLocal8Bit("D:/أحدالأنشطة.txt"));
If that also doesn't work, then you need to find out the character set your editor is using.

Related

printf to show QString

I'm debugging a program using QString.
I added printf to show contents of QString but it only shows 1st letter.
Code is as below. fprintf is what I added.
QString profilePath = mltPath;
fprintf(stderr, "profilePath: %s\n", profilePath.data());
Output is
profilePath: /
profilePath.data() is a QChar* which is a 16 bit unicode character. https://doc.qt.io/qt-5/qchar.html
One solution to convert to a const char* is to this is to use qPrintable(profilePath) to convert the QString to const char*
QString profilePath = mltPath;
fprintf(stderr, "profilePath: %s\n", qPrintable(profilePath));
The documentation for const char * qPrintable(const QString& str) is here: https://doc.qt.io/qt-5/qtglobal.html#qPrintable
Just use QString::toUtf8(), e.g.
fprintf(stderr, "profilePath: %s\n", profilePath.toUtf8());
You shouldn't use printf as it is mostly used in C (or well should be).
Since you are working with Qt, why not use QDebug?
Then all you have to do is call: qDebug() << "profilePath:" << profilePath;
If you use QDebug, you also gain the advantage of categorized logging.
It seems you can use the toLocal8Bit() method to convert it to a QByteArray with your local encoding on your system (documentation).
So you would want this in your code:
QString profilePath = mltPath;
fprintf(stderr, "profilePath: %s\n", profilePath.toLocal8Bit().constData());

fopen with const char * from QString not possible

To dynamically open a FILE I am passing a QString full path.
If passed as a variable, the code fails.
If entered directy (not via a variable) everything works just fine. What is going on here?
QString outputfile_qstring("C:/temp/out.mp3");
qDebug()<<"Original output file " << outputfile_qstring;
const char* outputfile = outputfile_qstring.toLatin1().constData();
qDebug()<<"Trying to open output file " << outputfile;
fout = fopen(outputfile, "wb+");
bool fileIsOpen = (fout != 0);
if ( !fileIsOpen ){
errStr_ = "Error opening the output file " + outputfile_qstring;
Q_ASSERT(false && "Could not open output file");
return false;
}
The QString to const char * conversion always fails.
Original output file "C:/temp/out.mp3"
Trying to open output file ????????????????????????aSC,_??r
The problem is here:
const char* outputfile = outputfile_qstring.toLatin1().constData();
The toLAtin1 function returns a QByteArray by value. And since you don't save that object, it will be destructed once the expression is finished, leaving you with outputfile being an invalid pointer to non-existing data.
The simple solution is to use the expression outputfile_qstring.toLatin1().constData() directly in the call to fopen. Or not use fopen and the C file functions at all and only use Qt files.

How to write Special characters in a file using mfc application?

I want to write special charaters like ô. ö‚`a¹½ˆ in a file. I am working in MFC and using UNICODE character set. While showing string in message box is working good but its not writing the characters to the file.
Here is parts of my code:
CString abc=_T("hello");
CString xyz=compress(abc); //compressing value and return special characters
CStdioFile file_object(_T("abc.txt"),CFile::modeCreate|CFile::modeWrite);
file_object.WriteString(xyz);
It seems that CStdioFile class does not support Unicode characters directly. You can use this workaround (from this CodeProject article)
// Open the file with the specified encoding
FILE *fStream;
errno_t e = _tfopen_s(&fStream, _T("abc.txt"), _T("wt,ccs=UTF-8"));
if (e != 0) return; // failed..
CStdioFile f(fStream); // open the file from this stream
f.WriteString(xyz);
f.Close();
//
// For Reading
//
// Open the file with the specified encoding
FILE *fStream;
errno_t e = _tfopen_s(&fStream, _T("abc.txt"), _T("rt,ccs=UTF-8"));
if (e != 0) return; // failed..CString sRead;
CStdioFile f(fStream); // open the file from this stream
CString sRead;
f.ReadString(sRead);
f.Close();
Instead of using "UTF-8" encoding, you can also use the following encodings:
“ccs=UNICODE” => UTF-16 (Big endian)
“ccs=UTF-8” => UTF-8
“ccs=UTF-16LE” => UTFS-16LE (Little endian)
“ccs=ANSI” => ANSI (default encoding of the OS)
I found one more method. It is working good...
CString text=_T("HelloÄ^°H©º+");
CString strFilePath=_T("C:\\try.txt");
CFile theFile(strFilePath, CFile::modeReadWrite | CFile::modeCreate);
theFile.Write( (LPCTSTR) text, text.GetLength() * sizeof(TCHAR));
theFile.Close();

Check unsupported file name for fopen

I'm trying to open a file to treat it later. My problem is that if my file name is not ANSI (Arabic, Hindi...) fopen_s and fopen refuse to open it and give me an Invalid argument error. I can't use CreateFile() to do that so I thought to check either my file name is supported by fopen or not(try to open it) and create a temporary file instead:
QString fileN=QString::fromWCharArray(fname);
QFileInfo file(DIRPath+"/"+fileN);
bool Supported=true;
if(file.exists()) {
QString temp;
char* Fname=(char*)malloc(260*sizeof(char));
strcpy(Fname,(QString(DIRPath+"/"+fileN).toStdString()).c_str());
FILE* Filedesc;
errno_t err=fopen_s(&Filedesc,Fname,"rb");
if(Filedesc!=NULL) {
qDebug()<<"\nfile opened ";
fclose(Filedesc);
} else if(err==22) {
qDebug()<<"\nfail to open file error 22: Invalid argument";
temp=QString(DIRPath+"/Temp"+QString::number(nb));
Supported=false;
} else qDebug()<<"\nfail to open file error"<<GetLastError()<<"errno"<<errno<<"strerrno"<<strerror(errno);
Fname=NULL;
free(Fname);
...
My question is: can anyone clarify for me the UNICODE/ANSI confusion? Am I safe so far or are there more precautions to consider? Is there a safer way to check if the given name is not ANSI?
Thank you in advance, any help will be appreciated.
EDIT 1
I tried this but in vain : CreateFile() return an INVALID_HANDLE_VALUE and GetLastError() return 0
//WCHAR fname[]=L"D:/أحدالأنشطة.txt";
char* name="D:/أحدالأنشطة.txt";
wchar_t* nameW=(wchar_t*)malloc(sizeof(wchar_t)*17);
qDebug()<<"s :"<<mbstowcs(nameW,name,17);
//QString path=QString::fromWCharArray(fname,17);
//QString path=QString::fromLatin1(name,17);
HANDLE fileHandle = CreateFile( nameW, // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
qDebug()<<"CreateFile failed!\n"<<GetLastError();
nameW=NULL;
free(nameW);
return 2;
}else
qDebug()<<"CreateFile succeeded!\n";
int fd = _open_osfhandle((intptr_t) fileHandle, _O_RDONLY);
FILE* fstr = _fdopen(fd, "r");
QFile indirect;
if (!indirect.open(fstr, QIODevice::ReadOnly))
qDebug()<<"QFile open against file descriptor failed!\n";
else
{
qDebug()<<"QFile open against file descriptor succeeded!\n";
indirect.close();
}
// This will fail
QFile direct(path);
if (!direct.open(QIODevice::ReadOnly))
qDebug()<<"QFile open of filename directly failed!\n";
else
{
qDebug()<<"QFile open of filename directly succeeded!\n";
direct.close();
}
nameW=NULL;
free(nameW);
EDIT 2
QString fname(QFile::decodeName("D:/أحدالأنشطة.txt"));
QFile qFile(fname);
bool b=qFile.open(QIODevice::ReadOnly);
if(b)
{
FILE* filedesc = fdopen(qFile.handle(), "rb");
if(filedesc!=NULL)
{
char* nb=(char*)malloc(2*sizeof(char));
qDebug()<<"opened ";
size_t size=fread(nb,sizeof(char),2,filedesc);
fclose(filedesc);
qDebug()<<"filedesc closed size "<<size<<"nb "<<QString::fromAscii(nb,2);
nb=NULL;
free(nb);
}else qDebug()<<"filedesc failed error"<<strerror(errno);
}else
qDebug()<<"qFile failed error"<<strerror(errno);
You should probably use QFile to open the file, and then pass QFile::handle() to your C function. In the C code you would then use fdopen() to associate a FILE* stream to the file descriptor. Note that the mode you use in fdopen() should be compatible with the mode you used in QFile::open(). For example:
void c_func(int fd)
{
FILE* file = fdopen(fd, "rb");
// ...
}

Opening a file from a Qt String

I am making a Qt application and I have a button to open a file, which is connected to a custom slot. This is the slot code so far:
void MainWindow::file_dialog() {
const QFileDialog *fd;
const QString filename = fd->getOpenFileName();
}
How could I have it then convert the file name to a const char *, open the file, read it and store the text in a QString, and then close the file. I am using Qt4.
To read the contents of a file, you can do this:
QString filename = QFileDialog::getOpenFileName();
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QString content = file.readAll();
file.close();