@@ -1561,8 +1561,8 @@ public: | |||
// manually write messages so we can take the lock for ourselves | |||
{ | |||
char tmpBuf[0xff+1]; | |||
tmpBuf[0xff] = '\0'; | |||
char tmpBuf[0xff]; | |||
tmpBuf[0xfe] = '\0'; | |||
const CarlaMutexLocker cml(fPipeServer.getPipeLock()); | |||
const CarlaScopedLocale csl; | |||
@@ -1575,12 +1575,17 @@ public: | |||
continue; | |||
const std::string& uri(*it); | |||
std::snprintf(tmpBuf, 0xff, "%u\n", u); | |||
if (! fPipeServer.writeMessage("urid\n", 5)) | |||
return; | |||
std::snprintf(tmpBuf, 0xfe, "%u\n", u); | |||
if (! fPipeServer.writeMessage(tmpBuf)) | |||
return; | |||
std::snprintf(tmpBuf, 0xfe, "%lu\n", static_cast<long unsigned>(uri.length())); | |||
if (! fPipeServer.writeMessage(tmpBuf)) | |||
return; | |||
if (! fPipeServer.writeAndFixMessage(uri.c_str())) | |||
return; | |||
} | |||
@@ -7252,15 +7257,16 @@ bool CarlaPipeServerLV2::msgReceived(const char* const msg) noexcept | |||
if (std::strcmp(msg, "atom") == 0) | |||
{ | |||
uint32_t index, size; | |||
uint32_t index, atomTotalSize, base64Size; | |||
const char* base64atom; | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(size), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(base64atom, false), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(atomTotalSize), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(base64Size), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(base64atom, false, base64Size), true); | |||
std::vector<uint8_t> chunk(carla_getChunkFromBase64String(base64atom)); | |||
CARLA_SAFE_ASSERT_RETURN(chunk.size() >= sizeof(LV2_Atom), true); | |||
CARLA_SAFE_ASSERT_UINT2_RETURN(chunk.size() >= sizeof(LV2_Atom), chunk.size(), sizeof(LV2_Atom), true); | |||
#ifdef CARLA_PROPER_CPP11_SUPPORT | |||
const LV2_Atom* const atom((const LV2_Atom*)chunk.data()); | |||
@@ -7291,11 +7297,12 @@ bool CarlaPipeServerLV2::msgReceived(const char* const msg) noexcept | |||
if (std::strcmp(msg, "urid") == 0) | |||
{ | |||
uint32_t urid; | |||
uint32_t urid, size; | |||
const char* uri; | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(urid), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uri, false), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(size), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uri, false, size), true); | |||
if (urid != 0) | |||
{ | |||
@@ -88,7 +88,7 @@ public: | |||
#endif | |||
delete[] fLastReadLine; | |||
fLastReadLine = CarlaPipeClient::_readlineblock(true, timeout); | |||
fLastReadLine = CarlaPipeClient::_readlineblock(true, 0, timeout); | |||
return fLastReadLine; | |||
} | |||
@@ -103,7 +103,7 @@ public: | |||
} | |||
#endif | |||
if (const char* const line = CarlaPipeClient::_readlineblock(false, timeout)) | |||
if (const char* const line = CarlaPipeClient::_readlineblock(false, 0, timeout)) | |||
return std::strcmp(line, "true") == 0; | |||
return false; | |||
@@ -120,7 +120,7 @@ public: | |||
} | |||
#endif | |||
if (const char* const line = CarlaPipeClient::_readlineblock(false, timeout)) | |||
if (const char* const line = CarlaPipeClient::_readlineblock(false, 0, timeout)) | |||
return std::atoi(line); | |||
return 0; | |||
@@ -137,7 +137,7 @@ public: | |||
} | |||
#endif | |||
if (const char* const line = CarlaPipeClient::_readlineblock(false, timeout)) | |||
if (const char* const line = CarlaPipeClient::_readlineblock(false, 0, timeout)) | |||
return std::atof(line); | |||
return 0.0; | |||
@@ -42,7 +42,8 @@ CarlaBridgeFormat::CarlaBridgeFormat() noexcept | |||
fLastMsgTimer(-1), | |||
fToolkit(nullptr), | |||
fLib(nullptr), | |||
fLibFilename() | |||
fLibFilename(), | |||
fBase64ReservedChunk() | |||
{ | |||
carla_debug("CarlaBridgeFormat::CarlaBridgeFormat()"); | |||
@@ -120,6 +121,50 @@ bool CarlaBridgeFormat::msgReceived(const char* const msg) noexcept | |||
if (fLastMsgTimer > 0) | |||
--fLastMsgTimer; | |||
if (std::strcmp(msg, "atom") == 0) | |||
{ | |||
uint32_t index, atomTotalSize, base64Size; | |||
const char* base64atom; | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(atomTotalSize), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(base64Size), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(base64atom, false, base64Size), true); | |||
carla_getChunkFromBase64String_impl(fBase64ReservedChunk, base64atom); | |||
CARLA_SAFE_ASSERT_UINT2_RETURN(fBase64ReservedChunk.size() >= sizeof(LV2_Atom), | |||
fBase64ReservedChunk.size(), sizeof(LV2_Atom), true); | |||
#ifdef CARLA_PROPER_CPP11_SUPPORT | |||
const LV2_Atom* const atom((const LV2_Atom*)fBase64ReservedChunk.data()); | |||
#else | |||
const LV2_Atom* const atom((const LV2_Atom*)&fBase64ReservedChunk.front()); | |||
#endif | |||
const uint32_t atomTotalSizeCheck(lv2_atom_total_size(atom)); | |||
CARLA_SAFE_ASSERT_UINT2_RETURN(atomTotalSizeCheck == atomTotalSize, atomTotalSizeCheck, atomTotalSize, true); | |||
CARLA_SAFE_ASSERT_UINT2_RETURN(atomTotalSizeCheck == fBase64ReservedChunk.size(), | |||
atomTotalSizeCheck, fBase64ReservedChunk.size(), true); | |||
dspAtomReceived(index, atom); | |||
return true; | |||
} | |||
if (std::strcmp(msg, "urid") == 0) | |||
{ | |||
uint32_t urid, size; | |||
const char* uri; | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(urid), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(size), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uri, false, size), true); | |||
if (urid != 0) | |||
dspURIDReceived(urid, uri); | |||
return true; | |||
} | |||
if (std::strcmp(msg, "control") == 0) | |||
{ | |||
uint32_t index; | |||
@@ -181,46 +226,6 @@ bool CarlaBridgeFormat::msgReceived(const char* const msg) noexcept | |||
return true; | |||
} | |||
if (std::strcmp(msg, "atom") == 0) | |||
{ | |||
uint32_t index, atomTotalSize; | |||
const char* base64atom; | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(atomTotalSize), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(base64atom, false), true); | |||
std::vector<uint8_t> chunk(carla_getChunkFromBase64String(base64atom)); | |||
CARLA_SAFE_ASSERT_RETURN(chunk.size() >= sizeof(LV2_Atom), true); | |||
#ifdef CARLA_PROPER_CPP11_SUPPORT | |||
const LV2_Atom* const atom((const LV2_Atom*)chunk.data()); | |||
#else | |||
const LV2_Atom* const atom((const LV2_Atom*)&chunk.front()); | |||
#endif | |||
const uint32_t atomTotalSizeCheck(lv2_atom_total_size(atom)); | |||
CARLA_SAFE_ASSERT_RETURN(atomTotalSizeCheck == atomTotalSize, true); | |||
CARLA_SAFE_ASSERT_RETURN(atomTotalSizeCheck == chunk.size(), true); | |||
dspAtomReceived(index, atom); | |||
return true; | |||
} | |||
if (std::strcmp(msg, "urid") == 0) | |||
{ | |||
uint32_t urid; | |||
const char* uri; | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(urid), true); | |||
CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uri, false), true); | |||
if (urid != 0) | |||
dspURIDReceived(urid, uri); | |||
return true; | |||
} | |||
if (std::strcmp(msg, "uiOptions") == 0) | |||
{ | |||
BridgeFormatOptions opts; | |||
@@ -27,6 +27,8 @@ | |||
#include "lv2/atom.h" | |||
#include "lv2/urid.h" | |||
#include <vector> | |||
CARLA_BRIDGE_UI_START_NAMESPACE | |||
/*! | |||
@@ -161,6 +163,7 @@ protected: | |||
lib_t fLib; | |||
CarlaString fLibFilename; | |||
std::vector<uint8_t> fBase64ReservedChunk; | |||
/*! @internal */ | |||
bool msgReceived(const char* const msg) noexcept override; | |||
@@ -108,7 +108,7 @@ public: | |||
// MacOS and Win32 have event-loops to run, so minimize sleep time | |||
carla_msleep(1); | |||
#else | |||
carla_msleep(20); | |||
carla_msleep(33); | |||
#endif | |||
} | |||
} | |||
@@ -60,15 +60,15 @@ bool isBase64Char(const char c) | |||
// ----------------------------------------------------------------------- | |||
static inline | |||
std::vector<uint8_t> carla_getChunkFromBase64String(const char* const base64string) | |||
void carla_getChunkFromBase64String_impl(std::vector<uint8_t>& vector, const char* const base64string) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(base64string != nullptr, std::vector<uint8_t>()); | |||
CARLA_SAFE_ASSERT_RETURN(base64string != nullptr,); | |||
uint i=0, j=0; | |||
uint charArray3[3], charArray4[4]; | |||
std::vector<uint8_t> ret; | |||
ret.reserve(std::strlen(base64string)*3/4 + 4); | |||
vector.clear(); | |||
vector.reserve(std::strlen(base64string)*3/4 + 4); | |||
for (std::size_t l=0, len=std::strlen(base64string); l<len; ++l) | |||
{ | |||
@@ -93,7 +93,7 @@ std::vector<uint8_t> carla_getChunkFromBase64String(const char* const base64stri | |||
charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; | |||
for (i=0; i<3; ++i) | |||
ret.push_back(static_cast<uint8_t>(charArray3[i])); | |||
vector.push_back(static_cast<uint8_t>(charArray3[i])); | |||
i = 0; | |||
} | |||
@@ -112,9 +112,16 @@ std::vector<uint8_t> carla_getChunkFromBase64String(const char* const base64stri | |||
charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; | |||
for (j=0; i>0 && j<i-1; j++) | |||
ret.push_back(static_cast<uint8_t>(charArray3[j])); | |||
vector.push_back(static_cast<uint8_t>(charArray3[j])); | |||
} | |||
} | |||
static inline | |||
std::vector<uint8_t> carla_getChunkFromBase64String(const char* const base64string) | |||
{ | |||
std::vector<uint8_t> ret; | |||
carla_getChunkFromBase64String_impl(ret, base64string); | |||
return ret; | |||
} | |||
@@ -660,10 +660,12 @@ void CarlaPipeCommon::idlePipe(const bool onlyOnce) noexcept | |||
for (;;) | |||
{ | |||
readSucess = false; | |||
const char* const msg = _readline(true, readSucess); | |||
const char* const msg = _readline(true, 0, readSucess); | |||
if (msg == nullptr || ! readSucess) | |||
if (! readSucess) | |||
break; | |||
if (msg == nullptr) | |||
continue; | |||
pData->isReading = true; | |||
@@ -836,11 +838,14 @@ bool CarlaPipeCommon::readNextLineAsDouble(double& value) const noexcept | |||
return false; | |||
} | |||
bool CarlaPipeCommon::readNextLineAsString(const char*& value, const bool allocateString) const noexcept | |||
bool CarlaPipeCommon::readNextLineAsString(const char*& value, const bool allocateString, uint32_t size) const noexcept | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(pData->isReading, false); | |||
if (const char* const msg = _readlineblock(allocateString)) | |||
if (size >= 0xffff) | |||
size = 0; | |||
if (const char* const msg = _readlineblock(allocateString, static_cast<uint16_t>(size))) | |||
{ | |||
value = msg; | |||
return true; | |||
@@ -1141,6 +1146,10 @@ void CarlaPipeCommon::writeLv2AtomMessage(const uint32_t index, const LV2_Atom* | |||
if (! _writeMsgBuffer(tmpBuf, std::strlen(tmpBuf))) | |||
return; | |||
std::snprintf(tmpBuf, 0xfe, "%lu\n", static_cast<long unsigned>(base64atom.length())); | |||
if (! _writeMsgBuffer(tmpBuf, std::strlen(tmpBuf))) | |||
return; | |||
if (! writeAndFixMessage(base64atom.buffer())) | |||
return; | |||
@@ -1164,6 +1173,10 @@ void CarlaPipeCommon::writeLv2UridMessage(const uint32_t urid, const char* const | |||
if (! _writeMsgBuffer(tmpBuf, std::strlen(tmpBuf))) | |||
return; | |||
std::snprintf(tmpBuf, 0xfe, "%lu\n", static_cast<long unsigned>(std::strlen(uri))); | |||
if (! _writeMsgBuffer(tmpBuf, std::strlen(tmpBuf))) | |||
return; | |||
if (! writeAndFixMessage(uri)) | |||
return; | |||
@@ -1173,7 +1186,7 @@ void CarlaPipeCommon::writeLv2UridMessage(const uint32_t urid, const char* const | |||
// ------------------------------------------------------------------- | |||
// internal | |||
const char* CarlaPipeCommon::_readline(const bool allocReturn, bool& readSucess) const noexcept | |||
const char* CarlaPipeCommon::_readline(const bool allocReturn, const uint16_t size, bool& readSucess) const noexcept | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(pData->pipeRecv != INVALID_PIPE_VALUE, nullptr); | |||
@@ -1184,31 +1197,79 @@ const char* CarlaPipeCommon::_readline(const bool allocReturn, bool& readSucess) | |||
pData->tmpStr.clear(); | |||
for (int i=0; i<0xfffe; ++i) | |||
if (size == 0 || size == 1) | |||
{ | |||
try { | |||
#ifdef CARLA_OS_WIN | |||
ret = ReadFileWin32(pData->pipeRecv, pData->ovRecv, &c, 1); | |||
#else | |||
ret = ::read(pData->pipeRecv, &c, 1); | |||
#endif | |||
} CARLA_SAFE_EXCEPTION_BREAK("CarlaPipeCommon::readline() - read"); | |||
for (int i=0; i<0xfffe; ++i) | |||
{ | |||
try { | |||
#ifdef CARLA_OS_WIN | |||
ret = ReadFileWin32(pData->pipeRecv, pData->ovRecv, &c, 1); | |||
#else | |||
ret = ::read(pData->pipeRecv, &c, 1); | |||
#endif | |||
} CARLA_SAFE_EXCEPTION_BREAK("CarlaPipeCommon::readline() - read"); | |||
if (ret != 1 || c == '\n') | |||
break; | |||
if (ret != 1 || c == '\n') | |||
break; | |||
if (c == '\r') | |||
c = '\n'; | |||
if (c == '\r') | |||
c = '\n'; | |||
*ptr++ = c; | |||
*ptr++ = c; | |||
if (i+1 == 0xfffe) | |||
{ | |||
i = 0; | |||
*ptr = '\0'; | |||
tooBig = true; | |||
pData->tmpStr += pData->tmpBuf; | |||
ptr = pData->tmpBuf; | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
uint16_t remaining = size; | |||
readSucess = false; | |||
if (i+1 == 0xfffe) | |||
for (;;) | |||
{ | |||
i = 0; | |||
try { | |||
#ifdef CARLA_OS_WIN | |||
ret = ReadFileWin32(pData->pipeRecv, pData->ovRecv, ptr, remaining); | |||
#else | |||
ret = ::read(pData->pipeRecv, ptr, remaining); | |||
#endif | |||
} CARLA_SAFE_EXCEPTION_RETURN("CarlaPipeCommon::readline() - read", nullptr); | |||
if (ret == -1 && errno == EAGAIN) | |||
continue; | |||
CARLA_SAFE_ASSERT_INT2_RETURN(ret > 0, ret, remaining, nullptr); | |||
CARLA_SAFE_ASSERT_INT2_RETURN(ret <= (ssize_t)remaining, ret, remaining, nullptr); | |||
for (ssize_t i=0; i<ret; ++i) | |||
{ | |||
if (ptr[i] == '\r') | |||
ptr[i] = '\n'; | |||
} | |||
ptr += ret; | |||
*ptr = '\0'; | |||
tooBig = true; | |||
pData->tmpStr += pData->tmpBuf; | |||
ptr = pData->tmpBuf; | |||
remaining = static_cast<uint16_t>(remaining - ret); | |||
if (remaining != 0) | |||
continue; | |||
readSucess = true; | |||
if (allocReturn) | |||
{ | |||
pData->tmpStr = pData->tmpBuf; | |||
return pData->tmpStr.releaseBufferPointer(); | |||
} | |||
return pData->tmpBuf; | |||
} | |||
} | |||
@@ -1230,14 +1291,17 @@ const char* CarlaPipeCommon::_readline(const bool allocReturn, bool& readSucess) | |||
return nullptr; | |||
} | |||
readSucess = true; | |||
if (! allocReturn && ! tooBig) | |||
return pData->tmpBuf; | |||
readSucess = true; | |||
return allocReturn ? pData->tmpStr.releaseBufferPointer() : pData->tmpStr.buffer(); | |||
} | |||
const char* CarlaPipeCommon::_readlineblock(const bool allocReturn, const uint32_t timeOutMilliseconds) const noexcept | |||
const char* CarlaPipeCommon::_readlineblock(const bool allocReturn, | |||
const uint16_t size, | |||
const uint32_t timeOutMilliseconds) const noexcept | |||
{ | |||
const uint32_t timeoutEnd = water::Time::getMillisecondCounter() + timeOutMilliseconds; | |||
bool readSucess; | |||
@@ -1245,7 +1309,7 @@ const char* CarlaPipeCommon::_readlineblock(const bool allocReturn, const uint32 | |||
for (;;) | |||
{ | |||
readSucess = false; | |||
const char* const msg = _readline(allocReturn, readSucess); | |||
const char* const msg = _readline(allocReturn, size, readSucess); | |||
if (readSucess) | |||
return msg; | |||
@@ -1265,7 +1329,7 @@ const char* CarlaPipeCommon::_readlineblock(const bool allocReturn, const uint32 | |||
for (;;) | |||
{ | |||
readSucess = false; | |||
const char* const msg = _readline(allocReturn, readSucess); | |||
const char* const msg = _readline(allocReturn, size, readSucess); | |||
if (readSucess) | |||
return msg; | |||
@@ -142,7 +142,7 @@ public: | |||
* Read the next line as a string. | |||
* @note: @a value must be deleted if valid. | |||
*/ | |||
bool readNextLineAsString(const char*& value, bool allocateString) const noexcept; | |||
bool readNextLineAsString(const char*& value, bool allocateString, uint32_t size = 0) const noexcept; | |||
// ------------------------------------------------------------------- | |||
// write messages, must be locked before calling | |||
@@ -236,10 +236,10 @@ protected: | |||
// ------------------------------------------------------------------- | |||
/*! @internal */ | |||
const char* _readline(bool allocReturn, bool& readSucess) const noexcept; | |||
const char* _readline(bool allocReturn, uint16_t size, bool& readSucess) const noexcept; | |||
/*! @internal */ | |||
const char* _readlineblock(bool allocReturn, uint32_t timeOutMilliseconds = 50) const noexcept; | |||
const char* _readlineblock(bool allocReturn, uint16_t size = 0, uint32_t timeOutMilliseconds = 50) const noexcept; | |||
/*! @internal */ | |||
bool _writeMsgBuffer(const char* msg, std::size_t size) const noexcept; | |||