Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DirAccess interface to file_access_memory #99851

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 153 additions & 48 deletions core/io/file_access_memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,91 +33,84 @@
#include "core/config/project_settings.h"

static HashMap<String, Vector<uint8_t>> *files = nullptr;
const static PackedByteArray DIRECTORY = String("<DIRECTORY>").to_utf8_buffer();

void FileAccessMemory::register_file(const String &p_name, const Vector<uint8_t> &p_data) {
if (!files) {
files = memnew((HashMap<String, Vector<uint8_t>>));
}

String name;
if (ProjectSettings::get_singleton()) {
name = ProjectSettings::get_singleton()->globalize_path(p_name);
} else {
name = p_name;
void FileAccessMemory::initialize() {
if (files) {
cleanup();
}
//name = DirAccess::normalize_path(name);

(*files)[name] = p_data;
files = memnew((HashMap<String, Vector<uint8_t>>));
}

void FileAccessMemory::cleanup() {
if (!files) {
return;
}

memdelete(files);
files = nullptr;
}

Ref<FileAccess> FileAccessMemory::create() {
return memnew(FileAccessMemory);
}

bool FileAccessMemory::file_exists(const String &p_name) {
String name = fix_path(p_name);
//name = DirAccess::normalize_path(name);

return files && (files->find(name) != nullptr);
return files->has(p_name);
}

Error FileAccessMemory::open_custom(const uint8_t *p_data, uint64_t p_len) {
data = (uint8_t *)p_data;
length = p_len;
if (!files) {
initialize();
}
current_file = "__temp__";
files->erase(current_file);
open_internal(current_file, FileAccess::WRITE);
store_buffer(p_data, p_len);
pos = 0;
return OK;
}

Error FileAccessMemory::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_NULL_V(files, ERR_FILE_NOT_FOUND);

String name = fix_path(p_path);
//name = DirAccess::normalize_path(name);
String name = p_path.simplify_path();

HashMap<String, Vector<uint8_t>>::Iterator E = files->find(name);
ERR_FAIL_COND_V_MSG(!E, ERR_FILE_NOT_FOUND, vformat("Can't find file '%s'.", p_path));
if (p_mode_flags & WRITE) {
files->insert(name, PackedByteArray());
}

data = E->value.ptrw();
length = E->value.size();
HashMap<String, Vector<uint8_t>>::Iterator E = files->find(name);
ERR_FAIL_COND_V_MSG(!E, ERR_FILE_NOT_FOUND, vformat("Can't find file '%s'.", name));
current_file = name;
pos = 0;

return OK;
}

bool FileAccessMemory::is_open() const {
return data != nullptr;
return !current_file.is_empty();
}

void FileAccessMemory::seek(uint64_t p_position) {
ERR_FAIL_NULL(data);
pos = p_position;
}

void FileAccessMemory::seek_end(int64_t p_position) {
ERR_FAIL_NULL(data);
pos = length + p_position;
pos = get_length() + p_position;
}

uint64_t FileAccessMemory::get_position() const {
ERR_FAIL_NULL_V(data, 0);
ERR_FAIL_COND_V(current_file.is_empty(), 0);
return pos;
}

uint64_t FileAccessMemory::get_length() const {
ERR_FAIL_NULL_V(data, 0);
return length;
ERR_FAIL_COND_V(current_file.is_empty(), 0);
return files->get(current_file).size();
}

bool FileAccessMemory::eof_reached() const {
return pos >= length;
return pos >= get_length();
}

uint64_t FileAccessMemory::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
Expand All @@ -126,43 +119,155 @@ uint64_t FileAccessMemory::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
}

ERR_FAIL_NULL_V(p_dst, -1);
ERR_FAIL_NULL_V(data, -1);
ERR_FAIL_COND_V(current_file.is_empty(), -1);

uint64_t left = length - pos;
uint64_t left = get_length() - pos;
uint64_t read = MIN(p_length, left);

if (read < p_length) {
WARN_PRINT("Reading less data than requested");
}

memcpy(p_dst, &data[pos], read);
memcpy(p_dst, files->get(current_file).ptrw() + pos, read);
pos += read;

return read;
}

Error FileAccessMemory::get_error() const {
return pos >= length ? ERR_FILE_EOF : OK;
return pos >= get_length() ? ERR_FILE_EOF : OK;
}

void FileAccessMemory::flush() {
ERR_FAIL_NULL(data);
ERR_FAIL_COND_MSG(current_file.is_empty(), "No opened file");
}

bool FileAccessMemory::store_buffer(const uint8_t *p_src, uint64_t p_length) {
if (!p_length) {
return true;
ERR_FAIL_COND_V(!p_src && p_length > 0, false);

PackedByteArray &p = files->get(current_file);
uint64_t length = get_length();
if (pos + p_length > length) {
p.resize(pos + p_length);
}
uint8_t *dst = p.ptrw() + pos;
memcpy(dst, p_src, p_length * sizeof(uint8_t));

pos += p_length;
return true;
}

Error DirAccessMemory::list_dir_begin() {
demolke marked this conversation as resolved.
Show resolved Hide resolved
list_items.clear();
for (auto f = files->begin(); f != files->end(); ++f) {
if (f->key.begins_with(current_dir)) {
String rest = f->key.substr(current_dir.length());
if (rest.begins_with("/")) {
rest = rest.substr(1);
}
if (!rest.is_empty()) {
list_items.push_back(rest);
}
}
}
return Error();
}

String DirAccessMemory::get_next() {
if (list_items.size()) {
current_item = list_items.front()->get();
list_items.pop_front();
return current_item;
}
return String();
}

ERR_FAIL_NULL_V(p_src, false);
bool DirAccessMemory::current_is_dir() const {
String name = current_dir.path_join(current_item);
return files->has(name) && files->get(name) == DIRECTORY;
}

uint64_t left = length - pos;
uint64_t write = MIN(p_length, left);
bool DirAccessMemory::current_is_hidden() const {
return false;
}

memcpy(&data[pos], p_src, write);
pos += write;
void DirAccessMemory::list_dir_end() {
current_item = "";
list_items.clear();
}

ERR_FAIL_COND_V_MSG(write < p_length, false, "Writing less data than requested.");
int DirAccessMemory::get_drive_count() {
return 0;
}

return true;
String DirAccessMemory::get_drive(int p_drive) {
return "";
}

Error DirAccessMemory::change_dir(String p_dir) {
String name = p_dir;
if (name.is_relative_path()) {
name = current_dir.path_join(name);
}
name = name.simplify_path();
if (name == "res://") {
files->insert(name, DIRECTORY);
}

if (dir_exists(name)) {
current_dir = name;
return OK;
}

return ERR_INVALID_PARAMETER;
}

String DirAccessMemory::get_current_dir(bool p_include_drive) const {
return current_dir;
}

String DirAccessMemory::_localize(const String &p_name) const {
String result = p_name;
if (result.is_relative_path()) {
result = current_dir.path_join(result);
}
result = result.simplify_path();
return result;
}

bool DirAccessMemory::file_exists(String p_file) {
String name = _localize(p_file);
return files->has(name) && files->get(name) != DIRECTORY;
}

bool DirAccessMemory::dir_exists(String p_dir) {
String name = _localize(p_dir);
return files->has(name) && files->get(name) == DIRECTORY;
}

Error DirAccessMemory::make_dir(String p_dir) {
String name = _localize(p_dir);
if (!dir_exists(name.get_base_dir())) {
return ERR_CANT_CREATE;
}
files->insert(name, DIRECTORY);
return OK;
}

Error DirAccessMemory::rename(String p_from, String p_to) {
return ERR_UNAVAILABLE;
}

Error DirAccessMemory::remove(String p_name) {
String name = _localize(p_name);
files->erase(name);
return OK;
}

uint64_t DirAccessMemory::get_space_left() {
return 0;
}

String DirAccessMemory::get_filesystem_type() const {
return "MEMORY";
}
45 changes: 42 additions & 3 deletions core/io/file_access_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@
#ifndef FILE_ACCESS_MEMORY_H
#define FILE_ACCESS_MEMORY_H

#include "core/io/dir_access.h"
#include "core/io/file_access.h"

class FileAccessMemory : public FileAccess {
uint8_t *data = nullptr;
uint64_t length = 0;
String current_file;
mutable uint64_t pos = 0;

static Ref<FileAccess> create();

public:
static void register_file(const String &p_name, const Vector<uint8_t> &p_data);
static void initialize();
static void cleanup();

virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file
Expand Down Expand Up @@ -79,4 +79,43 @@ class FileAccessMemory : public FileAccess {
FileAccessMemory() {}
};

class DirAccessMemory : public DirAccess {
String current_dir;
List<String> list_items;
String current_item;

String _localize(const String &p_name) const;

public:
virtual Error list_dir_begin() override;
virtual String get_next() override;
virtual bool current_is_dir() const override;
virtual bool current_is_hidden() const override;
virtual void list_dir_end() override;

virtual int get_drive_count() override;
virtual String get_drive(int p_drive) override;

virtual Error change_dir(String p_dir) override;
virtual String get_current_dir(bool p_include_drive = true) const override;

virtual bool file_exists(String p_file) override;
virtual bool dir_exists(String p_dir) override;

virtual Error make_dir(String p_dir) override;

virtual Error rename(String p_from, String p_to) override;
virtual Error remove(String p_name) override;

uint64_t get_space_left() override;

virtual bool is_link(String p_file) override { return false; }
virtual String read_link(String p_file) override { return p_file; }
virtual Error create_link(String p_source, String p_target) override { return FAILED; }

virtual String get_filesystem_type() const override;

DirAccessMemory() {}
};

#endif // FILE_ACCESS_MEMORY_H
3 changes: 3 additions & 0 deletions core/os/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ class OS {

protected:
friend class Main;
// Needed to reset default fs access on test start.
friend struct GodotTestCaseListener;
// Needed by tests to setup command-line args.
friend int test_main(int argc, char *argv[]);

Expand All @@ -115,6 +117,7 @@ class OS {

virtual void initialize() = 0;
virtual void initialize_joypads() = 0;
virtual void initialize_default_fs_access() {}

virtual void set_main_loop(MainLoop *p_main_loop) = 0;
virtual void delete_main_loop() = 0;
Expand Down
14 changes: 9 additions & 5 deletions drivers/unix/os_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,18 +154,22 @@ int OS_Unix::unix_initialize_audio(int p_audio_driver) {
return 0;
}

void OS_Unix::initialize_core() {
#ifdef THREADS_ENABLED
init_thread_posix();
#endif

void OS_Unix::initialize_default_fs_access() {
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
FileAccess::make_default<FileAccessUnixPipe>(FileAccess::ACCESS_PIPE);
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES);
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
}

void OS_Unix::initialize_core() {
#ifdef THREADS_ENABLED
init_thread_posix();
#endif

initialize_default_fs_access();

#ifndef UNIX_SOCKET_UNAVAILABLE
NetSocketUnix::make_default();
Expand Down
Loading