QXMLStreamreader reading from slow QProcess - qt

In Qt 5.1, I'm having an issue with QXMLStreamReader waiting for a QProcess to produce more data.
If I read lines from an unbuffered QProcess, it works fine:
while(!vupProcess.state() == QProcess::NotRunning)
{
if (vupProcess.atEnd())
{
vupProcess.waitForReadyRead();
}
qDebug() << vupProcess.readLine();
}
It's pretty clear cut: when the buffer is out of data, it waits until there is more. When there is more, it will print lines without waiting.
Now, if I want to do the same with QXMLStreamReader, it works, but the processing of the XML elements happens at the wrong moment (too late).
Consider this:
QXmlStreamReader xml;
xml.setDevice(&vupProcess);
QStack<VUPDevice *> deviceStack;
QXmlStreamReader::TokenType tokenType = QXmlStreamReader::NoToken;
while (tokenType != QXmlStreamReader::EndDocument && !xml.hasError())
{
if (xml.device()->atEnd())
{
xml.device()->waitForReadyRead(XML_READNEXT_TIMEOUT);
}
tokenType = xml.readNext();
if (xml.hasError())
{
qDebug() << "ERROR";
return;
}
...
}
By the time waitForReadyRead(int) is called, a lot of elements are available already, and I need them processed to update the GUI. However, it won't continue until the QProcess starts to output more. It seems to be because the underlying QProcess is read till it's empty as fast as possible, and then my parser unnecessarily hangs in the early stages, because the QProcess doesn't output anymore.
What I need, is xml.hasMoreElements(), so that I can make:
if (xml.device()->atEnd() && !xml.hasMoreElements())
{
xml.device()->waitForReadyRead(XML_READNEXT_TIMEOUT);
}
But I can't seem to find an API call that does this for me.
So, how do I not wait for more data when it's not necessery?

I guess I solved it. There is no method for asking if there ar more XML elements, but the readNext() call will put the QXMLStreamReader object in a state you can detect, and use to have the back-end device wait:
QXmlStreamReader::TokenType tokenType = xml.readNext();
while (xml.error() == QXmlStreamReader::PrematureEndOfDocumentError)
{
xml.device()->waitForReadyRead(XML_READNEXT_TIMEOUT);
tokenType = xml.readNext();
}
if (xml.hasError())
{
...
}

Related

QDataStream not working as well and return error with reusing

I am storing some data in QDataStream and immediately taking the data
bool M_FILEMANAGER::readFromDataFile(QString& fileName,RADARBEAMPATTERN *radbeam)
{
// for reading from file sequence .....
QFile fin(m_folderPath +"/"+ fileName);
if (fin.open(QIODevice::ReadOnly)) {
QDataStream in(&fin);
in.device()->startTransaction();
in >> radbeam->nPoints;
qDebug()<<"nPoints : "<<radbeam->nPoints;
fin.close();
return true;
}else{
return false;
}
}
it works fine for one use but when i reuse this function i get error
segmentation fault.
thanks in advance.
1) Strange use of QIODevice::startTransaction(). Did you mean to use QDataStream:startTransaction()? You shouldn't need that at all, but if you meant to use it to check for "valid" (complete) data in the file, do it properly (although this is typically used with async devices like sockets):
int nPoints; // temp variable to hold data, assuming radbeam->nPoints is an int
QDataStream in(&fin);
in.startTransaction();
in >> nPoints;
if (in.commitTransaction() && radbeam != nullptr)
radbeam->nPoints = nPoints;
fin.close();
2) Segfault is most likely due to radbeam pointer (eg. being null), but possibly if you're trying to read corrupted data directly into the member variable nPoints. Impossible to determine cause w/out MCVE.

How does fork and pipe work in a unix process system?

I'm trying to study for an exam and I'm just not able to figure out a simple fork program.
I have this piece of code and have to add code to it In order for the parent process to send through a PIPE the value n to the child. The child should double the value, not print anything and return it to the parent.
Then the parent should print it on the screen.
int main() {
int n=1;
if(fork() == 0) {
}
printf(“%d\n”, n);
return 1;
}
I don't really know how PIPEs work and how to use them. Can anyone help me?
pid_t cp;
int fi[2],st;
int n;
if(pipe(fi)==-1) {perror("pipe error");exit(0);}
if((cp=fork())==-1) {perror("fork"); exit(0);}
else if(cp==0)
{
sleep(2);
close(fi[1]);
read(fi[0],&n,2);
n*=2;
close(fi[0]);
exit(n);
}
else
{
close(fi[0]);
write(fi[1],n,2);
close(fi[1]);
waitpid(cp,&st,0);
printf("%d",st);
exit(0);
}}
The working of pipes is very simple. A PIPE contains two ends, 1 for reading and another for writing. You have to close the appropriate end while reading or writing. After that you use it as a regular file with read() and write() functions. Forgive me for my formatting, I'm typing on a mobile.

Why QProcess signal readyReadStandardOutput() emited twice?

I use QProcess and connect it's readyReadStandardOutput to slot. But after starting slot execute twice. Tell me please why is it?
{
myProcess = new QProcess(parent);
myProcess->start("mayabatch.exe -file "+scene);
connect(myProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput()));
}
void MainWindow::readOutput()
{
qDebug()<<"Read";
QByteArray outData = myProcess->readAllStandardOutput();
qDebug()<<QString(outData);
}
OUTPUT:
Read
"File read in 0 seconds.
"
Read
"cacheFi"
Read
"le -attachFile -fileName "nClothShape1" -directory ...
Last string was broken. "Read" appears between words.
From the documentation of QProcess::readyReadStandardOutput()
This signal is emitted when the process has made new data available through its standard output channel (stdout). It is emitted regardless of the current read channel.
The slot is executed more than once for the simple reason that the underlying process flushed the output in separate and random ways. You should not be caring about this because it depends on things you cannot control.
If you want to save the whole output you should be doing
void MainWindow::readOutput(){
bigbuffer.append(myProcess->readAllStandardOutput();)
}
If you want to read line by line, then
void MainWindow::readOutput(){
while(myProcess.canReadLine()){
qDebug() << myProcess.readLine();
}
}
The second call will leave data in the process buffer such that you don't have "broken" reads like cacheFi.

QList for touch-points not being created, "A data abort exception has occurred"

I am trying to get touch inputs for my program targeting an N8 (and a C7), and I am not able to create a QList for keeping touchpoints using QTouchEvent::touchPoints(). The program crashes with the following line: Thread has crashed: A data abort exception has occurred accessing 0xee
The overloaded events function looks like:
bool GLWindow::event(QEvent *event)
{
switch ( event->type() ) {
case QEvent::TouchBegin: {
QList<QTouchEvent::TouchPoint> touchBeginPoints =
static_cast<QTouchEvent *>(event)->touchPoints();
foreach (const QTouchEvent::TouchPoint &touchBeginPoint, touchBeginPoints)
{
float touchBeginX = touchBeginPoint.pos().x();
float touchBeginY = touchBeginPoint.pos().y();
qDebug() << "touchBeginPoint := " << touchBeginX << ", " << touchBeginY;
}
break;
}
case QEvent::TouchUpdate: {
// same as touch begin: getting touch point
break;
}
case QEvent::TouchEnd: {
// same as touch begin: getting touch point
break;
}
default: {
qDebug() << "Goodbye";
return true;
}
}
return true;
}
Now,
I have never worked with containers before. But creating and using a QList in another part of the program works fine. Should I be including something in my .pro file? (Most problems seem to end up regarding this with me!)
I read (a bit) about exceptions in Qt and Symbian, but I am not able to get most of that. BUT I am not doing any networking or resource based i/o or manipulation except textures for 3D objects. Is it possible that memory allocation while running the program is creating some problem?
Basically I am just trying to print the touch point. But I am clueless as to why I can’t create a QList. The code compiles fine. I tried my best (unsuccessfully), but is there any other way to get the screen coordinates of a touchpoint (one that does not require a QList)? Any comments are welcome.
[Reposting from qt-project.org.]
Your syntax is 100% correct. Just look at this example: http://www.developer.nokia.com/Community/Wiki/Painting_in_Qt
What I'm guessing happens is that QTouchEvent::touchPoints() returns a list big enough that it overflows your stack. Try increasing the stack size for your application.
Is your syntax correct ? The compilation error seems to reinforce teukkam point...
What happens when you replace
static_cast<QTouchEvent *>(event)->touchPoints()
With
(dynamic_cast<QTouchEvent *>(event))->touchPoints()
Notice the parentheses...

Unix Networking Programming - Client and Server. List Function That wait for input after 40 lines

I am currently in the process of making a Client and Server in the Unix/Windows environment but right now I am just working on the Unix side of it. One of the function we have to create for the program is similar to the list function in Unix which shows all files within a dir but we also have to show more information about the file such as its owner and creation date. Right now I am able to get all this information and print it to the client however we have to also add that once the program has printing 40 lines it waits for the client to push any key before it continues to print.
I have gotta the program to sort of do this but it will cause my client and server to become out of sync or at least the std out to become out of sync. This means that if i enter the command 'asdad' it should print invalid command but it won't print that message until i enter another command. I have added my list functions code below. I am open to suggestions how how to complete this requirement as the method I have chosen does not seem to be working out.
Thank-you in advance.
Server - Fork Function: This is called when the list command is enter. eg
fork_request(newsockfd, "list", buf);
int fork_request(int fd, char req[], char buf[])
{
#ifndef WIN
int pid = fork();
if (pid ==-1)
{
printf("Failed To Fork...\n");
return-1;
}
if (pid !=0)
{
wait(NULL);
return 10;
}
dup2(fd,1); //redirect standard output to the clients std output.
close(fd); //close the socket
execl(req, req, buf, NULL); //run the program
exit(1);
#else
#endif
}
Here is the function used to get all the info about a file in a dir
void longOutput(char str[])
{
char cwd[1024];
DIR *dip;
struct dirent *dit;
int total;
char temp[100];
struct stat FileAttrib;
struct tm *pTm;
int fileSize;
int lineTotal;
if(strcmp(str, "") == 0)
{
getcwd(cwd, sizeof(cwd));
}
else
{
strcpy (cwd, str);
}
if (cwd != NULL)
{
printf("\n Using Dir: %s\n", cwd);
dip = opendir(cwd);
if(dip != NULL)
{
while ((dit = readdir(dip)) != NULL)
{
printf("\n%s",dit->d_name);
stat(dit->d_name, &FileAttrib);
pTm = gmtime(&FileAttrib.st_ctime);
fileSize = FileAttrib.st_size;
printf("\nFile Size: %d Bytes", fileSize);
printf("\nFile created on: %.2i/%.2i/%.2i at %.2i:%.2i:%.2i GMT \n", (pTm->tm_mon + 1), pTm->tm_mday,(pTm->tm_year % 100),pTm->tm_hour,pTm->tm_min, pTm->tm_sec);;
lineTotal = lineTotal + 4;
if(lineTotal == 40)
{
printf("40 Lines: Waiting For Input!");
fflush(stdout);
gets(&temp);
}
}
printf("\n %d \n", lineTotal);
}
else
{
perror ("");
}
}
}
At here is the section of the client where i check that a ! was not found in the returned message. If there is it means that there were more lines to print.
if(strchr(command,'!') != NULL)
{
char temp[1000];
gets(&temp);
}
Sorry for the long post but if you need anything please just ask.
Although, I didn't see any TCP/IP code, I once had a similar problem when I wrote a server-client chat program in C++. In my case, the problem was that I didn't clearly define how messages were structured in my application. Once, I defined how my protocol was suppose to work--it was a lot easier to debug communication problems.
Maybe you should check how your program determines if a message is complete. In TCP, packets are guaranteed to arrive in order with no data loss, etc. Much like a conversation over a telephone. The only thing you have to be careful of is that it's possible to receive a message partially when you read the buffer for the socket. The only way you know to stop reading is when you determine a message is complete. This could be as simple as two '\n' characters or "\n\r".
If you are using UDP, then that is a completely different beast all together (i.e. messages can arrive out of order and can be lost in transit, et cetera).
Also, it looks like you are sending across strings and no binary data. If this is the case, then you don't have to worry about endianess.

Resources