diff --git a/scripts/test.sh b/scripts/test.sh index 56a7c1c..5dbded7 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -39,6 +39,7 @@ COMPILE_COMMANDS=( "$CXX_WITH_FLAGS src/test/nbt_write_string_failure_mode.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_write_string_failure_mode" "$CXX_WITH_FLAGS src/test/nbt_tags.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_tags" "$CXX_WITH_FLAGS src/test/nbt_size_helpers.cpp -I./include -Lbin/lib -l:nbt.so -l:javacompat.so -o bin/test/nbt_size_helpers" + "$CXX_WITH_FLAGS src/test/file.cpp -I./include -Lbin/lib -l:file.so -o bin/test/file" ) for command in ${!COMPILE_COMMANDS[@]}; do echo "${COMPILE_COMMANDS[command]}" diff --git a/src/lib/error.hpp b/src/lib/error.hpp index 58c44eb..5380322 100644 --- a/src/lib/error.hpp +++ b/src/lib/error.hpp @@ -91,6 +91,10 @@ namespace ErrorCodes { const uint8_t INVALID_TYPE = 8; + //file errors + const uint8_t FILE_READ_FAILED = 9; + const uint8_t FILE_NOT_FOUND = 10; + const uint8_t UNIMPLEMENTED = 254; const uint8_t UNKNOWN = 255; diff --git a/src/lib/file.cpp b/src/lib/file.cpp index d163e33..11d30cf 100644 --- a/src/lib/file.cpp +++ b/src/lib/file.cpp @@ -1,7 +1,7 @@ // 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 @@ -16,4 +16,156 @@ // 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" +#include "error.h" + +File::File(std::string path, char mode, uint64_t cursorPosition): mode(mode), path(path), cursorPosition(cursorPosition){ + switch(this->mode){ + case 'w': + case 'm': + this->fileStream.open(path, std::fstream::out | std::fstream::binary); + break; + case 'r': + case 'e': + this->fileStream.open(path, std::fstream::in | std::fstream::binary); + break; + case 'a': + this->fileStream.open(path, std::fstream::app | std::fstream::binary); + break; + default: + break; + } + + try{ + std::filesystem::path filePath = path; + this->size = ErrorOr(std::filesystem::file_size(filePath)); + }catch(std::exception e){ + this->size = ErrorOr(true, ErrorCodes::FILE_NOT_FOUND); + } +} + +File::File(const File& file){ + this->mode = file.getMode(); + this->isOpen = file.isOpen; + this->eof = file.eof; + this->path = file.path; + this->cursorPosition = file.cursorPosition; + this->size = file.size; + + if(this->isOpen){ + this->open(); + } +} + +File& File::operator=(const File& file){ + File cpFile(file); + return cpFile; +} + +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; + } + + try{ + std::filesystem::path filePath = this->path; + this->size = ErrorOr(std::filesystem::file_size(filePath)); + }catch(std::exception e){ + this->size = ErrorOr(true, ErrorCodes::FILE_NOT_FOUND); + } +} + +void File::close(){ + this->fileStream.close(); + this->isOpen = false; +} + +char File::getMode() const{ + return this->mode; +} + +ErrorOr File::readByte(){ + if(this->size.isError){ + return ErrorOr(true, this->size.errorCode); + } + + this->cursorPosition += 1; + this->fileStream.seekg(this->cursorPosition); + + char* byte = new char; + try{ + this->fileStream.read(byte, 1); + delete byte; + }catch(std::exception e){ + return ErrorOr(true, ErrorCodes::FILE_READ_FAILED); + } + return ErrorOr((uint8_t) *byte); +} + +ErrorOr> File::read(uint64_t bytes){ + if(this->size.isError){ + return ErrorOr>(true, this->size.errorCode); + } + + this->cursorPosition += 1; + this->fileStream.seekg(this->cursorPosition); + + char* buffer = new char[bytes]; + std::vector data; + try{ + this->fileStream.read(buffer, bytes); + for(uint64_t i=0; i>(true, ErrorCodes::FILE_READ_FAILED); + } + return ErrorOr>(data); +} + +ErrorOr File::readString(uint64_t bytes){ + if(this->size.isError){ + return ErrorOr(true, this->size.errorCode); + } + + 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){ + File *file = new File(path, mode, startPosition); + file->isOpen = true; + file->eof = false; + + if(file->size.isError){ + return ErrorOr(true, file->size.errorCode); //if file is not found + } + + return ErrorOr(file); +} diff --git a/src/lib/file.hpp b/src/lib/file.hpp index 6c08359..d0e5229 100644 --- a/src/lib/file.hpp +++ b/src/lib/file.hpp @@ -1,7 +1,7 @@ // Copyright 2022, FOSS-VG Developers and Contributers // // Author(s): -// BodgeMaster +// 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 @@ -18,31 +18,39 @@ #include #include +#include #include #include #include "error.hpp" + class File { private: //TODO: add other necessary internals to this section as needed char mode; + std::fstream fileStream; //TODO: add other necessary details to the constructor as needed // For example, the fstream (or whatever mechanism is used) needs // to be handed over from File::open() to the File object. // // Remember to add a destructor to the public section if pointers // are to be used. - File(char mode, uint64_t cursorPosition); + File(std::string path, char mode, uint64_t cursorPosition); public: bool isOpen; bool eof; + std::string path; uint64_t cursorPosition; // may be error if not a regular file or size cannot be determined ErrorOr size; + File() = default; + File(const File& file); + File& operator=(const File& file); void open(); void close(); + char getMode() const; // only applicable to read and edit modes // moves the cursor to the right of the read section @@ -86,5 +94,5 @@ class File { // // A startPosition of 0xFFFFFFFF is considered to be the end of // the file whatever its size. - static ErrorOr open(std::string path, char mode, uint64_t startPosition=0); -}; + static ErrorOr open(std::string path, char mode, uint64_t startPosition=0); +}; \ No newline at end of file diff --git a/src/test/file.cpp b/src/test/file.cpp new file mode 100644 index 0000000..48bd9e4 --- /dev/null +++ b/src/test/file.cpp @@ -0,0 +1,31 @@ +// Copyright 2022, FOSS-VG Developers and Contributers +// +// 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 "assert.hpp" +#include "tinyutf8/tinyutf8.h" +#include "../lib/file.hpp" + +int main(){ + std::cout << "################################################################################" << std::endl; + std::cout << "File tests" << std::endl; + std::cout << "################################################################################" << std::endl; + File *file; + + //read test + file = File::open("../../resources/unicode_data/normal_utf-8", 'r').value; + tiny_utf8::string data = file->readString(file->size.value).value; + std::cout << file->size.isError << std::endl; + std::cout << data << std::endl; +} \ No newline at end of file