25bd585c25
* Corrections of Find, FindUntil and FindMulti Find has some bug that is not working with Ethernet.find() so, I copied code from Stream.h and Stream.cpp in AVR-CORE library and now it's working perfectly. I don't know where was the error, but an Ethernet.find compiled to MEGA2560 was working but not working when compiled to esp32, after corrections of code (copy of AVR-Core libraries) it's working perfect. So probably has some error on original ESP32-Core library. Below is part of code that was working with MEGA2560 and not with ESP32 libraries. client.find never return TRUE with ESP32 original library and with AVR it's works. boolean esp32_fw_update(EthernetClient &client, DecodedHeader &header, const String &field_filename, const String &field_crc) { char bound[header.boundary.length()+3]; char term[]="\r\n"; strcpy(bound,header.boundary.c_str()); strcat(bound,term); while (client.find(bound)) { String line=client.readStringUntil('\r'); * Update Stream.h * Update Stream.cpp Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
338 lines
9.1 KiB
C++
338 lines
9.1 KiB
C++
/*
|
|
Stream.cpp - adds parsing methods to Stream class
|
|
Copyright (c) 2008 David A. Mellis. All right reserved.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
Created July 2011
|
|
parsing functions based on TextFinder library by Michael Margolis
|
|
*/
|
|
|
|
#include "Arduino.h"
|
|
#include "Stream.h"
|
|
#include "esp32-hal.h"
|
|
|
|
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
|
|
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
|
|
|
|
// private method to read stream with timeout
|
|
int Stream::timedRead()
|
|
{
|
|
int c;
|
|
_startMillis = millis();
|
|
do {
|
|
c = read();
|
|
if(c >= 0) {
|
|
return c;
|
|
}
|
|
} while(millis() - _startMillis < _timeout);
|
|
return -1; // -1 indicates timeout
|
|
}
|
|
|
|
// private method to peek stream with timeout
|
|
int Stream::timedPeek()
|
|
{
|
|
int c;
|
|
_startMillis = millis();
|
|
do {
|
|
c = peek();
|
|
if(c >= 0) {
|
|
return c;
|
|
}
|
|
} while(millis() - _startMillis < _timeout);
|
|
return -1; // -1 indicates timeout
|
|
}
|
|
|
|
// returns peek of the next digit in the stream or -1 if timeout
|
|
// discards non-numeric characters
|
|
int Stream::peekNextDigit()
|
|
{
|
|
int c;
|
|
while(1) {
|
|
c = timedPeek();
|
|
if(c < 0) {
|
|
return c; // timeout
|
|
}
|
|
if(c == '-') {
|
|
return c;
|
|
}
|
|
if(c >= '0' && c <= '9') {
|
|
return c;
|
|
}
|
|
read(); // discard non-numeric
|
|
}
|
|
}
|
|
|
|
// Public Methods
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
|
|
{
|
|
_timeout = timeout;
|
|
}
|
|
unsigned long Stream::getTimeout(void) {
|
|
return _timeout;
|
|
}
|
|
|
|
// find returns true if the target string is found
|
|
bool Stream::find(const char *target)
|
|
{
|
|
return findUntil(target, strlen(target), NULL, 0);
|
|
}
|
|
|
|
// reads data from the stream until the target string of given length is found
|
|
// returns true if target string is found, false if timed out
|
|
bool Stream::find(const char *target, size_t length)
|
|
{
|
|
return findUntil(target, length, NULL, 0);
|
|
}
|
|
|
|
// as find but search ends if the terminator string is found
|
|
bool Stream::findUntil(const char *target, const char *terminator)
|
|
{
|
|
return findUntil(target, strlen(target), terminator, strlen(terminator));
|
|
}
|
|
|
|
// reads data from the stream until the target string of the given length is found
|
|
// search terminated if the terminator string is found
|
|
// returns true if target string is found, false if terminated or timed out
|
|
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen)
|
|
{
|
|
if (terminator == NULL) {
|
|
MultiTarget t[1] = {{target, targetLen, 0}};
|
|
return findMulti(t, 1) == 0 ? true : false;
|
|
} else {
|
|
MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
|
|
return findMulti(t, 2) == 0 ? true : false;
|
|
}
|
|
}
|
|
|
|
int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
|
|
// any zero length target string automatically matches and would make
|
|
// a mess of the rest of the algorithm.
|
|
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
|
|
if (t->len <= 0)
|
|
return t - targets;
|
|
}
|
|
|
|
while (1) {
|
|
int c = timedRead();
|
|
if (c < 0)
|
|
return -1;
|
|
|
|
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
|
|
// the simple case is if we match, deal with that first.
|
|
if (c == t->str[t->index]) {
|
|
if (++t->index == t->len)
|
|
return t - targets;
|
|
else
|
|
continue;
|
|
}
|
|
|
|
// if not we need to walk back and see if we could have matched further
|
|
// down the stream (ie '1112' doesn't match the first position in '11112'
|
|
// but it will match the second position so we can't just reset the current
|
|
// index to 0 when we find a mismatch.
|
|
if (t->index == 0)
|
|
continue;
|
|
|
|
int origIndex = t->index;
|
|
do {
|
|
--t->index;
|
|
// first check if current char works against the new current index
|
|
if (c != t->str[t->index])
|
|
continue;
|
|
|
|
// if it's the only char then we're good, nothing more to check
|
|
if (t->index == 0) {
|
|
t->index++;
|
|
break;
|
|
}
|
|
|
|
// otherwise we need to check the rest of the found string
|
|
int diff = origIndex - t->index;
|
|
size_t i;
|
|
for (i = 0; i < t->index; ++i) {
|
|
if (t->str[i] != t->str[i + diff])
|
|
break;
|
|
}
|
|
|
|
// if we successfully got through the previous loop then our current
|
|
// index is good.
|
|
if (i == t->index) {
|
|
t->index++;
|
|
break;
|
|
}
|
|
|
|
// otherwise we just try the next index
|
|
} while (t->index);
|
|
}
|
|
}
|
|
// unreachable
|
|
return -1;
|
|
}
|
|
|
|
// returns the first valid (long) integer value from the current position.
|
|
// initial characters that are not digits (or the minus sign) are skipped
|
|
// function is terminated by the first character that is not a digit.
|
|
long Stream::parseInt()
|
|
{
|
|
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
|
|
}
|
|
|
|
// as above but a given skipChar is ignored
|
|
// this allows format characters (typically commas) in values to be ignored
|
|
long Stream::parseInt(char skipChar)
|
|
{
|
|
boolean isNegative = false;
|
|
long value = 0;
|
|
int c;
|
|
|
|
c = peekNextDigit();
|
|
// ignore non numeric leading characters
|
|
if(c < 0) {
|
|
return 0; // zero returned if timeout
|
|
}
|
|
|
|
do {
|
|
if(c == skipChar) {
|
|
} // ignore this charactor
|
|
else if(c == '-') {
|
|
isNegative = true;
|
|
} else if(c >= '0' && c <= '9') { // is c a digit?
|
|
value = value * 10 + c - '0';
|
|
}
|
|
read(); // consume the character we got with peek
|
|
c = timedPeek();
|
|
} while((c >= '0' && c <= '9') || c == skipChar);
|
|
|
|
if(isNegative) {
|
|
value = -value;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
// as parseInt but returns a floating point value
|
|
float Stream::parseFloat()
|
|
{
|
|
return parseFloat(NO_SKIP_CHAR);
|
|
}
|
|
|
|
// as above but the given skipChar is ignored
|
|
// this allows format characters (typically commas) in values to be ignored
|
|
float Stream::parseFloat(char skipChar)
|
|
{
|
|
boolean isNegative = false;
|
|
boolean isFraction = false;
|
|
long value = 0;
|
|
int c;
|
|
float fraction = 1.0;
|
|
|
|
c = peekNextDigit();
|
|
// ignore non numeric leading characters
|
|
if(c < 0) {
|
|
return 0; // zero returned if timeout
|
|
}
|
|
|
|
do {
|
|
if(c == skipChar) {
|
|
} // ignore
|
|
else if(c == '-') {
|
|
isNegative = true;
|
|
} else if(c == '.') {
|
|
isFraction = true;
|
|
} else if(c >= '0' && c <= '9') { // is c a digit?
|
|
value = value * 10 + c - '0';
|
|
if(isFraction) {
|
|
fraction *= 0.1;
|
|
}
|
|
}
|
|
read(); // consume the character we got with peek
|
|
c = timedPeek();
|
|
} while((c >= '0' && c <= '9') || c == '.' || c == skipChar);
|
|
|
|
if(isNegative) {
|
|
value = -value;
|
|
}
|
|
if(isFraction) {
|
|
return value * fraction;
|
|
} else {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
// read characters from stream into buffer
|
|
// terminates if length characters have been read, or timeout (see setTimeout)
|
|
// returns the number of characters placed in the buffer
|
|
// the buffer is NOT null terminated.
|
|
//
|
|
size_t Stream::readBytes(char *buffer, size_t length)
|
|
{
|
|
size_t count = 0;
|
|
while(count < length) {
|
|
int c = timedRead();
|
|
if(c < 0) {
|
|
break;
|
|
}
|
|
*buffer++ = (char) c;
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
// as readBytes with terminator character
|
|
// terminates if length characters have been read, timeout, or if the terminator character detected
|
|
// returns the number of characters placed in the buffer (0 means no valid data found)
|
|
|
|
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
|
|
{
|
|
if(length < 1) {
|
|
return 0;
|
|
}
|
|
size_t index = 0;
|
|
while(index < length) {
|
|
int c = timedRead();
|
|
if(c < 0 || c == terminator) {
|
|
break;
|
|
}
|
|
*buffer++ = (char) c;
|
|
index++;
|
|
}
|
|
return index; // return number of characters, not including null terminator
|
|
}
|
|
|
|
String Stream::readString()
|
|
{
|
|
String ret;
|
|
int c = timedRead();
|
|
while(c >= 0) {
|
|
ret += (char) c;
|
|
c = timedRead();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
String Stream::readStringUntil(char terminator)
|
|
{
|
|
String ret;
|
|
int c = timedRead();
|
|
while(c >= 0 && c != terminator) {
|
|
ret += (char) c;
|
|
c = timedRead();
|
|
}
|
|
return ret;
|
|
}
|
|
|