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 (guarding against a zero element size to avoid division by zero)
129 size_t newCount = count;
130 if (size > 0 && 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. Only commit the new pointer/size if realloc succeeds, so a failed
504 // reallocation leaves the original buffer (and its size) intact instead of leaking it and
505 // claiming a capacity the buffer does not actually have.
506 uint8_t* newBuffer = (uint8_t*)realloc(_buffer, newBufferSize);
507 if (newBuffer == nullptr) return;
508 _buffer = newBuffer;
509 _bufferSize = newBufferSize;
510 }
511
516 size_t _size = 0;
517
521 size_t _bufferSize = 0;
522
526 uint8_t* _buffer = nullptr;
527
531 bool _readonly = false;
532
536 bool _writeonly = false;
537
541 bool _opened = false;
542
546 size_t _head = 0;
547
551 int _errorCode = 0;
552
556 bool _writeCallbackDefined = false;
557
561 std::function<void(const int64_t, MemoryFile* const)> _writeCallback;
562
566 bool _readCallbackDefined = false;
567
571 std::function<void(const int64_t, MemoryFile* const)> _readCallback;
572};
573
579{
580public:
581 MemoryFileDirectory() = default;
582
593 __JAFFAR_COMMON_INLINE__ MemoryFile* fopen(const std::string filename, const std::string mode)
594 {
595 // Parsing mode
596 mode_t openMode = mode_t::none;
597 if (mode.find("r") != std::string::npos) openMode = mode_t::read;
598 if (mode.find("w") != std::string::npos)
599 {
600 if (openMode != mode_t::none) return NULL; // Conflicting modes selected
601 openMode = mode_t::write;
602 }
603 if (mode.find("a") != std::string::npos)
604 {
605 if (openMode != mode_t::none) return NULL; // Conflicting modes selected
606 openMode = mode_t::append;
607 }
608
609 // If appending, fail because mem buffers have static size
610 if (openMode == mode_t::append) return NULL;
611
612 // If no mode chosen, fail
613 if (openMode == mode_t::none) return NULL;
614
615 // Parsing extended
616 bool extendedMode = false;
617 if (mode.find("+") != std::string::npos) extendedMode = true;
618
619 // Parsing extended
620 bool noCreateMode = false;
621 if (mode.find("x") != std::string::npos) noCreateMode = true;
622
623 // Checking if file already exists
624 bool fileExists = _fileMap.contains(filename);
625
626 // Check if file needs to be created
627 bool createFile = false;
628
629 // Evaluating the case where the file doesn't exist
630 if (fileExists == false)
631 {
632 // Check if the no-create flag has been provided
633 if (noCreateMode == true) return NULL;
634
635 // If reading, return NULL
636 if (openMode == mode_t::read) return NULL;
637
638 // Otherwise, create a new one
639 createFile = true;
640 }
641
642 // Evaluating the case where the file does exist
643 if (fileExists == true)
644 {
645 // Check if opened. If it is, then we cannot re-open it now
646 if (_fileMap.at(filename)->isOpened() == true) return NULL;
647
648 // If writing, overwrite file
649 if (openMode == mode_t::write) createFile = true;
650 }
651
652 // Creating new file, if required
653 if (createFile == true) _fileMap[filename] = std::make_unique<MemoryFile>();
654
655 // Getting file
656 MemoryFile* file = _fileMap.at(filename).get();
657
658 // Otherwise, we set it as opened
659 file->setOpened();
660
661 // If reading, set as read only
662 if (openMode == mode_t::read)
663 {
664 file->setReadOnly();
665 file->unsetWriteOnly();
666 }
667
668 // If writing, set as write only
669 if (openMode == mode_t::write)
670 {
671 file->setWriteOnly();
672 file->unsetReadOnly();
673 }
674
675 // If extended mode, all operations are permitted
676 if (extendedMode == true)
677 {
678 file->unsetWriteOnly();
679 file->unsetReadOnly();
680 }
681
682 // Set file head to the start
683 MemoryFile::rewind(file);
684
685 // Return file
686 return file;
687 }
688
695 int fclose(MemoryFile* const file)
696 {
697 if (file == NULL) return -1;
698
699 // Check if file already closed
700 if (file->isOpened() == false) return -2;
701
702 // Set the file as closed
703 file->unsetOpened();
704
705 return 0;
706 }
707
714 int fdestroy(const std::string& filename)
715 {
716 // Checking if file already exists
717 if (_fileMap.contains(filename) == false) return -1;
718
719 // Getting file
720 MemoryFile* file = _fileMap.at(filename).get();
721
722 // Check if opened. Cannot delete it yet
723 if (file->isOpened() == true) return -2;
724
725 // Delete it now
726 _fileMap.erase(filename);
727
728 return 0;
729 }
730
737 bool contains(const std::string& filename) const { return _fileMap.contains(filename); }
738
745 int64_t getFileSize(const std::string& filename) const
746 {
747 if (contains(filename) == false) return -1;
748 return _fileMap.at(filename)->getSize();
749 }
750
757 uint8_t* getFileBuffer(const std::string& filename) const
758 {
759 if (contains(filename) == false) return nullptr;
760 return _fileMap.at(filename)->getBuffer();
761 }
762
763private:
767 enum mode_t
768 {
769 none,
770 read,
771 write,
772 append
773 };
774
778 std::map<std::string, std::unique_ptr<MemoryFile>> _fileMap;
779};
780
781} // namespace file
782
783} // namespace jaffarCommon
uint8_t * getFileBuffer(const std::string &filename) const
Definition file.hpp:757
bool contains(const std::string &filename) const
Definition file.hpp:737
int64_t getFileSize(const std::string &filename) const
Definition file.hpp:745
__JAFFAR_COMMON_INLINE__ MemoryFile * fopen(const std::string filename, const std::string mode)
Definition file.hpp:593
int fdestroy(const std::string &filename)
Definition file.hpp:714
int fclose(MemoryFile *const file)
Definition file.hpp:695
Definition file.hpp:87
__JAFFAR_COMMON_INLINE__ void unsetOpened()
Definition file.hpp:383
static __JAFFAR_COMMON_INLINE__ int64_t ftell(MemoryFile *const file)
Definition file.hpp:214
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
__JAFFAR_COMMON_INLINE__ void unsetReadOnly()
Definition file.hpp:363
static __JAFFAR_COMMON_INLINE__ void clearerr(MemoryFile *const file)
Definition file.hpp:339
static __JAFFAR_COMMON_INLINE__ int fseek(MemoryFile *const file, const int64_t offset, const int origin)
Definition file.hpp:285
__JAFFAR_COMMON_INLINE__ int resize(const size_t newSize)
Definition file.hpp:443
__JAFFAR_COMMON_INLINE__ bool isOpened() const
Definition file.hpp:401
__JAFFAR_COMMON_INLINE__ void setOpened()
Definition file.hpp:378
__JAFFAR_COMMON_INLINE__ void setWriteCallback(const std::function< void(const int64_t, MemoryFile *)> callback)
Definition file.hpp:408
__JAFFAR_COMMON_INLINE__ void unsetWriteCallback()
Definition file.hpp:428
static __JAFFAR_COMMON_INLINE__ void rewind(MemoryFile *const file)
Definition file.hpp:232
__JAFFAR_COMMON_INLINE__ void unsetWriteOnly()
Definition file.hpp:373
__JAFFAR_COMMON_INLINE__ void setSize(const size_t size)
Definition file.hpp:482
~MemoryFile()
Definition file.hpp:98
static __JAFFAR_COMMON_INLINE__ int64_t ftello64(MemoryFile *const file)
Definition file.hpp:206
static __JAFFAR_COMMON_INLINE__ int feof(MemoryFile *const file)
Definition file.hpp:321
static __JAFFAR_COMMON_INLINE__ int ferror(MemoryFile *const file)
Definition file.hpp:353
__JAFFAR_COMMON_INLINE__ bool isReadOnly() const
Definition file.hpp:389
__JAFFAR_COMMON_INLINE__ void setReadCallback(const std::function< void(const int64_t, MemoryFile *)> callback)
Definition file.hpp:419
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__ size_t getSize() const
Definition file.hpp:489
__JAFFAR_COMMON_INLINE__ void setReadOnly()
Definition file.hpp:358
static __JAFFAR_COMMON_INLINE__ int fseeko64(MemoryFile *const file, const int64_t offset, const int origin)
Definition file.hpp:274
__JAFFAR_COMMON_INLINE__ bool isWriteOnly() const
Definition file.hpp:395
static __JAFFAR_COMMON_INLINE__ int fflush(MemoryFile *file)
Definition file.hpp:251
__JAFFAR_COMMON_INLINE__ void setWriteOnly()
Definition file.hpp:368
__JAFFAR_COMMON_INLINE__ void unsetReadCallback()
Definition file.hpp:433
static __JAFFAR_COMMON_INLINE__ bool loadStringFromFile(std::string &dst, const std::string &fileName)
Definition file.hpp:45
static __JAFFAR_COMMON_INLINE__ std::string slurp(std::ifstream &in)
Definition file.hpp:31
static __JAFFAR_COMMON_INLINE__ bool saveStringToFile(const std::string &src, const std::string &fileName)
Definition file.hpp:68