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