Updated getTLV() so it uses a fixed buffer as intermediate step

This is much more memory efficient.  Instead of decoding entire STRING from base64 to a temporary buffer or potentially very large size and then unpacking into TLV object, we decode a maximum of 48 characters at a time and unpack the resulting 36 (max) bytes until entire STRING is consumed.

getTLV() returns pack_size of final TLV, unless there is a problem with conversion, in which cae TLV is wiped and return value=0
This commit is contained in:
Gregg 2024-03-31 21:13:17 -05:00
parent eb821f002f
commit f137b0bee5
4 changed files with 38 additions and 20 deletions

View File

@ -735,24 +735,40 @@ class SpanCharacteristic{
setValFinish(notify); setValFinish(notify);
} }
size_t getTLV(TLV8 &tlv){
size_t getTLV(TLV8 &tlv){
if(format<FORMAT::TLV_ENC) if(format<FORMAT::TLV_ENC)
return(0); return(0);
size_t olen; const size_t bufSize=36; // maximum size of buffer to store decoded bytes before unpacking into TLV; must be multiple of 3
mbedtls_base64_decode(NULL,0,&olen,(uint8_t *)value.STRING,strlen(value.STRING)); // get length of buffer needed to decode TempBuffer<uint8_t> tBuf(bufSize); // create fixed-size buffer to store decoded bytes
TempBuffer<uint8_t> tBuf(olen); // create temporary buffer tlv.wipe(); // clear TLV completely
int ret=mbedtls_base64_decode(tBuf,olen,&olen,(uint8_t *)value.STRING,strlen(value.STRING)); size_t nChars=strlen(value.STRING); // total characters to decode
uint8_t *p=(uint8_t *)value.STRING; // set pointer to beginning of value
const size_t decodeSize=bufSize/3*4; // number of characters to decode in each pass
int status=0;
if(ret==MBEDTLS_ERR_BASE64_INVALID_CHARACTER){ while(nChars>0){
LOG0("\n*** WARNING: Can't decode Characteristic::%s with getTLV(). Data is not in base-64 format\n\n",hapName); size_t olen;
return(0); size_t n=nChars<decodeSize?nChars:decodeSize;
int ret=mbedtls_base64_decode(tBuf,tBuf.len(),&olen,p,n);
if(ret==MBEDTLS_ERR_BASE64_INVALID_CHARACTER){
LOG0("\n*** WARNING: Can't decode Characteristic::%s with getTLV(). Data is not in base-64 format\n\n",hapName);
tlv.wipe();
return(0);
}
status=tlv.unpack(tBuf,olen);
p+=n;
nChars-=n;
} }
if(status>0){
tlv.unpack(tBuf,olen); LOG0("\n*** WARNING: Can't unpack Characteristic::%s with getTLV(). TLV record is incomplete or corrupted\n\n",hapName);
return(tlv.pack_size()); tlv.wipe();
return(0);
}
return(tlv.pack_size());
} }
void setTLV(TLV8 &tlv, boolean notify=true){ void setTLV(TLV8 &tlv, boolean notify=true){

View File

@ -160,7 +160,10 @@ size_t TLV8::pack(uint8_t *buf, size_t bufSize){
///////////////////////////////////// /////////////////////////////////////
void TLV8::unpack(uint8_t *buf, size_t bufSize){ int TLV8::unpack(uint8_t *buf, size_t bufSize){
if(bufSize==0)
return(-1);
if(empty()) if(empty())
unpackPhase=0; unpackPhase=0;
@ -171,18 +174,17 @@ void TLV8::unpack(uint8_t *buf, size_t bufSize){
case 0: case 0:
unpackTag=*buf++; unpackTag=*buf++;
bufSize--; bufSize--;
add(unpackTag);
unpackPhase=1; unpackPhase=1;
break; break;
case 1: case 1:
unpackBytes=*buf++; unpackBytes=*buf++;
bufSize--; bufSize--;
if(unpackBytes==0){ if(unpackBytes==0)
add(unpackTag);
unpackPhase=0; unpackPhase=0;
} else { else
unpackPhase=2; unpackPhase=2;
}
break; break;
case 2: case 2:
@ -196,6 +198,7 @@ void TLV8::unpack(uint8_t *buf, size_t bufSize){
break; break;
} }
} }
return(unpackPhase);
} }

View File

@ -107,7 +107,7 @@ class TLV8 : public std::list<tlv8_t, Mallocator<tlv8_t>> {
void osprint(std::ostream& os, TLV8_it it1){osprint(os, it1, it1++);} void osprint(std::ostream& os, TLV8_it it1){osprint(os, it1, it1++);}
void osprint(std::ostream& os){osprint(os, begin(), end());} void osprint(std::ostream& os){osprint(os, begin(), end());}
void unpack(uint8_t *buf, size_t bufSize); int unpack(uint8_t *buf, size_t bufSize);
void wipe(){std::list<tlv8_t, Mallocator<tlv8_t>>().swap(*this);} void wipe(){std::list<tlv8_t, Mallocator<tlv8_t>>().swap(*this);}

View File

@ -122,8 +122,7 @@ struct HomeSpanTV : Service::Television {
HomeSpanTV *hsTV=(HomeSpanTV *)arg; HomeSpanTV *hsTV=(HomeSpanTV *)arg;
TLV8 orderTLV; TLV8 orderTLV;
Serial.printf("BEFORE:\n");
hsTV->displayOrder->getTLV(orderTLV); hsTV->displayOrder->getTLV(orderTLV);
orderTLV.print(); orderTLV.print();
orderTLV.wipe(); orderTLV.wipe();