Commit 2f3a2fa283abfcb587ef7d269e1790dc8246930e

Authored by Scott Klum
1 parent 78eb9f12

Change qtutils to unix encoding from dos

openbr/core/qtutils.cpp
1 -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  
2 - * Copyright 2012 The MITRE Corporation *  
3 - * *  
4 - * Licensed under the Apache License, Version 2.0 (the "License"); *  
5 - * you may not use this file except in compliance with the License. *  
6 - * You may obtain a copy of the License at *  
7 - * *  
8 - * http://www.apache.org/licenses/LICENSE-2.0 *  
9 - * *  
10 - * Unless required by applicable law or agreed to in writing, software *  
11 - * distributed under the License is distributed on an "AS IS" BASIS, *  
12 - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *  
13 - * See the License for the specific language governing permissions and *  
14 - * limitations under the License. *  
15 - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */  
16 -  
17 -#include <QCryptographicHash>  
18 -#include <QDebug>  
19 -#ifndef BR_EMBEDDED  
20 -#include <QDesktopServices>  
21 -#endif // BR_EMBEDDED  
22 -#include <QFile>  
23 -#include <QFileInfo>  
24 -#include <QProcess>  
25 -#include <QProcessEnvironment>  
26 -#include <QRegExp>  
27 -#include <QRegularExpression>  
28 -#include <QStack>  
29 -#include <QUrl>  
30 -#include <openbr/openbr_plugin.h>  
31 -  
32 -#include "alphanum.hpp"  
33 -#include "qtutils.h"  
34 -#include "opencvutils.h"  
35 -  
36 -using namespace br;  
37 -  
38 -namespace QtUtils  
39 -{  
40 -  
41 -QStringList readLines(const QString &file)  
42 -{  
43 - QStringList lines;  
44 - readFile(file, lines);  
45 - return lines;  
46 -}  
47 -  
48 -void readFile(const QString &file, QStringList &lines)  
49 -{  
50 - QByteArray data;  
51 - readFile(file, data);  
52 - lines = QString(data).split(QRegularExpression("[\n|\r\n|\r]"), QString::SkipEmptyParts);  
53 - for (int i=0; i<lines.size(); i++)  
54 - lines[i] = lines[i].simplified();  
55 -}  
56 -  
57 -void readFile(const QString &file, QByteArray &data, bool uncompress)  
58 -{  
59 - QFile f(file);  
60 - if (!f.open(QFile::ReadOnly)) {  
61 - if (f.exists()) qFatal("Unable to open %s for reading. Check file permissions.", qPrintable(file));  
62 - else qFatal("Unable to open %s for reading. File does not exist.", qPrintable(file));  
63 - }  
64 - data = f.readAll();  
65 - if (uncompress) data = qUncompress(data);  
66 - f.close();  
67 -}  
68 -  
69 -void writeFile(const QString &file, const QStringList &lines)  
70 -{  
71 - if (file.isEmpty()) return;  
72 - const QString baseName = QFileInfo(file).baseName();  
73 -  
74 - if (baseName == "terminal") {  
75 - printf("%s\n", qPrintable(lines.join("\n")));  
76 - } else if (baseName == "buffer") {  
77 - Globals->buffer = lines.join("\n").toStdString().c_str();  
78 - } else {  
79 - QFile f(file);  
80 - touchDir(f);  
81 -  
82 - if (!f.open(QFile::WriteOnly))  
83 - qFatal("Failed to open %s for writing.", qPrintable(file));  
84 -  
85 - foreach (const QString &line, lines)  
86 - f.write((line+"\n").toLocal8Bit());  
87 -  
88 - f.close();  
89 - }  
90 -}  
91 -  
92 -void writeFile(const QString &file, const QString &data)  
93 -{  
94 - writeFile(file, data.toLocal8Bit());  
95 -}  
96 -  
97 -void writeFile(const QString &file, const QByteArray &data, int compression)  
98 -{  
99 - if (file.isEmpty()) return;  
100 - const QString baseName = QFileInfo(file).baseName();  
101 - const QByteArray contents = (compression == 0) ? data : qCompress(data, compression);  
102 - if (baseName == "terminal") {  
103 - printf("%s\n", qPrintable(contents));  
104 - } else if (baseName == "buffer") {  
105 - Globals->buffer = data;  
106 - } else {  
107 - QFile f(file);  
108 - touchDir(f);  
109 - if (!f.open(QFile::WriteOnly))  
110 - qFatal("Failed to open %s for writing.", qPrintable(file));  
111 - f.write(contents);  
112 - f.close();  
113 - }  
114 -}  
115 -  
116 -void copyFile(const QString &src, const QString &dst)  
117 -{  
118 - touchDir(QFileInfo(dst));  
119 - if (!QFile::copy(src, dst)) {  
120 - if (QFileInfo(src).exists()) qFatal("Unable to copy %s to %s. Check file permissions.", qPrintable(src), qPrintable(dst));  
121 - else qFatal("Unable to copy %s to %s. File does not exist.", qPrintable(src), qPrintable(dst));  
122 - }  
123 -}  
124 -  
125 -void touchDir(const QDir &dir)  
126 -{  
127 - if (dir.exists(".")) return;  
128 - if (!dir.mkpath("."))  
129 - qFatal("Unable to create path to dir %s", qPrintable(dir.absolutePath()));  
130 -}  
131 -  
132 -void touchDir(const QFile &file)  
133 -{  
134 - touchDir(QFileInfo(file));  
135 -}  
136 -  
137 -void touchDir(const QFileInfo &fileInfo)  
138 -{  
139 - touchDir(fileInfo.dir());  
140 -}  
141 -  
142 -void emptyDir(QDir &dir)  
143 -{  
144 - foreach (const QString &folder, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks)) {  
145 - QDir subdir(dir);  
146 - bool success = subdir.cd(folder); if (!success) qFatal("cd failure.");  
147 - emptyDir(subdir);  
148 - }  
149 -  
150 - foreach (const QString &file, dir.entryList(QDir::Files))  
151 - dir.remove(file);  
152 -  
153 - foreach (const QString &folder, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks))  
154 - dir.rmdir(folder);  
155 -  
156 - foreach (const QString &symlink, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))  
157 - dir.remove(symlink);  
158 -}  
159 -  
160 -void deleteDir(QDir &dir)  
161 -{  
162 - emptyDir(dir);  
163 - dir.rmdir(".");  
164 -}  
165 -  
166 -QString find(const QString &file, const QString &alt)  
167 -{  
168 - if (QFileInfo(file).exists()) return file;  
169 - if (QFileInfo(alt).exists()) return alt;  
170 - qFatal("Can't find file %s or alt %s\n", qPrintable(file), qPrintable(alt));  
171 - return "";  
172 -}  
173 -  
174 -bool toBool(const QString &string)  
175 -{  
176 - bool ok;  
177 - bool result = (string.toFloat(&ok) != 0.f);  
178 - if (ok) return result;  
179 - else return (string != "FALSE") && (string != "false") && (string != "F") && (string != "f");  
180 -}  
181 -  
182 -int toInt(const QString &string)  
183 -{  
184 - bool ok;  
185 - int result = string.toInt(&ok); if (!ok) qFatal("Expected integer value, got %s.", qPrintable(string));  
186 - return result;  
187 -}  
188 -  
189 -float toFloat(const QString &string)  
190 -{  
191 - bool ok;  
192 - float result = string.toFloat(&ok); if (!ok) qFatal("Expected floating point value, got %s.", qPrintable(string));  
193 - return result;  
194 -}  
195 -  
196 -QList<float> toFloats(const QStringList &strings)  
197 -{  
198 - QList<float> floats;  
199 - bool ok;  
200 - foreach (const QString &string, strings) {  
201 - floats.append(string.toFloat(&ok));  
202 - if (!ok) qFatal("Failed to convert %s to floating point format.", qPrintable(string));  
203 - }  
204 - return floats;  
205 -}  
206 -  
207 -QStringList toStringList(const QList<float> &values)  
208 -{  
209 - QStringList result; result.reserve(values.size());  
210 - foreach (float value, values)  
211 - result.append(QString::number(value));  
212 - return result;  
213 -}  
214 -  
215 -QStringList toStringList(const std::vector<std::string> &string_list)  
216 -{  
217 - QStringList result;  
218 - foreach (const std::string &string, string_list)  
219 - result.append(QString::fromStdString(string));  
220 - return result;  
221 -}  
222 -  
223 -QStringList toStringList(int num_strings, const char *strings[])  
224 -{  
225 - QStringList result;  
226 - for (int i=0; i<num_strings; i++)  
227 - result.append(strings[i]);  
228 - return result;  
229 -}  
230 -  
231 -QString shortTextHash(QString string)  
232 -{  
233 - string.remove(QRegExp("[{}<>&]"));  
234 - return QString(QCryptographicHash::hash(qPrintable(string), QCryptographicHash::Md5).toBase64()).remove(QRegExp("[^a-zA-Z1-9]")).left(6);  
235 -}  
236 -  
237 -QStringList parse(QString args, char split, bool *ok)  
238 -{  
239 - if (args.isEmpty()) return QStringList();  
240 -  
241 - QStringList words;  
242 - int start = 0;  
243 - bool inQuote = false;  
244 - QStack<QChar> subexpressions;  
245 - for (int i=0; i<args.size(); i++) {  
246 - if (inQuote) {  
247 - if (args[i] == '\'')  
248 - inQuote = false;  
249 - } else {  
250 - if (args[i] == '\'') {  
251 - inQuote = true;  
252 - } else if ((args[i] == '(') || (args[i] == '[') || (args[i] == '<') || (args[i] == '{')) {  
253 - subexpressions.push(args[i]);  
254 - } else if (args[i] == ')') {  
255 - if (subexpressions.isEmpty() || (subexpressions.pop() != '(')) {  
256 - if (ok) *ok = false;  
257 - else qFatal("Unexpected ')'.");  
258 - return words;  
259 - }  
260 - } else if (args[i] == ']') {  
261 - if (subexpressions.isEmpty() || (subexpressions.pop() != '[')) {  
262 - if (ok) *ok = false;  
263 - else qFatal("Unexpected ']'.");  
264 - return words;  
265 - }  
266 - } else if (args[i] == '>') {  
267 - if (subexpressions.isEmpty() || (subexpressions.pop() != '<')) {  
268 - if (ok) *ok = false;  
269 - else qFatal("Unexpected '>'.");  
270 - return words;  
271 - }  
272 - } else if (args[i] == '}') {  
273 - if (subexpressions.isEmpty() || (subexpressions.pop() != '{')) {  
274 - if (ok) *ok = false;  
275 - else qFatal("Unexpected '}'.");  
276 - return words;  
277 - }  
278 - } else if (subexpressions.isEmpty() && (args[i] == split)) {  
279 - words.append(args.mid(start, i-start).trimmed());  
280 - start = i+1;  
281 - }  
282 - }  
283 - }  
284 -  
285 - if (ok) *ok = true;  
286 - words.append(args.mid(start).trimmed());  
287 - return words;  
288 -}  
289 -  
290 -void checkArgsSize(const QString &name, const QStringList &args, int min, int max)  
291 -{  
292 - if (max == -1) max = std::numeric_limits<int>::max();  
293 - if (max == 0) max = min;  
294 - if (args.size() < min) qFatal("%s expects at least %d arguments, got %d", qPrintable(name), min, args.size());  
295 - if (args.size() > max) qFatal("%s expects no more than %d arguments, got %d", qPrintable(name), max, args.size());  
296 -}  
297 -  
298 -QPointF toPoint(const QString &string, bool *ok)  
299 -{  
300 - if (string.startsWith('(') && string.endsWith(')')) {  
301 - bool okParse;  
302 - const QStringList words = parse(string.mid(1, string.size()-2), ',', &okParse);  
303 - if (okParse && (words.size() == 2)) {  
304 - float x, y;  
305 - bool okX, okY;  
306 - x = words[0].toFloat(&okX);  
307 - y = words[1].toFloat(&okY);  
308 - if (okX && okY) {  
309 - if (ok) *ok = true;  
310 - return QPointF(x, y);  
311 - }  
312 - }  
313 - }  
314 -  
315 - if (ok) *ok = false;  
316 - return QPointF();  
317 -}  
318 -  
319 -QRectF toRect(const QString &string, bool *ok)  
320 -{  
321 - if (string.startsWith('(') && string.endsWith(')')) {  
322 - bool okParse;  
323 - const QStringList words = parse(string.mid(1, string.size()-2), ',', &okParse);  
324 - if (okParse && (words.size() == 4)) {  
325 - float x, y, width, height;  
326 - bool okX, okY, okWidth, okHeight;  
327 - x = words[0].toFloat(&okX);  
328 - y = words[1].toFloat(&okY);  
329 - width = words[2].toFloat(&okWidth);  
330 - height = words[3].toFloat(&okHeight);  
331 - if (okX && okY && okWidth && okHeight) {  
332 - if (ok) *ok = true;  
333 - return QRectF(x, y, width, height);  
334 - }  
335 - }  
336 - }  
337 -  
338 - if (ok) *ok = false;  
339 - return QRectF();  
340 -}  
341 -  
342 -QStringList naturalSort(const QStringList &strings)  
343 -{  
344 - QList<std::string> stdStrings; stdStrings.reserve(strings.size());  
345 - foreach (const QString &string, strings)  
346 - stdStrings.append(string.toStdString());  
347 -  
348 - std::sort(stdStrings.begin(), stdStrings.end(), doj::alphanum_less<std::string>());  
349 -  
350 - QStringList result; result.reserve(strings.size());  
351 - foreach (const std::string &stdString, stdStrings)  
352 - result.append(QString::fromStdString(stdString));  
353 -  
354 - return result;  
355 -}  
356 -  
357 -bool runRScript(const QString &file)  
358 -{  
359 -// iOS doesn't support QProcess  
360 -#ifdef QT_NO_PROCESS  
361 - (void) file;  
362 - return false;  
363 -#else // !QT_NO_PROCESS  
364 - QProcess RScript;  
365 - RScript.start("Rscript", QStringList() << file);  
366 - RScript.waitForFinished(-1);  
367 - bool result = ((RScript.exitCode() == 0) && (RScript.error() == QProcess::UnknownError));  
368 - if (!result) qDebug("Failed to run 'Rscript', did you forget to install R? "  
369 - "See online documentation of 'br_plot' for required R packages. "  
370 - "Otherwise, try running Rscript on %s to get the exact error.", qPrintable(file));  
371 - return result;  
372 -#endif // QT_NO_PROCESS  
373 -}  
374 -  
375 -bool runDot(const QString &file)  
376 -{  
377 -// iOS doesn't support QProcess  
378 -#ifdef QT_NO_PROCESS  
379 - (void) file;  
380 - return false;  
381 -#else // !QT_NO_PROCESS  
382 - QProcess dot;  
383 - dot.start("dot -Tpdf -O " + file);  
384 - dot.waitForFinished(-1);  
385 - return ((dot.exitCode() == 0) && (dot.error() == QProcess::UnknownError));  
386 -#endif // QT_NO_PROCESS  
387 -}  
388 -  
389 -void showFile(const QString &file)  
390 -{  
391 -#ifndef BR_EMBEDDED  
392 - (void) file;  
393 - // A bug in Qt5 currently prevents us from doing this:  
394 - // QDesktopServices::openUrl(QUrl::fromLocalFile(file));  
395 -#else // BR_EMBEDDED  
396 - (void) file;  
397 -#endif // BR_EMBEDDED  
398 -}  
399 -  
400 -QString toString(const QVariant &variant)  
401 -{  
402 - if (variant.canConvert(QVariant::List)) return toString(qvariant_cast<QVariantList>(variant));  
403 - else if (variant.canConvert(QVariant::String)) return variant.toString();  
404 - else if (variant.canConvert(QVariant::PointF)) {  
405 - QPointF point = qvariant_cast<QPointF>(variant);  
406 - return QString("(%1,%2)").arg(QString::number(point.x()),QString::number(point.y()));  
407 - } else if (variant.canConvert(QVariant::RectF)) {  
408 - QRectF rect = qvariant_cast<QRectF>(variant);  
409 - return QString("(%1,%2,%3,%4)").arg(QString::number(rect.x()),  
410 - QString::number(rect.y()),  
411 - QString::number(rect.width()),  
412 - QString::number(rect.height()));  
413 - } else if (variant.canConvert<cv::Mat>()) {  
414 - return OpenCVUtils::matrixToString(variant.value<cv::Mat>());  
415 - } else if (variant.canConvert<cv::RotatedRect>()) {  
416 - return OpenCVUtils::rotatedRectToString(variant.value<cv::RotatedRect>());  
417 - }  
418 -  
419 - return QString();  
420 -}  
421 -  
422 -QString toString(const QVariantList &variantList)  
423 -{  
424 - QStringList variants;  
425 -  
426 - foreach (const QVariant &variant, variantList)  
427 - variants.append(toString(variant));  
428 -  
429 - if (!variants.isEmpty()) return "[" + variants.join(", ") + "]";  
430 -  
431 - return QString();  
432 -}  
433 -  
434 -QString toString(const QMap<QString,QVariant> &variantMap)  
435 -{  
436 - QStringList variants = toStringList(variantMap);  
437 -  
438 - if (!variants.isEmpty()) return "[" + variants.join(", ") + "]";  
439 -  
440 - return QString();  
441 -}  
442 -  
443 -QStringList toStringList(const QMap<QString,QVariant> &variantMap)  
444 -{  
445 - QStringList variants;  
446 -  
447 - QMapIterator<QString, QVariant> i(variantMap);  
448 - while (i.hasNext()) {  
449 - i.next();  
450 - variants.append(i.key() + "=" + toString(i.value()));  
451 - }  
452 -  
453 - return variants;  
454 -}  
455 -  
456 -QString toTime(int s)  
457 -{  
458 - int h = s / (60*60);  
459 - int m = (s - h*60*60) / 60;  
460 - s = (s - h*60*60 - m*60);  
461 -  
462 - const QChar fillChar = QLatin1Char('0');  
463 -  
464 - return QString("%1:%2:%3").arg(h,2,10,fillChar).arg(m,2,10,fillChar).arg(s,2,10,fillChar);  
465 -}  
466 -  
467 -float euclideanLength(const QPointF &point)  
468 -{  
469 - return sqrt(pow(point.x(), 2) + pow(point.y(), 2));  
470 -}  
471 -  
472 -float orientation(const QPointF &pointA, const QPointF &pointB)  
473 -{  
474 - return atan2(pointB.y() - pointA.y(), pointB.x() - pointA.x());  
475 -}  
476 -  
477 -float overlap(const QRectF &r, const QRectF &s) {  
478 - QRectF intersection = r & s;  
479 -  
480 - return (intersection.width()*intersection.height())/(r.width()*r.height());  
481 -}  
482 -  
483 -  
484 -QString getAbsolutePath(const QString &filename)  
485 -{  
486 - // Try adding the global path, if present  
487 - QString withPath = (Globals->path.isEmpty() ? "" : Globals->path + "/") + filename;  
488 -  
489 - // we weren't necessarily using it to begin with, so see if that file  
490 - // exists  
491 - QFileInfo wpInfo(withPath);  
492 - if (wpInfo.exists() )  
493 - return wpInfo.absoluteFilePath();  
494 -  
495 - // If no, just use the nominal filename  
496 - return QFileInfo(filename).absoluteFilePath();  
497 -}  
498 -  
499 -const int base_block = 100000000;  
500 -  
501 -BlockCompression::BlockCompression(QIODevice *_basis)  
502 -{  
503 - blockSize = base_block;  
504 - setBasis(_basis);  
505 -}  
506 -  
507 -BlockCompression::BlockCompression() { blockSize = base_block;};  
508 -  
509 -bool BlockCompression::open(QIODevice::OpenMode mode)  
510 -{  
511 - this->setOpenMode(mode);  
512 - bool res = basis->open(mode);  
513 -  
514 - if (!res)  
515 - return false;  
516 -  
517 - blockReader.setDevice(basis);  
518 - blockWriter.setDevice(basis);  
519 -  
520 - if (mode & QIODevice::WriteOnly) {  
521 - precompressedBlockWriter.open(QIODevice::WriteOnly);  
522 - }  
523 - else if (mode & QIODevice::ReadOnly) {  
524 -  
525 - // Read an initial compressed block from the underlying QIODevice,  
526 - // decompress, and set up a reader on it  
527 - QByteArray compressedBlock;  
528 - quint32 block_size;  
529 - blockReader >> block_size;  
530 - compressedBlock.resize(block_size);  
531 - int read_count = blockReader.readRawData(compressedBlock.data(), block_size);  
532 - if (read_count != int(block_size))  
533 - qFatal("Failed to read initial block");  
534 -  
535 - decompressedBlock = qUncompress(compressedBlock);  
536 -  
537 - decompressedBlockReader.setBuffer(&decompressedBlock);  
538 - decompressedBlockReader.open(QIODevice::ReadOnly);  
539 - }  
540 -  
541 - return true;  
542 -}  
543 -  
544 -void BlockCompression::close()  
545 -{  
546 - // flush output buffer, since we may have a partial block which hasn't been  
547 - // written to disk yet.  
548 - if ((openMode() & QIODevice::WriteOnly) && precompressedBlockWriter.isOpen()) {  
549 - QByteArray compressedBlock = qCompress(precompressedBlockWriter.buffer());  
550 - precompressedBlockWriter.close();  
551 -  
552 - quint32 bsize= compressedBlock.size();  
553 - blockWriter << bsize;  
554 - blockWriter.writeRawData(compressedBlock.constData(), compressedBlock.size());  
555 - }  
556 - // close the underlying device.  
557 - basis->close();  
558 -}  
559 -  
560 -void BlockCompression::setBasis(QIODevice *_basis)  
561 -{  
562 - basis = _basis;  
563 - blockReader.setDevice(basis);  
564 - blockWriter.setDevice(basis);  
565 -}  
566 -  
567 -// read from current decompressed block, if out of space, read and decompress another  
568 -// block from basis  
569 -qint64 BlockCompression::readData(char *data, qint64 remaining)  
570 -{  
571 - qint64 read = 0;  
572 - while (remaining > 0) {  
573 - // attempt to read the target amount of data  
574 - qint64 single_read = decompressedBlockReader.read(data, remaining);  
575 - if (single_read == -1)  
576 - qFatal("miss read");  
577 -  
578 - remaining -= single_read;  
579 - read += single_read;  
580 - data += single_read;  
581 -  
582 - // need a new block if we didn't get enough bytes from the previous read  
583 - if (remaining > 0) {  
584 - QByteArray compressedBlock;  
585 -  
586 - // read the size of the next block  
587 - quint32 block_size;  
588 - blockReader >> block_size;  
589 - if (block_size == 0)  
590 - break;  
591 -  
592 - compressedBlock.resize(block_size);  
593 - int actualRead = blockReader.readRawData(compressedBlock.data(), block_size);  
594 - if (actualRead != int(block_size))  
595 - qFatal("Bad read on nominal block size: %d, only got %d", block_size, int(remaining));  
596 -  
597 - decompressedBlock = qUncompress(compressedBlock);  
598 -  
599 - decompressedBlockReader.close();  
600 - decompressedBlockReader.setBuffer(&decompressedBlock);  
601 - decompressedBlockReader.open(QIODevice::ReadOnly);  
602 - }  
603 - }  
604 -  
605 - bool condition = blockReader.atEnd() && !basis->isReadable() ;  
606 - if (condition)  
607 - qWarning("Returning -1 from read");  
608 -  
609 - return condition ? -1 : read;  
610 -}  
611 -  
612 -bool BlockCompression::isSequential() const  
613 -{  
614 - return true;  
615 -}  
616 -  
617 -qint64 BlockCompression::writeData(const char *data, qint64 remaining)  
618 -{  
619 - const char * endPoint = data + remaining;  
620 - qint64 initial = remaining;  
621 -  
622 - qint64 written = 0;  
623 -  
624 - while (remaining > 0) {  
625 - // how much more can be put in this buffer?  
626 - qint64 capacity = blockSize - precompressedBlockWriter.pos();  
627 - if (capacity < 0)  
628 - qFatal("Negative capacity!!!");  
629 -  
630 - // don't try to write beyond capacity  
631 - qint64 write_size = qMin(capacity, remaining);  
632 -  
633 - qint64 singleWrite = precompressedBlockWriter.write(data, write_size);  
634 -  
635 - if (singleWrite == -1)  
636 - qFatal("matrix write failure?");  
637 -  
638 - remaining -= singleWrite;  
639 - data += singleWrite;  
640 - written += singleWrite;  
641 - if (data > endPoint)  
642 - qFatal("Wrote past the end");  
643 -  
644 - if (remaining > 0) {  
645 - QByteArray compressedBlock = qCompress(precompressedBlockWriter.buffer(), -1);  
646 -  
647 - if (precompressedBlockWriter.buffer().size() != 0) {  
648 - quint32 block_size = compressedBlock.size();  
649 - blockWriter << block_size;  
650 -  
651 - int write_count = blockWriter.writeRawData(compressedBlock.constData(), block_size);  
652 - if (write_count != int(block_size))  
653 - qFatal("Didn't write enough data");  
654 - }  
655 - else  
656 - qFatal("serialized empty compressed block (?)");  
657 -  
658 - precompressedBlockWriter.close();  
659 - precompressedBlockWriter.open(QIODevice::WriteOnly);  
660 - }  
661 - }  
662 -  
663 - if (written != initial)  
664 - qFatal("didn't write enough bytes");  
665 -  
666 - bool condition = basis->isWritable();  
667 - if (!condition)  
668 - qWarning("Returning -1 from write");  
669 -  
670 - return basis->isWritable() ? written : -1;  
671 -}  
672 -  
673 -  
674 -  
675 -} // namespace QtUtils  
676 - 1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <QCryptographicHash>
  18 +#include <QDebug>
  19 +#ifndef BR_EMBEDDED
  20 +#include <QDesktopServices>
  21 +#endif // BR_EMBEDDED
  22 +#include <QFile>
  23 +#include <QFileInfo>
  24 +#include <QProcess>
  25 +#include <QProcessEnvironment>
  26 +#include <QRegExp>
  27 +#include <QRegularExpression>
  28 +#include <QStack>
  29 +#include <QUrl>
  30 +#include <openbr/openbr_plugin.h>
  31 +
  32 +#include "alphanum.hpp"
  33 +#include "qtutils.h"
  34 +#include "opencvutils.h"
  35 +
  36 +using namespace br;
  37 +
  38 +namespace QtUtils
  39 +{
  40 +
  41 +QStringList readLines(const QString &file)
  42 +{
  43 + QStringList lines;
  44 + readFile(file, lines);
  45 + return lines;
  46 +}
  47 +
  48 +void readFile(const QString &file, QStringList &lines)
  49 +{
  50 + QByteArray data;
  51 + readFile(file, data);
  52 + lines = QString(data).split(QRegularExpression("[\n|\r\n|\r]"), QString::SkipEmptyParts);
  53 + for (int i=0; i<lines.size(); i++)
  54 + lines[i] = lines[i].simplified();
  55 +}
  56 +
  57 +void readFile(const QString &file, QByteArray &data, bool uncompress)
  58 +{
  59 + QFile f(file);
  60 + if (!f.open(QFile::ReadOnly)) {
  61 + if (f.exists()) qFatal("Unable to open %s for reading. Check file permissions.", qPrintable(file));
  62 + else qFatal("Unable to open %s for reading. File does not exist.", qPrintable(file));
  63 + }
  64 + data = f.readAll();
  65 + if (uncompress) data = qUncompress(data);
  66 + f.close();
  67 +}
  68 +
  69 +void writeFile(const QString &file, const QStringList &lines)
  70 +{
  71 + if (file.isEmpty()) return;
  72 + const QString baseName = QFileInfo(file).baseName();
  73 +
  74 + if (baseName == "terminal") {
  75 + printf("%s\n", qPrintable(lines.join("\n")));
  76 + } else if (baseName == "buffer") {
  77 + Globals->buffer = lines.join("\n").toStdString().c_str();
  78 + } else {
  79 + QFile f(file);
  80 + touchDir(f);
  81 +
  82 + if (!f.open(QFile::WriteOnly))
  83 + qFatal("Failed to open %s for writing.", qPrintable(file));
  84 +
  85 + foreach (const QString &line, lines)
  86 + f.write((line+"\n").toLocal8Bit());
  87 +
  88 + f.close();
  89 + }
  90 +}
  91 +
  92 +void writeFile(const QString &file, const QString &data)
  93 +{
  94 + writeFile(file, data.toLocal8Bit());
  95 +}
  96 +
  97 +void writeFile(const QString &file, const QByteArray &data, int compression)
  98 +{
  99 + if (file.isEmpty()) return;
  100 + const QString baseName = QFileInfo(file).baseName();
  101 + const QByteArray contents = (compression == 0) ? data : qCompress(data, compression);
  102 + if (baseName == "terminal") {
  103 + printf("%s\n", qPrintable(contents));
  104 + } else if (baseName == "buffer") {
  105 + Globals->buffer = data;
  106 + } else {
  107 + QFile f(file);
  108 + touchDir(f);
  109 + if (!f.open(QFile::WriteOnly))
  110 + qFatal("Failed to open %s for writing.", qPrintable(file));
  111 + f.write(contents);
  112 + f.close();
  113 + }
  114 +}
  115 +
  116 +void copyFile(const QString &src, const QString &dst)
  117 +{
  118 + touchDir(QFileInfo(dst));
  119 + if (!QFile::copy(src, dst)) {
  120 + if (QFileInfo(src).exists()) qFatal("Unable to copy %s to %s. Check file permissions.", qPrintable(src), qPrintable(dst));
  121 + else qFatal("Unable to copy %s to %s. File does not exist.", qPrintable(src), qPrintable(dst));
  122 + }
  123 +}
  124 +
  125 +void touchDir(const QDir &dir)
  126 +{
  127 + if (dir.exists(".")) return;
  128 + if (!dir.mkpath("."))
  129 + qFatal("Unable to create path to dir %s", qPrintable(dir.absolutePath()));
  130 +}
  131 +
  132 +void touchDir(const QFile &file)
  133 +{
  134 + touchDir(QFileInfo(file));
  135 +}
  136 +
  137 +void touchDir(const QFileInfo &fileInfo)
  138 +{
  139 + touchDir(fileInfo.dir());
  140 +}
  141 +
  142 +void emptyDir(QDir &dir)
  143 +{
  144 + foreach (const QString &folder, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks)) {
  145 + QDir subdir(dir);
  146 + bool success = subdir.cd(folder); if (!success) qFatal("cd failure.");
  147 + emptyDir(subdir);
  148 + }
  149 +
  150 + foreach (const QString &file, dir.entryList(QDir::Files))
  151 + dir.remove(file);
  152 +
  153 + foreach (const QString &folder, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks))
  154 + dir.rmdir(folder);
  155 +
  156 + foreach (const QString &symlink, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
  157 + dir.remove(symlink);
  158 +}
  159 +
  160 +void deleteDir(QDir &dir)
  161 +{
  162 + emptyDir(dir);
  163 + dir.rmdir(".");
  164 +}
  165 +
  166 +QString find(const QString &file, const QString &alt)
  167 +{
  168 + if (QFileInfo(file).exists()) return file;
  169 + if (QFileInfo(alt).exists()) return alt;
  170 + qFatal("Can't find file %s or alt %s\n", qPrintable(file), qPrintable(alt));
  171 + return "";
  172 +}
  173 +
  174 +bool toBool(const QString &string)
  175 +{
  176 + bool ok;
  177 + bool result = (string.toFloat(&ok) != 0.f);
  178 + if (ok) return result;
  179 + else return (string != "FALSE") && (string != "false") && (string != "F") && (string != "f");
  180 +}
  181 +
  182 +int toInt(const QString &string)
  183 +{
  184 + bool ok;
  185 + int result = string.toInt(&ok); if (!ok) qFatal("Expected integer value, got %s.", qPrintable(string));
  186 + return result;
  187 +}
  188 +
  189 +float toFloat(const QString &string)
  190 +{
  191 + bool ok;
  192 + float result = string.toFloat(&ok); if (!ok) qFatal("Expected floating point value, got %s.", qPrintable(string));
  193 + return result;
  194 +}
  195 +
  196 +QList<float> toFloats(const QStringList &strings)
  197 +{
  198 + QList<float> floats;
  199 + bool ok;
  200 + foreach (const QString &string, strings) {
  201 + floats.append(string.toFloat(&ok));
  202 + if (!ok) qFatal("Failed to convert %s to floating point format.", qPrintable(string));
  203 + }
  204 + return floats;
  205 +}
  206 +
  207 +QStringList toStringList(const QList<float> &values)
  208 +{
  209 + QStringList result; result.reserve(values.size());
  210 + foreach (float value, values)
  211 + result.append(QString::number(value));
  212 + return result;
  213 +}
  214 +
  215 +QStringList toStringList(const std::vector<std::string> &string_list)
  216 +{
  217 + QStringList result;
  218 + foreach (const std::string &string, string_list)
  219 + result.append(QString::fromStdString(string));
  220 + return result;
  221 +}
  222 +
  223 +QStringList toStringList(int num_strings, const char *strings[])
  224 +{
  225 + QStringList result;
  226 + for (int i=0; i<num_strings; i++)
  227 + result.append(strings[i]);
  228 + return result;
  229 +}
  230 +
  231 +QString shortTextHash(QString string)
  232 +{
  233 + string.remove(QRegExp("[{}<>&]"));
  234 + return QString(QCryptographicHash::hash(qPrintable(string), QCryptographicHash::Md5).toBase64()).remove(QRegExp("[^a-zA-Z1-9]")).left(6);
  235 +}
  236 +
  237 +QStringList parse(QString args, char split, bool *ok)
  238 +{
  239 + if (args.isEmpty()) return QStringList();
  240 +
  241 + QStringList words;
  242 + int start = 0;
  243 + bool inQuote = false;
  244 + QStack<QChar> subexpressions;
  245 + for (int i=0; i<args.size(); i++) {
  246 + if (inQuote) {
  247 + if (args[i] == '\'')
  248 + inQuote = false;
  249 + } else {
  250 + if (args[i] == '\'') {
  251 + inQuote = true;
  252 + } else if ((args[i] == '(') || (args[i] == '[') || (args[i] == '<') || (args[i] == '{')) {
  253 + subexpressions.push(args[i]);
  254 + } else if (args[i] == ')') {
  255 + if (subexpressions.isEmpty() || (subexpressions.pop() != '(')) {
  256 + if (ok) *ok = false;
  257 + else qFatal("Unexpected ')'.");
  258 + return words;
  259 + }
  260 + } else if (args[i] == ']') {
  261 + if (subexpressions.isEmpty() || (subexpressions.pop() != '[')) {
  262 + if (ok) *ok = false;
  263 + else qFatal("Unexpected ']'.");
  264 + return words;
  265 + }
  266 + } else if (args[i] == '>') {
  267 + if (subexpressions.isEmpty() || (subexpressions.pop() != '<')) {
  268 + if (ok) *ok = false;
  269 + else qFatal("Unexpected '>'.");
  270 + return words;
  271 + }
  272 + } else if (args[i] == '}') {
  273 + if (subexpressions.isEmpty() || (subexpressions.pop() != '{')) {
  274 + if (ok) *ok = false;
  275 + else qFatal("Unexpected '}'.");
  276 + return words;
  277 + }
  278 + } else if (subexpressions.isEmpty() && (args[i] == split)) {
  279 + words.append(args.mid(start, i-start).trimmed());
  280 + start = i+1;
  281 + }
  282 + }
  283 + }
  284 +
  285 + if (ok) *ok = true;
  286 + words.append(args.mid(start).trimmed());
  287 + return words;
  288 +}
  289 +
  290 +void checkArgsSize(const QString &name, const QStringList &args, int min, int max)
  291 +{
  292 + if (max == -1) max = std::numeric_limits<int>::max();
  293 + if (max == 0) max = min;
  294 + if (args.size() < min) qFatal("%s expects at least %d arguments, got %d", qPrintable(name), min, args.size());
  295 + if (args.size() > max) qFatal("%s expects no more than %d arguments, got %d", qPrintable(name), max, args.size());
  296 +}
  297 +
  298 +QPointF toPoint(const QString &string, bool *ok)
  299 +{
  300 + if (string.startsWith('(') && string.endsWith(')')) {
  301 + bool okParse;
  302 + const QStringList words = parse(string.mid(1, string.size()-2), ',', &okParse);
  303 + if (okParse && (words.size() == 2)) {
  304 + float x, y;
  305 + bool okX, okY;
  306 + x = words[0].toFloat(&okX);
  307 + y = words[1].toFloat(&okY);
  308 + if (okX && okY) {
  309 + if (ok) *ok = true;
  310 + return QPointF(x, y);
  311 + }
  312 + }
  313 + }
  314 +
  315 + if (ok) *ok = false;
  316 + return QPointF();
  317 +}
  318 +
  319 +QRectF toRect(const QString &string, bool *ok)
  320 +{
  321 + if (string.startsWith('(') && string.endsWith(')')) {
  322 + bool okParse;
  323 + const QStringList words = parse(string.mid(1, string.size()-2), ',', &okParse);
  324 + if (okParse && (words.size() == 4)) {
  325 + float x, y, width, height;
  326 + bool okX, okY, okWidth, okHeight;
  327 + x = words[0].toFloat(&okX);
  328 + y = words[1].toFloat(&okY);
  329 + width = words[2].toFloat(&okWidth);
  330 + height = words[3].toFloat(&okHeight);
  331 + if (okX && okY && okWidth && okHeight) {
  332 + if (ok) *ok = true;
  333 + return QRectF(x, y, width, height);
  334 + }
  335 + }
  336 + }
  337 +
  338 + if (ok) *ok = false;
  339 + return QRectF();
  340 +}
  341 +
  342 +QStringList naturalSort(const QStringList &strings)
  343 +{
  344 + QList<std::string> stdStrings; stdStrings.reserve(strings.size());
  345 + foreach (const QString &string, strings)
  346 + stdStrings.append(string.toStdString());
  347 +
  348 + std::sort(stdStrings.begin(), stdStrings.end(), doj::alphanum_less<std::string>());
  349 +
  350 + QStringList result; result.reserve(strings.size());
  351 + foreach (const std::string &stdString, stdStrings)
  352 + result.append(QString::fromStdString(stdString));
  353 +
  354 + return result;
  355 +}
  356 +
  357 +bool runRScript(const QString &file)
  358 +{
  359 +// iOS doesn't support QProcess
  360 +#ifdef QT_NO_PROCESS
  361 + (void) file;
  362 + return false;
  363 +#else // !QT_NO_PROCESS
  364 + QProcess RScript;
  365 + RScript.start("Rscript", QStringList() << file);
  366 + RScript.waitForFinished(-1);
  367 + bool result = ((RScript.exitCode() == 0) && (RScript.error() == QProcess::UnknownError));
  368 + if (!result) qDebug("Failed to run 'Rscript', did you forget to install R? "
  369 + "See online documentation of 'br_plot' for required R packages. "
  370 + "Otherwise, try running Rscript on %s to get the exact error.", qPrintable(file));
  371 + return result;
  372 +#endif // QT_NO_PROCESS
  373 +}
  374 +
  375 +bool runDot(const QString &file)
  376 +{
  377 +// iOS doesn't support QProcess
  378 +#ifdef QT_NO_PROCESS
  379 + (void) file;
  380 + return false;
  381 +#else // !QT_NO_PROCESS
  382 + QProcess dot;
  383 + dot.start("dot -Tpdf -O " + file);
  384 + dot.waitForFinished(-1);
  385 + return ((dot.exitCode() == 0) && (dot.error() == QProcess::UnknownError));
  386 +#endif // QT_NO_PROCESS
  387 +}
  388 +
  389 +void showFile(const QString &file)
  390 +{
  391 +#ifndef BR_EMBEDDED
  392 + (void) file;
  393 + // A bug in Qt5 currently prevents us from doing this:
  394 + // QDesktopServices::openUrl(QUrl::fromLocalFile(file));
  395 +#else // BR_EMBEDDED
  396 + (void) file;
  397 +#endif // BR_EMBEDDED
  398 +}
  399 +
  400 +QString toString(const QVariant &variant)
  401 +{
  402 + if (variant.canConvert(QVariant::List)) return toString(qvariant_cast<QVariantList>(variant));
  403 + else if (variant.canConvert(QVariant::String)) return variant.toString();
  404 + else if (variant.canConvert(QVariant::PointF)) {
  405 + QPointF point = qvariant_cast<QPointF>(variant);
  406 + return QString("(%1,%2)").arg(QString::number(point.x()),QString::number(point.y()));
  407 + } else if (variant.canConvert(QVariant::RectF)) {
  408 + QRectF rect = qvariant_cast<QRectF>(variant);
  409 + return QString("(%1,%2,%3,%4)").arg(QString::number(rect.x()),
  410 + QString::number(rect.y()),
  411 + QString::number(rect.width()),
  412 + QString::number(rect.height()));
  413 + } else if (variant.canConvert<cv::Mat>()) {
  414 + return OpenCVUtils::matrixToString(variant.value<cv::Mat>());
  415 + } else if (variant.canConvert<cv::RotatedRect>()) {
  416 + return OpenCVUtils::rotatedRectToString(variant.value<cv::RotatedRect>());
  417 + }
  418 +
  419 + return QString();
  420 +}
  421 +
  422 +QString toString(const QVariantList &variantList)
  423 +{
  424 + QStringList variants;
  425 +
  426 + foreach (const QVariant &variant, variantList)
  427 + variants.append(toString(variant));
  428 +
  429 + if (!variants.isEmpty()) return "[" + variants.join(", ") + "]";
  430 +
  431 + return QString();
  432 +}
  433 +
  434 +QString toString(const QMap<QString,QVariant> &variantMap)
  435 +{
  436 + QStringList variants = toStringList(variantMap);
  437 +
  438 + if (!variants.isEmpty()) return "[" + variants.join(", ") + "]";
  439 +
  440 + return QString();
  441 +}
  442 +
  443 +QStringList toStringList(const QMap<QString,QVariant> &variantMap)
  444 +{
  445 + QStringList variants;
  446 +
  447 + QMapIterator<QString, QVariant> i(variantMap);
  448 + while (i.hasNext()) {
  449 + i.next();
  450 + variants.append(i.key() + "=" + toString(i.value()));
  451 + }
  452 +
  453 + return variants;
  454 +}
  455 +
  456 +QString toTime(int s)
  457 +{
  458 + int h = s / (60*60);
  459 + int m = (s - h*60*60) / 60;
  460 + s = (s - h*60*60 - m*60);
  461 +
  462 + const QChar fillChar = QLatin1Char('0');
  463 +
  464 + return QString("%1:%2:%3").arg(h,2,10,fillChar).arg(m,2,10,fillChar).arg(s,2,10,fillChar);
  465 +}
  466 +
  467 +float euclideanLength(const QPointF &point)
  468 +{
  469 + return sqrt(pow(point.x(), 2) + pow(point.y(), 2));
  470 +}
  471 +
  472 +float orientation(const QPointF &pointA, const QPointF &pointB)
  473 +{
  474 + return atan2(pointB.y() - pointA.y(), pointB.x() - pointA.x());
  475 +}
  476 +
  477 +float overlap(const QRectF &r, const QRectF &s) {
  478 + QRectF intersection = r & s;
  479 +
  480 + return (intersection.width()*intersection.height())/(r.width()*r.height());
  481 +}
  482 +
  483 +
  484 +QString getAbsolutePath(const QString &filename)
  485 +{
  486 + // Try adding the global path, if present
  487 + QString withPath = (Globals->path.isEmpty() ? "" : Globals->path + "/") + filename;
  488 +
  489 + // we weren't necessarily using it to begin with, so see if that file
  490 + // exists
  491 + QFileInfo wpInfo(withPath);
  492 + if (wpInfo.exists() )
  493 + return wpInfo.absoluteFilePath();
  494 +
  495 + // If no, just use the nominal filename
  496 + return QFileInfo(filename).absoluteFilePath();
  497 +}
  498 +
  499 +const int base_block = 100000000;
  500 +
  501 +BlockCompression::BlockCompression(QIODevice *_basis)
  502 +{
  503 + blockSize = base_block;
  504 + setBasis(_basis);
  505 +}
  506 +
  507 +BlockCompression::BlockCompression() { blockSize = base_block;};
  508 +
  509 +bool BlockCompression::open(QIODevice::OpenMode mode)
  510 +{
  511 + this->setOpenMode(mode);
  512 + bool res = basis->open(mode);
  513 +
  514 + if (!res)
  515 + return false;
  516 +
  517 + blockReader.setDevice(basis);
  518 + blockWriter.setDevice(basis);
  519 +
  520 + if (mode & QIODevice::WriteOnly) {
  521 + precompressedBlockWriter.open(QIODevice::WriteOnly);
  522 + }
  523 + else if (mode & QIODevice::ReadOnly) {
  524 +
  525 + // Read an initial compressed block from the underlying QIODevice,
  526 + // decompress, and set up a reader on it
  527 + QByteArray compressedBlock;
  528 + quint32 block_size;
  529 + blockReader >> block_size;
  530 + compressedBlock.resize(block_size);
  531 + int read_count = blockReader.readRawData(compressedBlock.data(), block_size);
  532 + if (read_count != int(block_size))
  533 + qFatal("Failed to read initial block");
  534 +
  535 + decompressedBlock = qUncompress(compressedBlock);
  536 +
  537 + decompressedBlockReader.setBuffer(&decompressedBlock);
  538 + decompressedBlockReader.open(QIODevice::ReadOnly);
  539 + }
  540 +
  541 + return true;
  542 +}
  543 +
  544 +void BlockCompression::close()
  545 +{
  546 + // flush output buffer, since we may have a partial block which hasn't been
  547 + // written to disk yet.
  548 + if ((openMode() & QIODevice::WriteOnly) && precompressedBlockWriter.isOpen()) {
  549 + QByteArray compressedBlock = qCompress(precompressedBlockWriter.buffer());
  550 + precompressedBlockWriter.close();
  551 +
  552 + quint32 bsize= compressedBlock.size();
  553 + blockWriter << bsize;
  554 + blockWriter.writeRawData(compressedBlock.constData(), compressedBlock.size());
  555 + }
  556 + // close the underlying device.
  557 + basis->close();
  558 +}
  559 +
  560 +void BlockCompression::setBasis(QIODevice *_basis)
  561 +{
  562 + basis = _basis;
  563 + blockReader.setDevice(basis);
  564 + blockWriter.setDevice(basis);
  565 +}
  566 +
  567 +// read from current decompressed block, if out of space, read and decompress another
  568 +// block from basis
  569 +qint64 BlockCompression::readData(char *data, qint64 remaining)
  570 +{
  571 + qint64 read = 0;
  572 + while (remaining > 0) {
  573 + // attempt to read the target amount of data
  574 + qint64 single_read = decompressedBlockReader.read(data, remaining);
  575 + if (single_read == -1)
  576 + qFatal("miss read");
  577 +
  578 + remaining -= single_read;
  579 + read += single_read;
  580 + data += single_read;
  581 +
  582 + // need a new block if we didn't get enough bytes from the previous read
  583 + if (remaining > 0) {
  584 + QByteArray compressedBlock;
  585 +
  586 + // read the size of the next block
  587 + quint32 block_size;
  588 + blockReader >> block_size;
  589 + if (block_size == 0)
  590 + break;
  591 +
  592 + compressedBlock.resize(block_size);
  593 + int actualRead = blockReader.readRawData(compressedBlock.data(), block_size);
  594 + if (actualRead != int(block_size))
  595 + qFatal("Bad read on nominal block size: %d, only got %d", block_size, int(remaining));
  596 +
  597 + decompressedBlock = qUncompress(compressedBlock);
  598 +
  599 + decompressedBlockReader.close();
  600 + decompressedBlockReader.setBuffer(&decompressedBlock);
  601 + decompressedBlockReader.open(QIODevice::ReadOnly);
  602 + }
  603 + }
  604 +
  605 + bool condition = blockReader.atEnd() && !basis->isReadable() ;
  606 + if (condition)
  607 + qWarning("Returning -1 from read");
  608 +
  609 + return condition ? -1 : read;
  610 +}
  611 +
  612 +bool BlockCompression::isSequential() const
  613 +{
  614 + return true;
  615 +}
  616 +
  617 +qint64 BlockCompression::writeData(const char *data, qint64 remaining)
  618 +{
  619 + const char * endPoint = data + remaining;
  620 + qint64 initial = remaining;
  621 +
  622 + qint64 written = 0;
  623 +
  624 + while (remaining > 0) {
  625 + // how much more can be put in this buffer?
  626 + qint64 capacity = blockSize - precompressedBlockWriter.pos();
  627 + if (capacity < 0)
  628 + qFatal("Negative capacity!!!");
  629 +
  630 + // don't try to write beyond capacity
  631 + qint64 write_size = qMin(capacity, remaining);
  632 +
  633 + qint64 singleWrite = precompressedBlockWriter.write(data, write_size);
  634 +
  635 + if (singleWrite == -1)
  636 + qFatal("matrix write failure?");
  637 +
  638 + remaining -= singleWrite;
  639 + data += singleWrite;
  640 + written += singleWrite;
  641 + if (data > endPoint)
  642 + qFatal("Wrote past the end");
  643 +
  644 + if (remaining > 0) {
  645 + QByteArray compressedBlock = qCompress(precompressedBlockWriter.buffer(), -1);
  646 +
  647 + if (precompressedBlockWriter.buffer().size() != 0) {
  648 + quint32 block_size = compressedBlock.size();
  649 + blockWriter << block_size;
  650 +
  651 + int write_count = blockWriter.writeRawData(compressedBlock.constData(), block_size);
  652 + if (write_count != int(block_size))
  653 + qFatal("Didn't write enough data");
  654 + }
  655 + else
  656 + qFatal("serialized empty compressed block (?)");
  657 +
  658 + precompressedBlockWriter.close();
  659 + precompressedBlockWriter.open(QIODevice::WriteOnly);
  660 + }
  661 + }
  662 +
  663 + if (written != initial)
  664 + qFatal("didn't write enough bytes");
  665 +
  666 + bool condition = basis->isWritable();
  667 + if (!condition)
  668 + qWarning("Returning -1 from write");
  669 +
  670 + return basis->isWritable() ? written : -1;
  671 +}
  672 +
  673 +
  674 +
  675 +} // namespace QtUtils
  676 +
openbr/core/qtutils.h
1 -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  
2 - * Copyright 2012 The MITRE Corporation *  
3 - * *  
4 - * Licensed under the Apache License, Version 2.0 (the "License"); *  
5 - * you may not use this file except in compliance with the License. *  
6 - * You may obtain a copy of the License at *  
7 - * *  
8 - * http://www.apache.org/licenses/LICENSE-2.0 *  
9 - * *  
10 - * Unless required by applicable law or agreed to in writing, software *  
11 - * distributed under the License is distributed on an "AS IS" BASIS, *  
12 - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *  
13 - * See the License for the specific language governing permissions and *  
14 - * limitations under the License. *  
15 - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */  
16 -  
17 -#ifndef QTUTILS_QTUTILS_H  
18 -#define QTUTILS_QTUTILS_H  
19 -  
20 -#include <QBuffer>  
21 -#include <QByteArray>  
22 -#include <QDataStream>  
23 -#include <QDir>  
24 -#include <QFile>  
25 -#include <QFileInfo>  
26 -#include <QFuture>  
27 -#include <QFutureSynchronizer>  
28 -#include <QMap>  
29 -#include <QString>  
30 -#include <QStringList>  
31 -#include <QThreadPool>  
32 -#include <string>  
33 -#include <vector>  
34 -  
35 -#include <openbr/openbr_export.h>  
36 -  
37 -namespace QtUtils  
38 -{  
39 - /**** File Utilities ****/  
40 - QStringList readLines(const QString &file);  
41 - void readFile(const QString &file, QStringList &lines);  
42 - void readFile(const QString &file, QByteArray &data, bool uncompress = false);  
43 - void writeFile(const QString &file, const QStringList &lines);  
44 - void writeFile(const QString &file, const QString &data);  
45 - void writeFile(const QString &file, const QByteArray &data, int compression = 0);  
46 - void copyFile(const QString &src, const QString &dst);  
47 -  
48 - /**** Directory Utilities ****/  
49 - void touchDir(const QDir &dir);  
50 - void touchDir(const QFile &file);  
51 - void touchDir(const QFileInfo &fileInfo);  
52 - void emptyDir(QDir &dir);  
53 - void deleteDir(QDir &dir);  
54 - QString find(const QString &file, const QString &alt);  
55 - QString getAbsolutePath(const QString &filename);  
56 -  
57 - /**** String Utilities ****/  
58 - bool toBool(const QString &string);  
59 - int toInt(const QString &string);  
60 - float toFloat(const QString &string);  
61 - QList<float> toFloats(const QStringList &strings);  
62 - QStringList toStringList(const QList<float> &values);  
63 - QStringList toStringList(const std::vector<std::string> &string_list);  
64 - QStringList toStringList(int num_strings, const char* strings[]);  
65 - QString shortTextHash(QString string);  
66 - QStringList parse(QString args, char split = ',', bool *ok = NULL);  
67 - void checkArgsSize(const QString &name, const QStringList &args, int min, int max);  
68 - BR_EXPORT QPointF toPoint(const QString &string, bool *ok = NULL);  
69 - BR_EXPORT QRectF toRect(const QString &string, bool *ok = NULL);  
70 - QStringList naturalSort(const QStringList &strings);  
71 - QString toTime(int s);  
72 -  
73 - /**** Process Utilities ****/  
74 - bool runRScript(const QString &file);  
75 - bool runDot(const QString &file);  
76 - void showFile(const QString &file);  
77 -  
78 - /**** Variant Utilities ****/  
79 - BR_EXPORT QString toString(const QVariant &variant);  
80 - QString toString(const QVariantList &variantList);  
81 - BR_EXPORT QString toString(const QVariantMap &QVariantMap);  
82 - BR_EXPORT QStringList toStringList(const QVariantMap &QVariantMap);  
83 -  
84 - template <typename T>  
85 - QVariantList toVariantList(const QList<T> &list)  
86 - {  
87 - QVariantList variantList;  
88 - foreach (const T &item, list)  
89 - variantList << item;  
90 -  
91 - return variantList;  
92 - }  
93 -  
94 - /**** Point Utilities ****/  
95 - float euclideanLength(const QPointF &point);  
96 - float orientation(const QPointF &pointA, const QPointF &pointB);  
97 -  
98 - /**** Rect Utilities ****/  
99 - float overlap(const QRectF &r, const QRectF &s);  
100 -  
101 -  
102 - class BlockCompression : public QIODevice  
103 - {  
104 - public:  
105 - BlockCompression(QIODevice *_basis);  
106 - BlockCompression();  
107 - int blockSize;  
108 - QIODevice *basis;  
109 -  
110 - bool open(QIODevice::OpenMode mode);  
111 -  
112 - void close();  
113 -  
114 - void setBasis(QIODevice *_basis);  
115 -  
116 - QDataStream blockReader;  
117 - QByteArray decompressedBlock;  
118 - QBuffer decompressedBlockReader;  
119 -  
120 - // read from current decompressed block, if out of space, read and decompress another  
121 - // block from basis  
122 - qint64 readData(char *data, qint64 remaining);  
123 -  
124 - bool isSequential() const;  
125 -  
126 - // write to a QByteArray, when max block sized is reached, compress and write  
127 - // it to basis  
128 - QBuffer precompressedBlockWriter;  
129 - QDataStream blockWriter;  
130 - qint64 writeData(const char *data, qint64 remaining);  
131 - };  
132 -}  
133 -  
134 -#endif // QTUTILS_QTUTILS_H 1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#ifndef QTUTILS_QTUTILS_H
  18 +#define QTUTILS_QTUTILS_H
  19 +
  20 +#include <QBuffer>
  21 +#include <QByteArray>
  22 +#include <QDataStream>
  23 +#include <QDir>
  24 +#include <QFile>
  25 +#include <QFileInfo>
  26 +#include <QFuture>
  27 +#include <QFutureSynchronizer>
  28 +#include <QMap>
  29 +#include <QString>
  30 +#include <QStringList>
  31 +#include <QThreadPool>
  32 +#include <string>
  33 +#include <vector>
  34 +
  35 +#include <openbr/openbr_export.h>
  36 +
  37 +namespace QtUtils
  38 +{
  39 + /**** File Utilities ****/
  40 + QStringList readLines(const QString &file);
  41 + void readFile(const QString &file, QStringList &lines);
  42 + void readFile(const QString &file, QByteArray &data, bool uncompress = false);
  43 + void writeFile(const QString &file, const QStringList &lines);
  44 + void writeFile(const QString &file, const QString &data);
  45 + void writeFile(const QString &file, const QByteArray &data, int compression = 0);
  46 + void copyFile(const QString &src, const QString &dst);
  47 +
  48 + /**** Directory Utilities ****/
  49 + void touchDir(const QDir &dir);
  50 + void touchDir(const QFile &file);
  51 + void touchDir(const QFileInfo &fileInfo);
  52 + void emptyDir(QDir &dir);
  53 + void deleteDir(QDir &dir);
  54 + QString find(const QString &file, const QString &alt);
  55 + QString getAbsolutePath(const QString &filename);
  56 +
  57 + /**** String Utilities ****/
  58 + bool toBool(const QString &string);
  59 + int toInt(const QString &string);
  60 + float toFloat(const QString &string);
  61 + QList<float> toFloats(const QStringList &strings);
  62 + QStringList toStringList(const QList<float> &values);
  63 + QStringList toStringList(const std::vector<std::string> &string_list);
  64 + QStringList toStringList(int num_strings, const char* strings[]);
  65 + QString shortTextHash(QString string);
  66 + QStringList parse(QString args, char split = ',', bool *ok = NULL);
  67 + void checkArgsSize(const QString &name, const QStringList &args, int min, int max);
  68 + BR_EXPORT QPointF toPoint(const QString &string, bool *ok = NULL);
  69 + BR_EXPORT QRectF toRect(const QString &string, bool *ok = NULL);
  70 + QStringList naturalSort(const QStringList &strings);
  71 + QString toTime(int s);
  72 +
  73 + /**** Process Utilities ****/
  74 + bool runRScript(const QString &file);
  75 + bool runDot(const QString &file);
  76 + void showFile(const QString &file);
  77 +
  78 + /**** Variant Utilities ****/
  79 + BR_EXPORT QString toString(const QVariant &variant);
  80 + QString toString(const QVariantList &variantList);
  81 + BR_EXPORT QString toString(const QVariantMap &QVariantMap);
  82 + BR_EXPORT QStringList toStringList(const QVariantMap &QVariantMap);
  83 +
  84 + template <typename T>
  85 + QVariantList toVariantList(const QList<T> &list)
  86 + {
  87 + QVariantList variantList;
  88 + foreach (const T &item, list)
  89 + variantList << item;
  90 +
  91 + return variantList;
  92 + }
  93 +
  94 + /**** Point Utilities ****/
  95 + float euclideanLength(const QPointF &point);
  96 + float orientation(const QPointF &pointA, const QPointF &pointB);
  97 +
  98 + /**** Rect Utilities ****/
  99 + float overlap(const QRectF &r, const QRectF &s);
  100 +
  101 +
  102 + class BlockCompression : public QIODevice
  103 + {
  104 + public:
  105 + BlockCompression(QIODevice *_basis);
  106 + BlockCompression();
  107 + int blockSize;
  108 + QIODevice *basis;
  109 +
  110 + bool open(QIODevice::OpenMode mode);
  111 +
  112 + void close();
  113 +
  114 + void setBasis(QIODevice *_basis);
  115 +
  116 + QDataStream blockReader;
  117 + QByteArray decompressedBlock;
  118 + QBuffer decompressedBlockReader;
  119 +
  120 + // read from current decompressed block, if out of space, read and decompress another
  121 + // block from basis
  122 + qint64 readData(char *data, qint64 remaining);
  123 +
  124 + bool isSequential() const;
  125 +
  126 + // write to a QByteArray, when max block sized is reached, compress and write
  127 + // it to basis
  128 + QBuffer precompressedBlockWriter;
  129 + QDataStream blockWriter;
  130 + qint64 writeData(const char *data, qint64 remaining);
  131 + };
  132 +}
  133 +
  134 +#endif // QTUTILS_QTUTILS_H