jaffarCommon
Loading...
Searching...
No Matches
file.hpp
Go to the documentation of this file.
1#pragma once
2
8#include <cstdio>
9#include <cstring>
10#include <fstream>
11#include <functional>
12#include <map>
13#include <memory>
14#include <sstream>
15#include <string>
16
17namespace jaffarCommon
18{
19
20namespace file
21{
22
31static __JAFFAR_COMMON__INLINE__ std::string slurp(std::ifstream& in)
32{
33 std::ostringstream sstr;
34 sstr << in.rdbuf();
35 return sstr.str();
36}
37
45static __JAFFAR_COMMON__INLINE__ bool loadStringFromFile(std::string& dst, const std::string& fileName)
46{
47 std::ifstream fi(fileName);
48
49 // If file not found or open, return false
50 if (fi.good() == false) return false;
51
52 // Reading entire file
53 dst = slurp(fi);
54
55 // Closing file
56 fi.close();
57
58 return true;
59}
60
68static __JAFFAR_COMMON__INLINE__ bool saveStringToFile(const std::string& src, const std::string& fileName)
69{
70 FILE* fid = fopen(fileName.c_str(), "w");
71 if (fid != NULL)
72 {
73 fwrite(src.c_str(), 1, src.size(), fid);
74 fclose(fid);
75 return true;
76 }
77 return false;
78}
79
80class MemoryFileDirectory;
81
87{
88public:
89 friend class MemoryFileDirectory;
90
91 MemoryFile() = default;
92 MemoryFile(const MemoryFile&) = delete;
93 void operator=(const MemoryFile&) = delete;
94
98 ~MemoryFile() { free(_buffer); }
99
112 static __JAFFAR_COMMON__INLINE__ int64_t fread(void* const buffer, const size_t size, const size_t count, MemoryFile* const file)
113 {
114 // Check if file is closed
115 if (file->isOpened() == false)
116 {
117 file->_errorCode = -1;
118 return file->_errorCode;
119 }
120
121 // Refuse operation if file is write only
122 if (file->isWriteOnly() == true)
123 {
124 file->_errorCode = -2;
125 return file->_errorCode;
126 }
127
128 // Ensuring we don't exceed mem buffer size
129 size_t newCount = count;
130 if (file->_head + (size * count) > file->_size) newCount = (file->_size - file->_head) / size;
131
132 // Getting requested size
133 const size_t requestedSize = size * newCount;
134
135 // Performing memcpy
136 if (requestedSize > 0) std::memcpy(buffer, &file->_buffer[file->_head], requestedSize);
137
138 // Advancing head
139 file->_head += requestedSize;
140
141 // Calling corresponding callback, if defined
142 if (file->_readCallbackDefined == true) file->_readCallback(requestedSize, file);
143
144 // Returning element count read
145 file->_errorCode = 0;
146 return newCount;
147 }
148
161 static __JAFFAR_COMMON__INLINE__ int64_t fwrite(const void* buffer, const size_t size, const size_t count, MemoryFile* const file)
162 {
163 // Check if file is closed
164 if (file->isOpened() == false)
165 {
166 file->_errorCode = -1;
167 return file->_errorCode;
168 }
169
170 // Refuse operation if file is read only
171 if (file->isReadOnly() == true)
172 {
173 file->_errorCode = -2;
174 return file->_errorCode;
175 }
176
177 // Getting requested size
178 const size_t requestedSize = size * count;
179
180 // Checking if internal buffer needs to be resized
181 const size_t endHeadPos = file->_head + requestedSize;
182 if (endHeadPos > file->_bufferSize) file->resizeToFit(endHeadPos + 1);
183
184 // Performing memcpy
185 if (requestedSize > 0) memcpy(&file->_buffer[file->_head], buffer, requestedSize);
186
187 // Advancing head until the next
188 file->_head += requestedSize;
189 if (file->_head > file->_size) file->_size = file->_head;
190
191 // Calling corresponding callback, if defined
192 if (file->_writeCallbackDefined == true) file->_writeCallback(requestedSize, file);
193
194 // Returning element count written
195 file->_errorCode = 0;
196 return count;
197 }
198
206 static __JAFFAR_COMMON__INLINE__ int64_t ftello64(MemoryFile* const file) { return ftell(file); }
207
214 static __JAFFAR_COMMON__INLINE__ int64_t ftell(MemoryFile* const file)
215 {
216 // Check if file is closed
217 if (file->isOpened() == false)
218 {
219 file->_errorCode = -1;
220 return file->_errorCode;
221 }
222
223 file->_errorCode = 0;
224 return file->_head;
225 }
226
232 static __JAFFAR_COMMON__INLINE__ void rewind(MemoryFile* const file)
233 {
234 // Check if file is closed
235 if (file->isOpened() == false)
236 {
237 file->_errorCode = -1;
238 return;
239 }
240
241 file->_errorCode = 0;
242 file->_head = 0;
243 }
244
251 static __JAFFAR_COMMON__INLINE__ int fflush(MemoryFile* file)
252 {
253 // Check if file is closed
254 if (file->isOpened() == false)
255 {
256 file->_errorCode = -1;
257 return file->_errorCode;
258 }
259
260 file->_errorCode = 0;
261 return 0;
262 }
263
274 static __JAFFAR_COMMON__INLINE__ int fseeko64(MemoryFile* const file, const int64_t offset, const int origin) { return fseek(file, offset, origin); }
275
285 static __JAFFAR_COMMON__INLINE__ int fseek(MemoryFile* const file, const int64_t offset, const int origin)
286 {
287 // Check if file is closed
288 if (file->isOpened() == false)
289 {
290 file->_errorCode = -1;
291 return file->_errorCode;
292 }
293
294 int64_t startPos = file->_head;
295 if (origin == SEEK_SET) startPos = 0;
296 if (origin == SEEK_END) startPos = file->_size;
297
298 int64_t desiredPos = startPos + offset;
299 if (desiredPos < 0)
300 {
301 file->_errorCode = -2;
302 return file->_errorCode;
303 }
304 if (desiredPos > (int64_t)file->_size)
305 {
306 file->_errorCode = -3;
307 return file->_errorCode;
308 }
309
310 file->_head = desiredPos;
311 file->_errorCode = 0;
312 return 0;
313 }
314
321 static __JAFFAR_COMMON__INLINE__ int feof(MemoryFile* const file)
322 {
323 // Check if file is closed
324 if (file->isOpened() == false)
325 {
326 file->_errorCode = -1;
327 return file->_errorCode;
328 }
329
330 file->_errorCode = 0;
331 return file->_head == file->_size;
332 }
333
339 static __JAFFAR_COMMON__INLINE__ void clearerr(MemoryFile* const file)
340 {
341 // Check if file is closed
342 if (file->isOpened() == false) return;
343
344 file->_errorCode = 0;
345 }
346
353 static __JAFFAR_COMMON__INLINE__ int ferror(MemoryFile* const file) { return file->_errorCode; }
354
358 __JAFFAR_COMMON__INLINE__ void setReadOnly() { _readonly = true; }
359
363 __JAFFAR_COMMON__INLINE__ void unsetReadOnly() { _readonly = false; }
364
368 __JAFFAR_COMMON__INLINE__ void setWriteOnly() { _writeonly = true; }
369
373 __JAFFAR_COMMON__INLINE__ void unsetWriteOnly() { _writeonly = false; }
374
378 __JAFFAR_COMMON__INLINE__ void setOpened() { _opened = true; }
379
383 __JAFFAR_COMMON__INLINE__ void unsetOpened() { _opened = false; }
384
389 __JAFFAR_COMMON__INLINE__ bool isReadOnly() const { return _readonly; }
390
395 __JAFFAR_COMMON__INLINE__ bool isWriteOnly() const { return _writeonly; }
396
401 __JAFFAR_COMMON__INLINE__ bool isOpened() const { return _opened; }
402
408 __JAFFAR_COMMON__INLINE__ void setWriteCallback(const std::function<void(const int64_t, MemoryFile*)> callback)
409 {
410 _writeCallback = callback;
411 _writeCallbackDefined = true;
412 }
413
419 __JAFFAR_COMMON__INLINE__ void setReadCallback(const std::function<void(const int64_t, MemoryFile*)> callback)
420 {
421 _readCallback = callback;
422 _readCallbackDefined = true;
423 }
424
428 __JAFFAR_COMMON__INLINE__ void unsetWriteCallback() { _writeCallbackDefined = false; }
429
433 __JAFFAR_COMMON__INLINE__ void unsetReadCallback() { _readCallbackDefined = false; }
434
443 __JAFFAR_COMMON__INLINE__ int resize(const size_t newSize)
444 {
445 // Check if file is closed
446 if (isOpened() == false)
447 {
448 _errorCode = -1;
449 return _errorCode;
450 }
451
452 // Refuse operation if file is read only
453 if (isReadOnly() == true)
454 {
455 _errorCode = -2;
456 return _errorCode;
457 }
458
459 // First, assign new size
460 // const size_t oldSize = _size;
461 _size = newSize;
462
463 // Then, resize the internal buffer, if needed
464 if (_bufferSize < _size)
465 {
466 resizeToFit(_size);
467 if (_buffer == nullptr) return -1;
468 }
469
470 // Then check head in case of shrinking file
471 if (_head > _size) _head = _size;
472
473 _errorCode = 0;
474 return 0;
475 }
476
482 __JAFFAR_COMMON__INLINE__ void setSize(const size_t size) { _size = size; }
483
489 __JAFFAR_COMMON__INLINE__ size_t getSize() const { return _size; }
490
491private:
492 uint8_t* getBuffer() const { return _buffer; }
493
494 void resizeToFit(const size_t target)
495 {
496 // Getting current buffer size
497 size_t newBufferSize = _bufferSize;
498 if (newBufferSize == 0) newBufferSize = 1;
499
500 // Duplicating new buffer size until the target fits
501 while (newBufferSize < target) newBufferSize <<= 1;
502
503 // Reallocating buffer
504 _bufferSize = newBufferSize;
505 _buffer = (uint8_t*)realloc(_buffer, newBufferSize);
506 }
507
512 size_t _size = 0;
513
517 size_t _bufferSize = 0;
518
522 uint8_t* _buffer = nullptr;
523
527 bool _readonly = false;
528
532 bool _writeonly = false;
533
537 bool _opened = false;
538
542 size_t _head = 0;
543
547 int _errorCode = 0;
548
552 bool _writeCallbackDefined = false;
553
557 std::function<void(const int64_t, MemoryFile* const)> _writeCallback;
558
562 bool _readCallbackDefined = false;
563
567 std::function<void(const int64_t, MemoryFile* const)> _readCallback;
568};
569
575{
576public:
577 MemoryFileDirectory() = default;
578
589 __JAFFAR_COMMON__INLINE__ MemoryFile* fopen(const std::string filename, const std::string mode)
590 {
591 // Parsing mode
592 mode_t openMode = mode_t::none;
593 if (mode.find("r") != std::string::npos) openMode = mode_t::read;
594 if (mode.find("w") != std::string::npos)
595 {
596 if (openMode != mode_t::none) return NULL; // Conflicting modes selected
597 openMode = mode_t::write;
598 }
599 if (mode.find("a") != std::string::npos)
600 {
601 if (openMode != mode_t::none) return NULL; // Conflicting modes selected
602 openMode = mode_t::append;
603 }
604
605 // If appending, fail because mem buffers have static size
606 if (openMode == mode_t::append) return NULL;
607
608 // If no mode chosen, fail
609 if (openMode == mode_t::none) return NULL;
610
611 // Parsing extended
612 bool extendedMode = false;
613 if (mode.find("+") != std::string::npos) extendedMode = true;
614
615 // Parsing extended
616 bool noCreateMode = false;
617 if (mode.find("x") != std::string::npos) noCreateMode = true;
618
619 // Checking if file already exists
620 bool fileExists = _fileMap.contains(filename);
621
622 // Check if file needs to be created
623 bool createFile = false;
624
625 // Evaluating the case where the file doesn't exist
626 if (fileExists == false)
627 {
628 // Check if the no-create flag has been provided
629 if (noCreateMode == true) return NULL;
630
631 // If reading, return NULL
632 if (openMode == mode_t::read) return NULL;
633
634 // Otherwise, create a new one
635 createFile = true;
636 }
637
638 // Evaluating the case where the file does exist
639 if (fileExists == true)
640 {
641 // Check if opened. If it is, then we cannot re-open it now
642 if (_fileMap.at(filename)->isOpened() == true) return NULL;
643
644 // If writing, overwrite file
645 if (openMode == mode_t::write) createFile = true;
646 }
647
648 // Creating new file, if required
649 if (createFile == true) _fileMap[filename] = std::make_unique<MemoryFile>();
650
651 // Getting file
652 MemoryFile* file = _fileMap.at(filename).get();
653
654 // Otherwise, we set it as opened
655 file->setOpened();
656
657 // If reading, set as read only
658 if (openMode == mode_t::read)
659 {
660 file->setReadOnly();
661 file->unsetWriteOnly();
662 }
663
664 // If writing, set as write only
665 if (openMode == mode_t::write)
666 {
667 file->setWriteOnly();
668 file->unsetReadOnly();
669 }
670
671 // If extended mode, all operations are permitted
672 if (extendedMode == true)
673 {
674 file->unsetWriteOnly();
675 file->unsetReadOnly();
676 }
677
678 // Set file head to the start
679 MemoryFile::rewind(file);
680
681 // Return file
682 return file;
683 }
684
691 int fclose(MemoryFile* const file)
692 {
693 if (file == NULL) return -1;
694
695 // Check if file already closed
696 if (file->isOpened() == false) return -2;
697
698 // Set the file as closed
699 file->unsetOpened();
700
701 return 0;
702 }
703
710 int fdestroy(const std::string& filename)
711 {
712 // Checking if file already exists
713 if (_fileMap.contains(filename) == false) return -1;
714
715 // Getting file
716 MemoryFile* file = _fileMap.at(filename).get();
717
718 // Check if opened. Cannot delete it yet
719 if (file->isOpened() == true) return -2;
720
721 // Delete it now
722 _fileMap.erase(filename);
723
724 return 0;
725 }
726
733 bool contains(const std::string& filename) const { return _fileMap.contains(filename); }
734
741 int64_t getFileSize(const std::string& filename) const
742 {
743 if (contains(filename) == false) return -1;
744 return _fileMap.at(filename)->getSize();
745 }
746
753 uint8_t* getFileBuffer(const std::string& filename) const
754 {
755 if (contains(filename) == false) return nullptr;
756 return _fileMap.at(filename)->getBuffer();
757 }
758
759private:
763 enum mode_t
764 {
765 none,
766 read,
767 write,
768 append
769 };
770
774 std::map<std::string, std::unique_ptr<MemoryFile>> _fileMap;
775};
776
777} // namespace file
778
779} // namespace jaffarCommon
uint8_t * getFileBuffer(const std::string &filename) const
Definition file.hpp:753
bool contains(const std::string &filename) const
Definition file.hpp:733
__JAFFAR_COMMON__INLINE__ MemoryFile * fopen(const std::string filename, const std::string mode)
Definition file.hpp:589
int64_t getFileSize(const std::string &filename) const
Definition file.hpp:741
int fdestroy(const std::string &filename)
Definition file.hpp:710
int fclose(MemoryFile *const file)
Definition file.hpp:691
Definition file.hpp:87
static __JAFFAR_COMMON__INLINE__ void clearerr(MemoryFile *const file)
Definition file.hpp:339
__JAFFAR_COMMON__INLINE__ void setReadOnly()
Definition file.hpp:358
static __JAFFAR_COMMON__INLINE__ int64_t ftello64(MemoryFile *const file)
Definition file.hpp:206
__JAFFAR_COMMON__INLINE__ void setOpened()
Definition file.hpp:378
__JAFFAR_COMMON__INLINE__ void setReadCallback(const std::function< void(const int64_t, MemoryFile *)> callback)
Definition file.hpp:419
__JAFFAR_COMMON__INLINE__ bool isReadOnly() const
Definition file.hpp:389
__JAFFAR_COMMON__INLINE__ bool isWriteOnly() const
Definition file.hpp:395
__JAFFAR_COMMON__INLINE__ size_t getSize() const
Definition file.hpp:489
static __JAFFAR_COMMON__INLINE__ int fseeko64(MemoryFile *const file, const int64_t offset, const int origin)
Definition file.hpp:274
__JAFFAR_COMMON__INLINE__ int resize(const size_t newSize)
Definition file.hpp:443
__JAFFAR_COMMON__INLINE__ void setWriteOnly()
Definition file.hpp:368
~MemoryFile()
Definition file.hpp:98
__JAFFAR_COMMON__INLINE__ void unsetOpened()
Definition file.hpp:383
static __JAFFAR_COMMON__INLINE__ int64_t fread(void *const buffer, const size_t size, const size_t count, MemoryFile *const file)
Definition file.hpp:112
__JAFFAR_COMMON__INLINE__ void setSize(const size_t size)
Definition file.hpp:482
__JAFFAR_COMMON__INLINE__ void unsetReadOnly()
Definition file.hpp:363
static __JAFFAR_COMMON__INLINE__ int fflush(MemoryFile *file)
Definition file.hpp:251
static __JAFFAR_COMMON__INLINE__ void rewind(MemoryFile *const file)
Definition file.hpp:232
static __JAFFAR_COMMON__INLINE__ int feof(MemoryFile *const file)
Definition file.hpp:321
__JAFFAR_COMMON__INLINE__ void unsetWriteCallback()
Definition file.hpp:428
__JAFFAR_COMMON__INLINE__ void unsetWriteOnly()
Definition file.hpp:373
__JAFFAR_COMMON__INLINE__ void setWriteCallback(const std::function< void(const int64_t, MemoryFile *)> callback)
Definition file.hpp:408
__JAFFAR_COMMON__INLINE__ void unsetReadCallback()
Definition file.hpp:433
__JAFFAR_COMMON__INLINE__ bool isOpened() const
Definition file.hpp:401
static __JAFFAR_COMMON__INLINE__ int ferror(MemoryFile *const file)
Definition file.hpp:353
static __JAFFAR_COMMON__INLINE__ int64_t fwrite(const void *buffer, const size_t size, const size_t count, MemoryFile *const file)
Definition file.hpp:161
static __JAFFAR_COMMON__INLINE__ int64_t ftell(MemoryFile *const file)
Definition file.hpp:214
static __JAFFAR_COMMON__INLINE__ int fseek(MemoryFile *const file, const int64_t offset, const int origin)
Definition file.hpp:285
static __JAFFAR_COMMON__INLINE__ bool loadStringFromFile(std::string &dst, const std::string &fileName)
Definition file.hpp:45
static __JAFFAR_COMMON__INLINE__ bool saveStringToFile(const std::string &src, const std::string &fileName)
Definition file.hpp:68
static __JAFFAR_COMMON__INLINE__ std::string slurp(std::ifstream &in)
Definition file.hpp:31