Arduino DLNA Server
Loading...
Searching...
No Matches
XMLAttributeParser.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstring>
4#include "basic/Str.h"
5
6namespace tiny_dlna {
7
18 public:
41 static bool extractAttribute(const char* xml, const char* tagName,
42 const char* attrName, char* outBuf,
43 size_t bufSize) {
44 if (!xml || !tagName || !attrName || !outBuf || bufSize == 0) return false;
45 const char* p = strstr(xml, tagName);
46 while (p) {
47 const char* tagEnd = strchr(p, '>');
48 if (!tagEnd) return false;
49 const char* attrPos = strstr(p, attrName);
50 if (attrPos && attrPos < tagEnd) {
51 // delegate actual quoted-value extraction to helper
52 return extractQuotedValue(attrPos, tagEnd, outBuf, bufSize);
53 }
54 p = strstr(p + 1, tagName);
55 }
56 return false;
57 }
58
75 static bool extractAttribute(const char* attrs, const char* attrName,
76 char* outBuf, size_t bufSize) {
77 if (!attrs || !attrName || !outBuf || bufSize == 0) return false;
78 const char* attrPos = strstr(attrs, attrName);
79 if (!attrPos) return false;
80 // No explicit boundary for attributes-only strings
81 return extractQuotedValue(attrPos, nullptr, outBuf, bufSize);
82 }
83
84 // Helper: given a pointer somewhere at/after the attribute name, find the
85 // next double-quoted value and copy it to outBuf. If `boundary` is non-null
86 // the quotes must be before or equal to boundary.
87 static bool extractQuotedValue(const char* attrPos, const char* boundary,
88 char* outBuf, size_t bufSize) {
89 if (!attrPos || !outBuf || bufSize == 0) return false;
90 memset(outBuf, 0, bufSize);
91 const char* q = strchr(attrPos, '"');
92 if (!q) return false;
93 if (boundary && q > boundary) return false;
94 q++;
95 const char* qend = strchr(q, '"');
96 if (!qend) return false;
97 if (boundary && qend > boundary) return false;
98 size_t vlen = (size_t)(qend - q);
99 size_t copyLen = vlen < (bufSize - 1) ? vlen : (bufSize - 1);
100 if (copyLen > 0) memcpy(outBuf, q, copyLen);
101 outBuf[copyLen] = '\0';
102 return copyLen > 0;
103 }
104
132 static bool extractAttributeToken(const char* xml, const char* tagName,
133 const char* attrName, int n,
134 char* outBuf, size_t bufSize) {
135 if (!xml || !tagName || !attrName || n <= 0 || !outBuf || bufSize == 0) return false;
136 char proto[256] = {0};
137 bool ok = extractAttribute(xml, tagName, attrName, proto, sizeof(proto));
138 if (!ok || proto[0] == '\0') return false;
139 // proto format: token1:token2:token3:token4
140 int col = 1;
141 const char* tokenStart = proto;
142 if (n > 1) {
143 for (size_t i = 0; proto[i] != '\0'; ++i) {
144 if (proto[i] == ':') {
145 ++col;
146 if (col == n) {
147 tokenStart = proto + i + 1;
148 break;
149 }
150 }
151 }
152 }
153 if (!tokenStart || *tokenStart == '\0') return false;
154 // copy token into outBuf until ':' or end
155 size_t j = 0;
156 for (; tokenStart[j] != '\0' && tokenStart[j] != ':' && j + 1 < bufSize; ++j) outBuf[j] = tokenStart[j];
157 outBuf[j] = '\0';
158 return outBuf[0] != '\0';
159 }
160
173 static bool extractElementText(const char* xml, const char* elementName,
174 Str& out) {
175 out.clear();
176 if (!xml || !elementName || !*elementName) return false;
177 size_t nameLen = strlen(elementName);
178 const char* p = strchr(xml, '<');
179 while (p) {
180 // match "<name" followed by '>', '/' or whitespace
181 if (strncmp(p + 1, elementName, nameLen) == 0) {
182 char next = p[1 + nameLen];
183 if (next == '>' || next == ' ' || next == '\t' || next == '\r' ||
184 next == '\n') {
185 const char* tagEnd = strchr(p, '>');
186 if (!tagEnd) return false;
187 // self-closing element: <name/>
188 if (tagEnd[-1] == '/') return false;
189 const char* textStart = tagEnd + 1;
190 const char* textEnd = strchr(textStart, '<');
191 if (!textEnd) return false;
192 out.copyFrom(textStart, (int)(textEnd - textStart));
193 unEscape(out);
194 return !out.isEmpty();
195 }
196 }
197 p = strchr(p + 1, '<');
198 }
199 return false;
200 }
201
203 static void unEscape(Str& str) {
204 str.replaceAll("&lt;", "<");
205 str.replaceAll("&gt;", ">");
206 str.replaceAll("&quot;", "\"");
207 str.replaceAll("&apos;", "'");
208 // must be last so that e.g. "&amp;lt;" becomes "&lt;" and not "<"
209 str.replaceAll("&amp;", "&");
210 }
211};
212
213} // namespace tiny_dlna
Heap-backed string utility used throughout tiny_dlna.
Definition: Str.h:27
bool isEmpty() const
True if empty.
Definition: Str.h:54
void copyFrom(const char *source, int len)
Copy from raw buffer with length.
Definition: Str.h:60
int replaceAll(const char *toReplace, const char *replaced)
Replace all occurrences of toReplace with replaced; returns count.
Definition: Str.h:279
void clear()
Clear contents (size -> 0)
Definition: Str.h:93
Small utility to extract attributes from a start-tag in an XML fragment.
Definition: XMLAttributeParser.h:17
static bool extractQuotedValue(const char *attrPos, const char *boundary, char *outBuf, size_t bufSize)
Definition: XMLAttributeParser.h:87
static bool extractAttribute(const char *attrs, const char *attrName, char *outBuf, size_t bufSize)
Extract an attribute value directly from an attributes string.
Definition: XMLAttributeParser.h:75
static bool extractAttributeToken(const char *xml, const char *tagName, const char *attrName, int n, char *outBuf, size_t bufSize)
Extract the nth (1-based) colon-separated token from an attribute value located on the first occurren...
Definition: XMLAttributeParser.h:132
static void unEscape(Str &str)
Expands the predefined XML entities (< > " ' &)
Definition: XMLAttributeParser.h:203
static bool extractElementText(const char *xml, const char *elementName, Str &out)
Extract the (unescaped) text content of the first element with the given name.
Definition: XMLAttributeParser.h:173
static bool extractAttribute(const char *xml, const char *tagName, const char *attrName, char *outBuf, size_t bufSize)
Find the first occurrence of a start-tag and extract an attribute value.
Definition: XMLAttributeParser.h:41
Definition: Allocator.h:13