diff options
author | hurikhan <m4r10.5ch14ck@gmail.com> | 2015-02-12 15:58:29 +0100 |
---|---|---|
committer | hurikhan <m4r10.5ch14ck@gmail.com> | 2015-02-12 15:58:29 +0100 |
commit | a13e180052d2e17275498a2fa78185cc299ace11 (patch) | |
tree | 6f9051d0b3d2444ac09c1bbf78f9e395af1782e9 /core | |
parent | df7d26ff5b89ce9852813abd370d1357aab1501b (diff) | |
parent | b3a6cc097d5bc60ee6e7ba30b177bed3a8aadc71 (diff) |
Merge remote-tracking branch 'upstream/master' into x11-window-management
Diffstat (limited to 'core')
-rw-r--r-- | core/io/http_client.cpp | 43 | ||||
-rw-r--r-- | core/io/http_client.h | 6 | ||||
-rw-r--r-- | core/resource.cpp | 2 | ||||
-rw-r--r-- | core/ustring.cpp | 296 | ||||
-rw-r--r-- | core/ustring.h | 8 | ||||
-rw-r--r-- | core/variant_op.cpp | 14 |
6 files changed, 352 insertions, 17 deletions
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index faead675d4..c7906018e9 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -273,7 +273,7 @@ Error HTTPClient::poll(){ while(true) { uint8_t byte; int rec=0; - Error err = connection->get_partial_data(&byte,1,rec); + Error err = _get_http_data(&byte,1,rec); if (err!=OK) { close(); status=STATUS_CONNECTION_ERROR; @@ -417,7 +417,7 @@ ByteArray HTTPClient::read_response_body_chunk() { //reading len uint8_t b; int rec=0; - err = connection->get_partial_data(&b,1,rec); + err = _get_http_data(&b,1,rec); if (rec==0) break; @@ -471,7 +471,7 @@ ByteArray HTTPClient::read_response_body_chunk() { } else { int rec=0; - err = connection->get_partial_data(&chunk[chunk.size()-chunk_left],chunk_left,rec); + err = _get_http_data(&chunk[chunk.size()-chunk_left],chunk_left,rec); if (rec==0) { break; } @@ -502,18 +502,23 @@ ByteArray HTTPClient::read_response_body_chunk() { } } else { + + int to_read = MIN(body_left,read_chunk_size); ByteArray ret; - ret.resize(MAX(body_left,tmp_read.size())); + ret.resize(to_read); ByteArray::Write w = ret.write(); int _offset = 0; - while (body_left > 0) { - ByteArray::Write r = tmp_read.write(); + while (to_read > 0) { int rec=0; - err = connection->get_partial_data(r.ptr(),MIN(body_left,tmp_read.size()),rec); + err = _get_http_data(w.ptr()+_offset,to_read,rec); if (rec>0) { - copymem(w.ptr()+_offset,r.ptr(),rec); body_left-=rec; + to_read-=rec; _offset += rec; + } else { + if (to_read>0) //ended up reading less + ret.resize(_offset); + break; } } if (body_left==0) { @@ -557,6 +562,20 @@ bool HTTPClient::is_blocking_mode_enabled() const{ return blocking; } +Error HTTPClient::_get_http_data(uint8_t* p_buffer, int p_bytes,int &r_received) { + + if (blocking) { + + Error err = connection->get_data(p_buffer,p_bytes); + if (err==OK) + r_received=p_bytes; + else + r_received=0; + return err; + } else { + return connection->get_partial_data(p_buffer,p_bytes,r_received); + } +} void HTTPClient::_bind_methods() { @@ -574,6 +593,7 @@ void HTTPClient::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_response_headers_as_dictionary"),&HTTPClient::_get_response_headers_as_dictionary); ObjectTypeDB::bind_method(_MD("get_response_body_length"),&HTTPClient::get_response_body_length); ObjectTypeDB::bind_method(_MD("read_response_body_chunk"),&HTTPClient::read_response_body_chunk); + ObjectTypeDB::bind_method(_MD("set_read_chunk_size","bytes"),&HTTPClient::set_read_chunk_size); ObjectTypeDB::bind_method(_MD("set_blocking_mode","enabled"),&HTTPClient::set_blocking_mode); ObjectTypeDB::bind_method(_MD("is_blocking_mode_enabled"),&HTTPClient::is_blocking_mode_enabled); @@ -664,6 +684,11 @@ void HTTPClient::_bind_methods() { } +void HTTPClient::set_read_chunk_size(int p_size) { + ERR_FAIL_COND(p_size<256 || p_size>(1<<24)); + read_chunk_size=p_size; +} + HTTPClient::HTTPClient(){ tcp_connection = StreamPeerTCP::create_ref(); @@ -677,7 +702,7 @@ HTTPClient::HTTPClient(){ response_num=0; ssl=false; blocking=false; - tmp_read.resize(4096); + read_chunk_size=4096; } HTTPClient::~HTTPClient(){ diff --git a/core/io/http_client.h b/core/io/http_client.h index 09ad64f48a..d0ebaa4596 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -157,7 +157,10 @@ private: static void _bind_methods(); StringArray _get_response_headers(); Dictionary _get_response_headers_as_dictionary(); - ByteArray tmp_read; + int read_chunk_size; + + Error _get_http_data(uint8_t* p_buffer, int p_bytes,int &r_received); + public: @@ -185,6 +188,7 @@ public: 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); Error poll(); diff --git a/core/resource.cpp b/core/resource.cpp index 987bd772b0..560ca9a1f2 100644 --- a/core/resource.cpp +++ b/core/resource.cpp @@ -130,7 +130,7 @@ void ResourceImportMetadata::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_editor","name"),&ResourceImportMetadata::set_editor); ObjectTypeDB::bind_method(_MD("get_editor"),&ResourceImportMetadata::get_editor); - ObjectTypeDB::bind_method(_MD("add_source","path","md5"),&ResourceImportMetadata::add_source); + ObjectTypeDB::bind_method(_MD("add_source","path","md5"),&ResourceImportMetadata::add_source, ""); ObjectTypeDB::bind_method(_MD("get_source_path","idx"),&ResourceImportMetadata::get_source_path); ObjectTypeDB::bind_method(_MD("get_source_md5","idx"),&ResourceImportMetadata::get_source_md5); ObjectTypeDB::bind_method(_MD("remove_source","idx"),&ResourceImportMetadata::remove_source); diff --git a/core/ustring.cpp b/core/ustring.cpp index 581cc29440..476ab3f936 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -34,6 +34,7 @@ #include "io/md5.h" #include "ucaps.h" #include "color.h" +#include "variant.h" #define MAX_DIGITS 6 #define UPPERCASE(m_c) (((m_c)>='a' && (m_c)<='z')?((m_c)-('a'-'A')):(m_c)) #define LOWERCASE(m_c) (((m_c)>='A' && (m_c)<='Z')?((m_c)+('a'-'A')):(m_c)) @@ -981,7 +982,7 @@ String String::num(double p_num,int p_decimals) { } -String String::num_int64(int64_t p_num) { +String String::num_int64(int64_t p_num, int base, bool capitalize_hex) { bool sign=p_num<0; int64_t num=ABS(p_num); @@ -990,7 +991,7 @@ String String::num_int64(int64_t p_num) { int chars=0; do { - n/=10; + n/=base; chars++; } while(n); @@ -1002,8 +1003,15 @@ String String::num_int64(int64_t p_num) { c[chars]=0; n=num; do { - c[--chars]='0'+(n%10); - n/=10; + int mod = n%base; + if (mod >= 10) { + char a = (capitalize_hex ? 'A' : 'a'); + c[--chars]=a+(mod - 10); + } else { + c[--chars]='0'+mod; + } + + n/=base; } while(n); if (sign) @@ -3518,4 +3526,284 @@ String rtoss(double p_val) { return String::num_scientific(p_val); } +// Right-pad with a character. +String String::rpad(int min_length, const String& character) const { + String s = *this; + int padding = min_length - s.length(); + if (padding > 0) { + for (int i = 0; i < padding; i++) s = s + character; + } + + return s; +} +// Left-pad with a character. +String String::lpad(int min_length, const String& character) const { + String s = *this; + int padding = min_length - s.length(); + if (padding > 0) { + for (int i = 0; i < padding; i++) s = character + s; + } + + return s; +} + +// sprintf is implemented in GDScript via: +// "fish %s pie" % "frog" +// "fish %s %d pie" % ["frog", 12] +String String::sprintf(const Array& values) const { + + String formatted; + CharType* self = (CharType*)c_str(); + int num_items = values.size(); + bool in_format = false; + int value_index = 0; + int min_chars; + int min_decimals; + bool in_decimals; + bool pad_with_zeroes; + bool left_justified; + bool show_sign; + + + for (; *self; self++) { + const CharType c = *self; + + if (in_format) { // We have % - lets see what else we get. + switch (c) { + case '%': { // Replace %% with % + formatted += chr(c); + in_format = false; + break; + } + case 'd': // Integer (signed) + case 'o': // Octal + case 'x': // Hexadecimal (lowercase) + case 'X': { // Hexadecimal (uppercase) + if (value_index >= values.size()) { + ERR_EXPLAIN("not enough arguments for format string"); + ERR_FAIL_V(""); + } + + if (!values[value_index].is_num()) { + ERR_EXPLAIN("a number is required"); + ERR_FAIL_V(""); + } + + int64_t value = values[value_index]; + int base; + bool capitalize = false; + switch (c) { + case 'd': base = 10; break; + case 'o': base = 8; break; + case 'x': base = 16; break; + case 'X': base = 16; capitalize = true; break; + } + // Get basic number. + String str = String::num_int64(value, base, capitalize); + + // Sign. + if (show_sign && value >= 0) { + str = str.insert(0, "+"); + } + + // Padding. + String pad_char = pad_with_zeroes ? String("0") : String(" "); + if (left_justified) { + str = str.rpad(min_chars, pad_char); + } else { + str = str.lpad(min_chars, pad_char); + } + + formatted += str; + ++value_index; + in_format = false; + + break; + } + case 'f': { // Float + if (value_index >= values.size()) { + ERR_EXPLAIN("not enough arguments for format string"); + ERR_FAIL_V(""); + } + + if (!values[value_index].is_num()) { + ERR_EXPLAIN("a number is required"); + ERR_FAIL_V(""); + } + + double value = values[value_index]; + String str = String::num(value, min_decimals); + + // Pad decimals out. + str = str.pad_decimals(min_decimals); + + // Show sign + if (show_sign && value >= 0) { + str = str.insert(0, "+"); + } + + // Padding + if (left_justified) { + str = str.rpad(min_chars); + } else { + str = str.lpad(min_chars); + } + + formatted += str; + ++value_index; + in_format = false; + + break; + } + case 's': { // String + if (value_index >= values.size()) { + ERR_EXPLAIN("not enough arguments for format string"); + ERR_FAIL_V(""); + } + + String str = values[value_index]; + // Padding. + if (left_justified) { + str = str.rpad(min_chars); + } else { + str = str.lpad(min_chars); + } + + formatted += str; + ++value_index; + in_format = false; + break; + } + case 'c': { + if (value_index >= values.size()) { + ERR_EXPLAIN("not enough arguments for format string"); + ERR_FAIL_V(""); + } + + // Convert to character. + String str; + if (values[value_index].is_num()) { + int value = values[value_index]; + if (value < 0) { + ERR_EXPLAIN("unsigned byte integer is lower than maximum") + ERR_FAIL_V(""); + } else if (value > 255) { + ERR_EXPLAIN("unsigned byte integer is greater than maximum") + ERR_FAIL_V(""); + } + str = chr(values[value_index]); + } else if (values[value_index].get_type() == Variant::STRING) { + str = values[value_index]; + if (str.length() != 1) { + ERR_EXPLAIN("%c requires number or single-character string"); + ERR_FAIL_V(""); + } + } else { + ERR_EXPLAIN("%c requires number or single-character string"); + ERR_FAIL_V(""); + } + + // Padding. + if (left_justified) { + str = str.rpad(min_chars); + } else { + str = str.lpad(min_chars); + } + formatted += str; + ++value_index; + in_format = false; + break; + } + case '-': { // Left justify + left_justified = true; + break; + } + case '+': { // Show + if positive. + show_sign = true; + break; + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + int n = c - '0'; + if (in_decimals) { + min_decimals *= 10; + min_decimals += n; + } else { + if (c == '0' && min_chars == 0) { + pad_with_zeroes = true; + } else { + min_chars *= 10; + min_chars += n; + } + } + break; + } + case '.': { // Float separtor. + if (in_decimals) { + ERR_EXPLAIN("too many decimal points in format"); + ERR_FAIL_V(""); + } + in_decimals = true; + min_decimals = 0; // We want to add the value manually. + break; + } + + case '*': { // Dyanmic width, based on value. + if (value_index >= values.size()) { + ERR_EXPLAIN("not enough arguments for format string"); + ERR_FAIL_V(""); + } + + if (!values[value_index].is_num()) { + ERR_EXPLAIN("* wants number"); + ERR_FAIL_V(""); + } + + int size = values[value_index]; + + if (in_decimals) { + min_decimals = size; + } else { + min_chars = size; + } + + ++value_index; + break; + } + + default: { + ERR_EXPLAIN("unsupported format character"); + ERR_FAIL_V(""); + } + } + } else { // Not in format string. + switch (c) { + case '%': + in_format = true; + // Back to defaults: + min_chars = 0; + min_decimals = 6; + pad_with_zeroes = false; + left_justified = false; + show_sign = false; + in_decimals = false; + break; + default: + formatted += chr(c); + } + } + } + + if (in_format) { + ERR_EXPLAIN("incomplete format"); + ERR_FAIL_V(""); + } + + if (value_index != values.size()) { + ERR_EXPLAIN("not all arguments converted during string formatting"); + ERR_FAIL_V(""); + } + + return formatted; +} diff --git a/core/ustring.h b/core/ustring.h index e1d6761742..af5ffb7c35 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -31,6 +31,7 @@ #include "typedefs.h" #include "vector.h" +#include "array.h" /** @author red <red@killy> @@ -127,10 +128,13 @@ public: String insert(int p_at_pos,String p_string) const; String pad_decimals(int p_digits) const; String pad_zeros(int p_digits) const; + String lpad(int min_length,const String& character=" ") const; + String rpad(int min_length,const String& character=" ") const; + String sprintf(const Array& values) const; static String num(double p_num,int p_decimals=-1); static String num_scientific(double p_num); static String num_real(double p_num); - static String num_int64(int64_t p_num); + static String num_int64(int64_t p_num,int base=10,bool capitalize_hex=false); static String chr(CharType p_char); static String md5(const uint8_t *p_md5); bool is_numeric() const; @@ -203,7 +207,7 @@ public: String xml_unescape() const; String c_escape() const; String c_unescape() const; - + String percent_encode() const; String percent_decode() const; diff --git a/core/variant_op.cpp b/core/variant_op.cpp index fbb5e2631d..21bbc8c7ee 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -736,6 +736,20 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant& } #endif _RETURN( p_a._data._int % p_b._data._int ); + + } else if (p_a.type==STRING) { + const String *str=reinterpret_cast<const String*>(p_a._data._mem); + + if (p_b.type==ARRAY) { + // e.g. "frog %s %d" % ["fish", 12] + const Array *arr=reinterpret_cast<const Array*>(p_b._data._mem); + _RETURN(str->sprintf(*arr)); + } else { + // e.g. "frog %d" % 12 + Array arr; + arr.push_back(p_b); + _RETURN(str->sprintf(arr)); + } } r_valid=false; |