QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
LogViewerULogParser.cc
Go to the documentation of this file.
2
3#include "PX4ULogUtility.h"
4
5#include <QtCore/QCoreApplication>
6#include "ULogFullHandler.h"
7
8#include <QtCore/QFile>
9
10#include <ulog_cpp/reader.hpp>
11
12#include <limits>
13
14namespace ULogParser {
15
16LogParseResult parseFile(const QString &filePath, const ProgressCallback &progressCallback, const CancelToken &cancelToken)
17{
18 LogParseResult result;
19
20 QFile file(filePath);
21 if (!file.open(QIODevice::ReadOnly)) {
22 result.errorMessage = QCoreApplication::translate("LogFileParser", "Failed to open file");
23 return result;
24 }
25
26 const qint64 fileSize = file.size();
27 if (fileSize <= 0) {
28 result.errorMessage = QCoreApplication::translate("LogFileParser", "File is empty");
29 return result;
30 }
31 if (fileSize > std::numeric_limits<qsizetype>::max()) {
32 result.errorMessage = QCoreApplication::translate("LogFileParser", "File is too large to parse");
33 return result;
34 }
35
36 uchar *const mappedData = file.map(0, fileSize);
37 if (mappedData == nullptr) {
38 result.errorMessage = QCoreApplication::translate("LogFileParser", "Failed to memory-map file");
39 return result;
40 }
41
42 struct ScopedUnmap {
43 QFile &file;
44 uchar *data = nullptr;
45 ~ScopedUnmap() { if (data) { file.unmap(data); } }
46 } scopedUnmap{file, mappedData};
47
48 const char *const raw = reinterpret_cast<const char *>(mappedData);
49
50 // Verify ULog magic
51 if (!PX4ULogUtility::isValidHeader(raw, fileSize)) {
52 result.errorMessage = QCoreApplication::translate("LogFileParser", "File does not appear to be a ULog file (invalid header)");
53 return result;
54 }
55
56 auto handler = std::make_shared<ULogFullHandler>(result, progressCallback);
57 ulog_cpp::Reader reader(handler);
58
59 static constexpr qint64 kChunkSize = 64 * 1024;
60 qint64 offset = 0;
61 while (offset < fileSize) {
62 const qint64 remaining = fileSize - offset;
63 const qint64 chunk = (remaining < kChunkSize) ? remaining : kChunkSize;
64 reader.readChunk(reinterpret_cast<const uint8_t *>(raw) + offset, static_cast<size_t>(chunk));
65 offset += chunk;
66 if (cancelToken && cancelToken->load(std::memory_order_relaxed)) {
67 return result; // cancelled; result.ok is false, discarded by requestId guard
68 }
69 if (progressCallback) {
70 progressCallback(static_cast<float>(offset) / static_cast<float>(fileSize));
71 }
72 }
73
74 if (handler->hadFatalError()) {
75 if (result.errorMessage.isEmpty()) {
76 result.errorMessage = QCoreApplication::translate("LogFileParser", "Fatal error while parsing ULog file");
77 }
78 return result;
79 }
80
81 if (!handler->isHeaderComplete()) {
82 result.errorMessage = QCoreApplication::translate("LogFileParser", "ULog file header is incomplete or corrupt");
83 return result;
84 }
85
86 handler->finalize();
87 return result;
88}
89
90} // namespace ULogParser
std::function< void(float)> ProgressCallback
std::shared_ptr< std::atomic< bool > > CancelToken
bool isValidHeader(const char *data, qint64 size)
LogParseResult parseFile(const QString &filePath, const ProgressCallback &progressCallback, const CancelToken &cancelToken)