1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7
8 #include <chrono>
9 #include <thread>
10
11 #include <QObject>
12 #include <QByteArray>
13 #include <QMessageBox>
14 #include <QProcess>
15 #include <QString>
16 #include <QStringList>
17 #include <QTextCodec>
18
19 #include "docim.h"
20 #include "gtwriter.h"
21 #include "scpaths.h"
22 #include "scribusstructs.h"
23 #include "ui/scmessagebox.h"
24
hasAntiword()25 bool hasAntiword()
26 {
27 static bool searched = false, found = false;
28 if (searched) // searched already in this run
29 return found;
30
31 QProcess *test = new QProcess();
32 QString exename("antiword");
33 #if defined(_WIN32)
34 exename = ScPaths::instance().libDir() + "tools/antiword/antiword.exe";
35 #endif
36 test->start(exename, QStringList());
37 if (test->waitForStarted())
38 {
39 found = true;
40 test->terminate();
41 std::this_thread::sleep_for(std::chrono::milliseconds(5));
42 test->kill();
43 }
44 delete test;
45 searched = true;
46 return found;
47 }
48
FileFormatName()49 QString FileFormatName()
50 {
51 if (hasAntiword())
52 return QObject::tr("Word Documents");
53 return QString();
54 }
55
FileExtensions()56 QStringList FileExtensions()
57 {
58 if (hasAntiword())
59 return QStringList("doc");
60 return QStringList();
61 }
62
GetText(const QString & filename,const QString & encoding,bool textOnly,gtWriter * writer)63 void GetText(const QString& filename, const QString& encoding, bool textOnly, gtWriter *writer)
64 {
65 if (!hasAntiword())
66 return;
67
68 DocIm *dim = new DocIm(filename, encoding, textOnly, writer);
69 while (dim->isRunning())
70 {
71 std::this_thread::sleep_for(std::chrono::milliseconds(5));
72 }
73 delete dim;
74 }
75
DocIm(const QString & fname,const QString & enc,bool textO,gtWriter * w)76 DocIm::DocIm(const QString& fname, const QString& enc, bool textO, gtWriter *w) : textBuffer(this), errorBuffer(this)
77 {
78 filename = fname;
79 encoding = enc;
80 writer = w;
81 textOnly = textO;
82 failed = false;
83
84 textBuffer.open(QIODevice::WriteOnly);
85 errorBuffer.open(QIODevice::WriteOnly);
86
87 proc = new QProcess();
88 QString exename("antiword");
89 #if defined(Q_OS_WIN32)
90 exename = ScPaths::instance().libDir() + "tools/antiword/antiword.exe";
91 QString homeDir = QDir::toNativeSeparators(ScPaths::instance().libDir() + "tools");
92 proc->setWorkingDirectory( ScPaths::instance().libDir() + "tools/antiword/" );
93 proc->setEnvironment( QStringList() << QString("HOME=%1").arg(homeDir));
94 #endif
95
96 QStringList args;
97 args << "-t" << "-w 0";
98 #if defined(Q_OS_WIN32)
99 // #10258 : use UTF-8 whenever possible
100 if (QFile::exists(ScPaths::instance().libDir() + "tools/antiword/UTF-8.txt"))
101 args << "-m" << "UTF-8.txt";
102 #endif
103 args << QDir::toNativeSeparators(filename);
104
105 //connect(proc, SIGNAL(readyReadStdout()), this, SLOT(slotReadOutput()));
106 //connect(proc, SIGNAL(readyReadStderr()), this, SLOT(slotReadErr()));
107 proc->start(exename, args);
108 if (!proc->waitForStarted())
109 {
110 failed = true;
111 return;
112 }
113 while (proc->waitForReadyRead())
114 {
115 std::this_thread::sleep_for(std::chrono::milliseconds(5));
116 }
117
118 while (!proc->atEnd() || proc->state() == QProcess::Running)
119 {
120 proc->setReadChannel(QProcess::StandardOutput);
121 if ( proc->canReadLine() )
122 {
123 QByteArray bo = proc->readAllStandardOutput();
124 if (bo.size() > 0)
125 textBuffer.write(bo);
126 }
127 else
128 {
129 proc->setReadChannel(QProcess::StandardError);
130 if ( proc->canReadLine() )
131 {
132 QByteArray be = proc->readAllStandardError();
133 if (be.size() > 0)
134 errorBuffer.write(be);
135 }
136 else
137 {
138 std::this_thread::sleep_for(std::chrono::milliseconds(5));
139 }
140 }
141 }
142
143 errorBuffer.close();
144 textBuffer.close();
145
146 if (proc->exitStatus() != QProcess::NormalExit)
147 {
148 failed = true;
149 return;
150 }
151
152 write();
153 }
154
isRunning()155 bool DocIm::isRunning()
156 {
157 return proc->state() == QProcess::Running;
158 }
159
write()160 void DocIm::write()
161 {
162 QTextCodec *codec = nullptr;
163
164 #if defined(Q_OS_WIN32)
165 // #10258 : use UTF-8 whenever possible
166 if (QFile::exists(ScPaths::instance().libDir() + "tools/antiword/UTF-8.txt"))
167 codec = QTextCodec::codecForName("UTF-8");
168 #endif
169
170 if (encoding.isEmpty() && !codec)
171 codec = QTextCodec::codecForLocale();
172 else if (!codec)
173 codec = QTextCodec::codecForName(encoding.toLocal8Bit());
174
175 if (failed)
176 {
177 QString error = codec->toUnicode( errorBuffer.data() );
178 ScMessageBox::information(nullptr, tr("Importing failed"),
179 tr("Importing Word document failed \n%1").arg(error),
180 QMessageBox::Ok);
181 return;
182 }
183
184 QString text = codec->toUnicode( textBuffer.data() );
185 writer->appendUnstyled(text);
186 }
187
~DocIm()188 DocIm::~DocIm()
189 {
190 delete proc;
191 }
192
193
194