// Copyright 2022, FOSS-VG Developers and Contributers // // Author(s): // Bodgemaster, Shwoomple // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Affero General Public License as published // by the Free Software Foundation, version 3. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // version 3 along with this program. // If not, see https://www.gnu.org/licenses/agpl-3.0.en.html #include #include #include #include #include #include "tinyutf8/tinyutf8.h" #include "file.hpp" File::File(std::string path, char mode, uint64_t cursorPosition): mode(mode), path(path), cursorPosition(cursorPosition){ std::filesystem::path filePath = path; this->size = ErrorOr(std::filesystem::file_size(filePath)); this->open(); } File::~File() { if (this->isOpen) { this->fileStream.close(); } } void File::open(){ switch(this->mode){ case 'w': case 'm': this->fileStream.open(this->path, std::fstream::out | std::fstream::binary); break; case 'r': case 'e': this->fileStream.open(this->path, std::fstream::in | std::fstream::binary); break; case 'a': this->fileStream.open(this->path, std::fstream::app | std::fstream::binary); break; default: break; } this->isOpen = this->fileStream.is_open(); } void File::close(){ this->fileStream.close(); this->isOpen = false; } bool File::eof() { return !this->size.isError && this->cursorPosition >= this->size.value; } ErrorOr File::readByte(){ if (!this->isOpen) { return ErrorOr(true, ErrorCodes::FILE_NOT_OPEN); } if (!this->size.isError && this->cursorPosition >= this->size.value) { return ErrorOr(true, ErrorCodes::OVERRUN); } uint8_t* nextPointer = new uint8_t; uint8_t nextByte; bool failure = false; try { this->fileStream.seekg(this->cursorPosition); this->fileStream.read(reinterpret_cast(nextPointer), 1); nextByte = *nextPointer; this->cursorPosition++; } catch (std::exception& e) { failure = true; } delete nextPointer; return failure? ErrorOr(true, ErrorCodes::UNKNOWN) : ErrorOr(nextByte); } ErrorOr> File::read(uint64_t bytes){ if (!this->isOpen) { return ErrorOr>(true, ErrorCodes::FILE_NOT_OPEN); } if (!this->size.isError && this->cursorPosition >= this->size.value+bytes) { return ErrorOr>(true, ErrorCodes::OVERRUN); } uint8_t* buffer = new uint8_t[bytes]; std::vector data; bool failure = false; try { this->fileStream.seekg(this->cursorPosition); this->fileStream.read(reinterpret_cast(buffer), bytes); data = std::vector(buffer, buffer+bytes); this->cursorPosition += bytes; } catch (std::exception& e) { failure = true; } delete[] buffer; return failure? ErrorOr>(true, ErrorCodes::UNKNOWN) : ErrorOr>(data); } ErrorOr File::readString(uint64_t bytes){ ErrorOr> data = this->read(bytes); if(data.isError){ return ErrorOr(true, data.errorCode); } std::string s; for(auto byte: data.value){ s.push_back(byte); } return ErrorOr(tiny_utf8::string(s)); } ErrorOr File::open(std::string path, char mode, uint64_t startPosition){ if (!std::filesystem::exists(path)) { return ErrorOr(true, ErrorCodes::FILE_NOT_FOUND, nullptr); } //TODO: check access perms return ErrorOr(new File(path, mode, startPosition)); }