diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino index 4902ec3a4..9dcf44ccb 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino @@ -654,21 +654,59 @@ extern "C" { } } -class StreamBytes: public Stream + +// a stream which writes to the Bytes object on the top of the stack +class StreamBeBytesWriter: public Stream { public: - StreamBytes(uint8_t * buf_in, int len_in) : buf(buf_in), offset(0), len(len_in) {}; + StreamBeBytesWriter(bvm *vm_in, int increment = 1024) : vm(vm_in), offset(0), incr(increment) {}; size_t write(const uint8_t *buffer, size_t size) override { - // AddLog(LOG_LEVEL_INFO, "FLASH: addr=%p hex=%*_H size=%i", addr_start + offset, 32, buffer, size); - if (size > 0) { - if (offset + size > len){ - AddLog(LOG_LEVEL_ERROR, "BERRYWC: bufer overrun"); - return size; + // we need size, not len, so can;t just get len with be_tobytes + be_getmember(vm, -1, ".size"); + int32_t signed_size = be_toint(vm, -1); + be_pop(vm, 1); /* bytes() instance is at top */ + + // if it won't fit, make the bytes object bigger + if (offset + size > signed_size){ + int newsize = offset + size + incr; + AddLog(LOG_LEVEL_INFO, "BE: realloc bytes in StreamBeBytesWriter newsize=%i", newsize); + be_getmember(vm, -1, "resize"); + be_pushvalue(vm, -2); + be_pushint(vm, size); + be_call(vm, 2); /* call b.resize(size) */ + be_pop(vm, 3); /* bytes() instance is at top */ + + // checkw e got it, because Berry just maxes out? + be_getmember(vm, -1, ".size"); + signed_size = be_toint(vm, -1); + be_pop(vm, 1); /* bytes() instance is at top */ + if (offset + size > signed_size){ + // what should we raise here??? + be_raise(vm, "alloc_error", "did not get enough extra bytes"); } - memcpy(buf+offset, buffer, size); - offset += size; } + + // AddLog(LOG_LEVEL_INFO, "FLASH: addr=%p hex=%*_H size=%i", addr_start + offset, 32, buffer, size); + if (offset + size > signed_size){ + AddLog(LOG_LEVEL_ERROR, "BERRYWC: buffer overrun"); + return size; + } + + char *bytebuf = (char*) be_tobytes(vm, -1, NULL); /* we get the address of the internam buffer of size 'size' */ + if (!bytebuf){ + AddLog(LOG_LEVEL_ERROR, "BERRYWC: buffer null??"); + return size; + } + + // stream in our chunk + memcpy(bytebuf + offset, buffer, size); + offset += size; + + // set the len + be_pushint(vm, offset); + be_setmember(vm, -2, ".len"); + be_pop(vm, 1); return size; } size_t write(uint8_t data) override { @@ -682,9 +720,9 @@ public: void flush() override { } protected: - uint8_t *buf; // start address + bvm *vm; // the berry VM uint32_t offset; // how many bytes have already been written - uint32_t len; // allocated len + size_t incr; // amount to add to size if it does not fit. }; extern "C" { @@ -693,14 +731,16 @@ extern "C" { HTTPClientLight * cl = wc_getclient(vm); int32_t sz = cl->getSize(); // abort if we exceed 32KB size, things will not go well otherwise - if (sz >= 32767 || sz < 0) { - be_raise(vm, "value_error", "response size -1 or too big (>32KB)"); + if (sz >= 32767) { + be_raise(vm, "value_error", "response size too big (>32KB)"); } - uint8_t * buf = (uint8_t*) be_pushbuffer(vm, sz); - StreamBytes memory_writer(buf, sz); + // default to 1K starter if contetn-length not present + if (sz < 0) sz = 1024; + // create a bytes object at top of stack. + // the streamwriter knows how to get it. + uint8_t * buf = (uint8_t*) be_pushbytes(vm, nullptr, sz); + StreamBeBytesWriter memory_writer(vm); int32_t written = cl->writeToStream(&memory_writer); - - be_pushbytes(vm, buf, sz); cl->end(); // free allocated memory ~16KB be_return(vm); /* return code */ }