Anything similar to libgen.h for SPIFFS/FS.h?
Posted:
Wed Sep 06, 2017 3:19 pm
by treii28
I'm wondering if there is anything similar to libgen.h or that might include utilities like basename and dirname that works in conjunction with the types/values of the SPIFFS and FS.h code? I need to manipulate pathnames and prefer not to re-design the wheel if I don't have to. I may try pulling over ligen.h and the associated c files from source code later if need be.
Re: Anything similar to libgen.h for SPIFFS/FS.h?
Posted:
Wed Sep 06, 2017 3:45 pm
by martinayotte
Beware that current SPIFFS doesn't support sub-directories ...
Re: Anything similar to libgen.h for SPIFFS/FS.h?
Posted:
Sun Sep 10, 2017 8:01 am
by treii28
Yeah, I kinda figured that out. It tries to emulate them. I was able to get something to work using combinations of .lastIndexOf() and .endsWith() String methods.
Code: Select alltypedef struct pathInfo {
String path;
String dir;
String name;
String base;
String ext;
String type;
bool gzip = false;
bool compress = false;
bool min = false;
} PINF;
PINF getPathInfo(String path) {
PINF pInfo;
pInfo.path = path;
int8_t lastIdx = path.lastIndexOf("/");
pInfo.dir = "";
pInfo.name = path;
if((lastIdx != -1) && (lastIdx > 0)) {
pInfo.dir = path.substring(0, lastIdx + 1);
pInfo.name = path.substring(lastIdx+1);
}
lastIdx = pInfo.name.lastIndexOf(".");
if(lastIdx != -1) {
pInfo.base = pInfo.name.substring(0, lastIdx);
pInfo.ext = pInfo.name.substring(lastIdx+1);
// comment out next 6 lines to keep .min. in basenames
lastIdx = pInfo.base.lastIndexOf(".min");
if(lastIdx != -1) {
pInfo.min = true;
pInfo.base = pInfo.base.substring(0, lastIdx) + pInfo.base.substring(lastIdx+4);
DBG_OUTPUT_PORT.println("unminified base: " + pInfo.base);
}
while((pInfo.ext == "gz") || (pInfo.ext == "Z") || (pInfo.ext == "z")) {
if(pInfo.ext == "gz") {
pInfo.gzip = true;
} else if((pInfo.ext == "Z") || (pInfo.ext == "z")) {
pInfo.compress = true;
}
lastIdx = pInfo.base.lastIndexOf(".");
if(lastIdx != -1) {
pInfo.ext = pInfo.base.substring(lastIdx+1);
pInfo.base = pInfo.base.substring(0, lastIdx);
}
}
} else {
pInfo.base = pInfo.name;
pInfo.ext = "";
}
pInfo.type = "application/octet-stream";
if(pInfo.ext == "htm") pInfo.type = "text/html";
else if(pInfo.ext == "txt") pInfo.type = "text/plain";
else if(pInfo.ext == "css") pInfo.type = "text/css";
else if(pInfo.ext == "xml") pInfo.type = "text/xml";
else if(pInfo.ext == "rtf") pInfo.type = "text/richtext";
else if(pInfo.ext == "csv") pInfo.type = "text/csv";
else if(pInfo.ext == "js") pInfo.type = "application/javascript";
else if(pInfo.ext == "png") pInfo.type = "image/png";
else if(pInfo.ext == "gif") pInfo.type = "image/gif";
else if((pInfo.ext == "jpg") || (pInfo.ext == "jpeg")) pInfo.type = "image/jpeg";
else if(pInfo.ext == "ico") pInfo.type = "image/x-icon";
else if(pInfo.ext == "svg") pInfo.type = "image/svg+xml";
else if(pInfo.ext == "pdf") pInfo.type = "application/pdf";
else if(pInfo.ext == "zip") pInfo.type = "application/zip";
return pInfo;
}
PINF getTruePathInfo(String fPath) {
PINF fpInf = getPathInfo(fPath);
if(SPIFFS.exists(fpInf.path))
return fpInf;
DBG_OUTPUT_PORT.println("path not found, trying alternatives...");
DBG_OUTPUT_PORT.println("Trying...");
String altPath = fpInf.path + ".gz";
DBG_OUTPUT_PORT.println(" " + altPath);
if((altPath.length() <= fs_info.maxPathLength) && SPIFFS.exists(altPath)) {
fpInf.gzip = true;
fpInf.path = altPath;
} else if(!fpInf.min && !fpInf.gzip && !fpInf.compress) {
altPath = fpInf.dir + fpInf.base + ".min." + fpInf.ext;
DBG_OUTPUT_PORT.println(" " + altPath);
if((altPath.length() <= fs_info.maxPathLength) && SPIFFS.exists(altPath)) {
fpInf.min = true;
fpInf.path = altPath;
} else {
altPath = altPath + ".gz";
DBG_OUTPUT_PORT.println(" " + altPath);
if((altPath.length() <= fs_info.maxPathLength) && SPIFFS.exists(altPath)) {
fpInf.gzip = true;
fpInf.path = altPath;
}
}
}
if(fPath != fpInf.path ) {
DBG_OUTPUT_PORT.println("using alternate path: " + altPath);
}
return fpInf;
}
bool printDir(AsyncWebServerRequest *request) {
String dPath = request->url();
// remove any trailing slash
if(!dPath.endsWith("/"))
dPath += "/";
DBG_OUTPUT_PORT.println("attempting printDir on '" + dPath + "'");
Dir webDir = SPIFFS.openDir(dPath);
String dirList = "";
while (webDir.next()) {
PINF pInfo = getPathInfo(webDir.fileName());
String fName = pInfo.base + "." + pInfo.ext;
dirList += "<tr><td><a href=\"" + pInfo.dir + fName + "\">" +fName + "</a></td><td> ... </td>";
File f = webDir.openFile("r");
dirList += "<td>" + String(f.size()) + "</td></tr>";
f.close();
}
if(dirList != "") {
DBG_OUTPUT_PORT.println("Sending directory listing.");
String dirHtml = "<html><head><title>" + dPath + " Directory Listing</title></head>";
dirHtml += "<body><h1>" + dPath + " Directory Listing</h1><hr /><table>" + dirList + "</table></body></html>";
request->send(200, "text/html", dirHtml);
return true;
} else {
return false;
}
}
bool loadFromFlash(AsyncWebServerRequest *request) {
String path = request->url();
DBG_OUTPUT_PORT.println("checking flash for " + path);
PINF upInf = getTruePathInfo(path);
// if upInf doesn't include an existing file, try index.htm and/or try listing directory
if(!SPIFFS.exists(upInf.path)) {
String dAlt;
if(path.endsWith("/")) { // user seems to be trying to get a dir listing
// check for index file in dir first
dAlt = path + "index.htm";
// filenames must be under 32 characters all told
if((dAlt.length() <= fs_info.maxPathLength) && SPIFFS.exists(dAlt)) {
upInf = getTruePathInfo(dAlt);
} else {
return printDir(request);
}
} else {
// try slash+index.htm just for kicks
dAlt = path + "/index.htm";
if ((dAlt.length() <= fs_info.maxPathLength) && SPIFFS.exists(dAlt)) {
upInf = getTruePathInfo(dAlt);
} else {
return printDir(request);
}
}
}
File webFile = SPIFFS.open(upInf.path, "r");
if (!webFile){
DBG_OUTPUT_PORT.println("problem opening " + upInf.path);
return false;
}
AsyncWebServerResponse *response = request->beginResponse(
webFile, upInf.path, upInf.type, false, NULL);
if(upInf.gzip)
response->addHeader("Content-Encoding", "gzip");
else if(upInf.compress)
response->addHeader("Content-Encoding", "compress");
request->send(response);
return true;
}
void handleNotFound(AsyncWebServerRequest *request){
String path = request->url();
if(loadFromFlash(request)){
return;
}
String message = "\nNo Handler\r\n";
message += "URI: ";
message += request->url();
message += "\nMethod: ";
message += (request->method() == HTTP_GET)?"GET":"POST";
message += "\nParameters: ";
message += request->params();
message += "\n";
for (uint8_t i=0; i<request->params(); i++){
AsyncWebParameter* p = request->getParam(i);
message += String(p->name().c_str()) + " : " + String(p->value().c_str()) + "\r\n";
}
request->send(404, "text/plain", message);
DBG_OUTPUT_PORT.print(message);
}