wiRedPanda
Logic Circuit Simulator
Loading...
Searching...
No Matches
DolphinFile.cpp
Go to the documentation of this file.
1// Copyright 2015 - 2026, GIBIS-UNIFESP and the wiRedPanda contributors
2// SPDX-License-Identifier: GPL-3.0-or-later
3
5
6#include <QCoreApplication>
7#include <QDataStream>
8#include <QFile>
9#include <QSaveFile>
10#include <QTextStream>
11
13#include "App/Core/Common.h"
15
16namespace DolphinFile {
17
18void save(const SignalModel &model, const QString &fileName, const int inputPorts)
19{
20 // QSaveFile writes to a temp file and atomically renames on commit,
21 // preventing data loss if the process is interrupted during a write
22 QSaveFile file(fileName);
23
24 if (!file.open(QIODevice::WriteOnly)) {
25 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Error opening file: %1", file.errorString());
26 }
27
28 if (fileName.endsWith(".dolphin")) {
29 qCDebug(zero) << "Saving dolphin file.";
30 QDataStream stream(&file);
32 DolphinSerializer::saveBinary(stream, &model, inputPorts);
33 } else {
34 qCDebug(zero) << "Saving CSV file.";
35 DolphinSerializer::saveCSV(file, &model);
36 }
37
38 if (!file.commit()) {
39 // Covered: TestDolphinFile::testSaveCommitFailureThrows() forces this via
40 // RLIMIT_FSIZE (ScopedTinyFsizeLimit) -- Qt defers write() errors, so a failed
41 // write during saveBinary()/saveCSV() above only surfaces here, at commit().
42 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Error saving file: %1", file.errorString());
43 }
44}
45
46DolphinSerializer::WaveformData load(const QString &fileName, const int maxInputPorts)
47{
48 QFile file(fileName);
49
50 if (!file.exists()) {
51 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "File \"%1\" does not exist!", fileName);
52 }
53
54 if (!file.open(QIODevice::ReadOnly)) {
55 qCDebug(zero) << "Could not open file in ReadOnly mode: " << file.errorString();
56 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Could not open file for reading: %1", file.errorString());
57 }
58
60
61 if (fileName.endsWith(".dolphin")) {
62 qCDebug(zero) << "Dolphin file opened.";
63 QDataStream stream(&file);
65 data = DolphinSerializer::loadBinary(stream, maxInputPorts);
66 } else if (fileName.endsWith(".csv")) {
67 qCDebug(zero) << "CSV file opened.";
68 data = DolphinSerializer::loadCSV(file, maxInputPorts);
69 } else {
70 qCDebug(zero) << "Format not supported. Could not open file: " << fileName;
71 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Format not supported. Could not open file: %1", fileName);
72 }
73
74 file.close();
75 return data;
76}
77
78DolphinSerializer::WaveformData parseTerminal(QTextStream &in, const int maxInputPorts)
79{
80 // Protocol: first line is "rows,cols"; subsequent lines contain comma-separated 0/1
81 // values per row. This allows driving the simulator from scripts without a GUI dialog.
82 QString str = in.readLine();
83 const auto wordList(str.split(','));
84
85 if (wordList.size() < 2) {
86 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Invalid header: expected 'rows,cols' on the first line.");
87 }
88
89 int rows = wordList.at(0).toInt();
90 const int cols = wordList.at(1).toInt();
91
92 if (rows <= 0) {
93 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Invalid row count %1: must be positive.", QString::number(rows));
94 }
95
96 // Clamp rows to the number of actual input ports to avoid out-of-bounds writes
97 if (rows > maxInputPorts) {
98 rows = maxInputPorts;
99 }
100
101 if ((cols < 1) || (cols > SignalModel::kMaxColumns)) {
102 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Invalid column count %1: must be between 1 and %2.", QString::number(cols), QString::number(SignalModel::kMaxColumns));
103 }
104
106 data.inputPorts = rows;
107 data.columns = cols;
108 data.values.resize(rows * cols);
109
110 for (int row = 0; row < rows; ++row) {
111 str = in.readLine();
112 const auto wordList2(str.split(','));
113
114 if (wordList2.size() < cols) {
115 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Row %1 has %2 value(s) but %3 are required.", QString::number(row), QString::number(wordList2.size()), QString::number(cols));
116 }
117
118 for (int col = 0; col < cols; ++col) {
119 data.values[row * cols + col] = wordList2.at(col).toInt();
120 }
121 }
122
123 return data;
124}
125
126} // namespace DolphinFile
Common logging utilities, the Pandaception error type, and helper macros.
#define PANDACEPTION_WITH_CONTEXT(context, msg,...)
Definition Common.h:102
#define qCDebug(category)
Definition Common.h:29
DolphinFile: reads/writes a SignalModel to .dolphin/.csv files on disk.
Circuit and waveform file serialization/deserialization utilities.
SignalModel for the beWavedDolphin waveform table.
static void readDolphinHeader(QDataStream &stream)
Reads and validates the BeWavedDolphin waveform file header.
static void writeDolphinHeader(QDataStream &stream)
Writes the BeWavedDolphin waveform file header to stream.
QStandardItemModel subclass that makes all cells non-editable.
Definition SignalModel.h:21
static constexpr int kMaxColumns
Definition SignalModel.h:37
Disk I/O for the beWavedDolphin formats: opens the file, dispatches by extension (....
DolphinSerializer::WaveformData parseTerminal(QTextStream &in, const int maxInputPorts)
DolphinSerializer::WaveformData load(const QString &fileName, const int maxInputPorts)
void save(const SignalModel &model, const QString &fileName, const int inputPorts)
Writes model to fileName atomically, choosing the format by extension.
void saveBinary(QDataStream &stream, const QStandardItemModel *model, const int inputPorts)
Serializes input rows to the binary .dolphin stream.
void saveCSV(QSaveFile &file, const QStandardItemModel *model)
Serializes all rows (inputs + outputs) to a .csv file.
WaveformData loadCSV(QFile &file, const int maxInputPorts)
Deserializes input rows from a .csv file.
WaveformData loadBinary(QDataStream &stream, const int maxInputPorts)
Deserializes input rows from a binary .dolphin stream.
Raw waveform data returned by the load functions.
Definition Serializer.h:33
int inputPorts
Number of input rows stored in values.
Definition Serializer.h:34
QVector< int > values
Cell values in row-major order (inputs only): index = row * columns + col.
Definition Serializer.h:37