Merge branch 'bug_570_playback_skip_fixes_and_cleanup_ml_aholst' into experimental
[vuplus_dvbapp] / main / xmlgenerator.cpp
1 #include <fstream>
2 #include <lib/base/eerror.h>
3 #include "xmlgenerator.h"
4
5 XmlGenerator::XmlGenerator(FILE *f) : m_file(f), m_indent(true), m_level(0)
6 {
7         ::fprintf(m_file, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
8 }
9
10 XmlGenerator::~XmlGenerator()
11 {
12 }
13
14 void XmlGenerator::vprint(const char *fmt, va_list ap, bool newline)
15 {
16         unsigned int i;
17
18         if (m_indent)
19                 for (i = 0; i < m_level; i++)
20                         ::fprintf(m_file, "\t");
21
22         ::vfprintf(m_file, fmt, ap);
23
24         if (newline)
25                 ::fprintf(m_file, "\n");
26 }
27
28 void XmlGenerator::print(const char *fmt, ...)
29 {
30         va_list ap;
31
32         ::va_start(ap, fmt);
33         vprint(fmt, ap, false);
34         ::va_end(ap);
35 }
36
37 void XmlGenerator::printLn(const char *fmt, ...)
38 {
39         va_list ap;
40
41         ::va_start(ap, fmt);
42         vprint(fmt, ap, true);
43         ::va_end(ap);
44 }
45
46 void XmlGenerator::open(const std::string &tag, bool newline)
47 {
48         if (newline) {
49                 printLn("<%s>", tag.c_str());
50         } else {
51                 print("<%s>", tag.c_str());
52                 m_indent = false;
53         }
54
55         m_tags.push(tag);
56         m_level++;
57 }
58
59 void XmlGenerator::open(const std::string &tag)
60 {
61         open(tag, true);
62 }
63
64 void XmlGenerator::close()
65 {
66         ASSERT(!m_tags.empty());
67         ASSERT(m_level > 0);
68         m_level--;
69
70         printLn("</%s>", m_tags.top().c_str());
71         m_indent = true;
72
73         m_tags.pop();
74 }
75
76 void XmlGenerator::comment(const std::string &str)
77 {
78         printLn("<!-- %s -->", str.c_str());
79 }
80
81 void XmlGenerator::commentFromErrno(const std::string &tag)
82 {
83         open(tag);
84         comment(strerror(errno));
85         close();
86 }
87
88 std::string XmlGenerator::cDataEscape(const std::string &str)
89 {
90         const std::string search = "]]>";
91         const std::string replace = "]]]]><![CDATA[>";
92         std::string ret;
93         size_t pos = 0, opos;
94
95         for (;;) {
96                 opos = pos;
97                 pos = str.find(search, opos);
98                 if (pos == std::string::npos)
99                         break;
100                 ret.append(str, opos, pos - opos);
101                 ret.append(replace);
102                 pos += search.size();
103         }
104
105         ret.append(str, opos, std::string::npos);
106         return ret;
107 }
108
109 void XmlGenerator::cDataFromCmd(const std::string &tag, const std::string &cmd)
110 {
111         FILE *pipe = ::popen(cmd.c_str(), "re");
112
113         if (pipe == 0) {
114                 commentFromErrno(tag);
115                 return;
116         }
117
118         std::string result;
119         char *lineptr = NULL;
120         size_t n = 0;
121
122         for (;;) {
123                 ssize_t ret = ::getline(&lineptr, &n, pipe);
124                 if (ret < 0)
125                         break;
126                 result.append(lineptr, ret);
127         }
128
129         if (lineptr)
130                 ::free(lineptr);
131
132         ::pclose(pipe);
133         cDataFromString(tag, result);
134 }
135
136 void XmlGenerator::cDataFromFile(const std::string &tag, const std::string &filename, const char *filter)
137 {
138         std::ifstream in(filename.c_str());
139         std::string line;
140         std::string content;
141
142         if (!in.good()) {
143                 commentFromErrno(tag);
144                 return;
145         }
146
147         while (std::getline(in, line))
148                 if (!filter || !line.find(filter))
149                         content += line + '\n';
150
151         in.close();
152         cDataFromString(tag, content);
153 }
154
155 void XmlGenerator::cDataFromString(const std::string &tag, const std::string &str)
156 {
157         bool indent = false;
158
159         open(tag);
160         printLn("<![CDATA[");
161         std::swap(m_indent, indent);
162         print("%s", cDataEscape(str).c_str());
163         printLn("]]>");
164         std::swap(m_indent, indent);
165         close();
166 }
167
168 void XmlGenerator::string(const std::string &tag, const std::string &str)
169 {
170         open(tag, false);
171         print("%s", str.c_str());
172         close();
173 }
174
175 void XmlGenerator::stringFromFile(const std::string &tag, const std::string &filename)
176 {
177         std::ifstream in(filename.c_str());
178         std::string line;
179
180         if (!in.good()) {
181                 commentFromErrno(tag);
182                 return;
183         }
184
185         std::getline(in, line);
186         in.close();
187         string(tag, line);
188 }