hannabox/src/DirectoryWalker.h

116 lines
3.6 KiB
C++

#ifndef DIRECTORY_WALKER_H
#define DIRECTORY_WALKER_H
#include <Arduino.h>
#include <vector>
#include "DirectoryNode.h"
struct WalkerState {
const DirectoryNode* node;
uint8_t phase; // 0: Start, 1: Files, 2: Subdirs, 3: End
size_t idx; // Index for vectors
WalkerState(const DirectoryNode* n) : node(n), phase(0), idx(0) {}
};
class DirectoryWalker {
private:
std::vector<WalkerState> stack;
String pending;
size_t pendingOffset;
void generateNext() {
if (stack.empty()) return;
WalkerState& state = stack.back();
const DirectoryNode* node = state.node;
switch (state.phase) {
case 0: // Start
if (node->getName() == "/") {
pending += F("<ul>\r\n");
} else {
pending += F("<li data-id=\"");
pending += String(node->getId());
pending += F("\"><b>");
pending += node->getName();
pending += F("</b></li>\r\n");
}
state.phase = 1;
state.idx = 0;
break;
case 1: // Files
if (state.idx < node->getMP3Files().size()) {
pending += F("<li data-id=\"");
pending += String(node->getFileIdAt(state.idx));
pending += F("\">");
pending += node->getMP3Files()[state.idx];
pending += F("</li>\r\n");
state.idx++;
} else {
state.phase = 2;
state.idx = 0;
}
break;
case 2: // Subdirs
if (state.idx < node->getSubdirectories().size()) {
// Push child
const DirectoryNode* child = node->getSubdirectories()[state.idx];
state.idx++; // Advance index for when we return
stack.emplace_back(child);
// Next loop will process the child (Phase 0)
} else {
state.phase = 3;
}
break;
case 3: // End
if (node->getName() == "/") {
pending += F("</ul>\r\n");
}
stack.pop_back();
break;
}
}
public:
DirectoryWalker(const DirectoryNode* root) : pendingOffset(0) {
if (root) {
stack.emplace_back(root);
// Reserve some space for pending string to avoid frequent reallocations
pending.reserve(256);
}
}
size_t read(uint8_t* buffer, size_t maxLen) {
size_t written = 0;
while (written < maxLen) {
// If pending buffer is empty or fully consumed, generate more
if (pending.length() == 0 || pendingOffset >= pending.length()) {
pending = ""; // Reset string content (capacity is kept)
pendingOffset = 0;
if (stack.empty()) {
break; // Done
}
generateNext();
}
// Copy from pending to output buffer
if (pending.length() > pendingOffset) {
size_t available = pending.length() - pendingOffset;
size_t toCopy = std::min(available, maxLen - written);
memcpy(buffer + written, pending.c_str() + pendingOffset, toCopy);
written += toCopy;
pendingOffset += toCopy;
}
}
return written;
}
};
#endif