matio-cpp  v0.2.5
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  int matio_mode = mode == matioCpp::FileMode::ReadOnly ? mat_acc::MAT_ACC_RDONLY : mat_acc::MAT_ACC_RDWR;
128  m_pimpl->reset(Mat_Open(name.c_str(), matio_mode), mode);
129  return isOpen();
130 }
131 
133 {
134  matioCpp::File newFile;
135 
136  std::size_t found = name.find_last_of("/\\");
137 
138  if (found != std::string::npos)
139  {
140  std::string path = name.substr(0, found);
141 
142  struct stat info;
143 
144  if( stat( path.c_str(), &info ) != 0 )
145  {
146  std::cerr << "[ERROR][matioCpp::File::Create] The path "<< path
147  << " does not exists (input file name " << name
148  << ")." <<std::endl;
149  return newFile;
150  }
151  else if(!(info.st_mode & S_IFDIR))
152  {
153  std::cerr << "[ERROR][matioCpp::File::Create] The path "<< path
154  << " is not a directory (input file name " << name
155  << ")." <<std::endl;
156  return newFile;
157  }
158 
159  }
160 
161  if (version == matioCpp::FileVersion::Undefined)
162  {
163  std::cerr << "[ERROR][matioCpp::File::Create] Cannot use Undefined as input version type." <<std::endl;
164  return newFile;
165  }
166 
167  mat_ft fileVer;
168 
169  switch (version)
170  {
172  fileVer = mat_ft::MAT_FT_MAT4;
173  break;
175  fileVer = mat_ft::MAT_FT_MAT5;
176  break;
178  fileVer = mat_ft::MAT_FT_MAT73;
179  break;
180  default:
181  fileVer = MAT_FT_DEFAULT;
182  break;
183  }
184 
185  std::string fileHeader = header;
186 
187  if (!fileHeader.size())
188  {
189  time_t rawtime;
190  time(&rawtime);
191  std::string timeString(ctime(&rawtime));
192  size_t end = timeString.find_last_of('\n');
193  timeString = timeString.substr(0,end);
194 
195  if (fileVer == mat_ft::MAT_FT_MAT73)
196  {
197  fileHeader = std::string("MATLAB 7.3 MAT-file, created by matioCpp v") + MATIOCPP_VER +
198  " via libmatio v" + std::to_string(MATIO_MAJOR_VERSION)
199  + "." + std::to_string(MATIO_MINOR_VERSION) + "." + std::to_string(MATIO_RELEASE_LEVEL) +
200  " on " + timeString + " HDF5 schema 0.5.";
201  }
202  else if (fileVer == mat_ft::MAT_FT_MAT5)
203  {
204  fileHeader = std::string("MATLAB 5.0 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 + ".";
208  }
209  //MAT4 does not have a header
210  }
211 
212  const char * matioHeader = fileHeader.size() ? fileHeader.c_str() : NULL;
213 
214  newFile.m_pimpl->reset(Mat_CreateVer(name.c_str(), matioHeader, fileVer), matioCpp::FileMode::ReadAndWrite);
215 
216  if (!newFile.isOpen())
217  {
218  std::cerr << "[ERROR][matioCpp::File::Create] Failed to open the file named "<< name << "." <<std::endl;
219  }
220 
221  return newFile;
222 }
223 
225 {
226  return std::remove(name.c_str()) == 0;
227 }
228 
230 {
232  return test.isOpen();
233 }
234 
236 {
237  if (!isOpen())
238  {
239  return "";
240  }
241 
242  return Mat_GetFilename(m_pimpl->mat_ptr);
243 }
244 
246 {
247  if (!isOpen())
248  {
249  return "";
250  }
251 
252 #if MATIO_VERSION >= 1515
253  return Mat_GetHeader(m_pimpl->mat_ptr);
254 #else
255  std::cerr << "[ERROR][matioCpp::File::header] The file header can be retrieved only with matio >= 1.5.15" << std::endl;
256  return "";
257 #endif
258 }
259 
261 {
262  if (!isOpen())
263  {
265  }
266 
267  switch (Mat_GetVersion(m_pimpl->mat_ptr))
268  {
269  case mat_ft::MAT_FT_MAT4:
271 
272  case mat_ft::MAT_FT_MAT5:
274 
275  case mat_ft::MAT_FT_MAT73:
277 
278  default:
280  }
281 }
282 
284 {
285  return m_pimpl->fileMode;
286 }
287 
289 {
290  std::vector<std::string> outputNames;
291  if (isOpen())
292  {
293  size_t list_size;
294  char* const* list = Mat_GetDir(m_pimpl->mat_ptr, &list_size);
295 
296  outputNames.resize(list_size);
297  for (size_t i = 0; i < list_size; ++i)
298  {
299  outputNames[i] = list[i];
300  }
301  }
302 
303  return outputNames;
304 }
305 
307 {
308  if (!isOpen())
309  {
310  std::cerr << "[ERROR][matioCpp::File::read] The file is not open." <<std::endl;
311  return matioCpp::Variable();
312  }
313 
314 #if defined(_MSC_VER) && MATIO_VERSION < 1519
315  if (version() == matioCpp::FileVersion::MAT7_3)
316  {
317  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;
318  return matioCpp::Variable();
319  }
320 #endif
321 
322  matvar_t *matVar = Mat_VarRead(m_pimpl->mat_ptr, name.c_str());
323 
324  matioCpp::Variable output((matioCpp::SharedMatvar(matVar)));
325 
326  if (!output.isValid())
327  {
328  std::cerr << "[ERROR][matioCpp::File::read] Failed to read variable " << name << ". The output is not valid." <<std::endl;
329  }
330 
331  return output;
332 }
333 
334 bool matioCpp::File::write(const Variable &variable, Compression compression)
335 {
336  if (!isOpen())
337  {
338  std::cerr << "[ERROR][matioCpp::File::write] The file is not open." <<std::endl;
339  return false;
340  }
341 
342  if (mode() != matioCpp::FileMode::ReadAndWrite)
343  {
344  std::cerr << "[ERROR][matioCpp::File::write] The file cannot be written." <<std::endl;
345  return false;
346  }
347 
348  std::string error = m_pimpl->isVariableValid(variable);
349  if (error.size() != 0)
350  {
351  std::cerr << "[ERROR][matioCpp::File::write] " << error << std::endl;
352  return false;
353  }
354 
355  SharedMatvar shallowCopy = SharedMatvar::GetMatvarShallowDuplicate(variable.toMatio()); // Shallow copy to remove const
356 
357  matio_compression matioCompression =
358  (compression == matioCpp::Compression::zlib) ? matio_compression::MAT_COMPRESSION_ZLIB : matio_compression::MAT_COMPRESSION_NONE;
359 
360  if (version() == matioCpp::FileVersion::MAT4)
361  {
362  switch (variable.variableType())
363  {
365  break;
367  break;
369  if (variable.dimensions().size() > 2)
370  {
371  std::cerr << "[ERROR][matioCpp::File::write] A MAT4 version does not support arrays with number of dimensions greater than 2." << std::endl;
372  return false;
373  }
374  break;
375  default:
376  std::cerr << "[ERROR][matioCpp::File::write] A MAT4 supports only element, vectors or matrices." << std::endl;
377  return false;
378  }
379 
380  matioCpp::ValueType valueType = variable.valueType();
381 
382  if ((valueType != matioCpp::ValueType::DOUBLE) && (valueType != matioCpp::ValueType::SINGLE) && (valueType != matioCpp::ValueType::LOGICAL)
383  && (valueType != matioCpp::ValueType::UINT8) && (valueType != matioCpp::ValueType::INT32)
384  && (valueType != matioCpp::ValueType::INT16) && (valueType != matioCpp::ValueType::UINT16))
385  {
386  std::cerr << "[ERROR][matioCpp::File::write] A MAT4 supports only variables of type LOGICAL, DOUBLE, SINGLE, UINT8, UINT16, INT16 and INT32." << std::endl;
387  return false;
388  }
389  }
390 
391  bool success = Mat_VarWrite(m_pimpl->mat_ptr, shallowCopy.get(), matioCompression) == 0;
392 
393  if (!success)
394  {
395  std::cerr << "[ERROR][matioCpp::File::write] Failed to write the variable to the file." <<std::endl;
396  return false;
397  }
398 
399  return true;
400 }
401 
403 {
404  return m_pimpl->mat_ptr;
405 }
406 
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:260
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:229
matioCpp::FileMode mode() const
The mode with which the file has been opened.
Definition: File.cpp:283
bool isOpen() const
Check if the file is open.
Definition: File.cpp:402
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:245
~File()
Destructor.
Definition: File.cpp:110
std::vector< std::string > variableNames() const
Get the list of variables in the file.
Definition: File.cpp:288
File()
Default Constructor.
Definition: File.cpp:93
static bool Delete(const std::string &name)
Delete the specified file.
Definition: File.cpp:224
std::string name() const
The file name.
Definition: File.cpp:235
matioCpp::Variable read(const std::string &name) const
Read a variable given the name.
Definition: File.cpp:306
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:132
bool write(const Variable &variable, matioCpp::Compression compression=matioCpp::Compression::None)
Write a Variable to a file.
Definition: File.cpp:334
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:494
const matvar_t * toMatio() const
Convert this Variable to a matio variable.
Definition: Variable.cpp:480
matioCpp::Span< const size_t > dimensions() const
Get the dimensions of this object.
Definition: Variable.cpp:528
bool isValid() const
Check if the variable is valid.
Definition: Variable.cpp:542
matioCpp::VariableType variableType() const
Get the VariableType.
Definition: Variable.cpp:506
matioCpp::ValueType valueType() const
Get the ValueType.
Definition: Variable.cpp:511
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)