--- a/libupnpp/device/vdir.cxx
+++ b/libupnpp/device/vdir.cxx
@@ -18,16 +18,16 @@
#include "vdir.hxx"
-#include <string.h> // for memcpy
-#include <sys/types.h> // for off_t
-#include <upnp/ixml.h> // for ixmlCloneDOMString
-#include <upnp/upnp.h> // for File_Info, etc
-
-#include <iostream> // for endl, basic_ostream, etc
-#include <utility> // for pair
-
-#include "libupnpp/log.hxx" // for LOGERR
-#include "libupnpp/upnpp_p.hxx" // for path_getfather, etc
+#include <string.h>
+#include <upnp/ixml.h>
+#include <upnp/upnp.h>
+
+#include <iostream>
+#include <utility>
+#include <unordered_map>
+
+#include "libupnpp/log.hxx"
+#include "libupnpp/upnpp_p.hxx"
using namespace std;
using namespace UPnPP;
@@ -36,40 +36,140 @@
static VirtualDir *theDir;
+class FileEnt {
+public:
+ time_t mtime;
+ std::string mimetype;
+ std::string content;
+};
+
+struct DirEnt {
+public:
+ DirEnt(bool vd = false) : isvd(vd) {}
+ bool isvd;
+ unordered_map<string, FileEnt> files;
+ VirtualDir::FileOps ops;
+};
+static unordered_map<string, DirEnt> m_dirs;
+
+static void pathcatslash(string& path)
+{
+ if (path.empty() || path[path.size() - 1] != '/') {
+ path += '/';
+ }
+}
+
+// Look up entry for pathname
+static FileEnt *vdgetentry(const char *pathname, DirEnt **de)
+{
+ //LOGDEB("vdgetentry: [" << pathname << "]" << endl);
+ *de = nullptr;
+
+ VirtualDir *thedir = VirtualDir::getVirtualDir();
+ if (thedir == 0) {
+ return 0;
+ }
+
+ string path = path_getfather(pathname);
+ string name= path_getsimple(pathname);
+
+ pathcatslash(path);
+
+ auto dir = m_dirs.find(path);
+ if (dir == m_dirs.end()) {
+ LOGERR("VirtualDir::vdgetentry: no dir: " << path << endl);
+ return 0;
+ }
+ *de = &dir->second;
+ if (dir->second.isvd) {
+ return 0;
+ } else {
+ auto f = dir->second.files.find(name);
+ if (f == dir->second.files.end()) {
+ LOGERR("VirtualDir::vdgetentry: no file: " << path << endl);
+ return 0;
+ }
+ return &(f->second);
+ }
+}
+
+bool VirtualDir::addFile(const string& _path, const string& name,
+ const string& content, const string& mimetype)
+{
+ string path(_path);
+ pathcatslash(path);
+
+ //LOGDEB("VirtualDir::addFile: path " << path << " name " << name << endl);
+
+ if (m_dirs.find(path) == m_dirs.end()) {
+ m_dirs[path] = DirEnt();
+ UpnpAddVirtualDir(path.c_str());
+ }
+
+ FileEnt entry;
+ entry.mtime = time(0);
+ entry.mimetype = mimetype;
+ entry.content = content;
+ m_dirs[path].files[name] = entry;
+ // LOGDEB("VirtualDir::addFile: added entry for dir " <<
+ // path << " name " << name << endl);
+ return true;
+}
+
+bool VirtualDir::addVDir(const std::string& _path, FileOps fops)
+{
+ string path(_path);
+ pathcatslash(path);
+ if (m_dirs.find(path) == m_dirs.end()) {
+ m_dirs[path] = DirEnt(true);
+ UpnpAddVirtualDir(path.c_str());
+ }
+ m_dirs[path].ops = fops;
+ return true;
+}
+
+
+//////////
+// Methods for the libupnp interface:
+
struct Handle {
- Handle(VirtualDir::FileEnt *e)
- : entry(e), offset(0) {
- }
- VirtualDir::FileEnt *entry;
+ Handle(FileEnt *e, DirEnt *d = nullptr, void *vh = 0)
+ : entry(e), dir(d), vhandle(vh), offset(0) {
+ }
+ FileEnt *entry;
+ DirEnt *dir;
+ void *vhandle;
size_t offset;
};
static int vdclose(UpnpWebFileHandle fileHnd)
{
Handle *h = (Handle*)fileHnd;
+ if (h->vhandle) {
+ h->dir->ops.close(h->vhandle);
+ }
delete h;
return 0;
}
-static VirtualDir::FileEnt *vdgetentry(const char *pathname)
-{
- //LOGDEB("vdgetentry: [" << pathname << "]" << endl);
- VirtualDir *thedir = VirtualDir::getVirtualDir();
- if (thedir == 0) {
- return 0;
- }
-
- string dir = path_getfather(pathname);
- string fn = path_getsimple(pathname);
-
- return theDir->getFile(dir, fn);
-}
-
static int vdgetinfo(const char *fn, struct File_Info* info)
{
//LOGDEB("vdgetinfo: [" << fn << "] off_t " << sizeof(off_t) <<
// " time_t " << sizeof(time_t) << endl);
- VirtualDir::FileEnt *entry = vdgetentry(fn);
+ DirEnt *dir;
+ FileEnt *entry = vdgetentry(fn, &dir);
+ if (dir && dir->isvd) {
+ VirtualDir::FileInfo inf;
+ int ret = dir->ops.getinfo(fn, &inf);
+ if (ret >= 0) {
+ info->file_length = inf.file_length;
+ info->last_modified = inf.last_modified;
+ info->is_directory = inf.is_directory;
+ info->is_readable = inf.is_readable;
+ info->content_type = ixmlCloneDOMString(inf.mime.c_str());
+ }
+ return ret;
+ }
if (entry == 0) {
LOGERR("vdgetinfo: no entry for " << fn << endl);
return -1;
@@ -87,7 +187,18 @@
static UpnpWebFileHandle vdopen(const char* fn, enum UpnpOpenFileMode)
{
//LOGDEB("vdopen: " << fn << endl);
- VirtualDir::FileEnt *entry = vdgetentry(fn);
+ DirEnt *dir;
+ FileEnt *entry = vdgetentry(fn, &dir);
+
+ if (dir && dir->isvd) {
+ void *vh = dir->ops.open(fn);
+ if (vh) {
+ return new Handle(nullptr, dir, vh);
+ } else {
+ return NULL;
+ }
+ }
+
if (entry == 0) {
LOGERR("vdopen: no entry for " << fn << endl);
return NULL;
@@ -102,6 +213,10 @@
return 0;
}
Handle *h = (Handle *)fileHnd;
+ if (h->vhandle) {
+ return h->dir->ops.read(h->vhandle, buf, buflen);
+ }
+
if (h->offset >= h->entry->content.size()) {
return 0;
}
@@ -116,6 +231,9 @@
{
// LOGDEB("vdseek: " << endl);
Handle *h = (Handle *)fileHnd;
+ if (h->vhandle) {
+ return h->dir->ops.seek(h->vhandle, offset, origin);
+ }
if (origin == 0) {
h->offset = offset;
} else if (origin == 1) {
@@ -152,53 +270,4 @@
return theDir;
}
-bool VirtualDir::addFile(const string& _path, const string& name,
- const string& content, const string& mimetype)
-{
- string path(_path);
- if (path.empty() || path[path.size() - 1] != '/') {
- path += '/';
- }
- //LOGDEB("VirtualDir::addFile: path " << path << " name " << name << endl);
-
- if (m_dirs.find(path) == m_dirs.end()) {
- m_dirs[path] = std::unordered_map<string, VirtualDir::FileEnt>();
- UpnpAddVirtualDir(path.c_str());
- }
-
- VirtualDir::FileEnt entry;
- entry.mtime = time(0);
- entry.mimetype = mimetype;
- entry.content = content;
- m_dirs[path][name] = entry;
- // LOGDEB("VirtualDir::addFile: added entry for dir " <<
- // path << " name " << name << endl);
- return true;
-}
-
-VirtualDir::FileEnt *VirtualDir::getFile(const string& _path,
- const string& name)
-{
- string path(_path);
- if (path.empty() || path[path.size() - 1] != '/') {
- path += '/';
- }
-
- // LOGDEB("VirtualDir::getFile: path " << path << " name " << name << endl);
-
- std::unordered_map<string, std::unordered_map<string, VirtualDir::FileEnt> >::iterator dir =
- m_dirs.find(path);
- if (dir == m_dirs.end()) {
- LOGERR("VirtualDir::getFile: no dir: " << path << endl);
- return 0;
- }
- std::unordered_map<string, FileEnt>::iterator f = dir->second.find(name);
- if (f == dir->second.end()) {
- LOGERR("VirtualDir::getFile: no file: " << path << endl);
- return 0;
- }
-
- return &(f->second);
-}
-
-}
+}