1/**************************************************************************/
2/* stream_peer.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "stream_peer.h"
32
33#include "core/io/marshalls.h"
34
35Error StreamPeer::_put_data(const Vector<uint8_t> &p_data) {
36 int len = p_data.size();
37 if (len == 0) {
38 return OK;
39 }
40 const uint8_t *r = p_data.ptr();
41 return put_data(&r[0], len);
42}
43
44Array StreamPeer::_put_partial_data(const Vector<uint8_t> &p_data) {
45 Array ret;
46
47 int len = p_data.size();
48 if (len == 0) {
49 ret.push_back(OK);
50 ret.push_back(0);
51 return ret;
52 }
53
54 const uint8_t *r = p_data.ptr();
55 int sent;
56 Error err = put_partial_data(&r[0], len, sent);
57
58 if (err != OK) {
59 sent = 0;
60 }
61 ret.push_back(err);
62 ret.push_back(sent);
63 return ret;
64}
65
66Array StreamPeer::_get_data(int p_bytes) {
67 Array ret;
68
69 Vector<uint8_t> data;
70 data.resize(p_bytes);
71 if (data.size() != p_bytes) {
72 ret.push_back(ERR_OUT_OF_MEMORY);
73 ret.push_back(Vector<uint8_t>());
74 return ret;
75 }
76
77 uint8_t *w = data.ptrw();
78 Error err = get_data(&w[0], p_bytes);
79
80 ret.push_back(err);
81 ret.push_back(data);
82 return ret;
83}
84
85Array StreamPeer::_get_partial_data(int p_bytes) {
86 Array ret;
87
88 Vector<uint8_t> data;
89 data.resize(p_bytes);
90 if (data.size() != p_bytes) {
91 ret.push_back(ERR_OUT_OF_MEMORY);
92 ret.push_back(Vector<uint8_t>());
93 return ret;
94 }
95
96 uint8_t *w = data.ptrw();
97 int received;
98 Error err = get_partial_data(&w[0], p_bytes, received);
99
100 if (err != OK) {
101 data.clear();
102 } else if (received != data.size()) {
103 data.resize(received);
104 }
105
106 ret.push_back(err);
107 ret.push_back(data);
108 return ret;
109}
110
111void StreamPeer::set_big_endian(bool p_big_endian) {
112 big_endian = p_big_endian;
113}
114
115bool StreamPeer::is_big_endian_enabled() const {
116 return big_endian;
117}
118
119void StreamPeer::put_u8(uint8_t p_val) {
120 put_data((const uint8_t *)&p_val, 1);
121}
122
123void StreamPeer::put_8(int8_t p_val) {
124 put_data((const uint8_t *)&p_val, 1);
125}
126
127void StreamPeer::put_u16(uint16_t p_val) {
128 if (big_endian) {
129 p_val = BSWAP16(p_val);
130 }
131 uint8_t buf[2];
132 encode_uint16(p_val, buf);
133 put_data(buf, 2);
134}
135
136void StreamPeer::put_16(int16_t p_val) {
137 if (big_endian) {
138 p_val = BSWAP16(p_val);
139 }
140 uint8_t buf[2];
141 encode_uint16(p_val, buf);
142 put_data(buf, 2);
143}
144
145void StreamPeer::put_u32(uint32_t p_val) {
146 if (big_endian) {
147 p_val = BSWAP32(p_val);
148 }
149 uint8_t buf[4];
150 encode_uint32(p_val, buf);
151 put_data(buf, 4);
152}
153
154void StreamPeer::put_32(int32_t p_val) {
155 if (big_endian) {
156 p_val = BSWAP32(p_val);
157 }
158 uint8_t buf[4];
159 encode_uint32(p_val, buf);
160 put_data(buf, 4);
161}
162
163void StreamPeer::put_u64(uint64_t p_val) {
164 if (big_endian) {
165 p_val = BSWAP64(p_val);
166 }
167 uint8_t buf[8];
168 encode_uint64(p_val, buf);
169 put_data(buf, 8);
170}
171
172void StreamPeer::put_64(int64_t p_val) {
173 if (big_endian) {
174 p_val = BSWAP64(p_val);
175 }
176 uint8_t buf[8];
177 encode_uint64(p_val, buf);
178 put_data(buf, 8);
179}
180
181void StreamPeer::put_float(float p_val) {
182 uint8_t buf[4];
183
184 encode_float(p_val, buf);
185 if (big_endian) {
186 uint32_t *p32 = (uint32_t *)buf;
187 *p32 = BSWAP32(*p32);
188 }
189
190 put_data(buf, 4);
191}
192
193void StreamPeer::put_double(double p_val) {
194 uint8_t buf[8];
195 encode_double(p_val, buf);
196 if (big_endian) {
197 uint64_t *p64 = (uint64_t *)buf;
198 *p64 = BSWAP64(*p64);
199 }
200 put_data(buf, 8);
201}
202
203void StreamPeer::put_string(const String &p_string) {
204 CharString cs = p_string.ascii();
205 put_u32(cs.length());
206 put_data((const uint8_t *)cs.get_data(), cs.length());
207}
208
209void StreamPeer::put_utf8_string(const String &p_string) {
210 CharString cs = p_string.utf8();
211 put_u32(cs.length());
212 put_data((const uint8_t *)cs.get_data(), cs.length());
213}
214
215void StreamPeer::put_var(const Variant &p_variant, bool p_full_objects) {
216 int len = 0;
217 Vector<uint8_t> buf;
218 encode_variant(p_variant, nullptr, len, p_full_objects);
219 buf.resize(len);
220 put_32(len);
221 encode_variant(p_variant, buf.ptrw(), len, p_full_objects);
222 put_data(buf.ptr(), buf.size());
223}
224
225uint8_t StreamPeer::get_u8() {
226 uint8_t buf[1];
227 get_data(buf, 1);
228 return buf[0];
229}
230
231int8_t StreamPeer::get_8() {
232 uint8_t buf[1];
233 get_data(buf, 1);
234 return buf[0];
235}
236
237uint16_t StreamPeer::get_u16() {
238 uint8_t buf[2];
239 get_data(buf, 2);
240 uint16_t r = decode_uint16(buf);
241 if (big_endian) {
242 r = BSWAP16(r);
243 }
244 return r;
245}
246
247int16_t StreamPeer::get_16() {
248 uint8_t buf[2];
249 get_data(buf, 2);
250 uint16_t r = decode_uint16(buf);
251 if (big_endian) {
252 r = BSWAP16(r);
253 }
254 return r;
255}
256
257uint32_t StreamPeer::get_u32() {
258 uint8_t buf[4];
259 get_data(buf, 4);
260 uint32_t r = decode_uint32(buf);
261 if (big_endian) {
262 r = BSWAP32(r);
263 }
264 return r;
265}
266
267int32_t StreamPeer::get_32() {
268 uint8_t buf[4];
269 get_data(buf, 4);
270 uint32_t r = decode_uint32(buf);
271 if (big_endian) {
272 r = BSWAP32(r);
273 }
274 return r;
275}
276
277uint64_t StreamPeer::get_u64() {
278 uint8_t buf[8];
279 get_data(buf, 8);
280 uint64_t r = decode_uint64(buf);
281 if (big_endian) {
282 r = BSWAP64(r);
283 }
284 return r;
285}
286
287int64_t StreamPeer::get_64() {
288 uint8_t buf[8];
289 get_data(buf, 8);
290 uint64_t r = decode_uint64(buf);
291 if (big_endian) {
292 r = BSWAP64(r);
293 }
294 return r;
295}
296
297float StreamPeer::get_float() {
298 uint8_t buf[4];
299 get_data(buf, 4);
300
301 if (big_endian) {
302 uint32_t *p32 = (uint32_t *)buf;
303 *p32 = BSWAP32(*p32);
304 }
305
306 return decode_float(buf);
307}
308
309double StreamPeer::get_double() {
310 uint8_t buf[8];
311 get_data(buf, 8);
312
313 if (big_endian) {
314 uint64_t *p64 = (uint64_t *)buf;
315 *p64 = BSWAP64(*p64);
316 }
317
318 return decode_double(buf);
319}
320
321String StreamPeer::get_string(int p_bytes) {
322 if (p_bytes < 0) {
323 p_bytes = get_u32();
324 }
325 ERR_FAIL_COND_V(p_bytes < 0, String());
326
327 Vector<char> buf;
328 Error err = buf.resize(p_bytes + 1);
329 ERR_FAIL_COND_V(err != OK, String());
330 err = get_data((uint8_t *)&buf[0], p_bytes);
331 ERR_FAIL_COND_V(err != OK, String());
332 buf.write[p_bytes] = 0;
333 return buf.ptr();
334}
335
336String StreamPeer::get_utf8_string(int p_bytes) {
337 if (p_bytes < 0) {
338 p_bytes = get_u32();
339 }
340 ERR_FAIL_COND_V(p_bytes < 0, String());
341
342 Vector<uint8_t> buf;
343 Error err = buf.resize(p_bytes);
344 ERR_FAIL_COND_V(err != OK, String());
345 err = get_data(buf.ptrw(), p_bytes);
346 ERR_FAIL_COND_V(err != OK, String());
347
348 String ret;
349 ret.parse_utf8((const char *)buf.ptr(), buf.size());
350 return ret;
351}
352
353Variant StreamPeer::get_var(bool p_allow_objects) {
354 int len = get_32();
355 Vector<uint8_t> var;
356 Error err = var.resize(len);
357 ERR_FAIL_COND_V(err != OK, Variant());
358 err = get_data(var.ptrw(), len);
359 ERR_FAIL_COND_V(err != OK, Variant());
360
361 Variant ret;
362 err = decode_variant(ret, var.ptr(), len, nullptr, p_allow_objects);
363 ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to decode Variant.");
364
365 return ret;
366}
367
368void StreamPeer::_bind_methods() {
369 ClassDB::bind_method(D_METHOD("put_data", "data"), &StreamPeer::_put_data);
370 ClassDB::bind_method(D_METHOD("put_partial_data", "data"), &StreamPeer::_put_partial_data);
371
372 ClassDB::bind_method(D_METHOD("get_data", "bytes"), &StreamPeer::_get_data);
373 ClassDB::bind_method(D_METHOD("get_partial_data", "bytes"), &StreamPeer::_get_partial_data);
374
375 ClassDB::bind_method(D_METHOD("get_available_bytes"), &StreamPeer::get_available_bytes);
376
377 ClassDB::bind_method(D_METHOD("set_big_endian", "enable"), &StreamPeer::set_big_endian);
378 ClassDB::bind_method(D_METHOD("is_big_endian_enabled"), &StreamPeer::is_big_endian_enabled);
379
380 ClassDB::bind_method(D_METHOD("put_8", "value"), &StreamPeer::put_8);
381 ClassDB::bind_method(D_METHOD("put_u8", "value"), &StreamPeer::put_u8);
382 ClassDB::bind_method(D_METHOD("put_16", "value"), &StreamPeer::put_16);
383 ClassDB::bind_method(D_METHOD("put_u16", "value"), &StreamPeer::put_u16);
384 ClassDB::bind_method(D_METHOD("put_32", "value"), &StreamPeer::put_32);
385 ClassDB::bind_method(D_METHOD("put_u32", "value"), &StreamPeer::put_u32);
386 ClassDB::bind_method(D_METHOD("put_64", "value"), &StreamPeer::put_64);
387 ClassDB::bind_method(D_METHOD("put_u64", "value"), &StreamPeer::put_u64);
388 ClassDB::bind_method(D_METHOD("put_float", "value"), &StreamPeer::put_float);
389 ClassDB::bind_method(D_METHOD("put_double", "value"), &StreamPeer::put_double);
390 ClassDB::bind_method(D_METHOD("put_string", "value"), &StreamPeer::put_string);
391 ClassDB::bind_method(D_METHOD("put_utf8_string", "value"), &StreamPeer::put_utf8_string);
392 ClassDB::bind_method(D_METHOD("put_var", "value", "full_objects"), &StreamPeer::put_var, DEFVAL(false));
393
394 ClassDB::bind_method(D_METHOD("get_8"), &StreamPeer::get_8);
395 ClassDB::bind_method(D_METHOD("get_u8"), &StreamPeer::get_u8);
396 ClassDB::bind_method(D_METHOD("get_16"), &StreamPeer::get_16);
397 ClassDB::bind_method(D_METHOD("get_u16"), &StreamPeer::get_u16);
398 ClassDB::bind_method(D_METHOD("get_32"), &StreamPeer::get_32);
399 ClassDB::bind_method(D_METHOD("get_u32"), &StreamPeer::get_u32);
400 ClassDB::bind_method(D_METHOD("get_64"), &StreamPeer::get_64);
401 ClassDB::bind_method(D_METHOD("get_u64"), &StreamPeer::get_u64);
402 ClassDB::bind_method(D_METHOD("get_float"), &StreamPeer::get_float);
403 ClassDB::bind_method(D_METHOD("get_double"), &StreamPeer::get_double);
404 ClassDB::bind_method(D_METHOD("get_string", "bytes"), &StreamPeer::get_string, DEFVAL(-1));
405 ClassDB::bind_method(D_METHOD("get_utf8_string", "bytes"), &StreamPeer::get_utf8_string, DEFVAL(-1));
406 ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &StreamPeer::get_var, DEFVAL(false));
407
408 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian_enabled");
409}
410
411////////////////////////////////
412
413Error StreamPeerExtension::get_data(uint8_t *r_buffer, int p_bytes) {
414 Error err;
415 int received = 0;
416 if (GDVIRTUAL_CALL(_get_data, r_buffer, p_bytes, &received, err)) {
417 return err;
418 }
419 WARN_PRINT_ONCE("StreamPeerExtension::_get_data is unimplemented!");
420 return FAILED;
421}
422
423Error StreamPeerExtension::get_partial_data(uint8_t *r_buffer, int p_bytes, int &r_received) {
424 Error err;
425 if (GDVIRTUAL_CALL(_get_partial_data, r_buffer, p_bytes, &r_received, err)) {
426 return err;
427 }
428 WARN_PRINT_ONCE("StreamPeerExtension::_get_partial_data is unimplemented!");
429 return FAILED;
430}
431
432Error StreamPeerExtension::put_data(const uint8_t *p_data, int p_bytes) {
433 Error err;
434 int sent = 0;
435 if (GDVIRTUAL_CALL(_put_data, p_data, p_bytes, &sent, err)) {
436 return err;
437 }
438 WARN_PRINT_ONCE("StreamPeerExtension::_put_data is unimplemented!");
439 return FAILED;
440}
441
442Error StreamPeerExtension::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
443 Error err;
444 if (GDVIRTUAL_CALL(_put_data, p_data, p_bytes, &r_sent, err)) {
445 return err;
446 }
447 WARN_PRINT_ONCE("StreamPeerExtension::_put_partial_data is unimplemented!");
448 return FAILED;
449}
450
451void StreamPeerExtension::_bind_methods() {
452 GDVIRTUAL_BIND(_get_data, "r_buffer", "r_bytes", "r_received");
453 GDVIRTUAL_BIND(_get_partial_data, "r_buffer", "r_bytes", "r_received");
454 GDVIRTUAL_BIND(_put_data, "p_data", "p_bytes", "r_sent");
455 GDVIRTUAL_BIND(_put_partial_data, "p_data", "p_bytes", "r_sent");
456 GDVIRTUAL_BIND(_get_available_bytes);
457}
458
459////////////////////////////////
460
461void StreamPeerBuffer::_bind_methods() {
462 ClassDB::bind_method(D_METHOD("seek", "position"), &StreamPeerBuffer::seek);
463 ClassDB::bind_method(D_METHOD("get_size"), &StreamPeerBuffer::get_size);
464 ClassDB::bind_method(D_METHOD("get_position"), &StreamPeerBuffer::get_position);
465 ClassDB::bind_method(D_METHOD("resize", "size"), &StreamPeerBuffer::resize);
466 ClassDB::bind_method(D_METHOD("set_data_array", "data"), &StreamPeerBuffer::set_data_array);
467 ClassDB::bind_method(D_METHOD("get_data_array"), &StreamPeerBuffer::get_data_array);
468 ClassDB::bind_method(D_METHOD("clear"), &StreamPeerBuffer::clear);
469 ClassDB::bind_method(D_METHOD("duplicate"), &StreamPeerBuffer::duplicate);
470
471 ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data_array"), "set_data_array", "get_data_array");
472}
473
474Error StreamPeerBuffer::put_data(const uint8_t *p_data, int p_bytes) {
475 if (p_bytes <= 0) {
476 return OK;
477 }
478
479 if (pointer + p_bytes > data.size()) {
480 data.resize(pointer + p_bytes);
481 }
482
483 uint8_t *w = data.ptrw();
484 memcpy(&w[pointer], p_data, p_bytes);
485
486 pointer += p_bytes;
487 return OK;
488}
489
490Error StreamPeerBuffer::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
491 r_sent = p_bytes;
492 return put_data(p_data, p_bytes);
493}
494
495Error StreamPeerBuffer::get_data(uint8_t *p_buffer, int p_bytes) {
496 int recv;
497 get_partial_data(p_buffer, p_bytes, recv);
498 if (recv != p_bytes) {
499 return ERR_INVALID_PARAMETER;
500 }
501
502 return OK;
503}
504
505Error StreamPeerBuffer::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) {
506 if (pointer + p_bytes > data.size()) {
507 r_received = data.size() - pointer;
508 if (r_received <= 0) {
509 r_received = 0;
510 return OK; //you got 0
511 }
512 } else {
513 r_received = p_bytes;
514 }
515
516 const uint8_t *r = data.ptr();
517 memcpy(p_buffer, r + pointer, r_received);
518
519 pointer += r_received;
520 // FIXME: return what? OK or ERR_*
521 // return OK for now so we don't maybe return garbage
522 return OK;
523}
524
525int StreamPeerBuffer::get_available_bytes() const {
526 return data.size() - pointer;
527}
528
529void StreamPeerBuffer::seek(int p_pos) {
530 ERR_FAIL_COND(p_pos < 0);
531 ERR_FAIL_COND(p_pos > data.size());
532 pointer = p_pos;
533}
534
535int StreamPeerBuffer::get_size() const {
536 return data.size();
537}
538
539int StreamPeerBuffer::get_position() const {
540 return pointer;
541}
542
543void StreamPeerBuffer::resize(int p_size) {
544 data.resize(p_size);
545}
546
547void StreamPeerBuffer::set_data_array(const Vector<uint8_t> &p_data) {
548 data = p_data;
549 pointer = 0;
550}
551
552Vector<uint8_t> StreamPeerBuffer::get_data_array() const {
553 return data;
554}
555
556void StreamPeerBuffer::clear() {
557 data.clear();
558 pointer = 0;
559}
560
561Ref<StreamPeerBuffer> StreamPeerBuffer::duplicate() const {
562 Ref<StreamPeerBuffer> spb;
563 spb.instantiate();
564 spb->data = data;
565 return spb;
566}
567