--- a/upmpd/ohmetacache.cxx
+++ b/upmpd/ohmetacache.cxx
@@ -17,15 +17,14 @@
#include <unistd.h>
#include <fcntl.h>
+#include <string.h>
#include <iostream>
using namespace std;
#include "ohmetacache.hxx"
-#include "conftree.hxx"
#include "libupnpp/workqueue.hxx"
#include "libupnpp/log.hxx"
-#include "base64.hxx"
class SaveCacheTask {
public:
@@ -38,21 +37,57 @@
};
static WorkQueue<SaveCacheTask*> saveQueue("SaveQueue");
-// We use base64 to encode names and value, and need to replace the '='
-static const char eqesc = '*';
-static void eqtoggle(string& nm)
+// Encode uris and values so that they can be decoded (escape %, =, and eol)
+static string encode(const string& in)
{
- int i = nm.size() - 1;
- while (i >= 0) {
- if (nm[i] == '=') {
- nm[i] = eqesc;
- } else if (nm[i] == eqesc) {
- nm[i] = '=';
- } else {
- break;
+ string out;
+ const char *cp = in.c_str();
+ for (string::size_type i = 0; i < in.size(); i++) {
+ unsigned int c;
+ const char *h = "0123456789ABCDEF";
+ c = cp[i];
+ if (c == '%' || c == '=' || c == '\n' || c == '\r') {
+ out += '%';
+ out += h[(c >> 4) & 0xf];
+ out += h[c & 0xf];
+ } else {
+ out += char(c);
+ }
+ }
+ return out;
+}
+
+static int h2d(int c)
+{
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ else if ('A' <= c && c <= 'F')
+ return 10 + c - 'A';
+ else
+ return -1;
+}
+
+static string decode(const string &in)
+{
+ string out;
+ const char *cp = in.c_str();
+ if (in.size() <= 2)
+ return in;
+ string::size_type i = 0;
+ for (; i < in.size() - 2; i++) {
+ if (cp[i] == '%') {
+ int d1 = h2d(cp[++i]);
+ int d2 = h2d(cp[++i]);
+ if (d1 != -1 && d2 != -1)
+ out += (d1 << 4) + d2;
+ } else {
+ out += cp[i];
}
- i--;
}
+ while (i < in.size()) {
+ out += cp[i++];
+ }
+ return out;
}
bool dmcacheSave(const string& fn, const mcache_type& cache)
@@ -81,33 +116,35 @@
LOGDEB("dmcacheSave: got save task: " << tsk->m_cache.size() <<
" entries to " << tsk->m_fn << endl);
- // Beware that calling the constructor with a std::string
- // would result in a memory-based object...
- ConfSimple cs(tsk->m_fn.c_str());
- cs.clear();
- if (cs.getStatus() != ConfSimple::STATUS_RW) {
+ ofstream output(tsk->m_fn, ios::out | ios::trunc);
+ if (!output.is_open()) {
LOGERR("dmcacheSave: could not open " << tsk->m_fn
<< " for writing" << endl);
delete tsk;
continue;
}
- cs.holdWrites(true);
+
for (mcache_type::const_iterator it = tsk->m_cache.begin();
it != tsk->m_cache.end(); it++) {
- string name = base64_encode(it->first);
- eqtoggle(name);
- string value = base64_encode(it->second);
- //LOGDEB("dmcacheSave: " << name << " -> " << value << endl);
- cs.set(name, value);
+ output << encode(it->first) << '=' << encode(it->second) << '\n';
+ if (!output.good()) {
+ LOGERR("dmcacheSave: write error while saving to " <<
+ tsk->m_fn << endl);
+ break;
+ }
}
-
- if (!cs.holdWrites(false)) {
- LOGERR("dmcacheSave: write error while saving to " <<
+ output.flush();
+ if (!output.good()) {
+ LOGERR("dmcacheSave: flush error while saving to " <<
tsk->m_fn << endl);
}
+
delete tsk;
}
}
+
+// Max size of metadata element ??
+#define LL 10*1024
bool dmcacheRestore(const string& fn, mcache_type& cache)
{
@@ -118,29 +155,29 @@
return false;
}
- // Beware that calling the constructor with a std::string
- // would result in a memory-based object...
- ConfSimple cs(fn.c_str(), 1);
- if (!cs.ok()) {
- LOGINF("dmcacheRestore: could not read metadata from " << fn << endl);
+ ifstream input;
+ input.open(fn, ios::in);
+ if (!input.is_open()) {
+ LOGERR("dmcacheRestore: could not open " << fn << endl);
return false;
}
- vector<string> names = cs.getNames("");
- for (auto &name : names) {
- string value;
- if (!cs.get(name, value)) {
- // ??
- LOGDEB("dmcacheRestore: no data for found name " << name << endl);
- continue;
+ char cline[LL];
+ for (;;) {
+ input.getline(cline, LL-1, '\n');
+ if (input.eof())
+ break;
+ if (!input.good()) {
+ LOGERR("dmcacheRestore: read error on " << fn << endl);
+ return false;
}
- eqtoggle(name);
- name = base64_decode(name);
- value = base64_decode(value);
- LOGDEB("dmcacheRestore: " << name << " -> " <<
- value.substr(0, 20) << endl);
- cache[name] = value;
+ char *cp = strchr(cline, '=');
+ if (cp == 0) {
+ LOGERR("dmcacheRestore: no = in line !" << endl);
+ return false;
+ }
+ *cp = 0;
+ cache[decode(cline)] = decode(cp+1);
}
return true;
}
-