Mercurial > projects > hoofbaby
comparison deps/Platinum/Source/Devices/MediaServer/PltDidl.cpp @ 0:3425707ddbf6
Initial import (hopefully this mercurial stuff works...)
author | fraserofthenight |
---|---|
date | Mon, 06 Jul 2009 08:06:28 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3425707ddbf6 |
---|---|
1 /***************************************************************** | |
2 | | |
3 | Platinum - DIDL | |
4 | | |
5 | Copyright (c) 2004-2008, Plutinosoft, LLC. | |
6 | All rights reserved. | |
7 | http://www.plutinosoft.com | |
8 | | |
9 | This program is free software; you can redistribute it and/or | |
10 | modify it under the terms of the GNU General Public License | |
11 | as published by the Free Software Foundation; either version 2 | |
12 | of the License, or (at your option) any later version. | |
13 | | |
14 | OEMs, ISVs, VARs and other distributors that combine and | |
15 | distribute commercially licensed software with Platinum software | |
16 | and do not wish to distribute the source code for the commercially | |
17 | licensed software under version 2, or (at your option) any later | |
18 | version, of the GNU General Public License (the "GPL") must enter | |
19 | into a commercial license agreement with Plutinosoft, LLC. | |
20 | | |
21 | This program is distributed in the hope that it will be useful, | |
22 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | GNU General Public License for more details. | |
25 | | |
26 | You should have received a copy of the GNU General Public License | |
27 | along with this program; see the file LICENSE.txt. If not, write to | |
28 | the Free Software Foundation, Inc., | |
29 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
30 | http://www.gnu.org/licenses/gpl-2.0.html | |
31 | | |
32 ****************************************************************/ | |
33 | |
34 /*---------------------------------------------------------------------- | |
35 | includes | |
36 +---------------------------------------------------------------------*/ | |
37 #include "PltDidl.h" | |
38 #include "PltXmlHelper.h" | |
39 #include "PltService.h" | |
40 | |
41 NPT_SET_LOCAL_LOGGER("platinum.media.server.didl") | |
42 | |
43 /*---------------------------------------------------------------------- | |
44 | globals | |
45 +---------------------------------------------------------------------*/ | |
46 const char* didl_header = "<DIDL-Lite xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\"" | |
47 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"" | |
48 " xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\"" | |
49 " xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\">"; | |
50 const char* didl_footer = "</DIDL-Lite>"; | |
51 const char* didl_namespace_dc = "http://purl.org/dc/elements/1.1/"; | |
52 const char* didl_namespace_upnp = "urn:schemas-upnp-org:metadata-1-0/upnp/"; | |
53 const char* didl_namespace_dlna = "urn:schemas-dlna-org:metadata-1-0/"; | |
54 | |
55 /*---------------------------------------------------------------------- | |
56 | PLT_Didl::ConvertFilterToMask | |
57 +---------------------------------------------------------------------*/ | |
58 NPT_UInt32 | |
59 PLT_Didl::ConvertFilterToMask(NPT_String filter) | |
60 { | |
61 // easy out | |
62 if (filter.GetLength() == 0) return PLT_FILTER_MASK_ALL; | |
63 | |
64 // a filter string is a comma delimited set of fields identifying | |
65 // a given DIDL property (or set of properties). | |
66 // These fields are or start with: upnp:, @, res@, res, dc:, container@ | |
67 | |
68 NPT_UInt32 mask = 0; | |
69 const char* s = filter; | |
70 int i = 0; | |
71 | |
72 while (s[i] != '\0') { | |
73 int next_comma = filter.Find(',', i); | |
74 int len = ((next_comma < 0)?filter.GetLength():next_comma)-i; | |
75 | |
76 if (NPT_String::CompareN(s+i, "*", 1) == 0) { | |
77 // return now, there's no point in parsing the rest | |
78 return PLT_FILTER_MASK_ALL; | |
79 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CREATOR, len) == 0) { | |
80 mask |= PLT_FILTER_MASK_CREATOR; | |
81 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ARTIST, len) == 0) { | |
82 mask |= PLT_FILTER_MASK_ARTIST; | |
83 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ACTOR, len) == 0) { | |
84 mask |= PLT_FILTER_MASK_ACTOR; | |
85 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_AUTHOR, len) == 0) { | |
86 mask |= PLT_FILTER_MASK_AUTHOR; | |
87 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_DATE, len) == 0) { | |
88 mask |= PLT_FILTER_MASK_DATE; | |
89 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ALBUM, len) == 0) { | |
90 mask |= PLT_FILTER_MASK_ALBUM; | |
91 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_GENRE, len) == 0) { | |
92 mask |= PLT_FILTER_MASK_GENRE; | |
93 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ALBUMARTURI, len) == 0) { | |
94 mask |= PLT_FILTER_MASK_ALBUMARTURI; | |
95 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_DESCRIPTION, len) == 0) { | |
96 mask |= PLT_FILTER_MASK_DESCRIPTION; | |
97 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ORIGINALTRACK, len) == 0) { | |
98 mask |= PLT_FILTER_MASK_ORIGINALTRACK; | |
99 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_SEARCHABLE, len) == 0) { | |
100 mask |= PLT_FILTER_MASK_SEARCHABLE; | |
101 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CONTAINER_SEARCHABLE, len) == 0) { | |
102 mask |= PLT_FILTER_MASK_SEARCHABLE; | |
103 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CHILDCOUNT, len) == 0) { | |
104 mask |= PLT_FILTER_MASK_CHILDCOUNT; | |
105 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CONTAINER_CHILDCOUNT, len) == 0) { | |
106 mask |= PLT_FILTER_MASK_CHILDCOUNT; | |
107 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_DURATION, len) == 0) { | |
108 mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_DURATION; | |
109 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_SIZE, len) == 0) { | |
110 mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_SIZE; | |
111 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_PROTECTION, len) == 0) { | |
112 mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_PROTECTION; | |
113 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_RESOLUTION, len) == 0) { | |
114 mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_RESOLUTION; | |
115 } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES, len) == 0) { | |
116 mask |= PLT_FILTER_MASK_RES; | |
117 } | |
118 | |
119 if (next_comma < 0) { | |
120 return mask; | |
121 } | |
122 | |
123 i = next_comma + 1; | |
124 } | |
125 | |
126 return mask; | |
127 } | |
128 | |
129 /*---------------------------------------------------------------------- | |
130 | PLT_Didl::AppendXmlUnEscape | |
131 +---------------------------------------------------------------------*/ | |
132 void | |
133 PLT_Didl::AppendXmlUnEscape(NPT_String& out, NPT_String& in) | |
134 { | |
135 const char* input = (const char*) in; | |
136 unsigned int i=0; | |
137 while (i<in.GetLength()) { | |
138 if (NPT_String::CompareN(input+i, "<", 4) == 0) { | |
139 out += '<'; | |
140 i +=4; | |
141 } else if (NPT_String::CompareN(input+i, ">", 4) == 0) { | |
142 out += '>'; | |
143 i += 4; | |
144 } else if (NPT_String::CompareN(input+i, "&", 5) == 0) { | |
145 out += '&'; | |
146 i += 5; | |
147 } else if (NPT_String::CompareN(input+i, """, 6) == 0) { | |
148 out += '"'; | |
149 i += 6; | |
150 } else if (NPT_String::CompareN(input+i, "'", 6) == 0) { | |
151 out += '\''; | |
152 i += 6; | |
153 } else { | |
154 out += *(input+i); | |
155 i++; | |
156 } | |
157 } | |
158 } | |
159 | |
160 /*---------------------------------------------------------------------- | |
161 | PLT_Didl::AppendXmlEscape | |
162 +---------------------------------------------------------------------*/ | |
163 void | |
164 PLT_Didl::AppendXmlEscape(NPT_String& out, NPT_String& in) | |
165 { | |
166 for (int i=0; i<(int)in.GetLength(); i++) { | |
167 if (in[i] == '<') { | |
168 out += "<"; | |
169 } else if (in[i] == '>') { | |
170 out += ">"; | |
171 } else if (in[i] == '&') { | |
172 out += "&"; | |
173 } else if (in[i] == '"') { | |
174 out += """; | |
175 } else if (in[i] == '\'') { | |
176 out += "'"; | |
177 } else { | |
178 out += in[i]; | |
179 } | |
180 } | |
181 } | |
182 | |
183 /*---------------------------------------------------------------------- | |
184 | PLT_Didl::FormatTimeStamp | |
185 +---------------------------------------------------------------------*/ | |
186 void | |
187 PLT_Didl::FormatTimeStamp(NPT_String& out, NPT_UInt32 seconds) | |
188 { | |
189 int hours = seconds/3600; | |
190 if (hours == 0) { | |
191 out += "00:"; | |
192 } else { | |
193 if (hours < 10) { | |
194 out += '0'; | |
195 } | |
196 out += NPT_String::FromInteger(hours) + ":"; | |
197 } | |
198 | |
199 int minutes = (seconds/60)%60; | |
200 if (minutes == 0) { | |
201 out += "00:"; | |
202 } else { | |
203 if (minutes < 10) { | |
204 out += '0'; | |
205 } | |
206 out += NPT_String::FromInteger(minutes) + ":"; | |
207 } | |
208 | |
209 int secs = seconds%60; | |
210 if (secs == 0) { | |
211 out += "00"; | |
212 } else { | |
213 if (secs < 10) { | |
214 out += '0'; | |
215 } | |
216 out += NPT_String::FromInteger(secs); | |
217 } | |
218 | |
219 out += ".000"; | |
220 } | |
221 | |
222 /*---------------------------------------------------------------------- | |
223 | PLT_Didl::ParseTimeStamp | |
224 +---------------------------------------------------------------------*/ | |
225 NPT_Result | |
226 PLT_Didl::ParseTimeStamp(NPT_String timestamp, NPT_UInt32& seconds) | |
227 { | |
228 // assume a timestamp in the format HH:MM:SS | |
229 int colon; | |
230 NPT_String str = timestamp; | |
231 NPT_UInt32 num; | |
232 | |
233 // extract millisecondsfirst | |
234 if ((colon = timestamp.ReverseFind('.')) != -1) { | |
235 str = timestamp.SubString(colon + 1); | |
236 timestamp = timestamp.Left(colon); | |
237 } | |
238 | |
239 // extract seconds first | |
240 str = timestamp; | |
241 if ((colon = timestamp.ReverseFind(':')) != -1) { | |
242 str = timestamp.SubString(colon + 1); | |
243 timestamp = timestamp.Left(colon); | |
244 } | |
245 | |
246 if (NPT_FAILED(str.ToInteger(num))) { | |
247 return NPT_FAILURE; | |
248 } | |
249 | |
250 seconds = num; | |
251 | |
252 // extract minutes | |
253 str = timestamp; | |
254 if (timestamp.GetLength()) { | |
255 if ((colon = timestamp.ReverseFind(':')) != -1) { | |
256 str = timestamp.SubString(colon + 1); | |
257 timestamp = timestamp.Left(colon); | |
258 } | |
259 | |
260 if (NPT_FAILED(str.ToInteger(num))) { | |
261 return NPT_FAILURE; | |
262 } | |
263 | |
264 seconds += 60*num; | |
265 } | |
266 | |
267 // extract hours | |
268 str = timestamp; | |
269 if (timestamp.GetLength()) { | |
270 if ((colon = timestamp.ReverseFind(':')) != -1) { | |
271 str = timestamp.SubString(colon + 1); | |
272 timestamp = timestamp.Left(colon); | |
273 } | |
274 | |
275 if (NPT_FAILED(str.ToInteger(num))) { | |
276 return NPT_FAILURE; | |
277 } | |
278 | |
279 seconds += 3600*num; | |
280 } | |
281 | |
282 return NPT_SUCCESS; | |
283 } | |
284 | |
285 /*---------------------------------------------------------------------- | |
286 | PLT_Didl::ToDidl | |
287 +---------------------------------------------------------------------*/ | |
288 NPT_Result | |
289 PLT_Didl::ToDidl(PLT_MediaObject& object, NPT_String filter, NPT_String& didl) | |
290 { | |
291 NPT_UInt32 mask = ConvertFilterToMask(filter); | |
292 | |
293 // Allocate enough space for the didl | |
294 didl.Reserve(2048); | |
295 | |
296 return object.ToDidl(mask, didl); | |
297 } | |
298 | |
299 /*---------------------------------------------------------------------- | |
300 | PLT_Didl::FromDidl | |
301 +---------------------------------------------------------------------*/ | |
302 NPT_Result | |
303 PLT_Didl::FromDidl(const char* xml, PLT_MediaObjectListReference& objects) | |
304 { | |
305 NPT_String str; | |
306 PLT_MediaObject* object = NULL; | |
307 NPT_XmlNode* node = NULL; | |
308 NPT_XmlElementNode* didl = NULL; | |
309 | |
310 NPT_LOG_FINE("Parsing Didl..."); | |
311 | |
312 NPT_XmlParser parser; | |
313 if (NPT_FAILED(parser.Parse(xml, node)) || !node || !node->AsElementNode()) { | |
314 goto cleanup; | |
315 } | |
316 | |
317 didl = node->AsElementNode(); | |
318 | |
319 NPT_LOG_FINE("Processing Didl xml..."); | |
320 if (didl->GetTag().Compare("DIDL-Lite", true)) { | |
321 goto cleanup; | |
322 } | |
323 | |
324 // create entry list | |
325 objects = new PLT_MediaObjectList(); | |
326 | |
327 // for each child, find out if it's a container or not | |
328 // and then invoke the FromDidl on it | |
329 for (NPT_List<NPT_XmlNode*>::Iterator children = didl->GetChildren().GetFirstItem(); children; children++) { | |
330 NPT_XmlElementNode* child = (*children)->AsElementNode(); | |
331 if (!child) continue; | |
332 | |
333 if (child->GetTag().Compare("Container", true) == 0) { | |
334 object = new PLT_MediaContainer(); | |
335 } else if (child->GetTag().Compare("item", true) == 0) { | |
336 object = new PLT_MediaItem(); | |
337 } else { | |
338 goto cleanup; | |
339 } | |
340 | |
341 if (NPT_FAILED(object->FromDidl(child))) { | |
342 goto cleanup; | |
343 } | |
344 objects->Add(object); | |
345 } | |
346 | |
347 delete node; | |
348 return NPT_SUCCESS; | |
349 | |
350 cleanup: | |
351 objects = NULL; | |
352 delete node; | |
353 delete object; | |
354 return NPT_FAILURE; | |
355 } |