Switch to unified view

a/libupnpp/upnpplib.cxx b/libupnpp/upnpplib.cxx
...
...
22
#include <iostream>
22
#include <iostream>
23
#include <sstream>
23
#include <sstream>
24
#include <map>
24
#include <map>
25
#include <vector>
25
#include <vector>
26
#include <set>
26
#include <set>
27
using std::string;
27
using namespace std;
28
using std::cerr;
29
using std::endl;
30
using std::map;
31
using std::vector;
32
using std::set;
33
28
34
#include <upnp/ixml.h>
29
#include <upnp/ixml.h>
35
30
36
#include "upnpp_p.hxx"
31
#include "upnpp_p.hxx"
37
#include "upnpplib.hxx"
32
#include "upnpplib.hxx"
...
...
42
#include "log.hxx"
37
#include "log.hxx"
43
38
44
static LibUPnP *theLib;
39
static LibUPnP *theLib;
45
40
46
LibUPnP *LibUPnP::getLibUPnP(bool serveronly, string* hwaddr,
41
LibUPnP *LibUPnP::getLibUPnP(bool serveronly, string* hwaddr,
47
                           const string ifname, const string ip,
42
                             const string ifname, const string ip,
48
                           unsigned short port)
43
                             unsigned short port)
49
{
44
{
50
  if (theLib == 0)
45
    if (theLib == 0)
51
      theLib = new LibUPnP(serveronly, hwaddr, ifname, ip, port);
46
        theLib = new LibUPnP(serveronly, hwaddr, ifname, ip, port);
52
  if (theLib && !theLib->ok()) {
47
    if (theLib && !theLib->ok()) {
53
      delete theLib;
48
        delete theLib;
54
      theLib = 0;
49
        theLib = 0;
55
      return 0;
50
        return 0;
56
  }
51
    }
57
  return theLib;
52
    return theLib;
58
}
53
}
59
54
60
55
61
LibUPnP::LibUPnP(bool serveronly, string* hwaddr,
56
LibUPnP::LibUPnP(bool serveronly, string* hwaddr,
62
               const string ifname, const string inip, unsigned short port)
57
                 const string ifname, const string inip, unsigned short port)
63
  : m_ok(false)
58
    : m_ok(false)
64
{
59
{
65
  LOGDEB("LibUPnP: serveronly " << serveronly << " &hwaddr " << hwaddr <<
60
    LOGDEB("LibUPnP: serveronly " << serveronly << " &hwaddr " << hwaddr <<
66
         " ifname [" << ifname << "] inip [" << inip << "] port " << port 
61
           " ifname [" << ifname << "] inip [" << inip << "] port " << port 
67
         << endl);
62
           << endl);
68
63
69
  // If our caller wants to retrieve an ethernet address (typically
64
    // If our caller wants to retrieve an ethernet address (typically
70
  // for uuid purposes), or has specified an interface we have to
65
    // for uuid purposes), or has specified an interface we have to
71
  // look at the network config.
66
    // look at the network config.
72
  const int ipalen(100);
67
    const int ipalen(100);
73
  char ip_address[ipalen];
68
    char ip_address[ipalen];
74
  ip_address[0] = 0;
69
    ip_address[0] = 0;
75
  if (hwaddr || !ifname.empty()) {
70
    if (hwaddr || !ifname.empty()) {
76
      char mac[20];
71
        char mac[20];
77
      if (getsyshwaddr(ifname.c_str(), ip_address, ipalen, mac, 13) < 0) {
72
        if (getsyshwaddr(ifname.c_str(), ip_address, ipalen, mac, 13) < 0) {
78
          LOGERR("LibUPnP::LibUPnP: failed retrieving addr" << endl);
73
            LOGERR("LibUPnP::LibUPnP: failed retrieving addr" << endl);
79
          return;
74
            return;
80
      }
75
        }
81
      if (hwaddr)
76
        if (hwaddr)
82
          *hwaddr = string(mac);
77
            *hwaddr = string(mac);
83
  }
78
    }
84
79
85
  // If the interface name was not specified, we possibly use the
80
    // If the interface name was not specified, we possibly use the
86
  // supplied IP address.
81
    // supplied IP address.
87
  if (ifname.empty())
82
    if (ifname.empty())
88
      strncpy(ip_address, inip.c_str(), ipalen);
83
        strncpy(ip_address, inip.c_str(), ipalen);
89
84
90
  m_init_error = UpnpInit(ip_address[0] ? ip_address : 0, port);
85
    m_init_error = UpnpInit(ip_address[0] ? ip_address : 0, port);
91
86
92
  if (m_init_error != UPNP_E_SUCCESS) {
87
    if (m_init_error != UPNP_E_SUCCESS) {
93
      LOGERR(errAsString("UpnpInit", m_init_error) << endl);
88
        LOGERR(errAsString("UpnpInit", m_init_error) << endl);
94
      return;
89
        return;
95
  }
90
    }
96
  setMaxContentLength(2000*1024);
91
    setMaxContentLength(2000*1024);
97
92
98
  LOGDEB("Using IP " << UpnpGetServerIpAddress() << " port " << 
93
    LOGDEB("Using IP " << UpnpGetServerIpAddress() << " port " << 
99
         UpnpGetServerPort() << endl);
94
           UpnpGetServerPort() << endl);
100
95
101
#if defined(HAVE_UPNPSETLOGLEVEL)
96
#if defined(HAVE_UPNPSETLOGLEVEL)
102
  UpnpCloseLog();
97
    UpnpCloseLog();
103
#endif
98
#endif
104
99
105
  // Client initialization is simple, just do it. Defer device
100
    // Client initialization is simple, just do it. Defer device
106
  // initialization because it's more complicated.
101
    // initialization because it's more complicated.
107
  if (serveronly) {
102
    if (serveronly) {
108
      m_ok = true;
103
        m_ok = true;
109
  } else {
104
    } else {
110
      m_init_error = UpnpRegisterClient(o_callback, (void *)this, &m_clh);
105
        m_init_error = UpnpRegisterClient(o_callback, (void *)this, &m_clh);
111
        
106
        
112
      if (m_init_error == UPNP_E_SUCCESS) {
107
        if (m_init_error == UPNP_E_SUCCESS) {
113
          m_ok = true;
108
            m_ok = true;
114
      } else {
109
        } else {
115
          LOGERR(errAsString("UpnpRegisterClient", m_init_error) << endl);
110
            LOGERR(errAsString("UpnpRegisterClient", m_init_error) << endl);
116
      }
111
        }
117
  }
112
    }
118
113
119
  // Servers sometimes make errors (e.g.: minidlna returns bad utf-8).
114
    // Servers sometimes make errors (e.g.: minidlna returns bad utf-8).
120
  ixmlRelaxParser(1);
115
    ixmlRelaxParser(1);
121
}
116
}
122
117
123
int LibUPnP::setupWebServer(const string& description)
118
int LibUPnP::setupWebServer(const string& description)
124
{
119
{
125
  int res = UpnpRegisterRootDevice2(
120
    int res = UpnpRegisterRootDevice2(
126
      UPNPREG_BUF_DESC,
121
        UPNPREG_BUF_DESC,
127
      description.c_str(), 
122
        description.c_str(), 
128
      description.size(), /* Desc filename len, ignored */
123
        description.size(), /* Desc filename len, ignored */
129
      1, /* URLBase*/
124
        1, /* URLBase*/
130
      o_callback, (void *)this, &m_dvh);
125
        o_callback, (void *)this, &m_dvh);
131
126
132
  if (res != UPNP_E_SUCCESS) {
127
    if (res != UPNP_E_SUCCESS) {
133
      LOGERR(errAsString("UpnpRegisterRootDevice2", m_init_error) << endl);
128
        LOGERR(errAsString("UpnpRegisterRootDevice2", m_init_error) << endl);
134
  }
129
    }
135
  return res;
130
    return res;
136
}
131
}
137
132
138
void LibUPnP::setMaxContentLength(int bytes)
133
void LibUPnP::setMaxContentLength(int bytes)
139
{
134
{
140
  UpnpSetMaxContentLength(bytes);
135
    UpnpSetMaxContentLength(bytes);
141
}
136
}
142
137
143
bool LibUPnP::setLogFileName(const std::string& fn, LogLevel level)
138
bool LibUPnP::setLogFileName(const std::string& fn, LogLevel level)
144
{
139
{
145
  PTMutexLocker lock(m_mutex);
140
    PTMutexLocker lock(m_mutex);
146
  if (fn.empty() || level == LogLevelNone) {
141
    if (fn.empty() || level == LogLevelNone) {
147
#if defined(HAVE_UPNPSETLOGLEVEL)
142
#if defined(HAVE_UPNPSETLOGLEVEL)
148
      UpnpCloseLog();
143
        UpnpCloseLog();
149
#endif
144
#endif
150
  } else {
145
    } else {
151
#if defined(HAVE_UPNPSETLOGLEVEL)
146
#if defined(HAVE_UPNPSETLOGLEVEL)
152
      setLogLevel(level);
147
        setLogLevel(level);
153
      UpnpSetLogFileNames(fn.c_str(), fn.c_str());
148
        UpnpSetLogFileNames(fn.c_str(), fn.c_str());
154
      int code = UpnpInitLog();
149
        int code = UpnpInitLog();
155
      if (code != UPNP_E_SUCCESS) {
150
        if (code != UPNP_E_SUCCESS) {
156
          LOGERR(errAsString("UpnpInitLog", code) << endl);
151
            LOGERR(errAsString("UpnpInitLog", code) << endl);
157
          return false;
152
            return false;
158
      }
153
        }
159
#endif
154
#endif
160
  }
155
    }
161
  return true;
156
    return true;
162
}
157
}
163
158
164
bool LibUPnP::setLogLevel(LogLevel level)
159
bool LibUPnP::setLogLevel(LogLevel level)
165
{
160
{
166
#if defined(HAVE_UPNPSETLOGLEVEL)
161
#if defined(HAVE_UPNPSETLOGLEVEL)
167
  switch (level) {
162
    switch (level) {
168
  case LogLevelNone: 
163
    case LogLevelNone: 
169
      setLogFileName("", LogLevelNone);
164
        setLogFileName("", LogLevelNone);
170
      break;
165
        break;
171
  case LogLevelError: 
166
    case LogLevelError: 
172
      UpnpSetLogLevel(UPNP_CRITICAL);
167
        UpnpSetLogLevel(UPNP_CRITICAL);
173
      break;
168
        break;
174
  case LogLevelDebug: 
169
    case LogLevelDebug: 
175
      UpnpSetLogLevel(UPNP_ALL);
170
        UpnpSetLogLevel(UPNP_ALL);
176
      break;
171
        break;
177
  }
172
    }
178
#endif
173
#endif
179
  return true;
174
    return true;
180
}
175
}
181
176
182
void LibUPnP::registerHandler(Upnp_EventType et, Upnp_FunPtr handler,
177
void LibUPnP::registerHandler(Upnp_EventType et, Upnp_FunPtr handler,
183
                            void *cookie)
178
                              void *cookie)
184
{
179
{
185
  PTMutexLocker lock(m_mutex);
180
    PTMutexLocker lock(m_mutex);
186
  if (handler == 0) {
181
    if (handler == 0) {
187
      m_handlers.erase(et);
182
        m_handlers.erase(et);
188
  } else {
183
    } else {
189
      Handler h(handler, cookie);
184
        Handler h(handler, cookie);
190
      m_handlers[et] = h;
185
        m_handlers[et] = h;
191
  }
186
    }
192
}
187
}
193
188
194
std::string LibUPnP::errAsString(const std::string& who, int code)
189
std::string LibUPnP::errAsString(const std::string& who, int code)
195
{
190
{
196
  std::ostringstream os;
191
    std::ostringstream os;
197
  os << who << " :" << code << ": " << UpnpGetErrorMessage(code);
192
    os << who << " :" << code << ": " << UpnpGetErrorMessage(code);
198
  return os.str();
193
    return os.str();
199
}
194
}
200
195
201
int LibUPnP::o_callback(Upnp_EventType et, void* evp, void* cookie)
196
int LibUPnP::o_callback(Upnp_EventType et, void* evp, void* cookie)
202
{
197
{
203
  LibUPnP *ulib = (LibUPnP *)cookie;
198
    LibUPnP *ulib = (LibUPnP *)cookie;
204
  if (ulib == 0) {
199
    if (ulib == 0) {
205
      // Because the asyncsearch calls uses a null cookie.
200
        // Because the asyncsearch calls uses a null cookie.
206
      //cerr << "o_callback: NULL ulib!" << endl;
201
        //cerr << "o_callback: NULL ulib!" << endl;
207
      ulib = theLib;
202
        ulib = theLib;
208
  }
203
    }
209
  PLOGDEB("LibUPnP::o_callback: event type: %s\n",evTypeAsString(et).c_str());
204
    LOGDEB("LibUPnP::o_callback: event type: " << evTypeAsString(et) << endl);
210
205
211
  map<Upnp_EventType, Handler>::iterator it = ulib->m_handlers.find(et);
206
    map<Upnp_EventType, Handler>::iterator it = ulib->m_handlers.find(et);
212
  if (it != ulib->m_handlers.end()) {
207
    if (it != ulib->m_handlers.end()) {
213
      (it->second.handler)(et, evp, it->second.cookie);
208
        (it->second.handler)(et, evp, it->second.cookie);
214
  }
209
    }
215
  return UPNP_E_SUCCESS;
210
    return UPNP_E_SUCCESS;
216
}
211
}
217
212
218
LibUPnP::~LibUPnP()
213
LibUPnP::~LibUPnP()
219
{
214
{
220
  int error = UpnpFinish();
215
    int error = UpnpFinish();
221
  if (error != UPNP_E_SUCCESS) {
216
    if (error != UPNP_E_SUCCESS) {
222
      PLOGINF("%s\n", errAsString("UpnpFinish", error).c_str());
217
        LOGINF("LibUPnP::~LibUPnP: " << errAsString("UpnpFinish", error)
223
  }
218
               << endl);
224
  PLOGDEB("LibUPnP: done\n");
219
    }
220
    LOGDEB1("LibUPnP: done" << endl);
225
}
221
}
226
222
227
string LibUPnP::makeDevUUID(const std::string& name, const std::string& hw)
223
string LibUPnP::makeDevUUID(const std::string& name, const std::string& hw)
228
{
224
{
229
  string digest;
225
    string digest;
230
  MD5String(name, digest);
226
    MD5String(name, digest);
231
  // digest has 16 bytes of binary data. UUID is like:
227
    // digest has 16 bytes of binary data. UUID is like:
232
  // f81d4fae-7dec-11d0-a765-00a0c91e6bf6
228
    // f81d4fae-7dec-11d0-a765-00a0c91e6bf6
233
  // Where the last 12 chars are provided by the hw addr
229
    // Where the last 12 chars are provided by the hw addr
234
230
235
  char uuid[100];
231
    char uuid[100];
236
  sprintf(uuid, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%s",
232
    sprintf(uuid, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%s",
237
          digest[0]&0xff, digest[1]&0xff, digest[2]&0xff, digest[3]&0xff,
233
            digest[0]&0xff, digest[1]&0xff, digest[2]&0xff, digest[3]&0xff,
238
          digest[4]&0xff, digest[5]&0xff,  digest[6]&0xff, digest[7]&0xff,
234
            digest[4]&0xff, digest[5]&0xff,  digest[6]&0xff, digest[7]&0xff,
239
          digest[8]&0xff, digest[9]&0xff, hw.c_str());
235
            digest[8]&0xff, digest[9]&0xff, hw.c_str());
240
  return uuid;
236
    return uuid;
241
}
237
}
242
238
243
239
244
string LibUPnP::evTypeAsString(Upnp_EventType et)
240
string LibUPnP::evTypeAsString(Upnp_EventType et)
245
{
241
{
246
  switch (et) {
242
    switch (et) {
247
  case UPNP_CONTROL_ACTION_REQUEST: return "UPNP_CONTROL_ACTION_REQUEST";
243
    case UPNP_CONTROL_ACTION_REQUEST: return "UPNP_CONTROL_ACTION_REQUEST";
248
  case UPNP_CONTROL_ACTION_COMPLETE: return "UPNP_CONTROL_ACTION_COMPLETE";
244
    case UPNP_CONTROL_ACTION_COMPLETE: return "UPNP_CONTROL_ACTION_COMPLETE";
249
  case UPNP_CONTROL_GET_VAR_REQUEST: return "UPNP_CONTROL_GET_VAR_REQUEST";
245
    case UPNP_CONTROL_GET_VAR_REQUEST: return "UPNP_CONTROL_GET_VAR_REQUEST";
250
  case UPNP_CONTROL_GET_VAR_COMPLETE: return "UPNP_CONTROL_GET_VAR_COMPLETE";
246
    case UPNP_CONTROL_GET_VAR_COMPLETE: return "UPNP_CONTROL_GET_VAR_COMPLETE";
251
  case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
247
    case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
252
      return "UPNP_DISCOVERY_ADVERTISEMENT_ALIVE";
248
        return "UPNP_DISCOVERY_ADVERTISEMENT_ALIVE";
253
  case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
249
    case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
254
      return "UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE";
250
        return "UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE";
255
  case UPNP_DISCOVERY_SEARCH_RESULT: return "UPNP_DISCOVERY_SEARCH_RESULT";
251
    case UPNP_DISCOVERY_SEARCH_RESULT: return "UPNP_DISCOVERY_SEARCH_RESULT";
256
  case UPNP_DISCOVERY_SEARCH_TIMEOUT: return "UPNP_DISCOVERY_SEARCH_TIMEOUT";
252
    case UPNP_DISCOVERY_SEARCH_TIMEOUT: return "UPNP_DISCOVERY_SEARCH_TIMEOUT";
257
  case UPNP_EVENT_SUBSCRIPTION_REQUEST:
253
    case UPNP_EVENT_SUBSCRIPTION_REQUEST:
258
      return "UPNP_EVENT_SUBSCRIPTION_REQUEST";
254
        return "UPNP_EVENT_SUBSCRIPTION_REQUEST";
259
  case UPNP_EVENT_RECEIVED: return "UPNP_EVENT_RECEIVED";
255
    case UPNP_EVENT_RECEIVED: return "UPNP_EVENT_RECEIVED";
260
  case UPNP_EVENT_RENEWAL_COMPLETE: return "UPNP_EVENT_RENEWAL_COMPLETE";
256
    case UPNP_EVENT_RENEWAL_COMPLETE: return "UPNP_EVENT_RENEWAL_COMPLETE";
261
  case UPNP_EVENT_SUBSCRIBE_COMPLETE: return "UPNP_EVENT_SUBSCRIBE_COMPLETE";
257
    case UPNP_EVENT_SUBSCRIBE_COMPLETE: return "UPNP_EVENT_SUBSCRIBE_COMPLETE";
262
  case UPNP_EVENT_UNSUBSCRIBE_COMPLETE:
258
    case UPNP_EVENT_UNSUBSCRIBE_COMPLETE:
263
      return "UPNP_EVENT_UNSUBSCRIBE_COMPLETE";
259
        return "UPNP_EVENT_UNSUBSCRIBE_COMPLETE";
264
  case UPNP_EVENT_AUTORENEWAL_FAILED: return "UPNP_EVENT_AUTORENEWAL_FAILED";
260
    case UPNP_EVENT_AUTORENEWAL_FAILED: return "UPNP_EVENT_AUTORENEWAL_FAILED";
265
  case UPNP_EVENT_SUBSCRIPTION_EXPIRED:
261
    case UPNP_EVENT_SUBSCRIPTION_EXPIRED:
266
      return "UPNP_EVENT_SUBSCRIPTION_EXPIRED";
262
        return "UPNP_EVENT_SUBSCRIPTION_EXPIRED";
267
  default: return "UPNP UNKNOWN EVENT";
263
    default: return "UPNP UNKNOWN EVENT";
268
  }
264
    }
269
}
265
}
270
266
271
/////////////////////// Small global helpers
267
/////////////////////// Small global helpers
272
/** Get rid of white space at both ends */
268
/** Get rid of white space at both ends */
273
void trimstring(string &s, const char *ws)
269
void trimstring(string &s, const char *ws)
274
{
270
{
275
  string::size_type pos = s.find_first_not_of(ws);
271
    string::size_type pos = s.find_first_not_of(ws);
276
  if (pos == string::npos) {
272
    if (pos == string::npos) {
277
      s.clear();
273
        s.clear();
278
      return;
274
        return;
279
  }
275
    }
280
  s.replace(0, pos, string());
276
    s.replace(0, pos, string());
281
277
282
  pos = s.find_last_not_of(ws);
278
    pos = s.find_last_not_of(ws);
283
  if (pos != string::npos && pos != s.length()-1)
279
    if (pos != string::npos && pos != s.length()-1)
284
      s.replace(pos+1, string::npos, string());
280
        s.replace(pos+1, string::npos, string());
285
}
281
}
286
string caturl(const string& s1, const string& s2)
282
string caturl(const string& s1, const string& s2)
287
{
283
{
288
  string out(s1);
284
    string out(s1);
289
  if (out[out.size()-1] == '/') {
285
    if (out[out.size()-1] == '/') {
290
      if (s2[0] == '/')
286
        if (s2[0] == '/')
291
          out.erase(out.size()-1);
287
            out.erase(out.size()-1);
292
  } else {
288
    } else {
293
      if (s2[0] != '/')
289
        if (s2[0] != '/')
294
          out.push_back('/');
290
            out.push_back('/');
295
  }
291
    }
296
  out += s2;
292
    out += s2;
297
  return out;
293
    return out;
298
}
294
}
299
295
300
string baseurl(const string& url)
296
string baseurl(const string& url)
301
{
297
{
302
    string::size_type pos = url.find("://");
298
    string::size_type pos = url.find("://");
...
...
310
        return url.substr(0, pos + 1);
306
        return url.substr(0, pos + 1);
311
    }
307
    }
312
}
308
}
313
309
314
static void path_catslash(string &s) {
310
static void path_catslash(string &s) {
315
  if (s.empty() || s[s.length() - 1] != '/')
311
    if (s.empty() || s[s.length() - 1] != '/')
316
      s += '/';
312
        s += '/';
317
}
313
}
318
string path_getfather(const string &s)
314
string path_getfather(const string &s)
319
{
315
{
320
  string father = s;
316
    string father = s;
321
317
322
  // ??
318
    // ??
323
  if (father.empty())
319
    if (father.empty())
324
      return "./";
320
        return "./";
325
321
326
  if (father[father.length() - 1] == '/') {
322
    if (father[father.length() - 1] == '/') {
327
      // Input ends with /. Strip it, handle special case for root
323
        // Input ends with /. Strip it, handle special case for root
328
      if (father.length() == 1)
324
        if (father.length() == 1)
329
          return father;
325
            return father;
330
      father.erase(father.length()-1);
326
        father.erase(father.length()-1);
331
  }
327
    }
332
328
333
  string::size_type slp = father.rfind('/');
329
    string::size_type slp = father.rfind('/');
334
  if (slp == string::npos)
330
    if (slp == string::npos)
335
      return "./";
331
        return "./";
336
332
337
  father.erase(slp);
333
    father.erase(slp);
338
  path_catslash(father);
334
    path_catslash(father);
339
  return father;
335
    return father;
340
}
336
}
341
string path_getsimple(const string &s) {
337
string path_getsimple(const string &s) {
342
    string simple = s;
338
    string simple = s;
343
339
344
    if (simple.empty())
340
    if (simple.empty())
...
...
352
    return simple;
348
    return simple;
353
}
349
}
354
350
355
template <class T> bool csvToStrings(const string &s, T &tokens)
351
template <class T> bool csvToStrings(const string &s, T &tokens)
356
{
352
{
357
  string current;
353
    string current;
358
  tokens.clear();
354
    tokens.clear();
359
  enum states {TOKEN, ESCAPE};
355
    enum states {TOKEN, ESCAPE};
360
  states state = TOKEN;
356
    states state = TOKEN;
361
  for (unsigned int i = 0; i < s.length(); i++) {
357
    for (unsigned int i = 0; i < s.length(); i++) {
362
      switch (s[i]) {
358
        switch (s[i]) {
363
      case ',':
359
        case ',':
364
          switch(state) {
360
            switch(state) {
365
          case TOKEN:
361
            case TOKEN:
366
              tokens.insert(tokens.end(), current);
362
                tokens.insert(tokens.end(), current);
367
              current.clear();
363
                current.clear();
368
              continue;
364
                continue;
369
          case ESCAPE:
365
            case ESCAPE:
370
              current += ',';
366
                current += ',';
371
              state = TOKEN;
367
                state = TOKEN;
372
              continue;
368
                continue;
373
          }
369
            }
374
          break;
370
            break;
375
      case '\\':
371
        case '\\':
376
          switch(state) {
372
            switch(state) {
377
          case TOKEN:
373
            case TOKEN:
378
              state=ESCAPE;
374
                state=ESCAPE;
379
              continue;
375
                continue;
380
          case ESCAPE:
376
            case ESCAPE:
381
              current += '\\';
377
                current += '\\';
382
              state = TOKEN;
378
                state = TOKEN;
383
              continue;
379
                continue;
384
          }
380
            }
385
          break;
381
            break;
386
382
387
      default:
383
        default:
388
          switch(state) {
384
            switch(state) {
389
          case ESCAPE:
385
            case ESCAPE:
390
              state = TOKEN;
386
                state = TOKEN;
391
              break;
387
                break;
392
          case TOKEN:
388
            case TOKEN:
393
              break;
389
                break;
394
          }
390
            }
395
          current += s[i];
391
            current += s[i];
396
      }
392
        }
397
  }
393
    }
398
  switch(state) {
394
    switch(state) {
399
  case TOKEN:
395
    case TOKEN:
400
      tokens.insert(tokens.end(), current);
396
        tokens.insert(tokens.end(), current);
401
      break;
397
        break;
402
  case ESCAPE:
398
    case ESCAPE:
403
      return false;
399
        return false;
404
  }
400
    }
405
  return true;
401
    return true;
406
}
402
}
407
403
408
//template bool csvToStrings<list<string> >(const string &, list<string> &);
404
//template bool csvToStrings<list<string> >(const string &, list<string> &);
409
template bool csvToStrings<vector<string> >(const string &, vector<string> &);
405
template bool csvToStrings<vector<string> >(const string &, vector<string> &);
410
template bool csvToStrings<set<string> >(const string &, set<string> &);
406
template bool csvToStrings<set<string> >(const string &, set<string> &);
411
/* Local Variables: */
412
/* mode: c++ */
413
/* c-basic-offset: 4 */
414
/* tab-width: 4 */
415
/* indent-tabs-mode: t */
416
/* End: */