Pull in ESP8266 String::replace() fixes, others (#3143)
Pull in bugfixes from the ESP8266 repo for problems in the SSO implementation of replace(). See the following patches for full details:54240d2cc5 (diff-8d9e71e16d437343017df828f0528f63)
78a1a66e6d (diff-8d9e71e16d437343017df828f0528f63)
4e9358445a (diff-8d9e71e16d437343017df828f0528f63)
Fixes #3140
This commit is contained in:
parent
f356ccd54a
commit
fd089d8fd3
@ -136,7 +136,7 @@ inline void String::init(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void String::invalidate(void) {
|
void String::invalidate(void) {
|
||||||
if(!sso() && wbuffer())
|
if(!isSSO() && wbuffer())
|
||||||
free(wbuffer());
|
free(wbuffer());
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
@ -154,17 +154,21 @@ unsigned char String::reserve(unsigned int size) {
|
|||||||
|
|
||||||
unsigned char String::changeBuffer(unsigned int maxStrLen) {
|
unsigned char String::changeBuffer(unsigned int maxStrLen) {
|
||||||
// Can we use SSO here to avoid allocation?
|
// Can we use SSO here to avoid allocation?
|
||||||
if (maxStrLen < sizeof(sso_buf)) {
|
if (maxStrLen < sizeof(sso.buff) - 1) {
|
||||||
if (sso() || !buffer()) {
|
if (isSSO() || !buffer()) {
|
||||||
// Already using SSO, nothing to do
|
// Already using SSO, nothing to do
|
||||||
|
uint16_t oldLen = len();
|
||||||
setSSO(true);
|
setSSO(true);
|
||||||
|
setLen(oldLen);
|
||||||
return 1;
|
return 1;
|
||||||
} else { // if bufptr && !sso()
|
} else { // if bufptr && !isSSO()
|
||||||
// Using bufptr, need to shrink into sso_buff
|
// Using bufptr, need to shrink into sso.buff
|
||||||
char temp[sizeof(sso_buf)];
|
char temp[sizeof(sso.buff)];
|
||||||
memcpy(temp, buffer(), maxStrLen);
|
memcpy(temp, buffer(), maxStrLen);
|
||||||
free(wbuffer());
|
free(wbuffer());
|
||||||
|
uint16_t oldLen = len();
|
||||||
setSSO(true);
|
setSSO(true);
|
||||||
|
setLen(oldLen);
|
||||||
memcpy(wbuffer(), temp, maxStrLen);
|
memcpy(wbuffer(), temp, maxStrLen);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -176,12 +180,12 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint16_t oldLen = len();
|
uint16_t oldLen = len();
|
||||||
char *newbuffer = (char *) realloc(sso() ? nullptr : wbuffer(), newSize);
|
char *newbuffer = (char *) realloc(isSSO() ? nullptr : wbuffer(), newSize);
|
||||||
if (newbuffer) {
|
if (newbuffer) {
|
||||||
size_t oldSize = capacity() + 1; // include NULL.
|
size_t oldSize = capacity() + 1; // include NULL.
|
||||||
if (sso()) {
|
if (isSSO()) {
|
||||||
// Copy the SSO buffer into allocated space
|
// Copy the SSO buffer into allocated space
|
||||||
memcpy(newbuffer, sso_buf, sizeof(sso_buf));
|
memmove(newbuffer, sso.buff, sizeof(sso.buff));
|
||||||
}
|
}
|
||||||
if (newSize > oldSize)
|
if (newSize > oldSize)
|
||||||
{
|
{
|
||||||
@ -206,7 +210,7 @@ String & String::copy(const char *cstr, unsigned int length) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
setLen(length);
|
setLen(length);
|
||||||
strcpy(wbuffer(), cstr);
|
memmove(wbuffer(), cstr, length + 1);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +220,7 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
setLen(length);
|
setLen(length);
|
||||||
strcpy_P(wbuffer(), (PGM_P)pstr);
|
memcpy_P(wbuffer(), (PGM_P)pstr, length + 1); // We know wbuffer() cannot ever be in PROGMEM, so memcpy safe here
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,20 +228,20 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) {
|
|||||||
void String::move(String &rhs) {
|
void String::move(String &rhs) {
|
||||||
if(buffer()) {
|
if(buffer()) {
|
||||||
if(capacity() >= rhs.len()) {
|
if(capacity() >= rhs.len()) {
|
||||||
strcpy(wbuffer(), rhs.buffer());
|
memmove(wbuffer(), rhs.buffer(), rhs.length() + 1);
|
||||||
setLen(rhs.len());
|
setLen(rhs.len());
|
||||||
rhs.invalidate();
|
rhs.invalidate();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (!sso()) {
|
if (!isSSO()) {
|
||||||
free(wbuffer());
|
free(wbuffer());
|
||||||
setBuffer(nullptr);
|
setBuffer(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rhs.sso()) {
|
if (rhs.isSSO()) {
|
||||||
setSSO(true);
|
setSSO(true);
|
||||||
memmove(sso_buf, rhs.sso_buf, sizeof(sso_buf));
|
memmove(sso.buff, rhs.sso.buff, sizeof(sso.buff));
|
||||||
} else {
|
} else {
|
||||||
setSSO(false);
|
setSSO(false);
|
||||||
setBuffer(rhs.wbuffer());
|
setBuffer(rhs.wbuffer());
|
||||||
@ -309,7 +313,7 @@ unsigned char String::concat(const String &s) {
|
|||||||
return 1;
|
return 1;
|
||||||
if (!reserve(newlen))
|
if (!reserve(newlen))
|
||||||
return 0;
|
return 0;
|
||||||
memcpy(wbuffer() + len(), buffer(), len());
|
memmove(wbuffer() + len(), buffer(), len());
|
||||||
setLen(newlen);
|
setLen(newlen);
|
||||||
wbuffer()[len()] = 0;
|
wbuffer()[len()] = 0;
|
||||||
return 1;
|
return 1;
|
||||||
@ -326,7 +330,12 @@ unsigned char String::concat(const char *cstr, unsigned int length) {
|
|||||||
return 1;
|
return 1;
|
||||||
if(!reserve(newlen))
|
if(!reserve(newlen))
|
||||||
return 0;
|
return 0;
|
||||||
strcpy(wbuffer() + len(), cstr);
|
if (cstr >= wbuffer() && cstr < wbuffer() + len())
|
||||||
|
// compatible with SSO in ram #6155 (case "x += x.c_str()")
|
||||||
|
memmove(wbuffer() + len(), cstr, length + 1);
|
||||||
|
else
|
||||||
|
// compatible with source in flash #6367
|
||||||
|
memcpy_P(wbuffer() + len(), cstr, length + 1);
|
||||||
setLen(newlen);
|
setLen(newlen);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -392,7 +401,7 @@ unsigned char String::concat(const __FlashStringHelper * str) {
|
|||||||
if (length == 0) return 1;
|
if (length == 0) return 1;
|
||||||
unsigned int newlen = len() + length;
|
unsigned int newlen = len() + length;
|
||||||
if (!reserve(newlen)) return 0;
|
if (!reserve(newlen)) return 0;
|
||||||
strcpy_P(wbuffer() + len(), (PGM_P)str);
|
memcpy_P(wbuffer() + len(), (PGM_P)str, length + 1);
|
||||||
setLen(newlen);
|
setLen(newlen);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,12 @@ class String {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
inline void clear(void) {
|
||||||
|
setLen(0);
|
||||||
|
}
|
||||||
|
inline bool isEmpty(void) const {
|
||||||
|
return length() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
// creates a copy of the assigned value. if the value is null or
|
// creates a copy of the assigned value. if the value is null or
|
||||||
// invalid, or if the memory allocation fails, the string will be
|
// invalid, or if the memory allocation fails, the string will be
|
||||||
@ -99,7 +105,7 @@ class String {
|
|||||||
|
|
||||||
// returns true on success, false on failure (in which case, the string
|
// returns true on success, false on failure (in which case, the string
|
||||||
// is left unchanged). if the argument is null or invalid, the
|
// is left unchanged). if the argument is null or invalid, the
|
||||||
// concatenation is considered unsucessful.
|
// concatenation is considered unsuccessful.
|
||||||
unsigned char concat(const String &str);
|
unsigned char concat(const String &str);
|
||||||
unsigned char concat(const char *cstr);
|
unsigned char concat(const char *cstr);
|
||||||
unsigned char concat(char c);
|
unsigned char concat(char c);
|
||||||
@ -200,7 +206,7 @@ class String {
|
|||||||
unsigned char startsWith(const String &prefix, unsigned int offset) const;
|
unsigned char startsWith(const String &prefix, unsigned int offset) const;
|
||||||
unsigned char endsWith(const String &suffix) const;
|
unsigned char endsWith(const String &suffix) const;
|
||||||
|
|
||||||
// character acccess
|
// character access
|
||||||
char charAt(unsigned int index) const;
|
char charAt(unsigned int index) const;
|
||||||
void setCharAt(unsigned int index, char c);
|
void setCharAt(unsigned int index, char c);
|
||||||
char operator [](unsigned int index) const;
|
char operator [](unsigned int index) const;
|
||||||
@ -251,27 +257,29 @@ class String {
|
|||||||
uint16_t cap;
|
uint16_t cap;
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
};
|
};
|
||||||
|
// This allows strings up up to 11 (10 + \0 termination) without any extra space.
|
||||||
// SSO is handled by checking the last byte of sso_buff.
|
enum { SSOSIZE = sizeof(struct _ptr) + 4 - 1 }; // Characters to allocate space for SSO, must be 12 or more
|
||||||
// When not in SSO mode, that byte is set to 0xff, while when in SSO mode it is always 0x00 (so it can serve as the string terminator as well as a flag)
|
struct _sso {
|
||||||
// This allows strings up up to 12 (11 + \0 termination) without any extra space.
|
char buff[SSOSIZE];
|
||||||
enum { SSOSIZE = sizeof(struct _ptr) + 4 }; // Characters to allocate space for SSO, must be 12 or more
|
unsigned char len : 7; // Ensure only one byte is allocated by GCC for the bitfields
|
||||||
enum { CAPACITY_MAX = 65535 }; // If size of capacity changed, be sure to update this enum
|
unsigned char isSSO : 1;
|
||||||
|
} __attribute__((packed)); // Ensure that GCC doesn't expand the flag byte to a 32-bit word for alignment issues
|
||||||
|
enum { CAPACITY_MAX = 65535 }; // If typeof(cap) changed from uint16_t, be sure to update this enum to the max value storable in the type
|
||||||
union {
|
union {
|
||||||
struct _ptr ptr;
|
struct _ptr ptr;
|
||||||
char sso_buf[SSOSIZE];
|
struct _sso sso;
|
||||||
};
|
};
|
||||||
// Accessor functions
|
// Accessor functions
|
||||||
inline bool sso() const { return sso_buf[SSOSIZE - 1] == 0; }
|
inline bool isSSO() const { return sso.isSSO; }
|
||||||
inline unsigned int len() const { return sso() ? strlen(sso_buf) : ptr.len; }
|
inline unsigned int len() const { return isSSO() ? sso.len : ptr.len; }
|
||||||
inline unsigned int capacity() const { return sso() ? SSOSIZE - 1 : ptr.cap; }
|
inline unsigned int capacity() const { return isSSO() ? (unsigned int)SSOSIZE - 1 : ptr.cap; } // Size of max string not including terminal NUL
|
||||||
inline void setSSO(bool sso) { sso_buf[SSOSIZE - 1] = sso ? 0x00 : 0xff; }
|
inline void setSSO(bool set) { sso.isSSO = set; }
|
||||||
inline void setLen(int len) { if (!sso()) ptr.len = len; }
|
inline void setLen(int len) { if (isSSO()) sso.len = len; else ptr.len = len; }
|
||||||
inline void setCapacity(int cap) { if (!sso()) ptr.cap = cap; }
|
inline void setCapacity(int cap) { if (!isSSO()) ptr.cap = cap; }
|
||||||
inline void setBuffer(char *buff) { if (!sso()) ptr.buff = buff; }
|
inline void setBuffer(char *buff) { if (!isSSO()) ptr.buff = buff; }
|
||||||
// Buffer accessor functions
|
// Buffer accessor functions
|
||||||
inline const char *buffer() const { return (const char *)(sso() ? sso_buf : ptr.buff); }
|
inline const char *buffer() const { return (const char *)(isSSO() ? sso.buff : ptr.buff); }
|
||||||
inline char *wbuffer() const { return sso() ? const_cast<char *>(sso_buf) : ptr.buff; } // Writable version of buffer
|
inline char *wbuffer() const { return isSSO() ? const_cast<char *>(sso.buff) : ptr.buff; } // Writable version of buffer
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void init(void);
|
void init(void);
|
||||||
|
Loading…
Reference in New Issue
Block a user