mirror of
https://github.com/esphome/esphome.git
synced 2024-11-27 01:08:03 +01:00
Fix parsing numbers from null-terminated buffers (#2755)
This commit is contained in:
parent
980b7cda8f
commit
8e1c9f5042
4 changed files with 26 additions and 24 deletions
|
@ -73,51 +73,52 @@ AnovaPacket *AnovaCodec::get_stop_request() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnovaCodec::decode(const uint8_t *data, uint16_t length) {
|
void AnovaCodec::decode(const uint8_t *data, uint16_t length) {
|
||||||
memset(this->buf_, 0, 32);
|
char buf[32];
|
||||||
strncpy(this->buf_, (char *) data, length);
|
memset(buf, 0, sizeof(buf));
|
||||||
|
strncpy(buf, (char *) data, std::min<uint16_t>(length, sizeof(buf) - 1));
|
||||||
this->has_target_temp_ = this->has_current_temp_ = this->has_unit_ = this->has_running_ = false;
|
this->has_target_temp_ = this->has_current_temp_ = this->has_unit_ = this->has_running_ = false;
|
||||||
switch (this->current_query_) {
|
switch (this->current_query_) {
|
||||||
case READ_DEVICE_STATUS: {
|
case READ_DEVICE_STATUS: {
|
||||||
if (!strncmp(this->buf_, "stopped", 7)) {
|
if (!strncmp(buf, "stopped", 7)) {
|
||||||
this->has_running_ = true;
|
this->has_running_ = true;
|
||||||
this->running_ = false;
|
this->running_ = false;
|
||||||
}
|
}
|
||||||
if (!strncmp(this->buf_, "running", 7)) {
|
if (!strncmp(buf, "running", 7)) {
|
||||||
this->has_running_ = true;
|
this->has_running_ = true;
|
||||||
this->running_ = true;
|
this->running_ = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case START: {
|
case START: {
|
||||||
if (!strncmp(this->buf_, "start", 5)) {
|
if (!strncmp(buf, "start", 5)) {
|
||||||
this->has_running_ = true;
|
this->has_running_ = true;
|
||||||
this->running_ = true;
|
this->running_ = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case STOP: {
|
case STOP: {
|
||||||
if (!strncmp(this->buf_, "stop", 4)) {
|
if (!strncmp(buf, "stop", 4)) {
|
||||||
this->has_running_ = true;
|
this->has_running_ = true;
|
||||||
this->running_ = false;
|
this->running_ = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case READ_TARGET_TEMPERATURE: {
|
case READ_TARGET_TEMPERATURE: {
|
||||||
this->target_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f);
|
this->target_temp_ = parse_number<float>(buf, sizeof(buf)).value_or(0.0f);
|
||||||
if (this->fahrenheit_)
|
if (this->fahrenheit_)
|
||||||
this->target_temp_ = ftoc(this->target_temp_);
|
this->target_temp_ = ftoc(this->target_temp_);
|
||||||
this->has_target_temp_ = true;
|
this->has_target_temp_ = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SET_TARGET_TEMPERATURE: {
|
case SET_TARGET_TEMPERATURE: {
|
||||||
this->target_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f);
|
this->target_temp_ = parse_number<float>(buf, sizeof(buf)).value_or(0.0f);
|
||||||
if (this->fahrenheit_)
|
if (this->fahrenheit_)
|
||||||
this->target_temp_ = ftoc(this->target_temp_);
|
this->target_temp_ = ftoc(this->target_temp_);
|
||||||
this->has_target_temp_ = true;
|
this->has_target_temp_ = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case READ_CURRENT_TEMPERATURE: {
|
case READ_CURRENT_TEMPERATURE: {
|
||||||
this->current_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f);
|
this->current_temp_ = parse_number<float>(buf, sizeof(buf)).value_or(0.0f);
|
||||||
if (this->fahrenheit_)
|
if (this->fahrenheit_)
|
||||||
this->current_temp_ = ftoc(this->current_temp_);
|
this->current_temp_ = ftoc(this->current_temp_);
|
||||||
this->has_current_temp_ = true;
|
this->has_current_temp_ = true;
|
||||||
|
@ -125,8 +126,8 @@ void AnovaCodec::decode(const uint8_t *data, uint16_t length) {
|
||||||
}
|
}
|
||||||
case SET_UNIT:
|
case SET_UNIT:
|
||||||
case READ_UNIT: {
|
case READ_UNIT: {
|
||||||
this->unit_ = this->buf_[0];
|
this->unit_ = buf[0];
|
||||||
this->fahrenheit_ = this->buf_[0] == 'f';
|
this->fahrenheit_ = buf[0] == 'f';
|
||||||
this->has_unit_ = true;
|
this->has_unit_ = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,6 @@ class AnovaCodec {
|
||||||
bool has_current_temp_;
|
bool has_current_temp_;
|
||||||
bool has_unit_;
|
bool has_unit_;
|
||||||
bool has_running_;
|
bool has_running_;
|
||||||
char buf_[32];
|
|
||||||
bool fahrenheit_;
|
bool fahrenheit_;
|
||||||
|
|
||||||
CurrentQuery current_query_;
|
CurrentQuery current_query_;
|
||||||
|
|
|
@ -32,7 +32,7 @@ void EZOSensor::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EZOSensor::loop() {
|
void EZOSensor::loop() {
|
||||||
uint8_t buf[20];
|
uint8_t buf[21];
|
||||||
if (!(this->state_ & EZO_STATE_WAIT)) {
|
if (!(this->state_ & EZO_STATE_WAIT)) {
|
||||||
if (this->state_ & EZO_STATE_SEND_TEMP) {
|
if (this->state_ & EZO_STATE_SEND_TEMP) {
|
||||||
int len = sprintf((char *) buf, "T,%0.3f", this->tempcomp_);
|
int len = sprintf((char *) buf, "T,%0.3f", this->tempcomp_);
|
||||||
|
@ -74,7 +74,7 @@ void EZOSensor::loop() {
|
||||||
if (buf[0] != 1)
|
if (buf[0] != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float val = parse_number<float>((char *) &buf[1], sizeof(buf) - 1).value_or(0);
|
float val = parse_number<float>((char *) &buf[1], sizeof(buf) - 2).value_or(0);
|
||||||
this->publish_state(val);
|
this->publish_state(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -362,45 +362,47 @@ std::string str_sanitize(const std::string &str);
|
||||||
/// @name Parsing & formatting
|
/// @name Parsing & formatting
|
||||||
///@{
|
///@{
|
||||||
|
|
||||||
/// Parse a unsigned decimal number.
|
/// Parse an unsigned decimal number (requires null-terminated string).
|
||||||
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
|
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
|
||||||
optional<T> parse_number(const char *str, size_t len) {
|
optional<T> parse_number(const char *str, size_t len) {
|
||||||
char *end = nullptr;
|
char *end = nullptr;
|
||||||
unsigned long value = ::strtoul(str, &end, 10); // NOLINT(google-runtime-int)
|
unsigned long value = ::strtoul(str, &end, 10); // NOLINT(google-runtime-int)
|
||||||
if (end == nullptr || end != str + len || value > std::numeric_limits<T>::max())
|
if (end == str || *end != '\0' || value > std::numeric_limits<T>::max())
|
||||||
return {};
|
return {};
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
/// Parse an unsigned decimal number.
|
||||||
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
|
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
|
||||||
optional<T> parse_number(const std::string &str) {
|
optional<T> parse_number(const std::string &str) {
|
||||||
return parse_number<T>(str.c_str(), str.length());
|
return parse_number<T>(str.c_str(), str.length() + 1);
|
||||||
}
|
}
|
||||||
/// Parse a signed decimal number.
|
/// Parse a signed decimal number (requires null-terminated string).
|
||||||
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
|
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
|
||||||
optional<T> parse_number(const char *str, size_t len) {
|
optional<T> parse_number(const char *str, size_t len) {
|
||||||
char *end = nullptr;
|
char *end = nullptr;
|
||||||
signed long value = ::strtol(str, &end, 10); // NOLINT(google-runtime-int)
|
signed long value = ::strtol(str, &end, 10); // NOLINT(google-runtime-int)
|
||||||
if (end == nullptr || end != str + len || value < std::numeric_limits<T>::min() ||
|
if (end == str || *end != '\0' || value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max())
|
||||||
value > std::numeric_limits<T>::max())
|
|
||||||
return {};
|
return {};
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
/// Parse a signed decimal number.
|
||||||
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
|
template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
|
||||||
optional<T> parse_number(const std::string &str) {
|
optional<T> parse_number(const std::string &str) {
|
||||||
return parse_number<T>(str.c_str(), str.length());
|
return parse_number<T>(str.c_str(), str.length() + 1);
|
||||||
}
|
}
|
||||||
/// Parse a decimal floating-point number.
|
/// Parse a decimal floating-point number (requires null-terminated string).
|
||||||
template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0>
|
template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0>
|
||||||
optional<T> parse_number(const char *str, size_t len) {
|
optional<T> parse_number(const char *str, size_t len) {
|
||||||
char *end = nullptr;
|
char *end = nullptr;
|
||||||
float value = ::strtof(str, &end);
|
float value = ::strtof(str, &end);
|
||||||
if (end == nullptr || end != str + len || value == HUGE_VALF)
|
if (end == str || *end != '\0' || value == HUGE_VALF)
|
||||||
return {};
|
return {};
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
/// Parse a decimal floating-point number.
|
||||||
template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0>
|
template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0>
|
||||||
optional<T> parse_number(const std::string &str) {
|
optional<T> parse_number(const std::string &str) {
|
||||||
return parse_number<T>(str.c_str(), str.length());
|
return parse_number<T>(str.c_str(), str.length() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
Loading…
Reference in a new issue