Replace File/Directory with FileAccess/DirAccess

This commit is contained in:
kobewi 2022-09-05 13:01:31 +02:00
parent 63c0dc690e
commit 9f2dc68279
39 changed files with 502 additions and 940 deletions

View File

@ -992,636 +992,6 @@ void Geometry3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &Geometry3D::clip_polygon); ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &Geometry3D::clip_polygon);
} }
////// File //////
Error File::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
Error err = open(p_path, p_mode_flags);
if (err) {
return err;
}
Ref<FileAccessEncrypted> fae;
fae.instantiate();
err = fae->open_and_parse(f, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
if (err) {
close();
return err;
}
f = fae;
return OK;
}
Error File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) {
Error err = open(p_path, p_mode_flags);
if (err) {
return err;
}
Ref<FileAccessEncrypted> fae;
fae.instantiate();
err = fae->open_and_parse_password(f, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
if (err) {
close();
return err;
}
f = fae;
return OK;
}
Error File::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
Ref<FileAccessCompressed> fac;
fac.instantiate();
fac->configure("GCPF", (Compression::Mode)p_compress_mode);
Error err = fac->_open(p_path, p_mode_flags);
if (err) {
return err;
}
f = fac;
return OK;
}
Error File::open(const String &p_path, ModeFlags p_mode_flags) {
Error err;
f = FileAccess::open(p_path, p_mode_flags, &err);
if (f.is_valid()) {
f->set_big_endian(big_endian);
}
return err;
}
void File::flush() {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before flushing.");
f->flush();
}
void File::close() {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened.");
f.unref();
}
bool File::is_open() const {
return f != nullptr;
}
String File::get_path() const {
ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
return f->get_path();
}
String File::get_path_absolute() const {
ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
return f->get_path_absolute();
}
void File::seek(int64_t p_position) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
ERR_FAIL_COND_MSG(p_position < 0, "Seek position must be a positive integer.");
f->seek(p_position);
}
void File::seek_end(int64_t p_position) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->seek_end(p_position);
}
uint64_t File::get_position() const {
ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_position();
}
uint64_t File::get_length() const {
ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_length();
}
bool File::eof_reached() const {
ERR_FAIL_COND_V_MSG(f.is_null(), false, "File must be opened before use, or is lacking read-write permission.");
return f->eof_reached();
}
uint8_t File::get_8() const {
ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_8();
}
uint16_t File::get_16() const {
ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_16();
}
uint32_t File::get_32() const {
ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_32();
}
uint64_t File::get_64() const {
ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_64();
}
float File::get_float() const {
ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_float();
}
double File::get_double() const {
ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_double();
}
real_t File::get_real() const {
ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
return f->get_real();
}
Vector<uint8_t> File::get_buffer(int64_t p_length) const {
Vector<uint8_t> data;
ERR_FAIL_COND_V_MSG(f.is_null(), data, "File must be opened before use, or is lacking read-write permission.");
ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0.");
if (p_length == 0) {
return data;
}
Error err = data.resize(p_length);
ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements.");
uint8_t *w = data.ptrw();
int64_t len = f->get_buffer(&w[0], p_length);
if (len < p_length) {
data.resize(len);
}
return data;
}
String File::get_as_text(bool p_skip_cr) const {
ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission.");
uint64_t original_pos = f->get_position();
const_cast<FileAccess *>(*f)->seek(0);
String text = f->get_as_utf8_string(p_skip_cr);
const_cast<FileAccess *>(*f)->seek(original_pos);
return text;
}
String File::get_md5(const String &p_path) const {
return FileAccess::get_md5(p_path);
}
String File::get_sha256(const String &p_path) const {
return FileAccess::get_sha256(p_path);
}
String File::get_line() const {
ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission.");
return f->get_line();
}
Vector<String> File::get_csv_line(const String &p_delim) const {
ERR_FAIL_COND_V_MSG(f.is_null(), Vector<String>(), "File must be opened before use, or is lacking read-write permission.");
return f->get_csv_line(p_delim);
}
/**< use this for files WRITTEN in _big_ endian machines (i.e. amiga/mac)
* It's not about the current CPU type but file formats.
* These flags get reset to false (little endian) on each open
*/
void File::set_big_endian(bool p_big_endian) {
big_endian = p_big_endian;
if (f.is_valid()) {
f->set_big_endian(p_big_endian);
}
}
bool File::is_big_endian() {
return big_endian;
}
Error File::get_error() const {
if (f.is_null()) {
return ERR_UNCONFIGURED;
}
return f->get_error();
}
void File::store_8(uint8_t p_dest) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_8(p_dest);
}
void File::store_16(uint16_t p_dest) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_16(p_dest);
}
void File::store_32(uint32_t p_dest) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_32(p_dest);
}
void File::store_64(uint64_t p_dest) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_64(p_dest);
}
void File::store_float(float p_dest) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_float(p_dest);
}
void File::store_double(double p_dest) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_double(p_dest);
}
void File::store_real(real_t p_real) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_real(p_real);
}
void File::store_string(const String &p_string) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_string(p_string);
}
void File::store_pascal_string(const String &p_string) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_pascal_string(p_string);
}
String File::get_pascal_string() {
ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
return f->get_pascal_string();
}
void File::store_line(const String &p_string) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_line(p_string);
}
void File::store_csv_line(const Vector<String> &p_values, const String &p_delim) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
f->store_csv_line(p_values, p_delim);
}
void File::store_buffer(const Vector<uint8_t> &p_buffer) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
uint64_t len = p_buffer.size();
if (len == 0) {
return;
}
const uint8_t *r = p_buffer.ptr();
f->store_buffer(&r[0], len);
}
bool File::file_exists(const String &p_name) {
return FileAccess::exists(p_name);
}
void File::store_var(const Variant &p_var, bool p_full_objects) {
ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
int len;
Error err = encode_variant(p_var, nullptr, len, p_full_objects);
ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
Vector<uint8_t> buff;
buff.resize(len);
uint8_t *w = buff.ptrw();
err = encode_variant(p_var, &w[0], len, p_full_objects);
ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
store_32(len);
store_buffer(buff);
}
Variant File::get_var(bool p_allow_objects) const {
ERR_FAIL_COND_V_MSG(f.is_null(), Variant(), "File must be opened before use, or is lacking read-write permission.");
uint32_t len = get_32();
Vector<uint8_t> buff = get_buffer(len);
ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant());
const uint8_t *r = buff.ptr();
Variant v;
Error err = decode_variant(v, &r[0], len, nullptr, p_allow_objects);
ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to encode Variant.");
return v;
}
uint64_t File::get_modified_time(const String &p_file) const {
return FileAccess::get_modified_time(p_file);
}
void File::_bind_methods() {
ClassDB::bind_method(D_METHOD("open_encrypted", "path", "mode_flags", "key"), &File::open_encrypted);
ClassDB::bind_method(D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &File::open_encrypted_pass);
ClassDB::bind_method(D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &File::open_compressed, DEFVAL(0));
ClassDB::bind_method(D_METHOD("open", "path", "flags"), &File::open);
ClassDB::bind_method(D_METHOD("flush"), &File::flush);
ClassDB::bind_method(D_METHOD("close"), &File::close);
ClassDB::bind_method(D_METHOD("get_path"), &File::get_path);
ClassDB::bind_method(D_METHOD("get_path_absolute"), &File::get_path_absolute);
ClassDB::bind_method(D_METHOD("is_open"), &File::is_open);
ClassDB::bind_method(D_METHOD("seek", "position"), &File::seek);
ClassDB::bind_method(D_METHOD("seek_end", "position"), &File::seek_end, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_position"), &File::get_position);
ClassDB::bind_method(D_METHOD("get_length"), &File::get_length);
ClassDB::bind_method(D_METHOD("eof_reached"), &File::eof_reached);
ClassDB::bind_method(D_METHOD("get_8"), &File::get_8);
ClassDB::bind_method(D_METHOD("get_16"), &File::get_16);
ClassDB::bind_method(D_METHOD("get_32"), &File::get_32);
ClassDB::bind_method(D_METHOD("get_64"), &File::get_64);
ClassDB::bind_method(D_METHOD("get_float"), &File::get_float);
ClassDB::bind_method(D_METHOD("get_double"), &File::get_double);
ClassDB::bind_method(D_METHOD("get_real"), &File::get_real);
ClassDB::bind_method(D_METHOD("get_buffer", "length"), &File::get_buffer);
ClassDB::bind_method(D_METHOD("get_line"), &File::get_line);
ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &File::get_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &File::get_as_text, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_md5", "path"), &File::get_md5);
ClassDB::bind_method(D_METHOD("get_sha256", "path"), &File::get_sha256);
ClassDB::bind_method(D_METHOD("is_big_endian"), &File::is_big_endian);
ClassDB::bind_method(D_METHOD("set_big_endian", "big_endian"), &File::set_big_endian);
ClassDB::bind_method(D_METHOD("get_error"), &File::get_error);
ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &File::get_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("store_8", "value"), &File::store_8);
ClassDB::bind_method(D_METHOD("store_16", "value"), &File::store_16);
ClassDB::bind_method(D_METHOD("store_32", "value"), &File::store_32);
ClassDB::bind_method(D_METHOD("store_64", "value"), &File::store_64);
ClassDB::bind_method(D_METHOD("store_float", "value"), &File::store_float);
ClassDB::bind_method(D_METHOD("store_double", "value"), &File::store_double);
ClassDB::bind_method(D_METHOD("store_real", "value"), &File::store_real);
ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &File::store_buffer);
ClassDB::bind_method(D_METHOD("store_line", "line"), &File::store_line);
ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &File::store_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("store_string", "string"), &File::store_string);
ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &File::store_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &File::store_pascal_string);
ClassDB::bind_method(D_METHOD("get_pascal_string"), &File::get_pascal_string);
ClassDB::bind_static_method("File", D_METHOD("file_exists", "path"), &File::file_exists);
ClassDB::bind_method(D_METHOD("get_modified_time", "file"), &File::get_modified_time);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
BIND_ENUM_CONSTANT(READ);
BIND_ENUM_CONSTANT(WRITE);
BIND_ENUM_CONSTANT(READ_WRITE);
BIND_ENUM_CONSTANT(WRITE_READ);
BIND_ENUM_CONSTANT(COMPRESSION_FASTLZ);
BIND_ENUM_CONSTANT(COMPRESSION_DEFLATE);
BIND_ENUM_CONSTANT(COMPRESSION_ZSTD);
BIND_ENUM_CONSTANT(COMPRESSION_GZIP);
}
////// Directory //////
Error Directory::open(const String &p_path) {
Error err;
Ref<DirAccess> alt = DirAccess::open(p_path, &err);
if (alt.is_null()) {
return err;
}
d = alt;
dir_open = true;
return OK;
}
bool Directory::is_open() const {
return d.is_valid() && dir_open;
}
Error Directory::list_dir_begin() {
ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
return d->list_dir_begin();
}
String Directory::get_next() {
ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
String next = d->get_next();
while (!next.is_empty() && ((!include_navigational && (next == "." || next == "..")) || (!include_hidden && d->current_is_hidden()))) {
next = d->get_next();
}
return next;
}
bool Directory::current_is_dir() const {
ERR_FAIL_COND_V_MSG(!is_open(), false, "Directory must be opened before use.");
return d->current_is_dir();
}
void Directory::list_dir_end() {
ERR_FAIL_COND_MSG(!is_open(), "Directory must be opened before use.");
d->list_dir_end();
}
PackedStringArray Directory::get_files() {
return _get_contents(false);
}
PackedStringArray Directory::get_directories() {
return _get_contents(true);
}
PackedStringArray Directory::_get_contents(bool p_directories) {
PackedStringArray ret;
ERR_FAIL_COND_V_MSG(!is_open(), ret, "Directory must be opened before use.");
list_dir_begin();
String s = get_next();
while (!s.is_empty()) {
if (current_is_dir() == p_directories) {
ret.append(s);
}
s = get_next();
}
ret.sort();
return ret;
}
void Directory::set_include_navigational(bool p_enable) {
include_navigational = p_enable;
}
bool Directory::get_include_navigational() const {
return include_navigational;
}
void Directory::set_include_hidden(bool p_enable) {
include_hidden = p_enable;
}
bool Directory::get_include_hidden() const {
return include_hidden;
}
int Directory::get_drive_count() {
ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
return d->get_drive_count();
}
String Directory::get_drive(int p_drive) {
ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
return d->get_drive(p_drive);
}
int Directory::get_current_drive() {
ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
return d->get_current_drive();
}
Error Directory::change_dir(String p_dir) {
ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
Error err = d->change_dir(p_dir);
if (err != OK) {
return err;
}
dir_open = true;
return OK;
}
String Directory::get_current_dir() {
ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
return d->get_current_dir();
}
Error Directory::make_dir(String p_dir) {
ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
if (!p_dir.is_relative_path()) {
Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
return da->make_dir(p_dir);
}
return d->make_dir(p_dir);
}
Error Directory::make_dir_recursive(String p_dir) {
ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
if (!p_dir.is_relative_path()) {
Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
return da->make_dir_recursive(p_dir);
}
return d->make_dir_recursive(p_dir);
}
bool Directory::file_exists(String p_file) {
ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly.");
if (!p_file.is_relative_path()) {
return FileAccess::exists(p_file);
}
return d->file_exists(p_file);
}
bool Directory::dir_exists(String p_dir) {
ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly.");
if (!p_dir.is_relative_path()) {
return DirAccess::exists(p_dir);
}
return d->dir_exists(p_dir);
}
uint64_t Directory::get_space_left() {
ERR_FAIL_COND_V_MSG(d.is_null(), 0, "Directory must be opened before use.");
return d->get_space_left() / 1024 * 1024; // Truncate to closest MiB.
}
Error Directory::copy(String p_from, String p_to) {
ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
return d->copy(p_from, p_to);
}
Error Directory::rename(String p_from, String p_to) {
ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
ERR_FAIL_COND_V_MSG(p_from.is_empty() || p_from == "." || p_from == "..", ERR_INVALID_PARAMETER, "Invalid path to rename.");
if (!p_from.is_relative_path()) {
Ref<DirAccess> da = DirAccess::create_for_path(p_from);
ERR_FAIL_COND_V_MSG(!da->file_exists(p_from) && !da->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
return da->rename(p_from, p_to);
}
ERR_FAIL_COND_V_MSG(!d->file_exists(p_from) && !d->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
return d->rename(p_from, p_to);
}
Error Directory::remove(String p_name) {
ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
if (!p_name.is_relative_path()) {
Ref<DirAccess> da = DirAccess::create_for_path(p_name);
return da->remove(p_name);
}
return d->remove(p_name);
}
void Directory::_bind_methods() {
ClassDB::bind_method(D_METHOD("open", "path"), &Directory::open);
ClassDB::bind_method(D_METHOD("list_dir_begin"), &Directory::list_dir_begin, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_next"), &Directory::get_next);
ClassDB::bind_method(D_METHOD("current_is_dir"), &Directory::current_is_dir);
ClassDB::bind_method(D_METHOD("list_dir_end"), &Directory::list_dir_end);
ClassDB::bind_method(D_METHOD("get_files"), &Directory::get_files);
ClassDB::bind_method(D_METHOD("get_directories"), &Directory::get_directories);
ClassDB::bind_method(D_METHOD("get_drive_count"), &Directory::get_drive_count);
ClassDB::bind_method(D_METHOD("get_drive", "idx"), &Directory::get_drive);
ClassDB::bind_method(D_METHOD("get_current_drive"), &Directory::get_current_drive);
ClassDB::bind_method(D_METHOD("change_dir", "todir"), &Directory::change_dir);
ClassDB::bind_method(D_METHOD("get_current_dir"), &Directory::get_current_dir);
ClassDB::bind_method(D_METHOD("make_dir", "path"), &Directory::make_dir);
ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &Directory::make_dir_recursive);
ClassDB::bind_method(D_METHOD("file_exists", "path"), &Directory::file_exists);
ClassDB::bind_method(D_METHOD("dir_exists", "path"), &Directory::dir_exists);
ClassDB::bind_method(D_METHOD("get_space_left"), &Directory::get_space_left);
ClassDB::bind_method(D_METHOD("copy", "from", "to"), &Directory::copy);
ClassDB::bind_method(D_METHOD("rename", "from", "to"), &Directory::rename);
ClassDB::bind_method(D_METHOD("remove", "path"), &Directory::remove);
ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &Directory::set_include_navigational);
ClassDB::bind_method(D_METHOD("get_include_navigational"), &Directory::get_include_navigational);
ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &Directory::set_include_hidden);
ClassDB::bind_method(D_METHOD("get_include_hidden"), &Directory::get_include_hidden);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
}
Directory::Directory() {
d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
}
////// Marshalls ////// ////// Marshalls //////
Marshalls *Marshalls::singleton = nullptr; Marshalls *Marshalls::singleton = nullptr;

View File

@ -355,156 +355,6 @@ public:
Geometry3D() { singleton = this; } Geometry3D() { singleton = this; }
}; };
class File : public RefCounted {
GDCLASS(File, RefCounted);
Ref<FileAccess> f;
bool big_endian = false;
protected:
static void _bind_methods();
public:
enum ModeFlags {
READ = 1,
WRITE = 2,
READ_WRITE = 3,
WRITE_READ = 7,
};
enum CompressionMode {
COMPRESSION_FASTLZ = Compression::MODE_FASTLZ,
COMPRESSION_DEFLATE = Compression::MODE_DEFLATE,
COMPRESSION_ZSTD = Compression::MODE_ZSTD,
COMPRESSION_GZIP = Compression::MODE_GZIP
};
Error open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
Error open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
Error open(const String &p_path, ModeFlags p_mode_flags); // open a file.
void flush(); // Flush a file (write its buffer to disk).
void close(); // Close a file.
bool is_open() const; // True when file is open.
String get_path() const; // Returns the path for the current open file.
String get_path_absolute() const; // Returns the absolute path for the current open file.
void seek(int64_t p_position); // Seek to a given position.
void seek_end(int64_t p_position = 0); // Seek from the end of file.
uint64_t get_position() const; // Get position in the file.
uint64_t get_length() const; // Get size of the file.
bool eof_reached() const; // Reading passed EOF.
uint8_t get_8() const; // Get a byte.
uint16_t get_16() const; // Get 16 bits uint.
uint32_t get_32() const; // Get 32 bits uint.
uint64_t get_64() const; // Get 64 bits uint.
float get_float() const;
double get_double() const;
real_t get_real() const;
Variant get_var(bool p_allow_objects = false) const;
Vector<uint8_t> get_buffer(int64_t p_length) const; // Get an array of bytes.
String get_line() const;
Vector<String> get_csv_line(const String &p_delim = ",") const;
String get_as_text(bool p_skip_cr = false) const;
String get_md5(const String &p_path) const;
String get_sha256(const String &p_path) const;
/*
* Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac).
* It's not about the current CPU type but file formats.
* This flag gets reset to `false` (little endian) on each open.
*/
void set_big_endian(bool p_big_endian);
bool is_big_endian();
Error get_error() const; // Get last error.
void store_8(uint8_t p_dest); // Store a byte.
void store_16(uint16_t p_dest); // Store 16 bits uint.
void store_32(uint32_t p_dest); // Store 32 bits uint.
void store_64(uint64_t p_dest); // Store 64 bits uint.
void store_float(float p_dest);
void store_double(double p_dest);
void store_real(real_t p_real);
void store_string(const String &p_string);
void store_line(const String &p_string);
void store_csv_line(const Vector<String> &p_values, const String &p_delim = ",");
virtual void store_pascal_string(const String &p_string);
virtual String get_pascal_string();
void store_buffer(const Vector<uint8_t> &p_buffer); // Store an array of bytes.
void store_var(const Variant &p_var, bool p_full_objects = false);
static bool file_exists(const String &p_name); // Return true if a file exists.
uint64_t get_modified_time(const String &p_file) const;
File() {}
};
class Directory : public RefCounted {
GDCLASS(Directory, RefCounted);
Ref<DirAccess> d;
bool dir_open = false;
bool include_navigational = false;
bool include_hidden = false;
protected:
static void _bind_methods();
public:
Error open(const String &p_path);
bool is_open() const;
Error list_dir_begin();
String get_next();
bool current_is_dir() const;
void list_dir_end();
PackedStringArray get_files();
PackedStringArray get_directories();
PackedStringArray _get_contents(bool p_directories);
void set_include_navigational(bool p_enable);
bool get_include_navigational() const;
void set_include_hidden(bool p_enable);
bool get_include_hidden() const;
int get_drive_count();
String get_drive(int p_drive);
int get_current_drive();
Error change_dir(String p_dir); // Can be relative or absolute, return false on success.
String get_current_dir(); // Return current dir location.
Error make_dir(String p_dir);
Error make_dir_recursive(String p_dir);
bool file_exists(String p_file);
bool dir_exists(String p_dir);
uint64_t get_space_left();
Error copy(String p_from, String p_to);
Error rename(String p_from, String p_to);
Error remove(String p_name);
Directory();
};
class Marshalls : public Object { class Marshalls : public Object {
GDCLASS(Marshalls, Object); GDCLASS(Marshalls, Object);
@ -738,9 +588,6 @@ VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType); VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType); VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType);
VARIANT_ENUM_CAST(core_bind::File::ModeFlags);
VARIANT_ENUM_CAST(core_bind::File::CompressionMode);
VARIANT_ENUM_CAST(core_bind::Thread::Priority); VARIANT_ENUM_CAST(core_bind::Thread::Priority);
#endif // CORE_BIND_H #endif // CORE_BIND_H

View File

@ -36,6 +36,8 @@
#include "core/os/os.h" #include "core/os/os.h"
#include "core/templates/local_vector.h" #include "core/templates/local_vector.h"
thread_local Error DirAccess::last_dir_open_error = OK;
String DirAccess::_get_root_path() const { String DirAccess::_get_root_path() const {
switch (_access_type) { switch (_access_type) {
case ACCESS_RESOURCES: case ACCESS_RESOURCES:
@ -249,6 +251,16 @@ Ref<DirAccess> DirAccess::open(const String &p_path, Error *r_error) {
return da; return da;
} }
Ref<DirAccess> DirAccess::_open(const String &p_path) {
Error err = OK;
Ref<DirAccess> da = open(p_path, &err);
last_dir_open_error = err;
if (err) {
return Ref<DirAccess>();
}
return da;
}
Ref<DirAccess> DirAccess::create(AccessType p_access) { Ref<DirAccess> DirAccess::create(AccessType p_access) {
Ref<DirAccess> da = create_func[p_access] ? create_func[p_access]() : nullptr; Ref<DirAccess> da = create_func[p_access] ? create_func[p_access]() : nullptr;
if (da.is_valid()) { if (da.is_valid()) {
@ -266,6 +278,10 @@ Ref<DirAccess> DirAccess::create(AccessType p_access) {
return da; return da;
} }
Error DirAccess::get_open_error() {
return last_dir_open_error;
}
String DirAccess::get_full_path(const String &p_path, AccessType p_access) { String DirAccess::get_full_path(const String &p_path, AccessType p_access) {
Ref<DirAccess> d = DirAccess::create(p_access); Ref<DirAccess> d = DirAccess::create(p_access);
if (d.is_null()) { if (d.is_null()) {
@ -424,3 +440,84 @@ bool DirAccess::exists(String p_dir) {
Ref<DirAccess> da = DirAccess::create_for_path(p_dir); Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
return da->change_dir(p_dir) == OK; return da->change_dir(p_dir) == OK;
} }
PackedStringArray DirAccess::get_files() {
return _get_contents(false);
}
PackedStringArray DirAccess::get_directories() {
return _get_contents(true);
}
PackedStringArray DirAccess::_get_contents(bool p_directories) {
PackedStringArray ret;
list_dir_begin();
String s = _get_next();
while (!s.is_empty()) {
if (current_is_dir() == p_directories) {
ret.append(s);
}
s = _get_next();
}
ret.sort();
return ret;
}
String DirAccess::_get_next() {
String next = get_next();
while (!next.is_empty() && ((!include_navigational && (next == "." || next == "..")) || (!include_hidden && current_is_hidden()))) {
next = get_next();
}
return next;
}
void DirAccess::set_include_navigational(bool p_enable) {
include_navigational = p_enable;
}
bool DirAccess::get_include_navigational() const {
return include_navigational;
}
void DirAccess::set_include_hidden(bool p_enable) {
include_hidden = p_enable;
}
bool DirAccess::get_include_hidden() const {
return include_hidden;
}
void DirAccess::_bind_methods() {
ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
ClassDB::bind_method(D_METHOD("list_dir_begin"), &DirAccess::list_dir_begin, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_next"), &DirAccess::_get_next);
ClassDB::bind_method(D_METHOD("current_is_dir"), &DirAccess::current_is_dir);
ClassDB::bind_method(D_METHOD("list_dir_end"), &DirAccess::list_dir_end);
ClassDB::bind_method(D_METHOD("get_files"), &DirAccess::get_files);
ClassDB::bind_method(D_METHOD("get_directories"), &DirAccess::get_directories);
ClassDB::bind_method(D_METHOD("get_drive_count"), &DirAccess::get_drive_count);
ClassDB::bind_method(D_METHOD("get_drive", "idx"), &DirAccess::get_drive);
ClassDB::bind_method(D_METHOD("get_current_drive"), &DirAccess::get_current_drive);
ClassDB::bind_method(D_METHOD("change_dir", "todir"), &DirAccess::change_dir);
ClassDB::bind_method(D_METHOD("get_current_dir", "include_drive"), &DirAccess::get_current_dir, DEFVAL(true));
ClassDB::bind_method(D_METHOD("make_dir", "path"), &DirAccess::make_dir);
ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &DirAccess::make_dir_recursive);
ClassDB::bind_method(D_METHOD("file_exists", "path"), &DirAccess::file_exists);
ClassDB::bind_method(D_METHOD("dir_exists", "path"), &DirAccess::dir_exists);
ClassDB::bind_method(D_METHOD("get_space_left"), &DirAccess::get_space_left);
ClassDB::bind_method(D_METHOD("copy", "from", "to", "chmod_flags"), &DirAccess::copy, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("rename", "from", "to"), &DirAccess::rename);
ClassDB::bind_method(D_METHOD("remove", "path"), &DirAccess::remove);
ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &DirAccess::set_include_navigational);
ClassDB::bind_method(D_METHOD("get_include_navigational"), &DirAccess::get_include_navigational);
ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden);
ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
}

View File

@ -37,6 +37,8 @@
//@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies //@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies
class DirAccess : public RefCounted { class DirAccess : public RefCounted {
GDCLASS(DirAccess, RefCounted);
public: public:
enum AccessType { enum AccessType {
ACCESS_RESOURCES, ACCESS_RESOURCES,
@ -53,7 +55,13 @@ private:
Error _copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod_flags, bool p_copy_links); Error _copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod_flags, bool p_copy_links);
thread_local static Error last_dir_open_error;
bool include_navigational = false;
bool include_hidden = false;
protected: protected:
static void _bind_methods();
String _get_root_path() const; String _get_root_path() const;
virtual String _get_root_string() const; virtual String _get_root_string() const;
@ -118,6 +126,7 @@ public:
static Ref<DirAccess> create_for_path(const String &p_path); static Ref<DirAccess> create_for_path(const String &p_path);
static Ref<DirAccess> create(AccessType p_access); static Ref<DirAccess> create(AccessType p_access);
static Error get_open_error();
template <class T> template <class T>
static void make_default(AccessType p_access) { static void make_default(AccessType p_access) {
@ -125,6 +134,17 @@ public:
} }
static Ref<DirAccess> open(const String &p_path, Error *r_error = nullptr); static Ref<DirAccess> open(const String &p_path, Error *r_error = nullptr);
static Ref<DirAccess> _open(const String &p_path);
PackedStringArray get_files();
PackedStringArray get_directories();
PackedStringArray _get_contents(bool p_directories);
String _get_next();
void set_include_navigational(bool p_enable);
bool get_include_navigational() const;
void set_include_hidden(bool p_enable);
bool get_include_hidden() const;
DirAccess() {} DirAccess() {}
virtual ~DirAccess() {} virtual ~DirAccess() {}

View File

@ -32,6 +32,8 @@
#include "core/config/project_settings.h" #include "core/config/project_settings.h"
#include "core/crypto/crypto_core.h" #include "core/crypto/crypto_core.h"
#include "core/io/file_access_compressed.h"
#include "core/io/file_access_encrypted.h"
#include "core/io/file_access_pack.h" #include "core/io/file_access_pack.h"
#include "core/io/marshalls.h" #include "core/io/marshalls.h"
#include "core/os/os.h" #include "core/os/os.h"
@ -41,6 +43,7 @@ FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = { nullptr, nullptr
FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = nullptr; FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = nullptr;
bool FileAccess::backup_save = false; bool FileAccess::backup_save = false;
thread_local Error FileAccess::last_file_open_error = OK;
Ref<FileAccess> FileAccess::create(AccessType p_access) { Ref<FileAccess> FileAccess::create(AccessType p_access) {
ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr); ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr);
@ -81,7 +84,7 @@ Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
} }
Error FileAccess::reopen(const String &p_path, int p_mode_flags) { Error FileAccess::reopen(const String &p_path, int p_mode_flags) {
return _open(p_path, p_mode_flags); return open_internal(p_path, p_mode_flags);
} }
Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) { Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) {
@ -99,7 +102,7 @@ Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *
} }
ret = create_for_path(p_path); ret = create_for_path(p_path);
Error err = ret->_open(p_path, p_mode_flags); Error err = ret->open_internal(p_path, p_mode_flags);
if (r_error) { if (r_error) {
*r_error = err; *r_error = err;
@ -111,6 +114,66 @@ Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *
return ret; return ret;
} }
Ref<FileAccess> FileAccess::_open(const String &p_path, ModeFlags p_mode_flags) {
Error err = OK;
Ref<FileAccess> fa = open(p_path, p_mode_flags, &err);
last_file_open_error = err;
if (err) {
return Ref<FileAccess>();
}
return fa;
}
Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
Ref<FileAccess> fa = _open(p_path, p_mode_flags);
if (fa.is_null()) {
return fa;
}
Ref<FileAccessEncrypted> fae;
fae.instantiate();
Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
if (err) {
last_file_open_error = err;
return Ref<FileAccess>();
}
return fae;
}
Ref<FileAccess> FileAccess::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) {
Ref<FileAccess> fa = _open(p_path, p_mode_flags);
if (fa.is_null()) {
return fa;
}
Ref<FileAccessEncrypted> fae;
fae.instantiate();
Error err = fae->open_and_parse_password(fa, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
if (err) {
last_file_open_error = err;
return Ref<FileAccess>();
}
return fae;
}
Ref<FileAccess> FileAccess::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
Ref<FileAccessCompressed> fac;
fac.instantiate();
fac->configure("GCPF", (Compression::Mode)p_compress_mode);
Error err = fac->open_internal(p_path, p_mode_flags);
if (err) {
last_file_open_error = err;
return Ref<FileAccess>();
}
return fac;
}
Error FileAccess::get_open_error() {
return last_file_open_error;
}
FileAccess::CreateFunc FileAccess::get_create_func(AccessType p_access) { FileAccess::CreateFunc FileAccess::get_create_func(AccessType p_access) {
return create_func[p_access]; return create_func[p_access];
} }
@ -227,6 +290,20 @@ real_t FileAccess::get_real() const {
} }
} }
Variant FileAccess::get_var(bool p_allow_objects) const {
uint32_t len = get_32();
Vector<uint8_t> buff = _get_buffer(len);
ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant());
const uint8_t *r = buff.ptr();
Variant v;
Error err = decode_variant(v, &r[0], len, nullptr, p_allow_objects);
ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to encode Variant.");
return v;
}
double FileAccess::get_double() const { double FileAccess::get_double() const {
MarshallDouble m; MarshallDouble m;
m.l = get_64(); m.l = get_64();
@ -370,6 +447,17 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
return strings; return strings;
} }
String FileAccess::get_as_text(bool p_skip_cr) const {
uint64_t original_pos = get_position();
const_cast<FileAccess *>(this)->seek(0);
String text = get_as_utf8_string(p_skip_cr);
const_cast<FileAccess *>(this)->seek(original_pos);
return text;
}
uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const { uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
@ -381,6 +469,27 @@ uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
return i; return i;
} }
Vector<uint8_t> FileAccess::_get_buffer(int64_t p_length) const {
Vector<uint8_t> data;
ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0.");
if (p_length == 0) {
return data;
}
Error err = data.resize(p_length);
ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements.");
uint8_t *w = data.ptrw();
int64_t len = get_buffer(&w[0], p_length);
if (len < p_length) {
data.resize(len);
}
return data;
}
String FileAccess::get_as_utf8_string(bool p_skip_cr) const { String FileAccess::get_as_utf8_string(bool p_skip_cr) const {
Vector<uint8_t> sourcef; Vector<uint8_t> sourcef;
uint64_t len = get_length(); uint64_t len = get_length();
@ -554,6 +663,33 @@ void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
} }
} }
void FileAccess::_store_buffer(const Vector<uint8_t> &p_buffer) {
uint64_t len = p_buffer.size();
if (len == 0) {
return;
}
const uint8_t *r = p_buffer.ptr();
store_buffer(&r[0], len);
}
void FileAccess::store_var(const Variant &p_var, bool p_full_objects) {
int len;
Error err = encode_variant(p_var, nullptr, len, p_full_objects);
ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
Vector<uint8_t> buff;
buff.resize(len);
uint8_t *w = buff.ptrw();
err = encode_variant(p_var, &w[0], len, p_full_objects);
ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
store_32(len);
_store_buffer(buff);
}
Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) { Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) {
Ref<FileAccess> f = FileAccess::open(p_path, READ, r_error); Ref<FileAccess> f = FileAccess::open(p_path, READ, r_error);
if (f.is_null()) { if (f.is_null()) {
@ -666,3 +802,69 @@ String FileAccess::get_sha256(const String &p_file) {
return String::hex_encode_buffer(hash, 32); return String::hex_encode_buffer(hash, 32);
} }
void FileAccess::_bind_methods() {
ClassDB::bind_static_method("FileAccess", D_METHOD("open", "path", "flags"), &FileAccess::_open);
ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::open_encrypted);
ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &FileAccess::open_encrypted_pass);
ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0));
ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error);
ClassDB::bind_method(D_METHOD("flush"), &FileAccess::flush);
ClassDB::bind_method(D_METHOD("get_path"), &FileAccess::get_path);
ClassDB::bind_method(D_METHOD("get_path_absolute"), &FileAccess::get_path_absolute);
ClassDB::bind_method(D_METHOD("is_open"), &FileAccess::is_open);
ClassDB::bind_method(D_METHOD("seek", "position"), &FileAccess::seek);
ClassDB::bind_method(D_METHOD("seek_end", "position"), &FileAccess::seek_end, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_position"), &FileAccess::get_position);
ClassDB::bind_method(D_METHOD("get_length"), &FileAccess::get_length);
ClassDB::bind_method(D_METHOD("eof_reached"), &FileAccess::eof_reached);
ClassDB::bind_method(D_METHOD("get_8"), &FileAccess::get_8);
ClassDB::bind_method(D_METHOD("get_16"), &FileAccess::get_16);
ClassDB::bind_method(D_METHOD("get_32"), &FileAccess::get_32);
ClassDB::bind_method(D_METHOD("get_64"), &FileAccess::get_64);
ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
ClassDB::bind_method(D_METHOD("get_buffer", "length"), &FileAccess::_get_buffer);
ClassDB::bind_method(D_METHOD("get_line"), &FileAccess::get_line);
ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text, DEFVAL(false));
ClassDB::bind_static_method("FileAccess", D_METHOD("get_md5", "path"), &FileAccess::get_md5);
ClassDB::bind_static_method("FileAccess", D_METHOD("get_sha256", "path"), &FileAccess::get_sha256);
ClassDB::bind_method(D_METHOD("is_big_endian"), &FileAccess::is_big_endian);
ClassDB::bind_method(D_METHOD("set_big_endian", "big_endian"), &FileAccess::set_big_endian);
ClassDB::bind_method(D_METHOD("get_error"), &FileAccess::get_error);
ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &FileAccess::get_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("store_8", "value"), &FileAccess::store_8);
ClassDB::bind_method(D_METHOD("store_16", "value"), &FileAccess::store_16);
ClassDB::bind_method(D_METHOD("store_32", "value"), &FileAccess::store_32);
ClassDB::bind_method(D_METHOD("store_64", "value"), &FileAccess::store_64);
ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &FileAccess::_store_buffer);
ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line);
ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string);
ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &FileAccess::store_var, DEFVAL(false));
ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &FileAccess::store_pascal_string);
ClassDB::bind_method(D_METHOD("get_pascal_string"), &FileAccess::get_pascal_string);
ClassDB::bind_static_method("FileAccess", D_METHOD("file_exists", "path"), &FileAccess::exists);
ClassDB::bind_static_method("FileAccess", D_METHOD("get_modified_time", "file"), &FileAccess::get_modified_time);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
BIND_ENUM_CONSTANT(READ);
BIND_ENUM_CONSTANT(WRITE);
BIND_ENUM_CONSTANT(READ_WRITE);
BIND_ENUM_CONSTANT(WRITE_READ);
BIND_ENUM_CONSTANT(COMPRESSION_FASTLZ);
BIND_ENUM_CONSTANT(COMPRESSION_DEFLATE);
BIND_ENUM_CONSTANT(COMPRESSION_ZSTD);
BIND_ENUM_CONSTANT(COMPRESSION_GZIP);
}

View File

@ -31,6 +31,7 @@
#ifndef FILE_ACCESS_H #ifndef FILE_ACCESS_H
#define FILE_ACCESS_H #define FILE_ACCESS_H
#include "core/io/compression.h"
#include "core/math/math_defs.h" #include "core/math/math_defs.h"
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
#include "core/os/memory.h" #include "core/os/memory.h"
@ -42,6 +43,8 @@
*/ */
class FileAccess : public RefCounted { class FileAccess : public RefCounted {
GDCLASS(FileAccess, RefCounted);
public: public:
enum AccessType { enum AccessType {
ACCESS_RESOURCES, ACCESS_RESOURCES,
@ -60,15 +63,18 @@ public:
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0; virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0;
protected: protected:
static void _bind_methods();
AccessType get_access_type() const; AccessType get_access_type() const;
String fix_path(const String &p_path) const; String fix_path(const String &p_path) const;
virtual Error _open(const String &p_path, int p_mode_flags) = 0; ///< open a file virtual Error open_internal(const String &p_path, int p_mode_flags) = 0; ///< open a file
virtual uint64_t _get_modified_time(const String &p_file) = 0; virtual uint64_t _get_modified_time(const String &p_file) = 0;
static FileCloseFailNotify close_fail_notify; static FileCloseFailNotify close_fail_notify;
private: private:
static bool backup_save; static bool backup_save;
thread_local static Error last_file_open_error;
AccessType _access_type = ACCESS_FILESYSTEM; AccessType _access_type = ACCESS_FILESYSTEM;
static CreateFunc create_func[ACCESS_MAX]; /** default file access creation function for a platform */ static CreateFunc create_func[ACCESS_MAX]; /** default file access creation function for a platform */
@ -89,6 +95,13 @@ public:
WRITE_READ = 7, WRITE_READ = 7,
}; };
enum CompressionMode {
COMPRESSION_FASTLZ = Compression::MODE_FASTLZ,
COMPRESSION_DEFLATE = Compression::MODE_DEFLATE,
COMPRESSION_ZSTD = Compression::MODE_ZSTD,
COMPRESSION_GZIP = Compression::MODE_GZIP
};
virtual bool is_open() const = 0; ///< true when file is open virtual bool is_open() const = 0; ///< true when file is open
virtual String get_path() const { return ""; } /// returns the path for the current open file virtual String get_path() const { return ""; } /// returns the path for the current open file
@ -110,10 +123,14 @@ public:
virtual double get_double() const; virtual double get_double() const;
virtual real_t get_real() const; virtual real_t get_real() const;
Variant get_var(bool p_allow_objects = false) const;
virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
Vector<uint8_t> _get_buffer(int64_t p_length) const;
virtual String get_line() const; virtual String get_line() const;
virtual String get_token() const; virtual String get_token() const;
virtual Vector<String> get_csv_line(const String &p_delim = ",") const; virtual Vector<String> get_csv_line(const String &p_delim = ",") const;
String get_as_text(bool p_skip_cr = false) const;
virtual String get_as_utf8_string(bool p_skip_cr = false) const; virtual String get_as_utf8_string(bool p_skip_cr = false) const;
/** /**
@ -144,6 +161,9 @@ public:
virtual String get_pascal_string(); virtual String get_pascal_string();
virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
void _store_buffer(const Vector<uint8_t> &p_buffer);
void store_var(const Variant &p_var, bool p_full_objects = false);
virtual bool file_exists(const String &p_name) = 0; ///< return true if a file exists virtual bool file_exists(const String &p_name) = 0; ///< return true if a file exists
@ -152,6 +172,13 @@ public:
static Ref<FileAccess> create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files. static Ref<FileAccess> create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files.
static Ref<FileAccess> create_for_path(const String &p_path); static Ref<FileAccess> create_for_path(const String &p_path);
static Ref<FileAccess> open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files. static Ref<FileAccess> open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files.
static Ref<FileAccess> _open(const String &p_path, ModeFlags p_mode_flags);
static Ref<FileAccess> open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
static Ref<FileAccess> open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
static Ref<FileAccess> open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
static Error get_open_error();
static CreateFunc get_create_func(AccessType p_access); static CreateFunc get_create_func(AccessType p_access);
static bool exists(const String &p_name); ///< return true if a file exists static bool exists(const String &p_name); ///< return true if a file exists
static uint64_t get_modified_time(const String &p_file); static uint64_t get_modified_time(const String &p_file);
@ -177,4 +204,7 @@ public:
virtual ~FileAccess() {} virtual ~FileAccess() {}
}; };
VARIANT_ENUM_CAST(FileAccess::CompressionMode);
VARIANT_ENUM_CAST(FileAccess::ModeFlags);
#endif // FILE_ACCESS_H #endif // FILE_ACCESS_H

View File

@ -95,7 +95,7 @@ Error FileAccessCompressed::open_after_magic(Ref<FileAccess> p_base) {
return ret == -1 ? ERR_FILE_CORRUPT : OK; return ret == -1 ? ERR_FILE_CORRUPT : OK;
} }
Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) { Error FileAccessCompressed::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags == READ_WRITE, ERR_UNAVAILABLE); ERR_FAIL_COND_V(p_mode_flags == READ_WRITE, ERR_UNAVAILABLE);
_close(); _close();

View File

@ -70,7 +70,7 @@ public:
Error open_after_magic(Ref<FileAccess> p_base); Error open_after_magic(Ref<FileAccess> p_base);
virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position virtual void seek(uint64_t p_position) override; ///< seek to a given position

View File

@ -111,7 +111,7 @@ Error FileAccessEncrypted::open_and_parse_password(Ref<FileAccess> p_base, const
return open_and_parse(p_base, key, p_mode); return open_and_parse(p_base, key, p_mode);
} }
Error FileAccessEncrypted::_open(const String &p_path, int p_mode_flags) { Error FileAccessEncrypted::open_internal(const String &p_path, int p_mode_flags) {
return OK; return OK;
} }

View File

@ -60,7 +60,7 @@ public:
Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true); Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode); Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open virtual bool is_open() const override; ///< true when file is open
virtual String get_path() const override; /// returns the path for the current open file virtual String get_path() const override; /// returns the path for the current open file

View File

@ -78,7 +78,7 @@ Error FileAccessMemory::open_custom(const uint8_t *p_data, uint64_t p_len) {
return OK; return OK;
} }
Error FileAccessMemory::_open(const String &p_path, int p_mode_flags) { Error FileAccessMemory::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND); ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND);
String name = fix_path(p_path); String name = fix_path(p_path);

View File

@ -45,7 +45,7 @@ public:
static void cleanup(); static void cleanup();
virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file
virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position virtual void seek(uint64_t p_position) override; ///< seek to a given position

View File

@ -252,7 +252,7 @@ void FileAccessNetwork::_respond(uint64_t p_len, Error p_status) {
pages.resize(pc); pages.resize(pc);
} }
Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) { Error FileAccessNetwork::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags != READ, ERR_UNAVAILABLE); ERR_FAIL_COND_V(p_mode_flags != READ, ERR_UNAVAILABLE);
_close(); _close();

View File

@ -132,7 +132,7 @@ public:
RESPONSE_GET_MODTIME, RESPONSE_GET_MODTIME,
}; };
virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position virtual void seek(uint64_t p_position) override; ///< seek to a given position

View File

@ -259,7 +259,7 @@ Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::Pack
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
Error FileAccessPack::_open(const String &p_path, int p_mode_flags) { Error FileAccessPack::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_V(ERR_UNAVAILABLE); ERR_FAIL_V(ERR_UNAVAILABLE);
return ERR_UNAVAILABLE; return ERR_UNAVAILABLE;
} }

View File

@ -148,7 +148,7 @@ class FileAccessPack : public FileAccess {
uint64_t off; uint64_t off;
Ref<FileAccess> f; Ref<FileAccess> f;
virtual Error _open(const String &p_path, int p_mode_flags) override; virtual Error open_internal(const String &p_path, int p_mode_flags) override;
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; } virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; } virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }

View File

@ -234,7 +234,7 @@ ZipArchive::~ZipArchive() {
packages.clear(); packages.clear();
} }
Error FileAccessZip::_open(const String &p_path, int p_mode_flags) { Error FileAccessZip::open_internal(const String &p_path, int p_mode_flags) {
_close(); _close();
ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, FAILED); ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, FAILED);

View File

@ -85,7 +85,7 @@ class FileAccessZip : public FileAccess {
void _close(); void _close();
public: public:
virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position virtual void seek(uint64_t p_position) override; ///< seek to a given position

View File

@ -1206,7 +1206,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
Ref<FileAccessCompressed> facw; Ref<FileAccessCompressed> facw;
facw.instantiate(); facw.instantiate();
facw->configure("RSCC"); facw->configure("RSCC");
err = facw->_open(p_path + ".depren", FileAccess::WRITE); err = facw->open_internal(p_path + ".depren", FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(err, ERR_FILE_CORRUPT, "Cannot create file '" + p_path + ".depren'."); ERR_FAIL_COND_V_MSG(err, ERR_FILE_CORRUPT, "Cannot create file '" + p_path + ".depren'.");
fw = facw; fw = facw;
@ -1986,7 +1986,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re
fac.instantiate(); fac.instantiate();
fac->configure("RSCC"); fac->configure("RSCC");
f = fac; f = fac;
err = fac->_open(p_path, FileAccess::WRITE); err = fac->open_internal(p_path, FileAccess::WRITE);
} else { } else {
f = FileAccess::open(p_path, FileAccess::WRITE, &err); f = FileAccess::open(p_path, FileAccess::WRITE, &err);
} }

View File

@ -228,8 +228,8 @@ void register_core_types() {
GDREGISTER_CLASS(ResourceFormatLoader); GDREGISTER_CLASS(ResourceFormatLoader);
GDREGISTER_CLASS(ResourceFormatSaver); GDREGISTER_CLASS(ResourceFormatSaver);
GDREGISTER_CLASS(core_bind::File); GDREGISTER_ABSTRACT_CLASS(FileAccess);
GDREGISTER_CLASS(core_bind::Directory); GDREGISTER_ABSTRACT_CLASS(DirAccess);
GDREGISTER_CLASS(core_bind::Thread); GDREGISTER_CLASS(core_bind::Thread);
GDREGISTER_CLASS(core_bind::Mutex); GDREGISTER_CLASS(core_bind::Mutex);
GDREGISTER_CLASS(core_bind::Semaphore); GDREGISTER_CLASS(core_bind::Semaphore);

View File

@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="Directory" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <class name="DirAccess" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description> <brief_description>
Type used to handle the filesystem. Type used to handle the filesystem.
</brief_description> </brief_description>
<description> <description>
Directory type. It is used to manage directories and their content (not restricted to the project folder). Directory type. It is used to manage directories and their content (not restricted to the project folder).
When creating a new [Directory], it must be explicitly opened using [method open] before most methods can be used. However, [method file_exists] and [method dir_exists] can be used without opening a directory. If so, they use a path relative to [code]res://[/code]. [DirAccess] can't be instantiated directly. Instead it is created with a static method that takes a path for which it will be opened.
[b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. Use [ResourceLoader] to access imported resources. [b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. Use [ResourceLoader] to access imported resources.
Here is an example on how to iterate through the files of a directory: Here is an example on how to iterate through the files of a directory:
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func dir_contents(path): func dir_contents(path):
var dir = Directory.new() var dir = DirAccess.open(path)
if dir.open(path) == OK: if dir:
dir.list_dir_begin() dir.list_dir_begin()
var file_name = dir.get_next() var file_name = dir.get_next()
while file_name != "": while file_name != "":
@ -27,8 +27,8 @@
[csharp] [csharp]
public void DirContents(string path) public void DirContents(string path)
{ {
var dir = new Directory(); var dir = DirAccess.Open(path);
if (dir.Open(path) == Error.Ok) if (dir != null)
{ {
dir.ListDirBegin(); dir.ListDirBegin();
string fileName = dir.GetNext(); string fileName = dir.GetNext();
@ -69,8 +69,10 @@
<return type="int" enum="Error" /> <return type="int" enum="Error" />
<param index="0" name="from" type="String" /> <param index="0" name="from" type="String" />
<param index="1" name="to" type="String" /> <param index="1" name="to" type="String" />
<param index="2" name="chmod_flags" type="int" default="-1" />
<description> <description>
Copies the [param from] file to the [param to] destination. Both arguments should be paths to files, either relative or absolute. If the destination file exists and is not access-protected, it will be overwritten. Copies the [param from] file to the [param to] destination. Both arguments should be paths to files, either relative or absolute. If the destination file exists and is not access-protected, it will be overwritten.
If [param chmod_flags] is different than [code]-1[/code], the unix permissions for the destination path will be set to the provided value, if available on the current operating system.
Returns one of the [enum Error] code constants ([code]OK[/code] on success). Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description> </description>
</method> </method>
@ -85,7 +87,7 @@
<param index="0" name="path" type="String" /> <param index="0" name="path" type="String" />
<description> <description>
Returns whether the target directory exists. The argument can be relative to the current directory, or an absolute path. Returns whether the target directory exists. The argument can be relative to the current directory, or an absolute path.
If the [Directory] is not open, the path is relative to [code]res://[/code]. If the [DirAccess] is not open, the path is relative to [code]res://[/code].
</description> </description>
</method> </method>
<method name="file_exists"> <method name="file_exists">
@ -93,11 +95,12 @@
<param index="0" name="path" type="String" /> <param index="0" name="path" type="String" />
<description> <description>
Returns whether the target file exists. The argument can be relative to the current directory, or an absolute path. Returns whether the target file exists. The argument can be relative to the current directory, or an absolute path.
If the [Directory] is not open, the path is relative to [code]res://[/code]. If the [DirAccess] is not open, the path is relative to [code]res://[/code].
</description> </description>
</method> </method>
<method name="get_current_dir"> <method name="get_current_dir" qualifiers="const">
<return type="String" /> <return type="String" />
<param index="0" name="include_drive" type="bool" default="true" />
<description> <description>
Returns the absolute path to the currently opened directory (e.g. [code]res://folder[/code] or [code]C:\tmp\folder[/code]). Returns the absolute path to the currently opened directory (e.g. [code]res://folder[/code] or [code]C:\tmp\folder[/code]).
</description> </description>
@ -144,8 +147,14 @@
<method name="get_next"> <method name="get_next">
<return type="String" /> <return type="String" />
<description> <description>
Returns the next element (file or directory) in the current directory (including [code].[/code] and [code]..[/code], unless [code]skip_navigational[/code] was given to [method list_dir_begin]). Returns the next element (file or directory) in the current directory.
The name of the file or directory is returned (and not its full path). Once the stream has been fully processed, the method returns an empty String and closes the stream automatically (i.e. [method list_dir_end] would not be mandatory in such a case). The name of the file or directory is returned (and not its full path). Once the stream has been fully processed, the method returns an empty [String] and closes the stream automatically (i.e. [method list_dir_end] would not be mandatory in such a case).
</description>
</method>
<method name="get_open_error" qualifiers="static">
<return type="int" enum="Error" />
<description>
Returns the result of the last [method open] call in the current thread.
</description> </description>
</method> </method>
<method name="get_space_left"> <method name="get_space_left">
@ -184,12 +193,12 @@
Returns one of the [enum Error] code constants ([code]OK[/code] on success). Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description> </description>
</method> </method>
<method name="open"> <method name="open" qualifiers="static">
<return type="int" enum="Error" /> <return type="DirAccess" />
<param index="0" name="path" type="String" /> <param index="0" name="path" type="String" />
<description> <description>
Opens an existing directory of the filesystem. The [param path] argument can be within the project tree ([code]res://folder[/code]), the user directory ([code]user://folder[/code]) or an absolute path of the user filesystem (e.g. [code]/tmp/folder[/code] or [code]C:\tmp\folder[/code]). Creates a new [DirAccess] object and opens an existing directory of the filesystem. The [param path] argument can be within the project tree ([code]res://folder[/code]), the user directory ([code]user://folder[/code]) or an absolute path of the user filesystem (e.g. [code]/tmp/folder[/code] or [code]C:\tmp\folder[/code]).
Returns one of the [enum Error] code constants ([code]OK[/code] on success). Returns [code]null[/code] if opening the directory failed. You can use [method get_open_error] to check the error that ocurred.
</description> </description>
</method> </method>
<method name="remove"> <method name="remove">
@ -212,11 +221,11 @@
</method> </method>
</methods> </methods>
<members> <members>
<member name="include_hidden" type="bool" setter="set_include_hidden" getter="get_include_hidden" default="false"> <member name="include_hidden" type="bool" setter="set_include_hidden" getter="get_include_hidden">
If [code]true[/code], hidden files are included when the navigating directory. If [code]true[/code], hidden files are included when the navigating directory.
Affects [method list_dir_begin], [method get_directories] and [method get_files]. Affects [method list_dir_begin], [method get_directories] and [method get_files].
</member> </member>
<member name="include_navigational" type="bool" setter="set_include_navigational" getter="get_include_navigational" default="false"> <member name="include_navigational" type="bool" setter="set_include_navigational" getter="get_include_navigational">
If [code]true[/code], [code].[/code] and [code]..[/code] are included when navigating the directory. If [code]true[/code], [code].[/code] and [code]..[/code] are included when navigating the directory.
Affects [method list_dir_begin] and [method get_directories]. Affects [method list_dir_begin] and [method get_directories].
</member> </member>

View File

@ -72,7 +72,7 @@
msgidsContextPlural.Add(new Godot.Collections.Array{"Only with context", "a friendly context", ""}); msgidsContextPlural.Add(new Godot.Collections.Array{"Only with context", "a friendly context", ""});
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
[b]Note:[/b] If you override parsing logic for standard script types (GDScript, C#, etc.), it would be better to load the [code]path[/code] argument using [method ResourceLoader.load]. This is because built-in scripts are loaded as [Resource] type, not [File] type. [b]Note:[/b] If you override parsing logic for standard script types (GDScript, C#, etc.), it would be better to load the [code]path[/code] argument using [method ResourceLoader.load]. This is because built-in scripts are loaded as [Resource] type, not [FileAccess] type.
For example: For example:
[codeblocks] [codeblocks]
[gdscript] [gdscript]

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="File" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <class name="FileAccess" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description> <brief_description>
Type to handle file reading and writing operations. Type to handle file reading and writing operations.
</brief_description> </brief_description>
@ -9,39 +9,36 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func save(content): func save(content):
var file = File.new() var file = FileAccess.open("user://save_game.dat", FileAccess.WRITE)
file.open("user://save_game.dat", File.WRITE)
file.store_string(content) file.store_string(content)
file.close()
func load(): func load():
var file = File.new() var file = FileAccess.open("user://save_game.dat", FileAccess.READ)
file.open("user://save_game.dat", File.READ)
var content = file.get_as_text() var content = file.get_as_text()
file.close()
return content return content
[/gdscript] [/gdscript]
[csharp] [csharp]
public void Save(string content) public void Save(string content)
{ {
var file = new File(); var file = FileAccess.Open("user://save_game.dat", File.ModeFlags.Write);
file.Open("user://save_game.dat", File.ModeFlags.Write);
file.StoreString(content); file.StoreString(content);
file.Close();
} }
public string Load() public string Load()
{ {
var file = new File(); var file = FileAccess.Open("user://save_game.dat", File.ModeFlags.Read);
file.Open("user://save_game.dat", File.ModeFlags.Read);
string content = file.GetAsText(); string content = file.GetAsText();
file.Close();
return content; return content;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
In the example above, the file will be saved in the user data folder as specified in the [url=$DOCS_URL/tutorials/io/data_paths.html]Data paths[/url] documentation. In the example above, the file will be saved in the user data folder as specified in the [url=$DOCS_URL/tutorials/io/data_paths.html]Data paths[/url] documentation.
[b]Note:[/b] To access project resources once exported, it is recommended to use [ResourceLoader] instead of the [File] API, as some files are converted to engine-specific formats and their original source files might not be present in the exported PCK package. There is no method to close a file in order to free it from use. Instead, [FileAccess] will close when it's freed, which happens when it goes out of scope or when it gets assigned with [code]null[/code].
[codeblock]
var file = FileAccess.open("res://something") # File is opened and locked for use.
file = null # File is closed.
[/codeblock]
[b]Note:[/b] To access project resources once exported, it is recommended to use [ResourceLoader] instead of the [FileAccess] API, as some files are converted to engine-specific formats and their original source files might not be present in the exported PCK package.
[b]Note:[/b] Files are automatically closed only if the process exits "normally" (such as by clicking the window manager's close button or pressing [b]Alt + F4[/b]). If you stop the project execution by pressing [b]F8[/b] while the project is running, the file won't be closed as the game process will be killed. You can work around this by calling [method flush] at regular intervals. [b]Note:[/b] Files are automatically closed only if the process exits "normally" (such as by clicking the window manager's close button or pressing [b]Alt + F4[/b]). If you stop the project execution by pressing [b]F8[/b] while the project is running, the file won't be closed as the game process will be killed. You can work around this by calling [method flush] at regular intervals.
</description> </description>
<tutorials> <tutorials>
@ -49,12 +46,6 @@
<link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/676</link> <link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/676</link>
</tutorials> </tutorials>
<methods> <methods>
<method name="close">
<return type="void" />
<description>
Closes the currently opened file and prevents subsequent read/write operations. Use [method flush] to persist the data to disk without closing the file.
</description>
</method>
<method name="eof_reached" qualifiers="const"> <method name="eof_reached" qualifiers="const">
<return type="bool" /> <return type="bool" />
<description> <description>
@ -85,7 +76,7 @@
<method name="flush"> <method name="flush">
<return type="void" /> <return type="void" />
<description> <description>
Writes the file's buffer to disk. Flushing is automatically performed when the file is closed. This means you don't need to call [method flush] manually before closing a file using [method close]. Still, calling [method flush] can be used to ensure the data is safe even if the project crashes instead of being closed gracefully. Writes the file's buffer to disk. Flushing is automatically performed when the file is closed. This means you don't need to call [method flush] manually before closing a file. Still, calling [method flush] can be used to ensure the data is safe even if the project crashes instead of being closed gracefully.
[b]Note:[/b] Only call [method flush] when you actually need it. Otherwise, it will decrease performance due to constant disk writes. [b]Note:[/b] Only call [method flush] when you actually need it. Otherwise, it will decrease performance due to constant disk writes.
</description> </description>
</method> </method>
@ -174,20 +165,26 @@
Text is interpreted as being UTF-8 encoded. Text is interpreted as being UTF-8 encoded.
</description> </description>
</method> </method>
<method name="get_md5" qualifiers="const"> <method name="get_md5" qualifiers="static">
<return type="String" /> <return type="String" />
<param index="0" name="path" type="String" /> <param index="0" name="path" type="String" />
<description> <description>
Returns an MD5 String representing the file at the given path or an empty [String] on failure. Returns an MD5 String representing the file at the given path or an empty [String] on failure.
</description> </description>
</method> </method>
<method name="get_modified_time" qualifiers="const"> <method name="get_modified_time" qualifiers="static">
<return type="int" /> <return type="int" />
<param index="0" name="file" type="String" /> <param index="0" name="file" type="String" />
<description> <description>
Returns the last time the [param file] was modified in Unix timestamp format or returns a [String] "ERROR IN [code]file[/code]". This Unix timestamp can be converted to another format using the [Time] singleton. Returns the last time the [param file] was modified in Unix timestamp format or returns a [String] "ERROR IN [code]file[/code]". This Unix timestamp can be converted to another format using the [Time] singleton.
</description> </description>
</method> </method>
<method name="get_open_error" qualifiers="static">
<return type="int" enum="Error" />
<description>
Returns the result of the last [method open] call in the current thread.
</description>
</method>
<method name="get_pascal_string"> <method name="get_pascal_string">
<return type="String" /> <return type="String" />
<description> <description>
@ -219,7 +216,7 @@
Returns the next bits from the file as a floating-point number. Returns the next bits from the file as a floating-point number.
</description> </description>
</method> </method>
<method name="get_sha256" qualifiers="const"> <method name="get_sha256" qualifiers="static">
<return type="String" /> <return type="String" />
<param index="0" name="path" type="String" /> <param index="0" name="path" type="String" />
<description> <description>
@ -240,41 +237,45 @@
Returns [code]true[/code] if the file is currently opened. Returns [code]true[/code] if the file is currently opened.
</description> </description>
</method> </method>
<method name="open"> <method name="open" qualifiers="static">
<return type="int" enum="Error" /> <return type="FileAccess" />
<param index="0" name="path" type="String" /> <param index="0" name="path" type="String" />
<param index="1" name="flags" type="int" enum="File.ModeFlags" /> <param index="1" name="flags" type="int" enum="FileAccess.ModeFlags" />
<description> <description>
Opens the file for writing or reading, depending on the flags. Creates a new [FileAccess] object and opens the file for writing or reading, depending on the flags.
Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred.
</description> </description>
</method> </method>
<method name="open_compressed"> <method name="open_compressed" qualifiers="static">
<return type="int" enum="Error" /> <return type="FileAccess" />
<param index="0" name="path" type="String" /> <param index="0" name="path" type="String" />
<param index="1" name="mode_flags" type="int" enum="File.ModeFlags" /> <param index="1" name="mode_flags" type="int" enum="FileAccess.ModeFlags" />
<param index="2" name="compression_mode" type="int" enum="File.CompressionMode" default="0" /> <param index="2" name="compression_mode" type="int" enum="FileAccess.CompressionMode" default="0" />
<description> <description>
Opens a compressed file for reading or writing. Creates a new [FileAccess] object and opens a compressed file for reading or writing.
[b]Note:[/b] [method open_compressed] can only read files that were saved by Godot, not third-party compression formats. See [url=https://github.com/godotengine/godot/issues/28999]GitHub issue #28999[/url] for a workaround. [b]Note:[/b] [method open_compressed] can only read files that were saved by Godot, not third-party compression formats. See [url=https://github.com/godotengine/godot/issues/28999]GitHub issue #28999[/url] for a workaround.
Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred.
</description> </description>
</method> </method>
<method name="open_encrypted"> <method name="open_encrypted" qualifiers="static">
<return type="int" enum="Error" /> <return type="FileAccess" />
<param index="0" name="path" type="String" /> <param index="0" name="path" type="String" />
<param index="1" name="mode_flags" type="int" enum="File.ModeFlags" /> <param index="1" name="mode_flags" type="int" enum="FileAccess.ModeFlags" />
<param index="2" name="key" type="PackedByteArray" /> <param index="2" name="key" type="PackedByteArray" />
<description> <description>
Opens an encrypted file in write or read mode. You need to pass a binary key to encrypt/decrypt it. Creates a new [FileAccess] object and opens an encrypted file in write or read mode. You need to pass a binary key to encrypt/decrypt it.
[b]Note:[/b] The provided key must be 32 bytes long. [b]Note:[/b] The provided key must be 32 bytes long.
Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred.
</description> </description>
</method> </method>
<method name="open_encrypted_with_pass"> <method name="open_encrypted_with_pass" qualifiers="static">
<return type="int" enum="Error" /> <return type="FileAccess" />
<param index="0" name="path" type="String" /> <param index="0" name="path" type="String" />
<param index="1" name="mode_flags" type="int" enum="File.ModeFlags" /> <param index="1" name="mode_flags" type="int" enum="FileAccess.ModeFlags" />
<param index="2" name="pass" type="String" /> <param index="2" name="pass" type="String" />
<description> <description>
Opens an encrypted file in write or read mode. You need to pass a password to encrypt/decrypt it. Creates a new [FileAccess] object and opens an encrypted file in write or read mode. You need to pass a password to encrypt/decrypt it.
Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that ocurred.
</description> </description>
</method> </method>
<method name="seek"> <method name="seek">
@ -432,7 +433,7 @@
</method> </method>
</methods> </methods>
<members> <members>
<member name="big_endian" type="bool" setter="set_big_endian" getter="is_big_endian" default="false"> <member name="big_endian" type="bool" setter="set_big_endian" getter="is_big_endian">
If [code]true[/code], the file is read with big-endian [url=https://en.wikipedia.org/wiki/Endianness]endianness[/url]. If [code]false[/code], the file is read with little-endian endianness. If in doubt, leave this to [code]false[/code] as most files are written with little-endian endianness. If [code]true[/code], the file is read with big-endian [url=https://en.wikipedia.org/wiki/Endianness]endianness[/url]. If [code]false[/code], the file is read with little-endian endianness. If in doubt, leave this to [code]false[/code] as most files are written with little-endian endianness.
[b]Note:[/b] [member big_endian] is only about the file format, not the CPU type. The CPU endianness doesn't affect the default endianness for files written. [b]Note:[/b] [member big_endian] is only about the file format, not the CPU type. The CPU endianness doesn't affect the default endianness for files written.
[b]Note:[/b] This is always reset to [code]false[/code] whenever you open the file. Therefore, you must set [member big_endian] [i]after[/i] opening the file, not before. [b]Note:[/b] This is always reset to [code]false[/code] whenever you open the file. Therefore, you must set [member big_endian] [i]after[/i] opening the file, not before.

View File

@ -522,7 +522,7 @@
<return type="int" enum="Error" /> <return type="int" enum="Error" />
<param index="0" name="path" type="String" /> <param index="0" name="path" type="String" />
<description> <description>
Moves the file or directory to the system's recycle bin. See also [method Directory.remove]. Moves the file or directory to the system's recycle bin. See also [method DirAccess.remove].
The method takes only global paths, so you may need to use [method ProjectSettings.globalize_path]. Do not use it for files in [code]res://[/code] as it will not work in exported project. The method takes only global paths, so you may need to use [method ProjectSettings.globalize_path]. Do not use it for files in [code]res://[/code] as it will not work in exported project.
[b]Note:[/b] If the user has disabled the recycle bin on their system, the file will be permanently deleted instead. [b]Note:[/b] If the user has disabled the recycle bin on their system, the file will be permanently deleted instead.
[codeblock] [codeblock]

View File

@ -65,7 +65,7 @@
<return type="PackedByteArray" /> <return type="PackedByteArray" />
<param index="0" name="compression_mode" type="int" default="0" /> <param index="0" name="compression_mode" type="int" default="0" />
<description> <description>
Returns a new [PackedByteArray] with the data compressed. Set the compression mode using one of [enum File.CompressionMode]'s constants. Returns a new [PackedByteArray] with the data compressed. Set the compression mode using one of [enum FileAccess.CompressionMode]'s constants.
</description> </description>
</method> </method>
<method name="count" qualifiers="const"> <method name="count" qualifiers="const">
@ -173,7 +173,7 @@
<param index="0" name="buffer_size" type="int" /> <param index="0" name="buffer_size" type="int" />
<param index="1" name="compression_mode" type="int" default="0" /> <param index="1" name="compression_mode" type="int" default="0" />
<description> <description>
Returns a new [PackedByteArray] with the data decompressed. Set [param buffer_size] to the size of the uncompressed data. Set the compression mode using one of [enum File.CompressionMode]'s constants. Returns a new [PackedByteArray] with the data decompressed. Set [param buffer_size] to the size of the uncompressed data. Set the compression mode using one of [enum FileAccess.CompressionMode]'s constants.
</description> </description>
</method> </method>
<method name="decompress_dynamic" qualifiers="const"> <method name="decompress_dynamic" qualifiers="const">
@ -181,7 +181,7 @@
<param index="0" name="max_output_size" type="int" /> <param index="0" name="max_output_size" type="int" />
<param index="1" name="compression_mode" type="int" default="0" /> <param index="1" name="compression_mode" type="int" default="0" />
<description> <description>
Returns a new [PackedByteArray] with the data decompressed. Set the compression mode using one of [enum File.CompressionMode]'s constants. [b]This method only accepts gzip and deflate compression modes.[/b] Returns a new [PackedByteArray] with the data decompressed. Set the compression mode using one of [enum FileAccess.CompressionMode]'s constants. [b]This method only accepts gzip and deflate compression modes.[/b]
This method is potentially slower than [code]decompress[/code], as it may have to re-allocate its output buffer multiple times while decompressing, whereas [code]decompress[/code] knows it's output buffer size from the beginning. This method is potentially slower than [code]decompress[/code], as it may have to re-allocate its output buffer multiple times while decompressing, whereas [code]decompress[/code] knows it's output buffer size from the beginning.
GZIP has a maximal compression ratio of 1032:1, meaning it's very possible for a small compressed payload to decompress to a potentially very large output. To guard against this, you may provide a maximum size this function is allowed to allocate in bytes via [param max_output_size]. Passing -1 will allow for unbounded output. If any positive value is passed, and the decompression exceeds that amount in bytes, then an error will be returned. GZIP has a maximal compression ratio of 1032:1, meaning it's very possible for a small compressed payload to decompress to a potentially very large output. To guard against this, you may provide a maximum size this function is allowed to allocate in bytes via [param max_output_size]. Passing -1 will allow for unbounded output. If any positive value is passed, and the decompression exceeds that amount in bytes, then an error will be returned.
</description> </description>

View File

@ -62,10 +62,10 @@
Do not save editor-specific metadata (identified by their [code]__editor[/code] prefix). Do not save editor-specific metadata (identified by their [code]__editor[/code] prefix).
</constant> </constant>
<constant name="FLAG_SAVE_BIG_ENDIAN" value="16" enum="SaverFlags" is_bitfield="true"> <constant name="FLAG_SAVE_BIG_ENDIAN" value="16" enum="SaverFlags" is_bitfield="true">
Save as big endian (see [member File.big_endian]). Save as big endian (see [member FileAccess.big_endian]).
</constant> </constant>
<constant name="FLAG_COMPRESS" value="32" enum="SaverFlags" is_bitfield="true"> <constant name="FLAG_COMPRESS" value="32" enum="SaverFlags" is_bitfield="true">
Compress the resource on save using [constant File.COMPRESSION_ZSTD]. Only available for binary resource types. Compress the resource on save using [constant FileAccess.COMPRESSION_ZSTD]. Only available for binary resource types.
</constant> </constant>
<constant name="FLAG_REPLACE_SUBRESOURCE_PATHS" value="64" enum="SaverFlags" is_bitfield="true"> <constant name="FLAG_REPLACE_SUBRESOURCE_PATHS" value="64" enum="SaverFlags" is_bitfield="true">
Take over the paths of the saved subresources (see [method Resource.take_over_path]). Take over the paths of the saved subresources (see [method Resource.take_over_path]).

View File

@ -4,7 +4,7 @@
Data buffer stream peer. Data buffer stream peer.
</brief_description> </brief_description>
<description> <description>
Data buffer stream peer that uses a byte array as the stream. This object can be used to handle binary data from network sessions. To handle binary data stored in files, [File] can be used directly. Data buffer stream peer that uses a byte array as the stream. This object can be used to handle binary data from network sessions. To handle binary data stored in files, [FileAccess] can be used directly.
A [StreamPeerBuffer] object keeps an internal cursor which is the offset in bytes to the start of the buffer. Get and put operations are performed at the cursor position and will move the cursor accordingly. A [StreamPeerBuffer] object keeps an internal cursor which is the offset in bytes to the start of the buffer. Get and put operations are performed at the cursor position and will move the cursor accordingly.
</description> </description>
<tutorials> <tutorials>

View File

@ -70,7 +70,7 @@ void FileAccessUnix::check_errors() const {
} }
} }
Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) {
_close(); _close();
path_src = p_path; path_src = p_path;

View File

@ -54,7 +54,7 @@ class FileAccessUnix : public FileAccess {
public: public:
static CloseNotificationFunc close_notification_func; static CloseNotificationFunc close_notification_func;
virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open virtual bool is_open() const override; ///< true when file is open
virtual String get_path() const override; /// returns the path for the current open file virtual String get_path() const override; /// returns the path for the current open file

View File

@ -58,7 +58,7 @@ void FileAccessWindows::check_errors() const {
} }
} }
Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
_close(); _close();
path_src = p_path; path_src = p_path;

View File

@ -51,7 +51,7 @@ class FileAccessWindows : public FileAccess {
void _close(); void _close();
public: public:
virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open virtual bool is_open() const override; ///< true when file is open
virtual String get_path() const override; /// returns the path for the current open file virtual String get_path() const override; /// returns the path for the current open file

View File

@ -38,6 +38,7 @@ const int ERROR_CODE = 77;
#include "modules/regex/regex.h" #include "modules/regex/regex.h"
#include "core/io/dir_access.h"
#include "core/os/time.h" #include "core/os/time.h"
#include "core/templates/hash_map.h" #include "core/templates/hash_map.h"
#include "core/templates/list.h" #include "core/templates/list.h"
@ -2229,22 +2230,23 @@ Vector<String> ProjectConverter3To4::check_for_files() {
Vector<String> directories_to_check = Vector<String>(); Vector<String> directories_to_check = Vector<String>();
directories_to_check.push_back("res://"); directories_to_check.push_back("res://");
core_bind::Directory dir = core_bind::Directory();
while (!directories_to_check.is_empty()) { while (!directories_to_check.is_empty()) {
String path = directories_to_check.get(directories_to_check.size() - 1); // Is there any pop_back function? String path = directories_to_check.get(directories_to_check.size() - 1); // Is there any pop_back function?
directories_to_check.resize(directories_to_check.size() - 1); // Remove last element. directories_to_check.resize(directories_to_check.size() - 1); // Remove last element
if (dir.open(path) == OK) {
dir.set_include_hidden(true); Ref<DirAccess> dir = DirAccess::create_for_path(path);
dir.list_dir_begin(); if (dir.is_valid()) {
String current_dir = dir.get_current_dir(); dir->set_include_hidden(true);
String file_name = dir.get_next(); dir->list_dir_begin();
String current_dir = dir->get_current_dir();
String file_name = dir->_get_next();
while (file_name != "") { while (file_name != "") {
if (file_name == ".git" || file_name == ".import" || file_name == ".godot") { if (file_name == ".git" || file_name == ".import" || file_name == ".godot") {
file_name = dir.get_next(); file_name = dir->_get_next();
continue; continue;
} }
if (dir.current_is_dir()) { if (dir->current_is_dir()) {
directories_to_check.append(current_dir.path_join(file_name) + "/"); directories_to_check.append(current_dir.path_join(file_name) + "/");
} else { } else {
bool proper_extension = false; bool proper_extension = false;
@ -2255,7 +2257,7 @@ Vector<String> ProjectConverter3To4::check_for_files() {
collected_files.append(current_dir.path_join(file_name)); collected_files.append(current_dir.path_join(file_name));
} }
} }
file_name = dir.get_next(); file_name = dir->_get_next();
} }
} else { } else {
print_verbose("Failed to open " + path); print_verbose("Failed to open " + path);

View File

@ -31,7 +31,6 @@
#ifndef PROJECT_CONVERTER_3_TO_4_H #ifndef PROJECT_CONVERTER_3_TO_4_H
#define PROJECT_CONVERTER_3_TO_4_H #define PROJECT_CONVERTER_3_TO_4_H
#include "core/core_bind.h"
#include "core/io/file_access.h" #include "core/io/file_access.h"
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
#include "core/string/ustring.h" #include "core/string/ustring.h"

View File

@ -69,51 +69,41 @@ namespace GodotTools.Build
private void LoadIssuesFromFile(string csvFile) private void LoadIssuesFromFile(string csvFile)
{ {
using (var file = new Godot.File()) using var file = FileAccess.Open(csvFile, FileAccess.ModeFlags.Read);
if (file == null)
return;
while (!file.EofReached())
{ {
try string[] csvColumns = file.GetCsvLine();
if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0]))
return;
if (csvColumns.Length != 7)
{ {
Error openError = file.Open(csvFile, Godot.File.ModeFlags.Read); GD.PushError($"Expected 7 columns, got {csvColumns.Length}");
continue;
if (openError != Error.Ok)
return;
while (!file.EofReached())
{
string[] csvColumns = file.GetCsvLine();
if (csvColumns.Length == 1 && string.IsNullOrEmpty(csvColumns[0]))
return;
if (csvColumns.Length != 7)
{
GD.PushError($"Expected 7 columns, got {csvColumns.Length}");
continue;
}
var issue = new BuildIssue
{
Warning = csvColumns[0] == "warning",
File = csvColumns[1],
Line = int.Parse(csvColumns[2]),
Column = int.Parse(csvColumns[3]),
Code = csvColumns[4],
Message = csvColumns[5],
ProjectFile = csvColumns[6]
};
if (issue.Warning)
WarningCount += 1;
else
ErrorCount += 1;
_issues.Add(issue);
}
} }
finally
var issue = new BuildIssue
{ {
file.Close(); // Disposing it is not enough. We need to call Close() Warning = csvColumns[0] == "warning",
} File = csvColumns[1],
Line = int.Parse(csvColumns[2]),
Column = int.Parse(csvColumns[3]),
Code = csvColumns[4],
Message = csvColumns[5],
ProjectFile = csvColumns[6]
};
if (issue.Warning)
WarningCount += 1;
else
ErrorCount += 1;
_issues.Add(issue);
} }
} }

View File

@ -45,7 +45,6 @@ using namespace godot;
// Headers for building as built-in module. // Headers for building as built-in module.
#include "core/config/project_settings.h" #include "core/config/project_settings.h"
#include "core/core_bind.h"
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/object/worker_thread_pool.h" #include "core/object/worker_thread_pool.h"
#include "core/string/print_string.h" #include "core/string/print_string.h"
@ -53,8 +52,6 @@ using namespace godot;
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen. #include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
using namespace core_bind;
#endif #endif
// Built-in ICU data. // Built-in ICU data.
@ -408,13 +405,12 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
if (!icu_data_loaded) { if (!icu_data_loaded) {
String filename = (p_filename.is_empty()) ? String("res://") + _MKSTR(ICU_DATA_NAME) : p_filename; String filename = (p_filename.is_empty()) ? String("res://") + _MKSTR(ICU_DATA_NAME) : p_filename;
Ref<File> f; Ref<FileAccess> f = FileAccess::open(filename, FileAccess::READ);
f.instantiate(); if (f.is_null()) {
if (f->open(filename, File::READ) != OK) {
return false; return false;
} }
uint64_t len = f->get_length(); uint64_t len = f->get_length();
PackedByteArray icu_data = f->get_buffer(len); PackedByteArray icu_data = f->_get_buffer(len);
UErrorCode err = U_ZERO_ERROR; UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(icu_data.ptr(), &err); udata_setCommonData(icu_data.ptr(), &err);
@ -455,16 +451,15 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const {
// Store data to the res file if it's available. // Store data to the res file if it's available.
Ref<File> f; Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::WRITE);
f.instantiate(); if (f.is_null()) {
if (f->open(p_filename, File::WRITE) != OK) {
return false; return false;
} }
PackedByteArray icu_data; PackedByteArray icu_data;
icu_data.resize(U_ICUDATA_SIZE); icu_data.resize(U_ICUDATA_SIZE);
memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
f->store_buffer(icu_data); f->_store_buffer(icu_data);
return true; return true;
#else #else

View File

@ -42,7 +42,7 @@ String FileAccessAndroid::get_path_absolute() const {
return absolute_path; return absolute_path;
} }
Error FileAccessAndroid::_open(const String &p_path, int p_mode_flags) { Error FileAccessAndroid::open_internal(const String &p_path, int p_mode_flags) {
_close(); _close();
path_src = p_path; path_src = p_path;

View File

@ -49,7 +49,7 @@ class FileAccessAndroid : public FileAccess {
public: public:
static AAssetManager *asset_manager; static AAssetManager *asset_manager;
virtual Error _open(const String &p_path, int p_mode_flags) override; // open a file virtual Error open_internal(const String &p_path, int p_mode_flags) override; // open a file
virtual bool is_open() const override; // true when file is open virtual bool is_open() const override; // true when file is open
/// returns the path for the current open file /// returns the path for the current open file

View File

@ -61,7 +61,7 @@ String FileAccessFilesystemJAndroid::get_path_absolute() const {
return absolute_path; return absolute_path;
} }
Error FileAccessFilesystemJAndroid::_open(const String &p_path, int p_mode_flags) { Error FileAccessFilesystemJAndroid::open_internal(const String &p_path, int p_mode_flags) {
if (is_open()) { if (is_open()) {
_close(); _close();
} }

View File

@ -60,7 +60,7 @@ class FileAccessFilesystemJAndroid : public FileAccess {
void _set_eof(bool eof); void _set_eof(bool eof);
public: public:
virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open virtual bool is_open() const override; ///< true when file is open
/// returns the path for the current open file /// returns the path for the current open file