Skip to content

Commit 317a8b4

Browse files
committed
initial import of rdata
1 parent e9c50d3 commit 317a8b4

16 files changed

+545
-5
lines changed

Common/utilenums.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#define UTILENUMS_H
33
#include "enumutilities.h"
44

5-
DECLARE_ENUM(FileTypeBase, jasp = 0, html, csv, txt, tsv, sav, zsav, ods, xls, xlsx, pdf, sas7bdat, sas7bcat, por, xpt, dta, database, empty, unknown );
5+
DECLARE_ENUM(FileTypeBase, jasp = 0, html, csv, txt, tsv, sav, zsav, ods, xls, xlsx, pdf, sas7bdat, sas7bcat, por, xpt, dta, database, rdata, rds, empty, unknown );
66

77
//const QStringList Database::dbTypes() const should be updated if DbType is changed.
88
DECLARE_ENUM(DbType, NOTCHOSEN, QDB2, /*QIBASE,*/ QMYSQL, QOCI, QODBC, QPSQL, QSQLITE /*, QSQLITE2, QTDS*/ );

Desktop/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,16 @@ target_include_directories(
107107
${PROJECT_SOURCE_DIR}/QMLComponents
108108
# ReadStat
109109
$<$<PLATFORM_ID:Windows>:${RTOOLS_LIBREADSTAT_H}>
110+
# librdata
111+
$<$<PLATFORM_ID:Windows>:${RTOOLS_LIBRDATA_H}>
110112
${LIBREADSTAT_INCLUDE_DIRS}
111113
# JSONCPP
112114
$<$<PLATFORM_ID:Linux>:${_PKGCONFIG_LIB_JSONCPP_INCLUDEDIR}>
113115
$<$<BOOL:${FLATPAK_USED}>:/app/include/QtCore5Compat>
114116
$<$<BOOL:${FLATPAK_USED}>:/app/include/QtWebEngineQuick>
115117
$<$<BOOL:${FLATPAK_USED}>:/app/include/QtWebEngineCore>
116118
${LIBFREEXL_INCLUDE_DIRS}
119+
${LIBRDATA_INCLUDE_DIRS}
117120
)
118121

119122
target_link_libraries(
@@ -158,11 +161,16 @@ target_link_libraries(
158161
${LIBREADSTAT_LIBRARIES}
159162
# MinGW's ReadStat
160163
$<$<PLATFORM_ID:Windows>:${RTOOLS_LIBREADSTAT_DLL_A}>
164+
# librdata -----------------------------------
165+
${LIBRDATA_LIBRARIES}
166+
$<$<PLATFORM_ID:Windows>:${RTOOLS_LIBRDATA_DLL_A}>
161167
# JSONCPP
162168
#$<$<PLATFORM_ID:Linux>:${_PKGCONFIG_LIB_JSONCPP_LIBRARIES}>
163169
#$<$<PLATFORM_ID:Linux>:${_PKGCONFIG_LIB_JSONCPP_LINK_LIBRARIES}>
164170
# R-Framework --------------------------------
165171
$<$<PLATFORM_ID:Darwin>:${_R_Framework}>
172+
# librdata
173+
${LIBRDATA_LIBRARIES}
166174
)
167175

168176
target_compile_definitions(JASP PUBLIC JASP_USES_QT_HERE)

Desktop/data/datasetloader.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "importers/odsimporter.h"
2727
#include "importers/readstatimporter.h"
2828
#include "importers/excelimporter.h"
29+
#include "importers/rdataimporter.h"
2930

3031

3132
#include <QFileInfo>
@@ -56,6 +57,8 @@ Importer* DataSetLoader::getImporter(const string & locator, const string &ext)
5657
if( boost::iequals(ext,".xls") ||
5758
boost::iequals(ext,".xlsx")) return new ExcelImporter();
5859
if( ReadStatImporter::extSupported(ext)) return new ReadStatImporter(ext);
60+
if( boost::iequals(ext,".rdata") ||
61+
boost::iequals(ext,".rds")) return new RDataImporter(ext);
5962

6063
return nullptr; //If NULL then JASP will try to load it as a .jasp file (if the extension matches)
6164
}

Desktop/data/fileevent.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ const std::string FileEvent::databaseStr() const
119119

120120
QString FileEvent::getProgressMsg() const
121121
{
122-
//jasp = 0, html, csv, txt, tsv, sav, zsav, ods, pdf, sas7bdat, sas7bcat, por, xpt, empty, unknown
122+
//jasp = 0, html, csv, txt, tsv, sav, zsav, ods, xls, xlsx, pdf, sas7bdat, sas7bcat, por, xpt, dta, database, rdata, rds, empty, unknown
123123
switch(_operation)
124124
{
125125
case FileEvent::FileOpen:
@@ -139,6 +139,8 @@ QString FileEvent::getProgressMsg() const
139139
case Utils::FileType::sas7bcat: return tr("Importing SAS File");
140140
case Utils::FileType::dta: return tr("Importing STATA File");
141141
case Utils::FileType::jasp: return tr("Loading JASP File");
142+
case Utils::FileType::rdata:
143+
case Utils::FileType::rds: return tr("Loading R Data File");
142144
default: return tr("Loading File");
143145
}
144146
break;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// Copyright (C) 2013-2025 University of Amsterdam
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 2 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
//
17+
18+
#include "rdataimportcolumn.h"
19+
#include "timers.h"
20+
21+
RDataImportColumn::RDataImportColumn(ImportDataSet* importDataSet, std::string name) : ImportColumn(importDataSet, name)
22+
{
23+
}
24+
25+
RDataImportColumn::RDataImportColumn(ImportDataSet *importDataSet, std::string name, long reserve) : ImportColumn(importDataSet, name)
26+
{
27+
_data.reserve(reserve);
28+
}
29+
30+
RDataImportColumn::~RDataImportColumn()
31+
{
32+
JASPTIMER_SCOPE(RDataImportColumn::~RDataImportColumn());
33+
}
34+
35+
size_t RDataImportColumn::size() const
36+
{
37+
return _data.size();
38+
}
39+
40+
void RDataImportColumn::addValue(const std::string &value)
41+
{
42+
_data.push_back(value);
43+
}
44+
45+
const std::vector<std::string> &RDataImportColumn::getValues() const
46+
{
47+
return _data;
48+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//
2+
// Copyright (C) 2013-2025 University of Amsterdam
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 2 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
//
17+
18+
#ifndef RDATAIMPORTCOLUMN_H
19+
#define RDATAIMPORTCOLUMN_H
20+
21+
#include "data/importers/importcolumn.h"
22+
23+
class RDataImportColumn : public ImportColumn
24+
{
25+
public:
26+
RDataImportColumn(ImportDataSet *importDataSet, std::string name);
27+
RDataImportColumn(ImportDataSet *importDataSet, std::string name, long reserve);
28+
~RDataImportColumn() override;
29+
30+
size_t size() const override;
31+
const stringvec &allValuesAsStrings() const override { return _data; }
32+
void addValue(const std::string &value);
33+
const stringvec &getValues() const;
34+
35+
private:
36+
stringvec _data;
37+
};
38+
39+
#endif // RDATAIMPORTCOLUMN_H
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
//
2+
// Copyright (C) 2013-2025 University of Amsterdam
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 2 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
//
17+
18+
#include "readrdata.h"
19+
#include "log.h"
20+
21+
RDataReader::RDataReader(const std::string &locator)
22+
{
23+
_filePath = locator;
24+
}
25+
26+
void RDataReader::open()
27+
{
28+
_parser = rdata_parser_init();
29+
30+
if (!_parser)
31+
{
32+
Log::log() << "Failed to initialize parser" << std::endl;
33+
throw std::runtime_error("Could not access file");
34+
}
35+
36+
if (_filePath.empty())
37+
throw std::invalid_argument("File path cannot be empty.");
38+
39+
rdata_set_table_handler(_parser, &_tableHandler);
40+
rdata_set_column_handler(_parser, &_columnHandler);
41+
rdata_set_text_value_handler(_parser, &_textValueHandler);
42+
rdata_set_column_name_handler(_parser, &_columnNameHandler);
43+
// rdata_set_value_label_handler(_parser, &_valueLabelHandler);
44+
45+
rdata_error_t result = rdata_parse(_parser, _filePath.c_str(), &_context);
46+
47+
_rowCount = _context.row_count;
48+
_colCount = _context.column_count;
49+
_columnNames = _context.column_names;
50+
_column_data = _context.column_data;
51+
52+
std::cout << "Total Columns: " << _colCount << ", Total Rows: " << _rowCount << std::endl;
53+
54+
if (result != RDATA_OK)
55+
{
56+
std::cerr << "Failed to parse file: " << rdata_error_message(result) << std::endl;
57+
}
58+
59+
if (_parser)
60+
{
61+
rdata_parser_free(_parser);
62+
_parser = nullptr;
63+
}
64+
}
65+
66+
int RDataReader::_tableHandler(const char *name, void *ctx)
67+
{
68+
RDataCtx *context = static_cast<RDataCtx *>(ctx);
69+
if (!name)
70+
{
71+
context->table_name = "DEF_table_name";
72+
}
73+
else
74+
{
75+
context->table_name = name;
76+
// Log::log() << "Table Name: " << name << std::endl;
77+
}
78+
return 0;
79+
}
80+
81+
int RDataReader::_columnHandler(const char *name, rdata_type_t type, void *data, long count, void *ctx)
82+
{
83+
84+
RDataCtx *context = static_cast<RDataCtx *>(ctx);
85+
// Log::log() << "Column name: " << name << ", Type: " << type << ", Count: " << count << std::endl;
86+
87+
context->column_count++;
88+
89+
if (count > context->row_count)
90+
{
91+
context->row_count = count;
92+
}
93+
94+
stringvec column_values;
95+
96+
if (type == RDATA_TYPE_STRING)
97+
{
98+
// Initialize an empty vector for string type to be filled in _textValueHandler
99+
context->column_data.emplace_back(stringvec(count, ""));
100+
}
101+
else
102+
{
103+
switch (type)
104+
{
105+
case RDATA_TYPE_INT32:
106+
case RDATA_TYPE_LOGICAL:
107+
{
108+
int32_t *values = static_cast<int32_t *>(data);
109+
for (size_t i = 0; i < count; i++)
110+
column_values.push_back(std::to_string(values[i]));
111+
break;
112+
}
113+
case RDATA_TYPE_REAL:
114+
{
115+
double *values = static_cast<double *>(data);
116+
for (size_t i = 0; i < count; i++)
117+
{
118+
if (std::isnan(values[i]))
119+
column_values.push_back("NA");
120+
else
121+
column_values.push_back(std::to_string(values[i]));
122+
}
123+
break;
124+
}
125+
default:
126+
Log::log() << "Unsupported data type for column: " << name << std::endl;
127+
break;
128+
}
129+
130+
context->column_data.push_back(column_values);
131+
}
132+
133+
return 0;
134+
}
135+
136+
int RDataReader::_columnNameHandler(const char *value, int index, void *ctx)
137+
{
138+
RDataCtx *context = static_cast<RDataCtx *>(ctx);
139+
140+
if (index >= context->column_names.size())
141+
{
142+
context->column_names.resize(index + 1);
143+
}
144+
145+
context->column_names[index] = value ? value : "Unnamed_Column";
146+
// Log::log() << "Column name [Index " << index << "]: " << context->column_names[index] << std::endl;
147+
return 0;
148+
}
149+
150+
void RDataReader::_errorHandler(const char *error_message, void *ctx)
151+
{
152+
Log::log() << "Error: " << error_message << std::endl;
153+
}
154+
155+
int RDataReader::_textValueHandler(const char *value, int index, void *ctx)
156+
{
157+
RDataCtx *context = static_cast<RDataCtx *>(ctx);
158+
159+
if (context->column_data.empty())
160+
{
161+
Log::log() << "Error: _textValueHandler called before _columnHandler." << std::endl;
162+
return 1; // Abort processing
163+
}
164+
165+
size_t column_index = context->column_data.size() - 1;
166+
if (index >= context->column_data[column_index].size())
167+
{
168+
context->column_data[column_index].resize(index + 1, "");
169+
}
170+
171+
context->column_data[column_index][index] = value ? value : "NA";
172+
173+
return 0;
174+
}
175+
176+
int RDataReader::_valueLabelHandler(const char *value, int index, void *ctx)
177+
{
178+
return 0;
179+
}

0 commit comments

Comments
 (0)