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 "util_file.h"
9
10 #ifdef _MSC_VER
11 # include <sys/utime.h>
12 #else
13 # include <utime.h>
14 #endif
15
16 #include <QByteArray>
17 #include <QDataStream>
18 #include <QDir>
19 #include <QFile>
20 #include <QFileInfo>
21 #include <QString>
22 #include <QProcess>
23 #include <QScopedPointer>
24 #include <QTemporaryFile>
25
26 #include "fileloader.h"
27 #include "loadsaveplugin.h"
28 #include "prefsmanager.h"
29 #include "scpaths.h"
30 #include "scribusdoc.h"
31 #include "scstreamfilter.h"
32 #include "selection.h"
33 #include "util.h"
34
copyData(QIODevice & src,QIODevice & dest)35 bool copyData(QIODevice& src, QIODevice& dest)
36 {
37 bool success = false;
38 if ((src.openMode() & QIODevice::ReadOnly) == 0)
39 return false;
40 if ((dest.openMode() & QIODevice::WriteOnly) == 0)
41 return false;
42 QByteArray bb( 65536, ' ' );
43 if (bb.size() > 0) // Check for memory allocation failure
44 {
45 qint64 byteswritten;
46 qint64 bytesread = src.read( bb.data(), bb.size() );
47 success = (bytesread > 0);
48 while (bytesread > 0)
49 {
50 byteswritten = dest.write( bb.data(), bytesread );
51 success &= (bytesread == byteswritten);
52 bytesread = src.read( bb.data(), bb.size() );
53 }
54 }
55 return success;
56 }
57
copyFile(const QString & source,const QString & target)58 bool copyFile(const QString& source, const QString& target)
59 {
60 bool success = true;
61 if ((source.isEmpty()) || (target.isEmpty()))
62 return false;
63 if (source == target)
64 return false;
65 QFile s(source);
66 if (!s.exists())
67 return false;
68 QFile t(target);
69 if (s.open(QIODevice::ReadOnly))
70 {
71 if (t.open(QIODevice::WriteOnly))
72 {
73 success = copyData(s, t);
74 success &= (s.error() == QFile::NoError && t.error() == QFile::NoError);
75 t.close();
76 }
77 s.close();
78 }
79 return success;
80 }
81
copyFileAtomic(const QString & source,const QString & target)82 bool copyFileAtomic(const QString& source, const QString& target)
83 {
84 bool success = false;
85 if ((source.isEmpty()) || (target.isEmpty()))
86 return false;
87 if (source == target)
88 return false;
89 QFile srcFile(source);
90 QString tempFileName;
91 QTemporaryFile* tempFile = new QTemporaryFile(target + "_XXXXXX");
92 if (!tempFile)
93 return false;
94 if (srcFile.open(QIODevice::ReadOnly))
95 {
96 if (tempFile->open())
97 {
98 tempFileName = tempFile->fileName();
99 success = copyData(srcFile, *tempFile);
100 success &= (srcFile.error() == QFile::NoError && tempFile->error() == QFile::NoError);
101 tempFile->close();
102 }
103 srcFile.close();
104 }
105 if (success)
106 {
107 if (QFile::exists(target))
108 success = QFile::remove(target);
109 if (success)
110 {
111 // We delete temporary file now to force file close
112 // QTemporaryFile::close() do not really close file
113 tempFile->setAutoRemove(false);
114 delete tempFile;
115 tempFile = nullptr;
116 success = QFile::rename(tempFileName, target);
117 }
118 }
119 delete tempFile;
120 return success;
121 }
122
copyFileToFilter(const QString & source,ScStreamFilter & target)123 bool copyFileToFilter(const QString& source, ScStreamFilter& target)
124 {
125 bool copySucceed = true;
126 if (source.isEmpty())
127 return false;
128 if (!QFile::exists(source))
129 return false;
130 QFile s(source);
131 QByteArray bb( 65536, ' ' );
132 if (bb.size() <= 0) // Check for memory allocation failure
133 return false;
134 if (s.open(QIODevice::ReadOnly))
135 {
136 int bytesread = s.read( bb.data(), bb.size() );
137 while (bytesread > 0)
138 {
139 copySucceed &= target.writeData(bb.data(), bytesread);
140 bytesread = s.read( bb.data(), bb.size() );
141 }
142 copySucceed &= (s.error() == QFile::NoError);
143 s.close();
144 }
145 return copySucceed;
146 }
147
copyFileToStream(const QString & source,QDataStream & target)148 bool copyFileToStream(const QString& source, QDataStream& target)
149 {
150 bool copySucceed = true;
151 if (source.isEmpty())
152 return false;
153 if (!QFile::exists(source))
154 return false;
155 if (!target.device()->isOpen() || !target.device()->isWritable())
156 return false;
157 QFile s(source);
158 QByteArray bb( 65536, ' ' );
159 if (bb.size() <= 0) // Check for memory allocation failure
160 return false;
161 if (s.open(QIODevice::ReadOnly))
162 {
163 int byteswrite = 0;
164 int bytesread = s.read( bb.data(), bb.size() );
165 while (bytesread > 0)
166 {
167 byteswrite = target.writeRawData(bb.data(), bytesread);
168 copySucceed &= (byteswrite == bytesread);
169 bytesread = s.read( bb.data(), bb.size() );
170 }
171 copySucceed &= (s.error() == QFile::NoError);
172 s.close();
173 }
174 return copySucceed;
175 }
176
moveFile(const QString & source,const QString & target)177 bool moveFile(const QString& source, const QString& target)
178 {
179 if (source.isEmpty() || target.isEmpty())
180 return false;
181 if (source == target)
182 return false;
183 bool moveSucceed = copyFile(source, target);
184 if (moveSucceed)
185 moveSucceed &= QFile::remove(source);
186 return moveSucceed;
187 }
188
touchFile(const QString & file)189 bool touchFile(const QString& file)
190 {
191 #if defined(_WIN32) && defined(HAVE_UNICODE)
192 return _wutime((const wchar_t*) file.utf16(), nullptr) == 0;
193 #else
194 QByteArray fname = file.toLocal8Bit();
195 return utime(fname.data(), nullptr) == 0;
196 #endif
197 }
198
199
fileInPath(const QString & filename)200 bool fileInPath(const QString& filename)
201 {
202 if (filename.isEmpty())
203 return false;
204 QString file = filename.split(' ', Qt::SkipEmptyParts).at(0); //Ignore parameters
205 #if defined(Q_OS_WIN32)
206 if (QFileInfo(file).suffix().isEmpty())
207 file += ".exe";
208 #endif
209
210 file = QDir::fromNativeSeparators(file);
211 if (file.indexOf('/') >= 0)
212 {
213 //Looks like an absolute path
214 QFileInfo info(file);
215 return info.exists();
216 }
217
218 //Get $PATH
219 QString path;
220 const QStringList env = QProcess::systemEnvironment();
221 for (const QString& line : env)
222 {
223 if (line.indexOf("PATH") == 0)
224 {
225 path = line.mid(5); //Strip "PATH="
226 break;
227 }
228 }
229
230 QChar envPathSeparator(ScPaths::envPathSeparator);
231 const QStringList splitpath = path.split(envPathSeparator, Qt::SkipEmptyParts);
232 for (const QString& dir : splitpath)
233 {
234 QFileInfo info(dir, file);
235 if (info.exists())
236 return true;
237 }
238 return false;
239 }
240
getVectorFileFromData(ScribusDoc * doc,QByteArray & data,const QString & ext,double x,double y,double w,double h)241 PageItem* getVectorFileFromData(ScribusDoc *doc, QByteArray &data, const QString& ext, double x, double y, double w, double h)
242 {
243 PageItem* retObj = nullptr;
244
245 QScopedPointer<QTemporaryFile> tempFile(new QTemporaryFile(QDir::tempPath() + "/scribus_temp_XXXXXX." + ext));
246 if (!tempFile->open())
247 return nullptr;
248
249 QString fileName = getLongPathName(tempFile->fileName());
250 if (fileName.isEmpty())
251 return nullptr;
252
253 tempFile->write(data);
254 tempFile->close();
255
256 FileLoader *fileLoader = new FileLoader(fileName);
257 int testResult = fileLoader->testFile();
258 delete fileLoader;
259
260 if (testResult == -1)
261 return nullptr;
262
263 const FileFormat * fmt = LoadSavePlugin::getFormatById(testResult);
264 if (!fmt)
265 return nullptr;
266
267 doc->m_Selection->clear();
268 doc->m_Selection->delaySignalsOn();
269 fmt->setupTargets(doc, nullptr, nullptr, nullptr, &(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts));
270 fmt->loadFile(fileName, LoadSavePlugin::lfUseCurrentPage|LoadSavePlugin::lfInteractive|LoadSavePlugin::lfScripted);
271 if (!doc->m_Selection->isEmpty())
272 {
273 retObj = doc->groupObjectsSelection();
274 retObj->setTextFlowMode(PageItem::TextFlowUsesBoundingBox);
275 retObj->setXYPos(x, y, true);
276 if ((w >= 0) && (h >= 0))
277 retObj->setWidthHeight(w, h, true);
278 retObj->updateClip();
279 retObj->update();
280 }
281 doc->m_Selection->clear();
282 doc->m_Selection->delaySignalsOff();
283
284 return retObj;
285 }
286
checkFileHash(const QString & directory,const QString & filename,const QString & hashFilename,QCryptographicHash::Algorithm method)287 bool checkFileHash(const QString& directory, const QString& filename, const QString& hashFilename, QCryptographicHash::Algorithm method)
288 {
289 //In a single directory, make a hash of filename, and compare it to the string for that file in hashFilename
290 //Assumption is that the hash file only has one line for now
291 QByteArray ba_hash;
292 if (!loadRawText(directory + hashFilename, ba_hash))
293 {
294 qDebug() << "checkFileHash: loadRawText file unsuccessful";
295 return false;
296 }
297
298 QFile source(directory + filename);
299 if (source.open(QIODevice::ReadOnly))
300 {
301 ba_hash = ba_hash.simplified();
302 QList<QByteArray> fileData(ba_hash.split(' '));
303 QCryptographicHash ch(method);
304 ch.addData(&source);
305 source.close();
306 if (fileData[0] == ch.result().toHex() && fileData[1] == filename)
307 return true;
308 qDebug()<<"checkFileHash: checksum failed for"<<directory<<filename;
309 }
310 return false;
311 }
312