v2.0.0
Loading...
Searching...
No Matches
mna_io.cpp
Go to the documentation of this file.
1//=============================================================================================================
34
35//=============================================================================================================
36// INCLUDES
37//=============================================================================================================
38
39#include "mna_io.h"
40
41//=============================================================================================================
42// QT INCLUDES
43//=============================================================================================================
44
45#include <QFile>
46#include <QFileInfo>
47#include <QJsonDocument>
48#include <QJsonObject>
49#include <QCborValue>
50#include <QCborMap>
51#include <QDebug>
52
53//=============================================================================================================
54// USED NAMESPACES
55//=============================================================================================================
56
57using namespace MNALIB;
58
59//=============================================================================================================
60// STATIC CONSTANTS
61//=============================================================================================================
62
63static const QByteArray MNX_MAGIC = QByteArrayLiteral("MNX1");
64
65//=============================================================================================================
66// DEFINE METHODS
67//=============================================================================================================
68
69MnaProject MnaIO::read(const QString& path)
70{
71 const QFileInfo fi(path);
72 const QString suffix = fi.suffix().toLower();
73
74 if(suffix == QLatin1String("mna")) {
75 return readJson(path);
76 } else if(suffix == QLatin1String("mnx")) {
77 return readCbor(path);
78 }
79
80 qWarning() << "[MnaIO::read] Unknown extension:" << suffix;
81 return MnaProject();
82}
83
84//=============================================================================================================
85
86bool MnaIO::write(const MnaProject& project, const QString& path)
87{
88 const QFileInfo fi(path);
89 const QString suffix = fi.suffix().toLower();
90
91 if(suffix == QLatin1String("mna")) {
92 return writeJson(project, path);
93 } else if(suffix == QLatin1String("mnx")) {
94 return writeCbor(project, path);
95 }
96
97 qWarning() << "[MnaIO::write] Unknown extension:" << suffix;
98 return false;
99}
100
101//=============================================================================================================
102
103MnaProject MnaIO::readJson(const QString& path)
104{
105 QFile file(path);
106 if(!file.open(QIODevice::ReadOnly)) {
107 qWarning() << "[MnaIO::readJson] Cannot open file:" << path;
108 return MnaProject();
109 }
110
111 const QByteArray data = file.readAll();
112 file.close();
113
114 QJsonParseError parseError;
115 const QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
116 if(parseError.error != QJsonParseError::NoError) {
117 qWarning() << "[MnaIO::readJson] Parse error:" << parseError.errorString();
118 return MnaProject();
119 }
120
121 const QJsonObject root = doc.object();
122
123 // Version check: reject if major version differs
124 const QString fileVersion = root[QLatin1String("mna_version")].toString();
125 const int fileMajor = fileVersion.section(QLatin1Char('.'), 0, 0).toInt();
126 const int currentMajor = QString::fromLatin1(MnaProject::CURRENT_SCHEMA_VERSION).section(QLatin1Char('.'), 0, 0).toInt();
127 if(fileMajor != currentMajor) {
128 qWarning() << "[MnaIO::readJson] Incompatible major version:" << fileVersion
129 << "(expected major" << currentMajor << ")";
130 return MnaProject();
131 }
132
133 return MnaProject::fromJson(root);
134}
135
136//=============================================================================================================
137
138bool MnaIO::writeJson(const MnaProject& project, const QString& path)
139{
140 QFile file(path);
141 if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
142 qWarning() << "[MnaIO::writeJson] Cannot open file for writing:" << path;
143 return false;
144 }
145
146 const QJsonDocument doc(project.toJson());
147 const QByteArray data = doc.toJson(QJsonDocument::Indented);
148 const qint64 written = file.write(data);
149 file.close();
150
151 return (written == data.size());
152}
153
154//=============================================================================================================
155
156MnaProject MnaIO::readCbor(const QString& path)
157{
158 QFile file(path);
159 if(!file.open(QIODevice::ReadOnly)) {
160 qWarning() << "[MnaIO::readCbor] Cannot open file:" << path;
161 return MnaProject();
162 }
163
164 // Verify magic header
165 const QByteArray magic = file.read(MNX_MAGIC.size());
166 if(magic != MNX_MAGIC) {
167 qWarning() << "[MnaIO::readCbor] Invalid magic header in:" << path;
168 file.close();
169 return MnaProject();
170 }
171
172 const QByteArray cborData = file.readAll();
173 file.close();
174
175 const QCborValue cborVal = QCborValue::fromCbor(cborData);
176 if(!cborVal.isMap()) {
177 qWarning() << "[MnaIO::readCbor] Root CBOR value is not a map";
178 return MnaProject();
179 }
180
181 const QCborMap root = cborVal.toMap();
182
183 // Version check: reject if major version differs
184 const QString fileVersion = root[QLatin1String("mna_version")].toString();
185 const int fileMajor = fileVersion.section(QLatin1Char('.'), 0, 0).toInt();
186 const int currentMajor = QString::fromLatin1(MnaProject::CURRENT_SCHEMA_VERSION).section(QLatin1Char('.'), 0, 0).toInt();
187 if(fileMajor != currentMajor) {
188 qWarning() << "[MnaIO::readCbor] Incompatible major version:" << fileVersion
189 << "(expected major" << currentMajor << ")";
190 return MnaProject();
191 }
192
193 return MnaProject::fromCbor(root);
194}
195
196//=============================================================================================================
197
198bool MnaIO::writeCbor(const MnaProject& project, const QString& path)
199{
200 QFile file(path);
201 if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
202 qWarning() << "[MnaIO::writeCbor] Cannot open file for writing:" << path;
203 return false;
204 }
205
206 // Write magic header
207 if(file.write(MNX_MAGIC) != MNX_MAGIC.size()) {
208 qWarning() << "[MnaIO::writeCbor] Failed to write magic header";
209 file.close();
210 return false;
211 }
212
213 const QCborValue cborVal(project.toCbor());
214 const QByteArray cborData = cborVal.toCbor();
215 const qint64 written = file.write(cborData);
216 file.close();
217
218 return (written == cborData.size());
219}
MnaIO class declaration.
MNE Analysis Container Format (mna/mnx).
static bool write(const MnaProject &project, const QString &path)
Definition mna_io.cpp:86
static MnaProject read(const QString &path)
Definition mna_io.cpp:69
QJsonObject toJson() const
static MnaProject fromJson(const QJsonObject &json)
static MnaProject fromCbor(const QCborMap &cbor)
static constexpr const char * CURRENT_SCHEMA_VERSION
Definition mna_project.h:81
QCborMap toCbor() const