mirror of
https://github.com/alexhopeoconnor/DFTE.git
synced 2026-10-03 22:21:59 +10:00
Add DYNAMIC_DATA placeholder for raw streamed template content
Support registering dynamic String/progmem data without re-parsing as nested templates, used by WiFiManager for composed portal stylesheets.
This commit is contained in:
@@ -90,6 +90,7 @@ public:
|
||||
* @return true if registered successfully
|
||||
*/
|
||||
bool registerRamData(const char* name, PlaceholderDataGetter getter);
|
||||
bool registerDynamicData(const char* name, const DynamicDataDescriptor* descriptor);
|
||||
bool registerDynamicTemplate(const char* name, const DynamicTemplateDescriptor* descriptor);
|
||||
bool registerConditional(const char* name, const ConditionalDescriptor* descriptor);
|
||||
bool registerIterator(const char* name, const IteratorDescriptor* descriptor);
|
||||
@@ -124,6 +125,7 @@ public:
|
||||
// Static helper functions for length calculation
|
||||
static size_t getProgmemLength(const void* data);
|
||||
static size_t getRamLength(const void* data);
|
||||
static size_t getDynamicDataLength(const DynamicDataDescriptor* descriptor, const char* data);
|
||||
static size_t getDynamicTemplateLength(const DynamicTemplateDescriptor* descriptor, const char* templateData);
|
||||
|
||||
private:
|
||||
@@ -138,6 +140,8 @@ private:
|
||||
uint8_t* dest, size_t maxLen);
|
||||
static size_t copyRamData(PlaceholderDataGetter getter, size_t offset,
|
||||
uint8_t* dest, size_t maxLen);
|
||||
static size_t copyDynamicData(const DynamicDataDescriptor* descriptor, size_t offset,
|
||||
uint8_t* dest, size_t maxLen);
|
||||
};
|
||||
|
||||
#endif // DEVICEFRAMEWORK_PLACEHOLDER_REGISTRY_H
|
||||
|
||||
@@ -31,6 +31,7 @@ enum class PlaceholderType {
|
||||
PROGMEM_DATA, // Large PROGMEM data (CSS, JS, base64 images)
|
||||
PROGMEM_TEMPLATE, // Nested template in PROGMEM
|
||||
RAM_DATA, // Dynamic RAM data via getter functions
|
||||
DYNAMIC_DATA, // Dynamic RAM data via getter + userData, rendered as raw bytes
|
||||
DYNAMIC_TEMPLATE,
|
||||
CONDITIONAL,
|
||||
ITERATOR
|
||||
@@ -64,6 +65,12 @@ typedef void* (*IteratorOpenHandler)(void* userData);
|
||||
typedef IteratorStepResult (*IteratorNextHandler)(void* handle, struct IteratorItemView& view);
|
||||
typedef void (*IteratorCloseHandler)(void* handle);
|
||||
|
||||
struct DynamicDataDescriptor {
|
||||
DynamicTemplateGetter getter;
|
||||
DynamicTemplateLengthGetter getLength;
|
||||
void* userData;
|
||||
};
|
||||
|
||||
struct DynamicTemplateDescriptor {
|
||||
DynamicTemplateGetter getter;
|
||||
DynamicTemplateLengthGetter getLength;
|
||||
|
||||
@@ -125,6 +125,39 @@ bool DeviceFrameworkPlaceholderRegistry::registerRamData(const char* name, Place
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFrameworkPlaceholderRegistry::registerDynamicData(const char* name, const DynamicDataDescriptor* descriptor) {
|
||||
if (placeholders == nullptr || maxPlaceholders == 0) {
|
||||
DFTE_LOG_ERROR("Placeholder registry not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count >= maxPlaceholders) {
|
||||
DFTE_LOG_ERROR("Placeholder registry full, cannot register: " + String(name));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!validatePlaceholderName(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (descriptor == nullptr || descriptor->getter == nullptr) {
|
||||
DFTE_LOG_ERROR("Invalid dynamic data descriptor for placeholder: " + String(name));
|
||||
return false;
|
||||
}
|
||||
|
||||
PlaceholderEntry& entry = placeholders[count];
|
||||
strncpy(entry.name, name, sizeof(entry.name) - 1);
|
||||
entry.name[sizeof(entry.name) - 1] = '\0';
|
||||
entry.type = PlaceholderType::DYNAMIC_DATA;
|
||||
entry.data = descriptor;
|
||||
entry.getLength = nullptr;
|
||||
entry.cachedLength = 0;
|
||||
entry.hasCachedLength = false;
|
||||
|
||||
count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFrameworkPlaceholderRegistry::registerDynamicTemplate(const char* name, const DynamicTemplateDescriptor* descriptor) {
|
||||
if (placeholders == nullptr || maxPlaceholders == 0) {
|
||||
DFTE_LOG_ERROR("Placeholder registry not initialized");
|
||||
@@ -296,6 +329,9 @@ size_t DeviceFrameworkPlaceholderRegistry::renderPlaceholder(const PlaceholderEn
|
||||
case PlaceholderType::RAM_DATA:
|
||||
return copyRamData((PlaceholderDataGetter)entry->data, offset, buffer, maxLen);
|
||||
|
||||
case PlaceholderType::DYNAMIC_DATA:
|
||||
return copyDynamicData(static_cast<const DynamicDataDescriptor*>(entry->data), offset, buffer, maxLen);
|
||||
|
||||
case PlaceholderType::DYNAMIC_TEMPLATE:
|
||||
case PlaceholderType::CONDITIONAL:
|
||||
case PlaceholderType::ITERATOR:
|
||||
@@ -323,6 +359,18 @@ size_t DeviceFrameworkPlaceholderRegistry::getRamLength(const void* data) {
|
||||
return strlen(str);
|
||||
}
|
||||
|
||||
size_t DeviceFrameworkPlaceholderRegistry::getDynamicDataLength(const DynamicDataDescriptor* descriptor, const char* data) {
|
||||
if (descriptor == nullptr || data == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (descriptor->getLength) {
|
||||
return descriptor->getLength(data, descriptor->userData);
|
||||
}
|
||||
|
||||
return strlen(data);
|
||||
}
|
||||
|
||||
size_t DeviceFrameworkPlaceholderRegistry::getDynamicTemplateLength(const DynamicTemplateDescriptor* descriptor, const char* templateData) {
|
||||
if (descriptor == nullptr || templateData == nullptr) {
|
||||
return 0;
|
||||
@@ -370,3 +418,25 @@ size_t DeviceFrameworkPlaceholderRegistry::copyRamData(PlaceholderDataGetter get
|
||||
return chunkSize;
|
||||
}
|
||||
|
||||
size_t DeviceFrameworkPlaceholderRegistry::copyDynamicData(const DynamicDataDescriptor* descriptor,
|
||||
size_t offset,
|
||||
uint8_t* dest,
|
||||
size_t maxLen) {
|
||||
if (descriptor == nullptr || descriptor->getter == nullptr || maxLen == 0) return 0;
|
||||
|
||||
const char* data = descriptor->getter(descriptor->userData);
|
||||
if (data == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t dataLen = getDynamicDataLength(descriptor, data);
|
||||
if (offset >= dataLen) return 0;
|
||||
|
||||
size_t remaining = dataLen - offset;
|
||||
constexpr size_t MAX_CHUNK = DFTE_RAM_CHUNK_SIZE;
|
||||
size_t chunkSize = min(min(maxLen, remaining), MAX_CHUNK);
|
||||
|
||||
memcpy(dest, data + offset, chunkSize);
|
||||
return chunkSize;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,15 @@ static bool pushPlaceholderEntry(DeviceFrameworkTemplateContext& ctx, const Plac
|
||||
dataCtx->context.data.offset = 0;
|
||||
return true;
|
||||
}
|
||||
case PlaceholderType::DYNAMIC_DATA: {
|
||||
if (!ctx.pushContext(RenderingContextType::PLACEHOLDER_DATA, name)) {
|
||||
return false;
|
||||
}
|
||||
RenderingContext* dataCtx = ctx.getCurrentContext();
|
||||
dataCtx->context.data.entry = entry;
|
||||
dataCtx->context.data.offset = 0;
|
||||
return true;
|
||||
}
|
||||
case PlaceholderType::PROGMEM_TEMPLATE: {
|
||||
if (!ctx.pushContext(RenderingContextType::PLACEHOLDER_TEMPLATE, name)) {
|
||||
return false;
|
||||
@@ -659,6 +668,7 @@ DeviceFrameworkTemplateRenderer::RenderOutcome DeviceFrameworkTemplateRenderer::
|
||||
switch (entry->type) {
|
||||
case PlaceholderType::PROGMEM_DATA:
|
||||
case PlaceholderType::RAM_DATA:
|
||||
case PlaceholderType::DYNAMIC_DATA:
|
||||
outcome.pushContext.type = RenderingContextType::PLACEHOLDER_DATA;
|
||||
outcome.pushContext.entry = entry;
|
||||
break;
|
||||
@@ -768,7 +778,11 @@ DeviceFrameworkTemplateRenderer::RenderOutcome DeviceFrameworkTemplateRenderer::
|
||||
}
|
||||
|
||||
size_t totalLength = 0;
|
||||
if (entry->hasCachedLength) {
|
||||
if (entry->type == PlaceholderType::DYNAMIC_DATA) {
|
||||
const auto* descriptor = static_cast<const DynamicDataDescriptor*>(entry->data);
|
||||
const char* data = (descriptor && descriptor->getter) ? descriptor->getter(descriptor->userData) : nullptr;
|
||||
totalLength = DeviceFrameworkPlaceholderRegistry::getDynamicDataLength(descriptor, data);
|
||||
} else if (entry->hasCachedLength) {
|
||||
totalLength = entry->cachedLength;
|
||||
} else if (entry->getLength != nullptr) {
|
||||
totalLength = entry->getLength(entry->data);
|
||||
|
||||
Reference in New Issue
Block a user