Switch to unified view

a/libupnpp/cdircontent.cxx b/libupnpp/cdircontent.cxx
...
...
18
18
19
#include <string>
19
#include <string>
20
#include <vector>
20
#include <vector>
21
#include <iostream>
21
#include <iostream>
22
#include <map>
22
#include <map>
23
#include <set>
23
24
using std::string;
24
using namespace std;
25
using std::cerr;
26
using std::endl;
27
using std::vector;
28
using std::map;
29
using std::set;
30
25
31
#include "expatmm.hxx"
26
#include "expatmm.hxx"
32
#include "upnpp_p.hxx"
27
#include "upnpp_p.hxx"
33
#include "cdircontent.hxx"
28
#include "cdircontent.hxx"
29
#include "log.hxx"
34
30
35
#if 0
36
static void listmap(const map<string,string>& mp)
37
{
38
  for (map<string,string>::const_iterator it = mp.begin();
39
       it != mp.end(); it++) {
40
      cerr << "[" << it->first << "]->[" << it->second << "] ";
41
  }
42
}
43
#endif
44
45
static const char* upnptags[] = {
46
  "upnp:artist",
47
  "upnp:album",
48
  "upnp:genre",
49
  "upnp:originalTrackNumber",
50
  "upnp:class",
51
};
52
static const int nupnptags = sizeof(upnptags) / sizeof(char*);
53
54
// An XML parser which builds directory contents from DIDL lite input.
31
// An XML parser which builds directory contents from DIDL-lite input.
55
class UPnPDirParser : public expatmm::inputRefXMLParser {
32
class UPnPDirParser : public expatmm::inputRefXMLParser {
56
public:
33
public:
57
  UPnPDirParser(UPnPDirContent& dir, const string& input)
34
    UPnPDirParser(UPnPDirContent& dir, const string& input)
58
      : inputRefXMLParser(input), m_dir(dir)
35
        : inputRefXMLParser(input), m_dir(dir)
59
      {
36
    {
60
          m_okitems["object.item.audioItem.musicTrack"] =
37
        m_okitems["object.item.audioItem.musicTrack"] =
61
              UPnPDirObject::audioItem_musicTrack;
38
            UPnPDirObject::audioItem_musicTrack;
62
          m_okitems["object.item.playlistItem"] =
39
        m_okitems["object.item.playlistItem"] =
63
              UPnPDirObject::audioItem_playlist;
40
            UPnPDirObject::audioItem_playlist;
64
      }
41
    }
65
  UPnPDirContent& m_dir;
42
    UPnPDirContent& m_dir;
66
43
67
protected:
44
protected:
68
  class StackEl {
45
    class StackEl {
69
  public:
46
    public:
70
      StackEl(const string& nm) : name(nm) {}
47
        StackEl(const string& nm) : name(nm) {}
71
      string name;
48
        string name;
72
      map<string,string> attributes;
49
        map<string,string> attributes;
73
  };
50
        string data;
51
    };
74
52
75
  virtual void StartElement(const XML_Char *name, const XML_Char **attrs)
53
    virtual void StartElement(const XML_Char *name, const XML_Char **attrs)
76
      {
54
    {
77
          //cerr << "startElement: name [" << name << "]" << endl;
55
        //LOGDEB("startElement: name [" << name << "]" << endl);
78
56
79
          m_path.push_back(StackEl(name));
57
        m_path.push_back(StackEl(name));
80
          for (int i = 0; attrs[i] != 0; i += 2) {
58
        for (int i = 0; attrs[i] != 0; i += 2) {
81
              m_path.back().attributes[attrs[i]] = attrs[i+1];
59
            m_path.back().attributes[attrs[i]] = attrs[i+1];
82
          }
60
        }
83
61
84
          switch (name[0]) {
62
        switch (name[0]) {
85
          case 'c':
63
        case 'c':
86
              if (!strcmp(name, "container")) {
64
            if (!strcmp(name, "container")) {
87
                  m_tobj.clear();
65
                m_tobj.clear();
88
                  m_tobj.m_type = UPnPDirObject::container;
66
                m_tobj.m_type = UPnPDirObject::container;
89
                  m_tobj.m_id = m_path.back().attributes["id"];
67
                m_tobj.m_id = m_path.back().attributes["id"];
90
                  m_tobj.m_pid = m_path.back().attributes["parentID"];
68
                m_tobj.m_pid = m_path.back().attributes["parentID"];
91
              }
69
            }
92
              break;
70
            break;
93
          case 'i':
71
        case 'i':
94
              if (!strcmp(name, "item")) {
72
            if (!strcmp(name, "item")) {
95
                  m_tobj.clear();
73
                m_tobj.clear();
96
                  m_tobj.m_type = UPnPDirObject::item;
74
                m_tobj.m_type = UPnPDirObject::item;
97
                  m_tobj.m_id = m_path.back().attributes["id"];
75
                m_tobj.m_id = m_path.back().attributes["id"];
98
                  m_tobj.m_pid = m_path.back().attributes["parentID"];
76
                m_tobj.m_pid = m_path.back().attributes["parentID"];
99
              }
77
            }
100
              break;
78
            break;
101
          default:
79
        default:
102
              break;
80
            break;
103
          }
81
        }
104
      }
82
    }
105
83
106
  virtual bool checkobjok()
84
    virtual bool checkobjok()
107
      {
85
    {
108
          bool ok =  !m_tobj.m_id.empty() && !m_tobj.m_pid.empty() &&
86
        bool ok =  !m_tobj.m_id.empty() && !m_tobj.m_pid.empty() &&
109
              !m_tobj.m_title.empty();
87
            !m_tobj.m_title.empty();
110
88
111
          if (ok && m_tobj.m_type == UPnPDirObject::item) {
89
        if (ok && m_tobj.m_type == UPnPDirObject::item) {
112
              map<string, UPnPDirObject::ItemClass>::const_iterator it;
90
            map<string, UPnPDirObject::ItemClass>::const_iterator it;
113
              it = m_okitems.find(m_tobj.m_props["upnp:class"]);
91
            it = m_okitems.find(m_tobj.m_props["upnp:class"]);
114
              if (it == m_okitems.end()) {
92
            if (it == m_okitems.end()) {
115
                  PLOGINF("checkobjok: found object of unknown class: [%s]\n",
93
                LOGINF("checkobjok: found object of unknown class: [" <<
116
                          m_tobj.m_props["upnp:class"].c_str());
94
                       m_tobj.m_props["upnp:class"] << endl);
117
                  ok = false;
95
                ok = false;
118
              } else {
96
            } else {
119
                  m_tobj.m_iclass = it->second;
97
                m_tobj.m_iclass = it->second;
120
              }
98
            }
121
          }
99
        }
122
100
123
          if (!ok) {
101
        if (!ok) {
124
              PLOGINF("checkobjok: skip: id [%s] pid [%s] clss [%s] tt [%s]\n",
102
            LOGINF("checkobjok:skip: id ["<< m_tobj.m_id<<"] pid ["<<
125
                      m_tobj.m_id.c_str(), m_tobj.m_pid.c_str(),
103
                   m_tobj.m_pid << "] clss [" << m_tobj.m_props["upnp:class"]
126
                      m_tobj.m_props["upnp:class"].c_str(),
104
                   << "] tt [" << m_tobj.m_title << endl);
127
                      m_tobj.m_title.c_str());
105
        }
128
          }
106
        return ok;
129
          return ok;
107
    }
130
      }
131
  virtual void EndElement(const XML_Char *name)
132
      {
133
          if (!strcmp(name, "container")) {
134
              if (checkobjok()) {
135
                  //cerr << "Pushing container: " << m_tobj.m_title << endl;
136
                  m_dir.m_containers.push_back(m_tobj);
137
              }
138
          } else if (!strcmp(name, "item")) {
139
              if (checkobjok()) {
140
                  //cerr << "Pushing item: " << m_tobj.m_title << endl;
141
                  m_dir.m_items.push_back(m_tobj);
142
              }
143
          } else if (!strcmp(name, "res")) {
144
              // <res protocolInfo="http-get:*:audio/mpeg:*" size="5171496"
145
              // bitrate="24576" duration="00:03:35" sampleFrequency="44100"
146
              // nrAudioChannels="2">
147
              string s;
148
              s="protocolInfo";m_tobj.m_props[s] = m_path.back().attributes[s];
149
              s="size";m_tobj.m_props[s] = m_path.back().attributes[s];
150
              s="bitrate";m_tobj.m_props[s] = m_path.back().attributes[s];
151
              s="duration";m_tobj.m_props[s] = m_path.back().attributes[s];
152
              s="sampleFrequency";m_tobj.m_props[s] = m_path.back().attributes[s];
153
              s="nrAudioChannels";m_tobj.m_props[s] = m_path.back().attributes[s];
154
          }
155
108
156
          m_path.pop_back();
109
    virtual void EndElement(const XML_Char *name)
157
      }
110
    {
111
        string parentname;
112
        if (m_path.size() == 1) {
113
            parentname = "root";
114
        } else {
115
            parentname = m_path[m_path.size()-2].name;
116
        }
117
        //LOGDEB("Closing element " << name << " inside element " << 
118
        // parentname << endl);
119
        if (!strcmp(name, "container")) {
120
            if (checkobjok()) {
121
                m_dir.m_containers.push_back(m_tobj);
122
            }
123
        } else if (!strcmp(name, "item")) {
124
            if (checkobjok()) {
125
                m_dir.m_items.push_back(m_tobj);
126
            }
127
        } else if (!parentname.compare("item")) {
128
            switch (name[0]) {
129
            case 'd':
130
                if (!strcmp(name, "dc:title"))
131
                    m_tobj.m_title = m_path.back().data;
132
                break;
133
            case 'r':
134
                if (!strcmp(name, "res")) {
135
                    // <res protocolInfo="http-get:*:audio/mpeg:*" size="517149"
136
                    // bitrate="24576" duration="00:03:35" 
137
                    // sampleFrequency="44100" nrAudioChannels="2">
138
                    UPnPResource res;
139
                    res.m_uri = m_path.back().data;
140
                    for (auto& entry: m_path.back().attributes) {
141
                        res.m_props[entry.first] = entry.second;
142
                    }
143
                    m_tobj.m_resources.push_back(res);
144
                }
145
                break;
146
            default:
147
                m_tobj.m_props[name] = m_path.back().data;
148
                break;
149
            }
158
150
151
        }
152
153
        m_path.pop_back();
154
    }
155
159
  virtual void CharacterData(const XML_Char *s, int len)
156
    virtual void CharacterData(const XML_Char *s, int len)
160
      {
157
    {
161
          if (s == 0 || *s == 0)
158
        if (s == 0 || *s == 0)
162
              return;
159
            return;
163
          string str(s, len);
160
        string str(s, len);
164
          trimstring(str);
161
        trimstring(str);
165
          switch (m_path.back().name[0]) {
162
        m_path.back().data += str;
166
          case 'd':
163
    }
167
              if (!m_path.back().name.compare("dc:title"))
168
                  m_tobj.m_title += str;
169
              break;
170
          case 'r':
171
              if (!m_path.back().name.compare("res")) {
172
                  m_tobj.m_props["url"] += str;
173
              }
174
              break;
175
          case 'u':
176
              for (int i = 0; i < nupnptags; i++) {
177
                  if (!m_path.back().name.compare(upnptags[i])) {
178
                      m_tobj.m_props[upnptags[i]] += str;
179
                  }
180
              }
181
              break;
182
          }
183
      }
184
164
185
private:
165
private:
186
  vector<StackEl> m_path;
166
    vector<StackEl> m_path;
187
  UPnPDirObject m_tobj;
167
    UPnPDirObject m_tobj;
188
  map<string, UPnPDirObject::ItemClass> m_okitems;
168
    map<string, UPnPDirObject::ItemClass> m_okitems;
189
};
169
};
190
170
191
bool UPnPDirContent::parse(const std::string& input)
171
bool UPnPDirContent::parse(const std::string& input)
192
{
172
{
193
  UPnPDirParser parser(*this, input);
173
    UPnPDirParser parser(*this, input);
194
  return parser.Parse();
174
    return parser.Parse();
195
}
175
}
196
/* Local Variables: */
197
/* mode: c++ */
198
/* c-basic-offset: 4 */
199
/* tab-width: 4 */
200
/* indent-tabs-mode: t */
201
/* End: */