FOSS-VG/src/lib/file.cpp

136 lines
4.0 KiB
C++

// 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 <fstream>
#include <filesystem>
#include <exception>
#include <vector>
#include <string>
#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<uint64_t>(std::filesystem::file_size(filePath));
this->open();
this->isOpen = true;
}
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;
}
}
void File::close(){
this->fileStream.close();
this->isOpen = false;
}
bool File::eof() {
return !this->size.isError && this->cursorPosition >= this->size.value;
}
ErrorOr<uint8_t> File::readByte(){
uint8_t* nextPointer = new uint8_t;
uint8_t nextByte;
bool failure = false;
if (!this->isOpen) {
return ErrorOr<uint8_t>(true, ErrorCodes::FILE_NOT_OPEN);
}
if (!this->size.isError && this->cursorPosition >= this->size.value) {
return ErrorOr<uint8_t>(true, ErrorCodes::OVERRUN);
}
try {
this->fileStream.seekg(this->cursorPosition);
this->fileStream.read(reinterpret_cast<char*>(nextPointer), 1);
nextByte = *nextPointer;
this->cursorPosition++;
} catch (std::exception& e) {
failure = true;
}
delete nextPointer;
return failure? ErrorOr<uint8_t>(true, ErrorCodes::UNKNOWN) : ErrorOr<uint8_t>(nextByte);
}
ErrorOr<std::vector<uint8_t>> File::read(uint64_t bytes){
uint8_t* buffer = new uint8_t[bytes];
std::vector<uint8_t> data;
bool failure = false;
if (!this->isOpen) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::FILE_NOT_OPEN);
}
if (!this->size.isError && this->cursorPosition >= this->size.value+bytes) {
return ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::OVERRUN);
}
try {
this->fileStream.seekg(this->cursorPosition);
this->fileStream.read(reinterpret_cast<char*>(buffer), bytes);
data = std::vector<uint8_t>(buffer, buffer+bytes);
this->cursorPosition += bytes;
} catch (std::exception& e) {
failure = true;
}
delete[] buffer;
return failure? ErrorOr<std::vector<uint8_t>>(true, ErrorCodes::UNKNOWN) : ErrorOr<std::vector<uint8_t>>(data);
}
ErrorOr<tiny_utf8::string> File::readString(uint64_t bytes){
ErrorOr<std::vector<uint8_t>> data = this->read(bytes);
if(data.isError){
return ErrorOr<tiny_utf8::string>(true, data.errorCode);
}
std::string s;
for(auto byte: data.value){
s.push_back(byte);
}
return ErrorOr<tiny_utf8::string>(tiny_utf8::string(s));
}
ErrorOr<File*> File::open(std::string path, char mode, uint64_t startPosition){
if (!std::filesystem::exists(path)) {
return ErrorOr<File*>(true, ErrorCodes::FILE_NOT_FOUND, nullptr);
}
//TODO: check access perms
return ErrorOr<File*>(new File(path, mode, startPosition));
}