matio-cpp  v0.2.6
A C++ wrapper of the matio library, with memory ownership handling, to read and write .mat files.
File.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020 Fondazione Istituto Italiano di Tecnologia
3  *
4  * This software may be modified and distributed under the terms of the
5  * BSD-2-Clause license (https://opensource.org/licenses/BSD-2-Clause).
6  */
7 
8 #define _CRT_SECURE_NO_WARNINGS //to silence the warning about c_time being unsafe
9 
10 #include <matioCpp/File.h>
11 #include <time.h>
12 #include <matioCpp/Config.h>
13 #include <sys/types.h> //To check if the directory in which we want to create a new file exists
14 #include <sys/stat.h> //To check if the directory in which we want to create a new file exists
15 
17 {
18 public:
19  mat_t* mat_ptr{nullptr};
21 
22  void close()
23  {
25  freePtr();
26  }
27 
28  void freePtr()
29  {
30  if (mat_ptr)
31  {
32  Mat_Close(mat_ptr);
33  mat_ptr = nullptr;
34  }
35  }
36 
37  void reset(mat_t* newPtr, matioCpp::FileMode mode)
38  {
39  freePtr();
40  mat_ptr = newPtr;
41  fileMode = mode;
42 
43  if (!newPtr)
44  {
46  }
47  }
48 
49  Impl()
50  { }
51 
53  {
54  close();
55  }
56 
58  {
59  if (!input.isValid())
60  {
61  return "The input variable is not valid.";
62  }
63 
64  const std::string& inputName = input.name();
65 
66  if (inputName.size() == 0)
67  {
68  return std::string("The input variable has an empty name.");
69  }
70 
71  if (inputName.size() > 63)
72  {
73  return std::string("The input variable name is too long (maximum 63 char allowed)."); // Many Matlab versions have this limitation
74  }
75 
76  if (!isalpha(inputName[0]))
77  {
78  return std::string("The first character of the variable name has to be a letter (Variable name = " + inputName + ").");
79  }
80 
81  for (size_t i = 1; i < inputName.size(); ++i)
82  {
83  if (!isalnum(inputName[i]) && (inputName[i] != '_'))
84  {
85  return std::string("The variable name can contain only alphanumeric characters or underscores (Variable name = \"" + inputName + "\").");
86  }
87  }
88 
89  return std::string(); //Empty string, no error
90  }
91 };
92 
94  : m_pimpl(std::make_unique<Impl>())
95 {
96 
97 }
98 
100  : m_pimpl(std::make_unique<Impl>())
101 {
102  open(name, mode);
103 }
104 
106 {
107  operator=(std::forward<matioCpp::File>(other));
108 }
109 
111 {
112 
113 }
114 
116 {
117  m_pimpl = std::move(other.m_pimpl);
118 }
119 
121 {
122  m_pimpl->close();
123 }
124 
126 {
127  struct stat info;
128 
129  if (stat(name.c_str(), &info) != 0)
130  {
131  std::cerr << "[ERROR][matioCpp::File::open] The file " << name << " does not exists." << std::endl;
132  return false;
133  }
134  int matio_mode = mode == matioCpp::FileMode::ReadOnly ? mat_acc::MAT_ACC_RDONLY : mat_acc::MAT_ACC_RDWR;
135  m_pimpl->reset(Mat_Open(name.c_str(), matio_mode), mode);
136  return isOpen();
137 }
138 
140 {
141  matioCpp::File newFile;
142 
143  std::size_t found = name.find_last_of("/\\");
144 
145  if (found != std::string::npos)
146  {
147  std::string path = name.substr(0, found);
148 
149  struct stat info;
150 
151  if( stat( path.c_str(), &info ) != 0 )
152  {
153  std::cerr << "[ERROR][matioCpp::File::Create] The path "<< path
154  << " does not exists (input file name " << name
155  << ")." <<std::endl;
156  return newFile;
157  }
158  else if(!(info.st_mode & S_IFDIR))
159  {
160  std::cerr << "[ERROR][matioCpp::File::Create] The path "<< path
161  << " is not a directory (input file name " << name
162  << ")." <<std::endl;
163  return newFile;
164  }
165 
166  }
167 
168  if (version == matioCpp::FileVersion::Undefined)
169  {
170  std::cerr << "[ERROR][matioCpp::File::Create] Cannot use Undefined as input version type." <<std::endl;
171  return newFile;
172  }
173 
174  mat_ft fileVer;
175 
176  switch (version)
177  {
179  fileVer = mat_ft::MAT_FT_MAT4;
180  break;
182  fileVer = mat_ft::MAT_FT_MAT5;
183  break;
185  fileVer = mat_ft::MAT_FT_MAT73;
186  break;
187  default:
188  fileVer = MAT_FT_DEFAULT;
189  break;
190  }
191 
192  std::string fileHeader = header;
193 
194  if (!fileHeader.size())
195  {
196  time_t rawtime;
197  time(&rawtime);
198  std::string timeString(ctime(&rawtime));
199  size_t end = timeString.find_last_of('\n');
200  timeString = timeString.substr(0,end);
201 
202  if (fileVer == mat_ft::MAT_FT_MAT73)
203  {
204  fileHeader = std::string("MATLAB 7.3 MAT-file, created by matioCpp v") + MATIOCPP_VER +
205  " via libmatio v" + std::to_string(MATIO_MAJOR_VERSION)
206  + "." + std::to_string(MATIO_MINOR_VERSION) + "." + std::to_string(MATIO_RELEASE_LEVEL) +
207  " on " + timeString + " HDF5 schema 0.5.";
208  }
209  else if (fileVer == mat_ft::MAT_FT_MAT5)
210  {
211  fileHeader = std::string("MATLAB 5.0 MAT-file, created by matioCpp v") + MATIOCPP_VER +
212  " via libmatio v" + std::to_string(MATIO_MAJOR_VERSION)
213  + "." + std::to_string(MATIO_MINOR_VERSION) + "." + std::to_string(MATIO_RELEASE_LEVEL) +
214  " on " + timeString + ".";
215  }
216  //MAT4 does not have a header
217  }
218 
219  const char * matioHeader = fileHeader.size() ? fileHeader.c_str() : NULL;
220 
221  newFile.m_pimpl->reset(Mat_CreateVer(name.c_str(), matioHeader, fileVer), matioCpp::FileMode::ReadAndWrite);
222 
223  if (!newFile.isOpen())
224  {
225  std::cerr << "[ERROR][matioCpp::File::Create] Failed to open the file named "<< name << "." <<std::endl;
226  }
227 
228  return newFile;
229 }
230 
232 {
233  return std::remove(name.c_str()) == 0;
234 }
235 
237 {
239  return test.isOpen();
240 }
241 
243 {
244  if (!isOpen())
245  {
246  return "";
247  }
248 
249  return Mat_GetFilename(m_pimpl->mat_ptr);
250 }
251 
253 {
254  if (!isOpen())
255  {
256  return "";
257  }
258 
259 #if MATIO_VERSION >= 1515
260  return Mat_GetHeader(m_pimpl->mat_ptr);
261 #else
262  std::cerr << "[ERROR][matioCpp::File::header] The file header can be retrieved only with matio >= 1.5.15" << std::endl;
263  return "";
264 #endif
265 }
266 
268 {
269  if (!isOpen())
270  {
272  }
273 
274  switch (Mat_GetVersion(m_pimpl->mat_ptr))
275  {
276  case mat_ft::MAT_FT_MAT4:
278 
279  case mat_ft::MAT_FT_MAT5:
281 
282  case mat_ft::MAT_FT_MAT73:
284 
285  default:
287  }
288 }
289 
291 {
292  return m_pimpl->fileMode;
293 }
294 
296 {
297  std::vector<std::string> outputNames;
298  if (isOpen())
299  {
300  size_t list_size;
301  char* const* list = Mat_GetDir(m_pimpl->mat_ptr, &list_size);
302 
303  outputNames.resize(list_size);
304  for (size_t i = 0; i < list_size; ++i)
305  {
306  outputNames[i] = list[i];
307  }
308  }
309 
310  return outputNames;
311 }
312 
314 {
315  if (!isOpen())
316  {
317  std::cerr << "[ERROR][matioCpp::File::read] The file is not open." <<std::endl;
318  return matioCpp::Variable();
319  }
320 
321 #if defined(_MSC_VER) && MATIO_VERSION < 1519
322  if (version() == matioCpp::FileVersion::MAT7_3)
323  {
324  std::cerr << "[ERROR][matioCpp::File::read] Reading to a 7.3 file on Windows with a matio version previous to 1.5.19 causes segfaults. The output will be an invalid Variable." << std::endl;
325  return matioCpp::Variable();
326  }
327 #endif
328 
329  matvar_t *matVar = Mat_VarRead(m_pimpl->mat_ptr, name.c_str());
330 
331  matioCpp::Variable output((matioCpp::SharedMatvar(matVar)));
332 
333  if (!output.isValid())
334  {
335  std::cerr << "[ERROR][matioCpp::File::read] Failed to read variable " << name << ". The output is not valid." <<std::endl;
336  }
337 
338  return output;
339 }
340 
341 bool matioCpp::File::write(const Variable &variable, Compression compression)
342 {
343  if (!isOpen())
344  {
345  std::cerr << "[ERROR][matioCpp::File::write] The file is not open." <<std::endl;
346  return false;
347  }
348 
349  if (mode() != matioCpp::FileMode::ReadAndWrite)
350  {
351  std::cerr << "[ERROR][matioCpp::File::write] The file cannot be written." <<std::endl;
352  return false;
353  }
354 
355  std::string error = m_pimpl->isVariableValid(variable);
356  if (error.size() != 0)
357  {
358  std::cerr << "[ERROR][matioCpp::File::write] " << error << std::endl;
359  return false;
360  }
361 
362  SharedMatvar shallowCopy = SharedMatvar::GetMatvarShallowDuplicate(variable.toMatio()); // Shallow copy to remove const
363 
364  matio_compression matioCompression =
365  (compression == matioCpp::Compression::zlib) ? matio_compression::MAT_COMPRESSION_ZLIB : matio_compression::MAT_COMPRESSION_NONE;
366 
367  if (version() == matioCpp::FileVersion::MAT4)
368  {
369  switch (variable.variableType())
370  {
372  break;
374  break;
376  if (variable.dimensions().size() > 2)
377  {
378  std::cerr << "[ERROR][matioCpp::File::write] A MAT4 version does not support arrays with number of dimensions greater than 2." << std::endl;
379  return false;
380  }
381  break;
382  default:
383  std::cerr << "[ERROR][matioCpp::File::write] A MAT4 supports only element, vectors or matrices." << std::endl;
384  return false;
385  }
386 
387  matioCpp::ValueType valueType = variable.valueType();
388 
389  if ((valueType != matioCpp::ValueType::DOUBLE) && (valueType != matioCpp::ValueType::SINGLE) && (valueType != matioCpp::ValueType::LOGICAL)
390  && (valueType != matioCpp::ValueType::UINT8) && (valueType != matioCpp::ValueType::INT32)
391  && (valueType != matioCpp::ValueType::INT16) && (valueType != matioCpp::ValueType::UINT16))
392  {
393  std::cerr << "[ERROR][matioCpp::File::write] A MAT4 supports only variables of type LOGICAL, DOUBLE, SINGLE, UINT8, UINT16, INT16 and INT32." << std::endl;
394  return false;
395  }
396  }
397 
398  bool success = Mat_VarWrite(m_pimpl->mat_ptr, shallowCopy.get(), matioCompression) == 0;
399 
400  if (!success)
401  {
402  std::cerr << "[ERROR][matioCpp::File::write] Failed to write the variable to the file." <<std::endl;
403  return false;
404  }
405 
406  return true;
407 }
408 
410 {
411  return m_pimpl->mat_ptr;
412 }
413 
T c_str(T... args)
mat_t * mat_ptr
Definition: File.cpp:19
void reset(mat_t *newPtr, matioCpp::FileMode mode)
Definition: File.cpp:37
matioCpp::FileMode fileMode
Definition: File.cpp:20
std::string isVariableValid(const matioCpp::Variable &input)
Definition: File.cpp:57
matioCpp::FileVersion version() const
The MAT file version.
Definition: File.cpp:267
void close()
Close the file.
Definition: File.cpp:120
static bool Exists(const std::string &name)
Check if file exists and can be opened.
Definition: File.cpp:236
matioCpp::FileMode mode() const
The mode with which the file has been opened.
Definition: File.cpp:290
bool isOpen() const
Check if the file is open.
Definition: File.cpp:409
void operator=(const File &other)=delete
Deleted copy assignment, to avoid confusion on whether the content has been copied or not.
bool open(const std::string &name, matioCpp::FileMode mode=matioCpp::FileMode::ReadAndWrite)
Open the specified file.
Definition: File.cpp:125
std::string header() const
The file header.
Definition: File.cpp:252
~File()
Destructor.
Definition: File.cpp:110
std::vector< std::string > variableNames() const
Get the list of variables in the file.
Definition: File.cpp:295
File()
Default Constructor.
Definition: File.cpp:93
static bool Delete(const std::string &name)
Delete the specified file.
Definition: File.cpp:231
std::string name() const
The file name.
Definition: File.cpp:242
matioCpp::Variable read(const std::string &name) const
Read a variable given the name.
Definition: File.cpp:313
static File Create(const std::string &name, matioCpp::FileVersion version=matioCpp::FileVersion::Default, const std::string &header="")
Create a new file (static)
Definition: File.cpp:139
bool write(const Variable &variable, matioCpp::Compression compression=matioCpp::Compression::None)
Write a Variable to a file.
Definition: File.cpp:341
static SharedMatvar GetMatvarShallowDuplicate(const matvar_t *inputPtr)
Get the shallow duplicate of an input Matvar.
virtual matvar_t * get() const final
Docs inherited.
The matioCpp::Variable class is the equivalent of matvar_t in matio.
Definition: Variable.h:23
std::string name() const
Get the name of the Variable.
Definition: Variable.cpp:498
const matvar_t * toMatio() const
Convert this Variable to a matio variable.
Definition: Variable.cpp:484
matioCpp::Span< const size_t > dimensions() const
Get the dimensions of this object.
Definition: Variable.cpp:532
bool isValid() const
Check if the variable is valid.
Definition: Variable.cpp:546
matioCpp::VariableType variableType() const
Get the VariableType.
Definition: Variable.cpp:510
matioCpp::ValueType valueType() const
Get the ValueType.
Definition: Variable.cpp:515
T endl(T... args)
T find_last_of(T... args)
T move(T... args)
FileVersion
The supported file versions.
@ MAT4
This is one of the following three depending on the matio installation.
@ MAT5
Matlab version 4 file
@ MAT7_3
Matlab version 5 file
@ Undefined
Matlab version 7.3 file
FileMode
The available modes with which a file can be opened.
ValueType
The list of types for an element of a certain variable type.
Compression
Compression type when writing to a file.
@ zlib
No compression.
STL namespace.
T remove(T... args)
T resize(T... args)
T size(T... args)
T substr(T... args)
T to_string(T... args)