summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/io/http_client.cpp143
-rw-r--r--core/io/http_client.h42
-rw-r--r--core/io/packet_peer.cpp10
-rw-r--r--core/io/packet_peer.h12
-rw-r--r--core/io/resource_format_binary.cpp68
-rw-r--r--core/io/resource_format_binary.h7
-rw-r--r--core/io/resource_loader.cpp68
-rw-r--r--core/io/resource_loader.h4
-rw-r--r--core/os/os.cpp4
-rw-r--r--core/os/os.h10
-rw-r--r--core/ustring.cpp19
-rw-r--r--core/ustring.h2
-rw-r--r--core/variant_call.cpp4
13 files changed, 247 insertions, 146 deletions
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 5097898314..e457a4ac1e 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -30,27 +30,53 @@
#include "http_client.h"
#include "io/stream_peer_ssl.h"
+const char *HTTPClient::_methods[METHOD_MAX] = {
+ "GET",
+ "HEAD",
+ "POST",
+ "PUT",
+ "DELETE",
+ "OPTIONS",
+ "TRACE",
+ "CONNECT",
+ "PATCH"
+};
+
#ifndef JAVASCRIPT_ENABLED
Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) {
close();
+
conn_port = p_port;
conn_host = p_host;
- if (conn_host.begins_with("http://")) {
+ ssl = p_ssl;
+ ssl_verify_host = p_verify_host;
+
+ String host_lower = conn_host.to_lower();
+ if (host_lower.begins_with("http://")) {
- conn_host = conn_host.replace_first("http://", "");
- } else if (conn_host.begins_with("https://")) {
- //use https
- conn_host = conn_host.replace_first("https://", "");
+ conn_host = conn_host.substr(7, conn_host.length() - 7);
+ } else if (host_lower.begins_with("https://")) {
+
+ ssl = true;
+ conn_host = conn_host.substr(8, conn_host.length() - 8);
+ }
+
+ ERR_FAIL_COND_V(conn_host.length() < HOST_MIN_LEN, ERR_INVALID_PARAMETER);
+
+ if (conn_port < 0) {
+ if (ssl) {
+ conn_port = PORT_HTTPS;
+ } else {
+ conn_port = PORT_HTTP;
+ }
}
- ssl = p_ssl;
- ssl_verify_host = p_verify_host;
connection = tcp_connection;
if (conn_host.is_valid_ip_address()) {
- //is ip
+ // Host contains valid IP
Error err = tcp_connection->connect_to_host(IP_Address(conn_host), p_port);
if (err) {
status = STATUS_CANT_CONNECT;
@@ -59,7 +85,7 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl,
status = STATUS_CONNECTING;
} else {
- //is hostname
+ // Host contains hostname and needs to be resolved to IP
resolving = IP::get_singleton()->resolve_hostname_queue_item(conn_host);
status = STATUS_RESOLVING;
}
@@ -82,23 +108,13 @@ Ref<StreamPeer> HTTPClient::get_connection() const {
Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const PoolVector<uint8_t> &p_body) {
ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA);
- static const char *_methods[METHOD_MAX] = {
- "GET",
- "HEAD",
- "POST",
- "PUT",
- "DELETE",
- "OPTIONS",
- "TRACE",
- "CONNECT"
- };
-
String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n";
- if ((ssl && conn_port == 443) || (!ssl && conn_port == 80)) {
- // don't append the standard ports
+ if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
+ // Don't append the standard ports
request += "Host: " + conn_host + "\r\n";
} else {
request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
@@ -112,17 +128,20 @@ Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector
}
if (add_clen) {
request += "Content-Length: " + itos(p_body.size()) + "\r\n";
- //should it add utf8 encoding? not sure
+ // Should it add utf8 encoding?
}
request += "\r\n";
CharString cs = request.utf8();
PoolVector<uint8_t> data;
-
- //Maybe this goes faster somehow?
- for (int i = 0; i < cs.length(); i++) {
- data.append(cs[i]);
+ data.resize(cs.length());
+ {
+ PoolVector<uint8_t>::Write data_write = data.write();
+ for (int i = 0; i < cs.length(); i++) {
+ data_write[i] = cs[i];
+ }
}
+
data.append_array(p_body);
PoolVector<uint8_t>::Read r = data.read();
@@ -142,23 +161,13 @@ Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector
Error HTTPClient::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) {
ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA);
- static const char *_methods[METHOD_MAX] = {
- "GET",
- "HEAD",
- "POST",
- "PUT",
- "DELETE",
- "OPTIONS",
- "TRACE",
- "CONNECT"
- };
-
String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n";
- if ((ssl && conn_port == 443) || (!ssl && conn_port == 80)) {
- // don't append the standard ports
+ if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
+ // Don't append the standard ports
request += "Host: " + conn_host + "\r\n";
} else {
request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
@@ -172,7 +181,7 @@ Error HTTPClient::request(Method p_method, const String &p_url, const Vector<Str
}
if (add_clen) {
request += "Content-Length: " + itos(p_body.utf8().length()) + "\r\n";
- //should it add utf8 encoding? not sure
+ // Should it add utf8 encoding?
}
request += "\r\n";
request += p_body;
@@ -251,7 +260,7 @@ Error HTTPClient::poll() {
IP::ResolverStatus rstatus = IP::get_singleton()->get_resolve_item_status(resolving);
switch (rstatus) {
case IP::RESOLVER_STATUS_WAITING:
- return OK; //still resolving
+ return OK; // Still resolving
case IP::RESOLVER_STATUS_DONE: {
@@ -283,7 +292,7 @@ Error HTTPClient::poll() {
switch (s) {
case StreamPeerTCP::STATUS_CONNECTING: {
- return OK; //do none
+ return OK;
} break;
case StreamPeerTCP::STATUS_CONNECTED: {
if (ssl) {
@@ -294,7 +303,6 @@ Error HTTPClient::poll() {
status = STATUS_SSL_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
- //print_line("SSL! TURNED ON!");
connection = ssl;
}
status = STATUS_CONNECTED;
@@ -310,7 +318,7 @@ Error HTTPClient::poll() {
}
} break;
case STATUS_CONNECTED: {
- //request something please
+ // Connection established, requests can now be made
return OK;
} break;
case STATUS_REQUESTING: {
@@ -326,7 +334,7 @@ Error HTTPClient::poll() {
}
if (rec == 0)
- return OK; //keep trying!
+ return OK; // Still requesting, keep trying!
response_str.push_back(byte);
int rs = response_str.size();
@@ -334,11 +342,10 @@ Error HTTPClient::poll() {
(rs >= 2 && response_str[rs - 2] == '\n' && response_str[rs - 1] == '\n') ||
(rs >= 4 && response_str[rs - 4] == '\r' && response_str[rs - 3] == '\n' && response_str[rs - 2] == '\r' && response_str[rs - 1] == '\n')) {
- //end of response, parse.
+ // End of response, parse.
response_str.push_back(0);
String response;
response.parse_utf8((const char *)response_str.ptr());
- //print_line("END OF RESPONSE? :\n"+response+"\n------");
Vector<String> responses = response.split("\n");
body_size = 0;
chunked = false;
@@ -361,7 +368,6 @@ Error HTTPClient::poll() {
if (s.begins_with("transfer-encoding:")) {
String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges();
- //print_line("TRANSFER ENCODING: "+encoding);
if (encoding == "chunked") {
chunked = true;
}
@@ -379,14 +385,14 @@ Error HTTPClient::poll() {
if (body_size == 0 && !chunked) {
- status = STATUS_CONNECTED; //ask for something again?
+ status = STATUS_CONNECTED; // Ready for new requests
} else {
status = STATUS_BODY;
}
return OK;
}
}
- //wait for response
+ // Wait for response
return OK;
} break;
case STATUS_DISCONNECTED: {
@@ -422,7 +428,7 @@ PoolByteArray HTTPClient::read_response_body_chunk() {
while (true) {
if (chunk_left == 0) {
- //reading len
+ // Reading length
uint8_t b;
int rec = 0;
err = _get_http_data(&b, 1, rec);
@@ -465,7 +471,7 @@ PoolByteArray HTTPClient::read_response_body_chunk() {
}
if (len == 0) {
- //end!
+ // End reached!
status = STATUS_CONNECTED;
chunk.clear();
return PoolByteArray();
@@ -523,7 +529,7 @@ PoolByteArray HTTPClient::read_response_body_chunk() {
to_read -= rec;
_offset += rec;
} else {
- if (to_read > 0) //ended up reading less
+ if (to_read > 0) // Ended up reading less
ret.resize(_offset);
break;
}
@@ -538,7 +544,7 @@ PoolByteArray HTTPClient::read_response_body_chunk() {
close();
if (err == ERR_FILE_EOF) {
- status = STATUS_DISCONNECTED; //server disconnected
+ status = STATUS_DISCONNECTED; // Server disconnected
} else {
status = STATUS_CONNECTION_ERROR;
@@ -591,7 +597,7 @@ HTTPClient::HTTPClient() {
tcp_connection = StreamPeerTCP::create_ref();
resolving = IP::RESOLVER_INVALID_ID;
status = STATUS_DISCONNECTED;
- conn_port = 80;
+ conn_port = -1;
body_size = 0;
chunked = false;
body_left = 0;
@@ -651,7 +657,7 @@ PoolStringArray HTTPClient::_get_response_headers() {
void HTTPClient::_bind_methods() {
- ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port", "use_ssl", "verify_host"), &HTTPClient::connect_to_host, DEFVAL(false), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port", "use_ssl", "verify_host"), &HTTPClient::connect_to_host, DEFVAL(-1), DEFVAL(false), DEFVAL(true));
ClassDB::bind_method(D_METHOD("set_connection", "connection"), &HTTPClient::set_connection);
ClassDB::bind_method(D_METHOD("get_connection"), &HTTPClient::get_connection);
ClassDB::bind_method(D_METHOD("request_raw", "method", "url", "headers", "body"), &HTTPClient::request_raw);
@@ -683,16 +689,17 @@ void HTTPClient::_bind_methods() {
BIND_ENUM_CONSTANT(METHOD_OPTIONS);
BIND_ENUM_CONSTANT(METHOD_TRACE);
BIND_ENUM_CONSTANT(METHOD_CONNECT);
+ BIND_ENUM_CONSTANT(METHOD_PATCH);
BIND_ENUM_CONSTANT(METHOD_MAX);
BIND_ENUM_CONSTANT(STATUS_DISCONNECTED);
- BIND_ENUM_CONSTANT(STATUS_RESOLVING); //resolving hostname (if passed a hostname)
+ BIND_ENUM_CONSTANT(STATUS_RESOLVING); // Resolving hostname (if hostname was passed in)
BIND_ENUM_CONSTANT(STATUS_CANT_RESOLVE);
- BIND_ENUM_CONSTANT(STATUS_CONNECTING); //connecting to ip
+ BIND_ENUM_CONSTANT(STATUS_CONNECTING); // Connecting to IP
BIND_ENUM_CONSTANT(STATUS_CANT_CONNECT);
- BIND_ENUM_CONSTANT(STATUS_CONNECTED); //connected ); requests only accepted here
- BIND_ENUM_CONSTANT(STATUS_REQUESTING); // request in progress
- BIND_ENUM_CONSTANT(STATUS_BODY); // request resulted in body ); which must be read
+ BIND_ENUM_CONSTANT(STATUS_CONNECTED); // Connected, now accepting requests
+ BIND_ENUM_CONSTANT(STATUS_REQUESTING); // Request in progress
+ BIND_ENUM_CONSTANT(STATUS_BODY); // Request resulted in body which must be read
BIND_ENUM_CONSTANT(STATUS_CONNECTION_ERROR);
BIND_ENUM_CONSTANT(STATUS_SSL_HANDSHAKE_ERROR);
@@ -709,6 +716,7 @@ void HTTPClient::_bind_methods() {
BIND_ENUM_CONSTANT(RESPONSE_RESET_CONTENT);
BIND_ENUM_CONSTANT(RESPONSE_PARTIAL_CONTENT);
BIND_ENUM_CONSTANT(RESPONSE_MULTI_STATUS);
+ BIND_ENUM_CONSTANT(RESPONSE_ALREADY_REPORTED);
BIND_ENUM_CONSTANT(RESPONSE_IM_USED);
// 3xx redirection
@@ -718,7 +726,9 @@ void HTTPClient::_bind_methods() {
BIND_ENUM_CONSTANT(RESPONSE_SEE_OTHER);
BIND_ENUM_CONSTANT(RESPONSE_NOT_MODIFIED);
BIND_ENUM_CONSTANT(RESPONSE_USE_PROXY);
+ BIND_ENUM_CONSTANT(RESPONSE_SWITCH_PROXY);
BIND_ENUM_CONSTANT(RESPONSE_TEMPORARY_REDIRECT);
+ BIND_ENUM_CONSTANT(RESPONSE_PERMANENT_REDIRECT);
// 4xx client error
BIND_ENUM_CONSTANT(RESPONSE_BAD_REQUEST);
@@ -739,10 +749,16 @@ void HTTPClient::_bind_methods() {
BIND_ENUM_CONSTANT(RESPONSE_UNSUPPORTED_MEDIA_TYPE);
BIND_ENUM_CONSTANT(RESPONSE_REQUESTED_RANGE_NOT_SATISFIABLE);
BIND_ENUM_CONSTANT(RESPONSE_EXPECTATION_FAILED);
+ BIND_ENUM_CONSTANT(RESPONSE_IM_A_TEAPOT);
+ BIND_ENUM_CONSTANT(RESPONSE_MISDIRECTED_REQUEST);
BIND_ENUM_CONSTANT(RESPONSE_UNPROCESSABLE_ENTITY);
BIND_ENUM_CONSTANT(RESPONSE_LOCKED);
BIND_ENUM_CONSTANT(RESPONSE_FAILED_DEPENDENCY);
BIND_ENUM_CONSTANT(RESPONSE_UPGRADE_REQUIRED);
+ BIND_ENUM_CONSTANT(RESPONSE_PRECONDITION_REQUIRED);
+ BIND_ENUM_CONSTANT(RESPONSE_TOO_MANY_REQUESTS);
+ BIND_ENUM_CONSTANT(RESPONSE_REQUEST_HEADER_FIELDS_TOO_LARGE);
+ BIND_ENUM_CONSTANT(RESPONSE_UNAVAILABLE_FOR_LEGAL_REASONS);
// 5xx server error
BIND_ENUM_CONSTANT(RESPONSE_INTERNAL_SERVER_ERROR);
@@ -751,6 +767,9 @@ void HTTPClient::_bind_methods() {
BIND_ENUM_CONSTANT(RESPONSE_SERVICE_UNAVAILABLE);
BIND_ENUM_CONSTANT(RESPONSE_GATEWAY_TIMEOUT);
BIND_ENUM_CONSTANT(RESPONSE_HTTP_VERSION_NOT_SUPPORTED);
+ BIND_ENUM_CONSTANT(RESPONSE_VARIANT_ALSO_NEGOTIATES);
BIND_ENUM_CONSTANT(RESPONSE_INSUFFICIENT_STORAGE);
+ BIND_ENUM_CONSTANT(RESPONSE_LOOP_DETECTED);
BIND_ENUM_CONSTANT(RESPONSE_NOT_EXTENDED);
+ BIND_ENUM_CONSTANT(RESPONSE_NETWORK_AUTH_REQUIRED);
}
diff --git a/core/io/http_client.h b/core/io/http_client.h
index db5dd115bd..3d8953c156 100644
--- a/core/io/http_client.h
+++ b/core/io/http_client.h
@@ -56,6 +56,7 @@ public:
RESPONSE_RESET_CONTENT = 205,
RESPONSE_PARTIAL_CONTENT = 206,
RESPONSE_MULTI_STATUS = 207,
+ RESPONSE_ALREADY_REPORTED = 208,
RESPONSE_IM_USED = 226,
// 3xx redirection
@@ -65,7 +66,9 @@ public:
RESPONSE_SEE_OTHER = 303,
RESPONSE_NOT_MODIFIED = 304,
RESPONSE_USE_PROXY = 305,
+ RESPONSE_SWITCH_PROXY = 306,
RESPONSE_TEMPORARY_REDIRECT = 307,
+ RESPONSE_PERMANENT_REDIRECT = 308,
// 4xx client error
RESPONSE_BAD_REQUEST = 400,
@@ -86,10 +89,16 @@ public:
RESPONSE_UNSUPPORTED_MEDIA_TYPE = 415,
RESPONSE_REQUESTED_RANGE_NOT_SATISFIABLE = 416,
RESPONSE_EXPECTATION_FAILED = 417,
+ RESPONSE_IM_A_TEAPOT = 418,
+ RESPONSE_MISDIRECTED_REQUEST = 421,
RESPONSE_UNPROCESSABLE_ENTITY = 422,
RESPONSE_LOCKED = 423,
RESPONSE_FAILED_DEPENDENCY = 424,
RESPONSE_UPGRADE_REQUIRED = 426,
+ RESPONSE_PRECONDITION_REQUIRED = 428,
+ RESPONSE_TOO_MANY_REQUESTS = 429,
+ RESPONSE_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
+ RESPONSE_UNAVAILABLE_FOR_LEGAL_REASONS = 451,
// 5xx server error
RESPONSE_INTERNAL_SERVER_ERROR = 500,
@@ -98,8 +107,11 @@ public:
RESPONSE_SERVICE_UNAVAILABLE = 503,
RESPONSE_GATEWAY_TIMEOUT = 504,
RESPONSE_HTTP_VERSION_NOT_SUPPORTED = 505,
+ RESPONSE_VARIANT_ALSO_NEGOTIATES = 506,
RESPONSE_INSUFFICIENT_STORAGE = 507,
+ RESPONSE_LOOP_DETECTED = 508,
RESPONSE_NOT_EXTENDED = 510,
+ RESPONSE_NETWORK_AUTH_REQUIRED = 511,
};
@@ -113,24 +125,37 @@ public:
METHOD_OPTIONS,
METHOD_TRACE,
METHOD_CONNECT,
+ METHOD_PATCH,
METHOD_MAX
+
};
enum Status {
+
STATUS_DISCONNECTED,
- STATUS_RESOLVING, //resolving hostname (if passed a hostname)
+ STATUS_RESOLVING, // Resolving hostname (if passed a hostname)
STATUS_CANT_RESOLVE,
- STATUS_CONNECTING, //connecting to ip
+ STATUS_CONNECTING, // Connecting to IP
STATUS_CANT_CONNECT,
- STATUS_CONNECTED, //connected, requests only accepted here
- STATUS_REQUESTING, // request in progress
- STATUS_BODY, // request resulted in body, which must be read
+ STATUS_CONNECTED, // Connected, requests can be made
+ STATUS_REQUESTING, // Request in progress
+ STATUS_BODY, // Request resulted in body, which must be read
STATUS_CONNECTION_ERROR,
STATUS_SSL_HANDSHAKE_ERROR,
};
private:
+ static const char *_methods[METHOD_MAX];
+ static const int HOST_MIN_LEN = 4;
+
+ enum Port {
+
+ PORT_HTTP = 80,
+ PORT_HTTPS = 443,
+
+ };
+
#ifndef JAVASCRIPT_ENABLED
Status status;
IP::ResolverID resolving;
@@ -167,8 +192,7 @@ private:
static void _bind_methods();
public:
- //Error connect_and_get(const String& p_url,bool p_verify_host=true); //connects to a full url and perform request
- Error connect_to_host(const String &p_host, int p_port, bool p_ssl = false, bool p_verify_host = true);
+ Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true);
void set_connection(const Ref<StreamPeer> &p_connection);
Ref<StreamPeer> get_connection() const;
@@ -186,9 +210,9 @@ public:
Error get_response_headers(List<String> *r_response);
int get_response_body_length() const;
- PoolByteArray read_response_body_chunk(); // can't get body as partial text because of most encodings UTF8, gzip, etc.
+ PoolByteArray read_response_body_chunk(); // Can't get body as partial text because of most encodings UTF8, gzip, etc.
- void set_blocking_mode(bool p_enable); //useful mostly if running in a thread
+ void set_blocking_mode(bool p_enable); // Useful mostly if running in a thread
bool is_blocking_mode_enabled() const;
void set_read_chunk_size(int p_size);
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index 16c73c26e7..c6b12f73ae 100644
--- a/core/io/packet_peer.cpp
+++ b/core/io/packet_peer.cpp
@@ -49,7 +49,7 @@ bool PacketPeer::is_object_decoding_allowed() const {
return allow_object_decoding;
}
-Error PacketPeer::get_packet_buffer(PoolVector<uint8_t> &r_buffer) const {
+Error PacketPeer::get_packet_buffer(PoolVector<uint8_t> &r_buffer) {
const uint8_t *buffer;
int buffer_size;
@@ -78,7 +78,7 @@ Error PacketPeer::put_packet_buffer(const PoolVector<uint8_t> &p_buffer) {
return put_packet(&r[0], len);
}
-Error PacketPeer::get_var(Variant &r_variant) const {
+Error PacketPeer::get_var(Variant &r_variant) {
const uint8_t *buffer;
int buffer_size;
@@ -107,7 +107,7 @@ Error PacketPeer::put_var(const Variant &p_packet) {
return put_packet(buf, len);
}
-Variant PacketPeer::_bnd_get_var() const {
+Variant PacketPeer::_bnd_get_var() {
Variant var;
get_var(var);
@@ -117,7 +117,7 @@ Variant PacketPeer::_bnd_get_var() const {
Error PacketPeer::_put_packet(const PoolVector<uint8_t> &p_buffer) {
return put_packet_buffer(p_buffer);
}
-PoolVector<uint8_t> PacketPeer::_get_packet() const {
+PoolVector<uint8_t> PacketPeer::_get_packet() {
PoolVector<uint8_t> raw;
last_get_error = get_packet_buffer(raw);
@@ -202,7 +202,7 @@ int PacketPeerStream::get_available_packet_count() const {
return count;
}
-Error PacketPeerStream::get_packet(const uint8_t **r_buffer, int &r_buffer_size) const {
+Error PacketPeerStream::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
ERR_FAIL_COND_V(peer.is_null(), ERR_UNCONFIGURED);
_poll_buffer();
diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h
index b08d44ad8a..a6d363ec12 100644
--- a/core/io/packet_peer.h
+++ b/core/io/packet_peer.h
@@ -37,13 +37,13 @@ class PacketPeer : public Reference {
GDCLASS(PacketPeer, Reference);
- Variant _bnd_get_var() const;
+ Variant _bnd_get_var();
void _bnd_put_var(const Variant &p_var);
static void _bind_methods();
Error _put_packet(const PoolVector<uint8_t> &p_buffer);
- PoolVector<uint8_t> _get_packet() const;
+ PoolVector<uint8_t> _get_packet();
Error _get_packet_error() const;
mutable Error last_get_error;
@@ -52,17 +52,17 @@ class PacketPeer : public Reference {
public:
virtual int get_available_packet_count() const = 0;
- virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) const = 0; ///< buffer is GONE after next get_packet
+ virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) = 0; ///< buffer is GONE after next get_packet
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) = 0;
virtual int get_max_packet_size() const = 0;
/* helpers / binders */
- virtual Error get_packet_buffer(PoolVector<uint8_t> &r_buffer) const;
+ virtual Error get_packet_buffer(PoolVector<uint8_t> &r_buffer);
virtual Error put_packet_buffer(const PoolVector<uint8_t> &p_buffer);
- virtual Error get_var(Variant &r_variant) const;
+ virtual Error get_var(Variant &r_variant);
virtual Error put_var(const Variant &p_packet);
void set_allow_object_decoding(bool p_enable);
@@ -91,7 +91,7 @@ protected:
public:
virtual int get_available_packet_count() const;
- virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) const;
+ virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
virtual int get_max_packet_size() const;
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index df0d41ea9d..92fdbc1581 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -104,7 +104,7 @@ StringName ResourceInteractiveLoaderBinary::_get_string() {
uint32_t id = f->get_32();
if (id & 0x80000000) {
- int len = id & 0x7FFFFFFF;
+ uint32_t len = id & 0x7FFFFFFF;
if (len > str_buf.size()) {
str_buf.resize(len);
}
@@ -734,6 +734,7 @@ Error ResourceInteractiveLoaderBinary::poll() {
for (int i = 0; i < pc; i++) {
StringName name = _get_string();
+
if (name == StringName()) {
error = ERR_FILE_CORRUPT;
ERR_FAIL_V(ERR_FILE_CORRUPT);
@@ -902,7 +903,9 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
ExtResource er;
er.type = get_unicode_string();
+
er.path = get_unicode_string();
+
external_resources.push_back(er);
}
@@ -1271,7 +1274,7 @@ String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
-void ResourceFormatSaverBinaryInstance::_pad_buffer(int p_bytes) {
+void ResourceFormatSaverBinaryInstance::_pad_buffer(FileAccess *f, int p_bytes) {
int extra = 4 - (p_bytes % 4);
if (extra < 4) {
@@ -1280,7 +1283,12 @@ void ResourceFormatSaverBinaryInstance::_pad_buffer(int p_bytes) {
}
}
-void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property, const PropertyInfo &p_hint) {
+void ResourceFormatSaverBinaryInstance::_write_variant(const Variant &p_property, const PropertyInfo &p_hint) {
+
+ write_variant(f, p_property, resource_set, external_resources, string_map, p_hint);
+}
+
+void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Variant &p_property, Set<RES> &resource_set, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint) {
switch (p_property.get_type()) {
@@ -1327,7 +1335,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property,
f->store_32(VARIANT_STRING);
String val = p_property;
- save_unicode_string(val);
+ save_unicode_string(f, val);
} break;
case Variant::VECTOR2: {
@@ -1453,10 +1461,20 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property,
if (np.is_absolute())
snc |= 0x8000;
f->store_16(snc);
- for (int i = 0; i < np.get_name_count(); i++)
- f->store_32(get_string_index(np.get_name(i)));
- for (int i = 0; i < np.get_subname_count(); i++)
- f->store_32(get_string_index(np.get_subname(i)));
+ for (int i = 0; i < np.get_name_count(); i++) {
+ if (string_map.has(np.get_name(i))) {
+ f->store_32(string_map[np.get_name(i)]);
+ } else {
+ save_unicode_string(f, np.get_name(i), true);
+ }
+ }
+ for (int i = 0; i < np.get_subname_count(); i++) {
+ if (string_map.has(np.get_subname(i))) {
+ f->store_32(string_map[np.get_subname(i)]);
+ } else {
+ save_unicode_string(f, np.get_subname(i), true);
+ }
+ }
} break;
case Variant::_RID: {
@@ -1508,8 +1526,8 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property,
continue;
*/
- write_variant(E->get());
- write_variant(d[E->get()]);
+ write_variant(f, E->get(), resource_set, external_resources, string_map);
+ write_variant(f, d[E->get()], resource_set, external_resources, string_map);
}
} break;
@@ -1520,7 +1538,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property,
f->store_32(uint32_t(a.size()));
for (int i = 0; i < a.size(); i++) {
- write_variant(a[i]);
+ write_variant(f, a[i], resource_set, external_resources, string_map);
}
} break;
@@ -1532,7 +1550,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property,
f->store_32(len);
PoolVector<uint8_t>::Read r = arr.read();
f->store_buffer(r.ptr(), len);
- _pad_buffer(len);
+ _pad_buffer(f, len);
} break;
case Variant::POOL_INT_ARRAY: {
@@ -1566,7 +1584,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant &p_property,
f->store_32(len);
PoolVector<String>::Read r = arr.read();
for (int i = 0; i < len; i++) {
- save_unicode_string(r[i]);
+ save_unicode_string(f, r[i]);
}
} break;
@@ -1693,10 +1711,14 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
}
}
-void ResourceFormatSaverBinaryInstance::save_unicode_string(const String &p_string) {
+void ResourceFormatSaverBinaryInstance::save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len) {
CharString utf8 = p_string.utf8();
- f->store_32(utf8.length() + 1);
+ if (p_bit_on_len) {
+ f->store_32(utf8.length() + 1 | 0x80000000);
+ } else {
+ f->store_32(utf8.length() + 1);
+ }
f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1);
}
@@ -1763,7 +1785,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
return ERR_CANT_CREATE;
}
- save_unicode_string(p_resource->get_class());
+ save_unicode_string(f, p_resource->get_class());
f->store_64(0); //offset to import metadata
for (int i = 0; i < 14; i++)
f->store_32(0); // reserved
@@ -1800,7 +1822,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
f->store_32(strings.size()); //string table size
for (int i = 0; i < strings.size(); i++) {
- save_unicode_string(strings[i]);
+ save_unicode_string(f, strings[i]);
}
// save external resource table
@@ -1814,10 +1836,10 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
for (int i = 0; i < save_order.size(); i++) {
- save_unicode_string(save_order[i]->get_save_class());
+ save_unicode_string(f, save_order[i]->get_save_class());
String path = save_order[i]->get_path();
path = relative_paths ? local_path.path_to_file(path) : path;
- save_unicode_string(path);
+ save_unicode_string(f, path);
}
// save internal resource table
f->store_32(saved_resources.size()); //amount of internal resources
@@ -1853,7 +1875,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
used_indices.insert(new_subindex);
}
- save_unicode_string("local://" + itos(r->get_subindex()));
+ save_unicode_string(f, "local://" + itos(r->get_subindex()));
if (takeover_paths) {
r->set_path(p_path + "::" + itos(r->get_subindex()), true);
}
@@ -1861,7 +1883,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
r->set_edited(false);
#endif
} else {
- save_unicode_string(r->get_path()); //actual external
+ save_unicode_string(f, r->get_path()); //actual external
}
ofs_pos.push_back(f->get_position());
f->store_64(0); //offset in 64 bits
@@ -1875,14 +1897,14 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p
ResourceData &rd = E->get();
ofs_table.push_back(f->get_position());
- save_unicode_string(rd.type);
+ save_unicode_string(f, rd.type);
f->store_32(rd.properties.size());
for (List<Property>::Element *F = rd.properties.front(); F; F = F->next()) {
Property &p = F->get();
f->store_32(p.name_idx);
- write_variant(p.value, F->get().pi);
+ _write_variant(p.value, F->get().pi);
}
}
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 687da0a9b4..176b8350cf 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -140,14 +140,15 @@ class ResourceFormatSaverBinaryInstance {
List<Property> properties;
};
- void _pad_buffer(int p_bytes);
- void write_variant(const Variant &p_property, const PropertyInfo &p_hint = PropertyInfo());
+ static void _pad_buffer(FileAccess *f, int p_bytes);
+ void _write_variant(const Variant &p_property, const PropertyInfo &p_hint = PropertyInfo());
void _find_resources(const Variant &p_variant, bool p_main = false);
- void save_unicode_string(const String &p_string);
+ static void save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len = false);
int get_string_index(const String &p_string);
public:
Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
+ static void write_variant(FileAccess *f, const Variant &p_property, Set<RES> &resource_set, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint = PropertyInfo());
};
class ResourceFormatSaverBinary : public ResourceFormatSaver {
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index ed0d491679..d2aad1d63a 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -196,19 +196,19 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
else
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
- bool xl_remapped = false;
- String path = _path_remap(local_path, &xl_remapped);
-
- ERR_FAIL_COND_V(path == "", RES());
-
- if (!p_no_cache && ResourceCache::has(path)) {
+ if (!p_no_cache && ResourceCache::has(local_path)) {
if (OS::get_singleton()->is_stdout_verbose())
- print_line("load resource: " + path + " (cached)");
+ print_line("load resource: " + local_path + " (cached)");
- return RES(ResourceCache::get(path));
+ return RES(ResourceCache::get(local_path));
}
+ bool xl_remapped = false;
+ String path = _path_remap(local_path, &xl_remapped);
+
+ ERR_FAIL_COND_V(path == "", RES());
+
if (OS::get_singleton()->is_stdout_verbose())
print_line("load resource: " + path);
@@ -247,23 +247,23 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
else
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
- bool xl_remapped = false;
- String path = _path_remap(local_path, &xl_remapped);
-
- ERR_FAIL_COND_V(path == "", Ref<ResourceInteractiveLoader>());
-
- if (!p_no_cache && ResourceCache::has(path)) {
+ if (!p_no_cache && ResourceCache::has(local_path)) {
if (OS::get_singleton()->is_stdout_verbose())
- print_line("load resource: " + path + " (cached)");
+ print_line("load resource: " + local_path + " (cached)");
- Ref<Resource> res_cached = ResourceCache::get(path);
+ Ref<Resource> res_cached = ResourceCache::get(local_path);
Ref<ResourceInteractiveLoaderDefault> ril = Ref<ResourceInteractiveLoaderDefault>(memnew(ResourceInteractiveLoaderDefault));
ril->resource = res_cached;
return ril;
}
+ bool xl_remapped = false;
+ String path = _path_remap(local_path, &xl_remapped);
+
+ ERR_FAIL_COND_V(path == "", Ref<ResourceInteractiveLoader>());
+
if (OS::get_singleton()->is_stdout_verbose())
print_line("load resource: ");
@@ -426,9 +426,11 @@ String ResourceLoader::get_resource_type(const String &p_path) {
String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_remapped) {
- if (translation_remaps.has(p_path)) {
+ String new_path = p_path;
- Vector<String> &v = *translation_remaps.getptr(p_path);
+ if (translation_remaps.has(new_path)) {
+
+ Vector<String> &v = *translation_remaps.getptr(new_path);
String locale = TranslationServer::get_singleton()->get_locale();
if (r_translation_remapped) {
*r_translation_remapped = true;
@@ -443,12 +445,16 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
continue;
if (l.begins_with(locale)) {
- return v[i].left(split);
+ new_path = v[i].left(split);
+ break;
}
}
}
- return p_path;
+ if (path_remaps.has(new_path)) {
+ new_path = path_remaps[new_path];
+ }
+ return new_path;
}
String ResourceLoader::import_remap(const String &p_path) {
@@ -515,6 +521,27 @@ void ResourceLoader::clear_translation_remaps() {
translation_remaps.clear();
}
+void ResourceLoader::load_path_remaps() {
+
+ if (!ProjectSettings::get_singleton()->has_setting("path_remap/remapped_paths"))
+ return;
+
+ PoolVector<String> remaps = ProjectSettings::get_singleton()->get("path_remap/remapped_paths");
+ int rc = remaps.size();
+ ERR_FAIL_COND(rc & 1); //must be even
+ PoolVector<String>::Read r = remaps.read();
+
+ for (int i = 0; i < rc; i += 2) {
+
+ path_remaps[r[i]] = r[i + 1];
+ }
+}
+
+void ResourceLoader::clear_path_remaps() {
+
+ path_remaps.clear();
+}
+
ResourceLoadErrorNotify ResourceLoader::err_notify = NULL;
void *ResourceLoader::err_notify_ud = NULL;
@@ -526,3 +553,4 @@ bool ResourceLoader::timestamp_on_load = false;
SelfList<Resource>::List ResourceLoader::remapped_list;
HashMap<String, Vector<String> > ResourceLoader::translation_remaps;
+HashMap<String, String> ResourceLoader::path_remaps;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 5deffbca1a..05f01d8d31 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -91,6 +91,7 @@ class ResourceLoader {
static DependencyErrorNotify dep_err_notify;
static bool abort_on_missing_resource;
static HashMap<String, Vector<String> > translation_remaps;
+ static HashMap<String, String> path_remaps;
static String _path_remap(const String &p_path, bool *r_translation_remapped = NULL);
friend class Resource;
@@ -137,6 +138,9 @@ public:
static String path_remap(const String &p_path);
static String import_remap(const String &p_path);
+ static void load_path_remaps();
+ static void clear_path_remaps();
+
static void reload_translation_remaps();
static void load_translation_remaps();
static void clear_translation_remaps();
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 8088a6fa74..d81e70e612 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -606,10 +606,6 @@ bool OS::has_feature(const String &p_feature) {
return false;
}
-void *OS::get_stack_bottom() const {
- return _stack_bottom;
-}
-
OS::OS() {
void *volatile stack_bottom;
diff --git a/core/os/os.h b/core/os/os.h
index 979ad7e92a..d9f7b91daa 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -191,7 +191,7 @@ public:
virtual bool is_window_maximized() const { return true; }
virtual void request_attention() {}
- virtual void set_borderless_window(int p_borderless) {}
+ virtual void set_borderless_window(bool p_borderless) {}
virtual bool get_borderless_window() { return 0; }
virtual void set_ime_position(const Point2 &p_pos) {}
@@ -442,15 +442,9 @@ public:
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
+ virtual void force_process_input(){};
bool has_feature(const String &p_feature);
- /**
- * Returns the stack bottom of the main thread of the application.
- * This may be of use when integrating languages with garbage collectors that
- * need to check whether a pointer is on the stack.
- */
- virtual void *get_stack_bottom() const;
-
bool is_hidpi_allowed() const { return _allow_hidpi; }
OS();
virtual ~OS();
diff --git a/core/ustring.cpp b/core/ustring.cpp
index 3a0708851e..1bf7d000c3 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -734,7 +734,7 @@ Vector<String> String::split_spaces() const {
return ret;
}
-Vector<String> String::split(const String &p_splitter, bool p_allow_empty) const {
+Vector<String> String::split(const String &p_splitter, bool p_allow_empty, int p_maxsplit) const {
Vector<String> ret;
int from = 0;
@@ -745,8 +745,21 @@ Vector<String> String::split(const String &p_splitter, bool p_allow_empty) const
int end = find(p_splitter, from);
if (end < 0)
end = len;
- if (p_allow_empty || (end > from))
- ret.push_back(substr(from, end - from));
+ if (p_allow_empty || (end > from)) {
+ if (p_maxsplit <= 0)
+ ret.push_back(substr(from, end - from));
+ else if (p_maxsplit > 0) {
+
+ // Put rest of the string and leave cycle.
+ if (p_maxsplit == ret.size()) {
+ ret.push_back(substr(from, len));
+ break;
+ }
+
+ // Otherwise, push items until positive limit is reached.
+ ret.push_back(substr(from, end - from));
+ }
+ }
if (end == len)
break;
diff --git a/core/ustring.h b/core/ustring.h
index 9c24133b55..6541642bd1 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -162,7 +162,7 @@ public:
String get_slice(String p_splitter, int p_slice) const;
String get_slicec(CharType p_splitter, int p_slice) const;
- Vector<String> split(const String &p_splitter, bool p_allow_empty = true) const;
+ Vector<String> split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
Vector<String> split_spaces() const;
Vector<float> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index f66cce85c9..2b99a60ba5 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -254,7 +254,7 @@ struct _VariantCall {
VCALL_LOCALMEM2R(String, replacen);
VCALL_LOCALMEM2R(String, insert);
VCALL_LOCALMEM0R(String, capitalize);
- VCALL_LOCALMEM2R(String, split);
+ VCALL_LOCALMEM3R(String, split);
VCALL_LOCALMEM2R(String, split_floats);
VCALL_LOCALMEM0R(String, to_upper);
VCALL_LOCALMEM0R(String, to_lower);
@@ -1446,7 +1446,7 @@ void register_variant_methods() {
ADDFUNC2R(STRING, STRING, String, replacen, STRING, "what", STRING, "forwhat", varray());
ADDFUNC2R(STRING, STRING, String, insert, INT, "position", STRING, "what", varray());
ADDFUNC0R(STRING, STRING, String, capitalize, varray());
- ADDFUNC2R(STRING, POOL_STRING_ARRAY, String, split, STRING, "divisor", BOOL, "allow_empty", varray(true));
+ ADDFUNC3R(STRING, POOL_STRING_ARRAY, String, split, STRING, "divisor", BOOL, "allow_empty", INT, "maxsplit", varray(true, 0));
ADDFUNC2R(STRING, POOL_REAL_ARRAY, String, split_floats, STRING, "divisor", BOOL, "allow_empty", varray(true));
ADDFUNC0R(STRING, STRING, String, to_upper, varray());