Switch to unified view

a b/src/protocolinfo.cxx
1
/* Copyright (C) 2016 J.F.Dockes
2
 *   This program is free software; you can redistribute it and/or modify
3
 *   it under the terms of the GNU General Public License as published by
4
 *   the Free Software Foundation; either version 2 of the License, or
5
 *   (at your option) any later version.
6
 *
7
 *   This program is distributed in the hope that it will be useful,
8
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 *   GNU General Public License for more details.
11
 *
12
 *   You should have received a copy of the GNU General Public License
13
 *   along with this program; if not, write to the
14
 *   Free Software Foundation, Inc.,
15
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16
 */
17
#include "protocolinfo.hxx"
18
19
#include "libupnpp/log.hxx"
20
#include "libupnpp/upnpavutils.hxx"
21
22
#include "main.hxx"
23
#include "smallut.h"
24
#include "pathut.h"
25
#include "upmpdutils.hxx"
26
27
#include <string>
28
29
#include <stdlib.h>
30
#include <time.h>
31
#include <sys/stat.h>
32
33
using namespace std;
34
35
class Protocolinfo::Internal {
36
public:
37
    string prototext;
38
    unordered_set<string> supportedformats;
39
    bool ok{false};
40
    time_t mtime{0};
41
    int64_t  sz{0};
42
    
43
    bool maybeUpdate();
44
};
45
46
static Protocolinfo *theProto;
47
48
Protocolinfo *Protocolinfo::the()
49
{
50
    if (theProto == 0)
51
        theProto = new Protocolinfo();
52
    if (theProto && !theProto->ok()) {
53
        delete theProto;
54
        theProto = 0;
55
        return 0;
56
    }
57
    return theProto;
58
}
59
60
Protocolinfo::Protocolinfo()
61
{
62
    m = new Internal();
63
    if (!m) {
64
        LOGFAT("Protocolinfo: out of mem\n");
65
        abort();
66
    }
67
    m->maybeUpdate();
68
}
69
70
bool Protocolinfo::ok()
71
{
72
    return m && m->ok;
73
}
74
75
const string& Protocolinfo::gettext()
76
{
77
    m->maybeUpdate();
78
    return m->prototext;
79
}
80
81
const std::unordered_set<std::string>& Protocolinfo::getsupportedformats()
82
{
83
    m->maybeUpdate();
84
    return m->supportedformats;
85
}
86
87
/** 
88
 * Read protocol info file. This contains the connection manager
89
 * protocol info data
90
 *
91
 * We strip white-space from beginning/ends of lines, and allow
92
 * #-started comments (on a line alone only, comments after data not allowed).
93
 */
94
static bool read_protocolinfo(const string& fn, bool enableL16, string& out)
95
{
96
    LOGDEB1("read_protocolinfo: fn " << fn << "\n");
97
    out.clear();
98
    ifstream input;
99
    input.open(fn, ios::in);
100
    if (!input.is_open()) {
101
        LOGERR("read_protocolinfo: open failed: " << fn << "\n");
102
  return false;
103
    }     
104
    bool eof = false;
105
    for (;;) {
106
        string line;
107
  getline(input, line);
108
  if (!input.good()) {
109
      if (input.bad()) {
110
                LOGERR("read_protocolinfo: read error: " << fn << "\n");
111
      return false;
112
      }
113
      // Must be eof ? But maybe we have a partial line which
114
      // must be processed. This happens if the last line before
115
      // eof ends with a backslash, or there is no final \n
116
            eof = true;
117
  }
118
        trimstring(line, " \t\n\r,");
119
        if (!line.empty()) {
120
            if (enableL16 && line[0] == '@') {
121
                line = regsub1("@ENABLEL16@", line, "");
122
            } else {
123
                line = regsub1("@ENABLEL16@", line, "#");
124
            }
125
            if (line[0] == '#')
126
                continue;
127
128
            out += line + ',';
129
        }
130
        if (eof) 
131
            break;
132
    }
133
    trimstring(out, ",");
134
    LOGDEB0("read_protocolinfo data: [" << out << "]\n");
135
    return true;
136
}
137
138
bool Protocolinfo::Internal::maybeUpdate()
139
{
140
    string protofile(path_cat(g_datadir, "protocolinfo.txt"));
141
    struct stat st;
142
    if (::stat(protofile.c_str(), &st) != 0) {
143
        LOGFAT("protocolinfo: stat() failed for " << protofile << endl);
144
        return ok=false;
145
    }
146
    if (mtime == st.st_mtime && sz == st.st_size) {
147
        return true;
148
    }
149
    if (!read_protocolinfo(protofile, g_enableL16, prototext)) {
150
        LOGFAT("Failed reading protocol info from " << protofile << endl);
151
        return ok=false;
152
    }
153
154
    vector<UPnPP::ProtocolinfoEntry> vpe;
155
    parseProtocolInfo(prototext, vpe);
156
    for (const auto& it : vpe) {
157
        supportedformats.insert(it.contentFormat);
158
    }
159
    mtime = st.st_mtime;
160
    sz = st.st_size;
161
    return ok=true;
162
}
163