I am porting a non-Qt C++ scientific calculation library to Android. For testing purposes, I am developing a simple GUI that reads setup parameters from a file, performs some calculation, and displays the result. The parameters are fixed (a version of the Periodic Table of the Elements).
In the original version of the library, which is portable between Windows, linux, and Mac, these parameters are stored in an external file and are read using C++ stdlib fopen / fread, etc. To simplify deployment to Android, I decided to embed this file as a resource in the qrc file. Embedding works fine - when the app is deployed to the Android device, the file is there and can be opened with QFile.
Unfortunately, it can't be opened with fopen() which does not appear to recognize the resource system URL. No problem. I modified the library to load from a string array instead of from a file, and I use QFile to read the lines from the resource file and load them into the string array.
Here's where the portability problem arises. Because the library is C++ only and is used in both Qt and non-Qt apps, the string array it uses is a std:: vector< std:: wstring >. The code that reads it looks like this:
QFile eleFile
( ":/res/Elements.ini" );
{
std::vector< std::wstring > lines;
while ( !eleFile.atEnd() )
{
lines.push_back( bytes.toStdWString() );
}
bResult = ElementIniFile::Read( lines, L"NIST Table", eleTable );
eleFile.close();
}
QFile eleFile( ":/res/Elements.ini" );
if ( eleFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
std::vector< std::wstring > lines;
while ( !eleFile.atEnd() )
{
QString bytes = QString( eleFile.readLine() ).trimmed();
lines.push_back( bytes.toStdWString() );
}
bResult = ElementIniFile::Read( lines, L"NIST Table", eleTable );
eleFile.close();
}
To copy to clipboard, switch view to plain text mode
The Elements.ini file is formatted like an INI file; the next to the last line (ElementIniFile:: Read()) parses the INI file lines into an internal data structure (eleTable) representing the periodic table of the elements and their isotopes.
This code works on Windows (using the MSVC 2008 toolchain). When I deploy and run the same code on Android (armeabi-v7a GCC 4.9 toolchain), the debugger shows me that the std:: vector<> contains the contents of the file as expected, but then the parsing into the element table fails (the entries in the table are empty, basically).
There is another problem which could be related: I have implemented a QValidator for use with a QLineEdit. This in turn converts the line edit's QString into an std:: wstring to pass into a validator contained in the C++ library. On Windows, this works fine. On Android, it appears to be failing, because I can never get the virtual keyboard to close after I have entered a valid input and tap "Done". I suspect that somewhere in the library, a wstring is being abused.
So the question is, are there differences between handling of wide strings between Windows (and any other desktop platform) and Android which could cause things like string comparisons and the like to return different results? Is there a compiler flag I'm missing which causes QString::toStdWString() to return an incompatible wstring?
Edit:
I see on stackoverflow that in some earlier versions of the Android NDK, wstring was not supported. I am using NDK version 10d (latest) and all of my code containing wstring compiles without complaint, so I presume it is supported. Could there be an alignment issue?
Further edit:
In the first failure, the library uses swscanf() to parse out the element and isotope information. On Android, this method returns -1 (not implemented). Searching online shows me that up until NDK release 10c, even the char version of this (sscanf()) was not implemented. What a drag. I'll have to find a workaround somehow.
So in this case, the failure turns out to be unrelated to Qt, but I'll update the post as I get to the bottom of the second failure (validation).
Bookmarks