Merge pull request #26220 from 78andyp/blurayfixes
[xbmc.git] / lib / libUPnP / Platinum / Source / Core / PltAction.cpp
blob78ff4b2b9ad6410807293c73dfcece77e04ff228
1 /*****************************************************************
3 | Platinum - Service Action
5 | Copyright (c) 2004-2010, Plutinosoft, LLC.
6 | All rights reserved.
7 | http://www.plutinosoft.com
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.
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 | licensing@plutinosoft.com
22 | This program is distributed in the hope that it will be useful,
23 | but WITHOUT ANY WARRANTY; without even the implied warranty of
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 | GNU General Public License for more details.
27 | You should have received a copy of the GNU General Public License
28 | along with this program; see the file LICENSE.txt. If not, write to
29 | the Free Software Foundation, Inc.,
30 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 | http://www.gnu.org/licenses/gpl-2.0.html
33 ****************************************************************/
35 /*----------------------------------------------------------------------
36 | includes
37 +---------------------------------------------------------------------*/
38 #include "PltAction.h"
39 #include "PltService.h"
40 #include "PltUtilities.h"
42 #define REMOVE_WMP_DATATYPE_EXTENSION
44 NPT_SET_LOCAL_LOGGER("platinum.core.action")
46 /*----------------------------------------------------------------------
47 | PLT_ActionDesc::PLT_ActionDesc
48 +---------------------------------------------------------------------*/
49 PLT_ActionDesc::PLT_ActionDesc(const char* name, PLT_Service* service) :
50 m_Name(name),
51 m_Service(service)
55 /*----------------------------------------------------------------------
56 | PLT_ActionDesc::~PLT_ActionDesc
57 +---------------------------------------------------------------------*/
58 PLT_ActionDesc::~PLT_ActionDesc()
60 m_ArgumentDescs.Apply(NPT_ObjectDeleter<PLT_ArgumentDesc>());
63 /*----------------------------------------------------------------------
64 | PLT_ActionDesc::GetSCPDXML
65 +---------------------------------------------------------------------*/
66 NPT_Result
67 PLT_ActionDesc::GetSCPDXML(NPT_XmlElementNode* node)
69 NPT_XmlElementNode* action = new NPT_XmlElementNode("action");
70 NPT_CHECK_SEVERE(node->AddChild(action));
71 NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(action, "name", m_Name));
73 NPT_XmlElementNode* argumentList = new NPT_XmlElementNode("argumentList");
74 NPT_CHECK_SEVERE(action->AddChild(argumentList));
76 // no arguments is ok
77 if (!m_ArgumentDescs.GetItemCount()) return NPT_SUCCESS;
79 return m_ArgumentDescs.ApplyUntil(
80 PLT_GetSCPDXMLIterator<PLT_ArgumentDesc>(argumentList),
81 NPT_UntilResultNotEquals(NPT_SUCCESS));
84 /*----------------------------------------------------------------------
85 | PLT_ActionDesc::GetService
86 +---------------------------------------------------------------------*/
87 PLT_Service*
88 PLT_ActionDesc::GetService()
90 return m_Service;
93 /*----------------------------------------------------------------------
94 | PLT_ActionDesc::GetArgumentDesc
95 +---------------------------------------------------------------------*/
96 PLT_ArgumentDesc*
97 PLT_ActionDesc::GetArgumentDesc(const char* name)
99 PLT_ArgumentDesc* arg_desc = NULL;
100 NPT_ContainerFind(m_ArgumentDescs, PLT_ArgumentDescNameFinder(name), arg_desc);
101 return arg_desc;
104 /*----------------------------------------------------------------------
105 | PLT_Action::PLT_Action
106 +---------------------------------------------------------------------*/
107 PLT_Action::PLT_Action(PLT_ActionDesc& action_desc) :
108 m_ActionDesc(action_desc),
109 m_ErrorCode(0)
113 /*----------------------------------------------------------------------
114 | PLT_Action::PLT_Action
115 +---------------------------------------------------------------------*/
116 PLT_Action::PLT_Action(PLT_ActionDesc& action_desc,
117 PLT_DeviceDataReference& root_device) :
118 m_ActionDesc(action_desc),
119 m_ErrorCode(0),
120 m_RootDevice(root_device)
124 /*----------------------------------------------------------------------
125 | PLT_Action::~PLT_Action
126 +---------------------------------------------------------------------*/
127 PLT_Action::~PLT_Action()
129 m_Arguments.Apply(NPT_ObjectDeleter<PLT_Argument>());
132 /*----------------------------------------------------------------------
133 | PLT_Action::GetArgumentValue
134 +---------------------------------------------------------------------*/
135 NPT_Result
136 PLT_Action::GetArgumentValue(const char* name, NPT_String& value)
138 PLT_Argument* arg = GetArgument(name);
139 if (arg == NULL) {
140 return NPT_FAILURE;
142 value = arg->GetValue();
143 return NPT_SUCCESS;
146 /*----------------------------------------------------------------------
147 | PLT_Action::GetArgumentValue
148 +---------------------------------------------------------------------*/
149 NPT_Result
150 PLT_Action::GetArgumentValue(const char* name, NPT_UInt32& value)
152 NPT_String tmp_value;
153 NPT_CHECK_WARNING(GetArgumentValue(name, tmp_value));
154 return tmp_value.ToInteger(value);
157 /*----------------------------------------------------------------------
158 | PLT_Action::GetArgumentValue
159 +---------------------------------------------------------------------*/
160 NPT_Result
161 PLT_Action::GetArgumentValue(const char* name, NPT_Int32& value)
163 NPT_String tmp_value;
164 NPT_CHECK_WARNING(GetArgumentValue(name, tmp_value));
165 return tmp_value.ToInteger(value);
168 /*----------------------------------------------------------------------
169 | PLT_Action::GetArgumentValue
170 +---------------------------------------------------------------------*/
171 NPT_Result
172 PLT_Action::GetArgumentValue(const char* name, bool& value)
174 NPT_String tmp_value;
175 NPT_CHECK_WARNING(GetArgumentValue(name, tmp_value));
176 if (tmp_value == "1" ||
177 !tmp_value.Compare("TRUE", true) ||
178 !tmp_value.Compare("YES", true)) {
179 value = true;
180 } else if (tmp_value == "0" ||
181 !tmp_value.Compare("FALSE", true) ||
182 !tmp_value.Compare("NO", true)) {
183 value = false;
184 } else {
185 return NPT_FAILURE;
187 return NPT_SUCCESS;
190 /*----------------------------------------------------------------------
191 | PLT_Action::GetArgument
192 +---------------------------------------------------------------------*/
193 PLT_Argument*
194 PLT_Action::GetArgument(const char* name)
196 PLT_Argument* argument = NULL;
197 NPT_ContainerFind(m_Arguments, PLT_ArgumentNameFinder(name), argument);
198 return argument;
201 /*----------------------------------------------------------------------
202 | PLT_Action::SetArgumentValue
203 +---------------------------------------------------------------------*/
204 NPT_Result
205 PLT_Action::SetArgumentValue(const char* name,
206 const char* value)
208 // look for this argument in our argument list
209 // and replace the value if we found it
210 PLT_Arguments::Iterator iter = NULL;
211 if (NPT_SUCCEEDED(NPT_ContainerFind(m_Arguments, PLT_ArgumentNameFinder(name), iter))) {
212 NPT_Result res = (*iter)->SetValue(value);
214 // remove argument from list if failed
215 // so that when we verify arguments later,
216 // we don't use a previously set value
217 if (NPT_FAILED(res)) m_Arguments.Erase(iter);
218 return res;
221 // since we didn't find it, create a clone
222 PLT_Argument* arg;
223 NPT_CHECK_SEVERE(PLT_Argument::CreateArgument(m_ActionDesc, name, value, arg));
225 // insert it at the right position
226 for (NPT_Cardinal i=0;
227 i<m_Arguments.GetItemCount();
228 i++) {
229 iter = m_Arguments.GetItem(i);
230 if ((*iter)->GetPosition() > arg->GetPosition()) {
231 return m_Arguments.Insert(iter, arg);
235 return m_Arguments.Add(arg);
238 /*----------------------------------------------------------------------
239 | PLT_Action::VerifyArgumentValue
240 +---------------------------------------------------------------------*/
241 NPT_Result
242 PLT_Action::VerifyArgumentValue(const char* name, const char* value)
244 NPT_String str;
245 NPT_CHECK_SEVERE(GetArgumentValue(name, str));
247 return str.Compare(value, true)?NPT_FAILURE:NPT_SUCCESS;
250 /*----------------------------------------------------------------------
251 | PLT_Action::VerifyArguments
252 +---------------------------------------------------------------------*/
253 NPT_Result
254 PLT_Action::VerifyArguments(bool input)
256 NPT_Cardinal count = 0;
258 // Check we have all the required parameters (in or out)
259 for(unsigned int i=0; i<m_ActionDesc.GetArgumentDescs().GetItemCount(); i++) {
260 PLT_ArgumentDesc* arg_desc = m_ActionDesc.GetArgumentDescs()[i];
262 // only input arguments are needed
263 if (arg_desc->GetDirection().Compare(input?"in":"out", true))
264 continue;
266 // look for this argument in the list we received
267 PLT_Argument* arg = NULL;
268 if (NPT_FAILED(NPT_ContainerFind(m_Arguments, PLT_ArgumentNameFinder(arg_desc->GetName()), arg))) {
269 NPT_LOG_WARNING_2("Argument %s for action %s not found",
270 (const char*) arg_desc->GetName(),
271 (const char*) m_ActionDesc.GetName());
272 return NPT_FAILURE;
274 ++count;
277 SetError(0, "");
278 return NPT_SUCCESS;
281 /*----------------------------------------------------------------------
282 | PLT_Action::SetArgumentOutFromStateVariable
283 +---------------------------------------------------------------------*/
284 NPT_Result
285 PLT_Action::SetArgumentOutFromStateVariable(PLT_ArgumentDesc* arg_desc)
287 // only output arguments can use a state variable
288 if (arg_desc->GetDirection().Compare("out", true)) {
289 return NPT_FAILURE;
292 PLT_StateVariable* variable = arg_desc->GetRelatedStateVariable();
293 if (!variable) return NPT_FAILURE;
295 // assign the value to an argument
296 NPT_CHECK_SEVERE(SetArgumentValue(arg_desc->GetName(), variable->GetValue()));
297 return NPT_SUCCESS;
300 /*----------------------------------------------------------------------
301 | PLT_Action::SetArgumentOutFromStateVariable
302 +---------------------------------------------------------------------*/
303 NPT_Result
304 PLT_Action::SetArgumentOutFromStateVariable(const char* name)
306 // look for this argument in the action list of arguments
307 PLT_ArgumentDesc* arg_desc = NULL;
308 NPT_CHECK_SEVERE(NPT_ContainerFind(m_ActionDesc.GetArgumentDescs(),
309 PLT_ArgumentDescNameFinder(name), arg_desc));
311 return SetArgumentOutFromStateVariable(arg_desc);
314 /*----------------------------------------------------------------------
315 | PLT_Action::SetArgumentsOutFromStateVariable
316 +---------------------------------------------------------------------*/
317 NPT_Result
318 PLT_Action::SetArgumentsOutFromStateVariable()
320 // go through the list of the action output arguments
321 for(unsigned int i=0; i<m_ActionDesc.GetArgumentDescs().GetItemCount(); i++) {
322 PLT_ArgumentDesc* arg_desc = m_ActionDesc.GetArgumentDescs()[i];
324 // only output arguments are needed
325 if (arg_desc->GetDirection().Compare("out", true))
326 continue;
328 NPT_CHECK_SEVERE(SetArgumentOutFromStateVariable(arg_desc));
331 return NPT_SUCCESS;
334 /*----------------------------------------------------------------------
335 | PLT_Action::SetError
336 +---------------------------------------------------------------------*/
337 NPT_Result
338 PLT_Action::SetError(unsigned int code, const char* description)
340 m_ErrorCode = code;
341 m_ErrorDescription = description;
342 return NPT_SUCCESS;
345 /*----------------------------------------------------------------------
346 | PLT_Action::GetError
347 +---------------------------------------------------------------------*/
348 const char*
349 PLT_Action::GetError(unsigned int* code /* = NULL */)
351 if (code) *code = m_ErrorCode;
352 return m_ErrorDescription;
355 /*----------------------------------------------------------------------
356 | PLT_Action::GetErrorCode
357 +---------------------------------------------------------------------*/
358 unsigned int
359 PLT_Action::GetErrorCode()
361 return m_ErrorCode;
364 /*----------------------------------------------------------------------
365 | PLT_Action::FormatSoapRequest
366 +---------------------------------------------------------------------*/
367 NPT_Result
368 PLT_Action::FormatSoapRequest(NPT_OutputStream& stream)
370 NPT_String str;
371 NPT_Result res;
372 NPT_XmlElementNode* body = NULL;
373 NPT_XmlElementNode* request = NULL;
374 NPT_XmlElementNode* envelope = new NPT_XmlElementNode("s", "Envelope");
376 NPT_CHECK_LABEL_SEVERE(res = envelope->SetNamespaceUri("s", "http://schemas.xmlsoap.org/soap/envelope/"), cleanup);
377 NPT_CHECK_LABEL_SEVERE(res = envelope->SetAttribute("s", "encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"), cleanup);
379 body = new NPT_XmlElementNode("s", "Body");
380 NPT_CHECK_LABEL_SEVERE(res = envelope->AddChild(body), cleanup);
382 request = new NPT_XmlElementNode("u", m_ActionDesc.GetName());
383 NPT_CHECK_LABEL_SEVERE(res = request->SetNamespaceUri("u", m_ActionDesc.GetService()->GetServiceType()), cleanup);
384 NPT_CHECK_LABEL_SEVERE(res = body->AddChild(request), cleanup);
386 for(unsigned int i=0; i<m_Arguments.GetItemCount(); i++) {
387 PLT_Argument* argument = m_Arguments[i];
388 if (argument->GetDesc().GetDirection().Compare("in", true) == 0) {
389 NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText(
390 request,
391 argument->GetDesc().GetName(),
392 argument->GetValue()), cleanup);
396 NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::Serialize(*envelope, str), cleanup);
397 delete envelope;
399 return stream.Write((const char*)str, str.GetLength());
401 cleanup:
402 delete envelope;
403 return res;
406 /*----------------------------------------------------------------------
407 | PLT_Action::FormatSoapResponse
408 +---------------------------------------------------------------------*/
409 NPT_Result
410 PLT_Action::FormatSoapResponse(NPT_OutputStream& stream)
412 if (m_ErrorCode) {
413 return FormatSoapError(m_ErrorCode, m_ErrorDescription, stream);
416 NPT_String str;
417 NPT_Result res;
418 NPT_XmlElementNode* body = NULL;
419 NPT_XmlElementNode* response = NULL;
420 NPT_XmlElementNode* node = NULL;
421 NPT_XmlElementNode* envelope = new NPT_XmlElementNode("s", "Envelope");
423 NPT_CHECK_LABEL_SEVERE(res = envelope->SetNamespaceUri("s", "http://schemas.xmlsoap.org/soap/envelope/"), cleanup);
424 NPT_CHECK_LABEL_SEVERE(res = envelope->SetAttribute("s", "encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"), cleanup);
426 body = new NPT_XmlElementNode("s", "Body");
427 NPT_CHECK_LABEL_SEVERE(res = envelope->AddChild(body), cleanup);
429 response = new NPT_XmlElementNode("u", m_ActionDesc.GetName() + "Response");
430 NPT_CHECK_LABEL_SEVERE(response->SetNamespaceUri("u", m_ActionDesc.GetService()->GetServiceType()), cleanup);
431 NPT_CHECK_LABEL_SEVERE(res = body->AddChild(response), cleanup);
433 for(unsigned int i=0; i<m_Arguments.GetItemCount(); i++) {
434 PLT_Argument* argument = m_Arguments[i];
435 if (argument->GetDesc().GetDirection().Compare("out", true) == 0) {
436 node = new NPT_XmlElementNode(argument->GetDesc().GetName());
437 NPT_CHECK_LABEL_SEVERE(res = node->AddText(argument->GetValue()), cleanup);
438 NPT_CHECK_LABEL_SEVERE(res = response->AddChild(node), cleanup);
440 #ifndef REMOVE_WMP_DATATYPE_EXTENSION
441 PLT_StateVariable* var = argument->GetDesc().GetRelatedStateVariable();
442 if (var) {
443 node->SetNamespaceUri("dt", "urn:schemas-microsoft-com:datatypes");
444 node->SetAttribute("dt", "dt", var->GetDataType());
446 #endif
450 // this will xmlescape any values that contain xml characters
451 NPT_CHECK_LABEL_SEVERE(PLT_XmlHelper::Serialize(*envelope, str), cleanup);
452 delete envelope;
454 return stream.Write((const char*)str, str.GetLength());
456 cleanup:
457 delete envelope;
458 return res;
461 /*----------------------------------------------------------------------
462 | PLT_Action::FormatSoapError
463 +---------------------------------------------------------------------*/
464 NPT_Result
465 PLT_Action::FormatSoapError(unsigned int code, NPT_String desc, NPT_OutputStream& stream)
467 NPT_String str;
468 NPT_Result res;
469 NPT_XmlElementNode* body = NULL;
470 NPT_XmlElementNode* fault = NULL;
471 NPT_XmlElementNode* detail = NULL;
472 NPT_XmlElementNode* UPnPError = NULL;
473 NPT_XmlElementNode* envelope = new NPT_XmlElementNode("s", "Envelope");
475 NPT_CHECK_LABEL_SEVERE(res = envelope->SetNamespaceUri("s", "http://schemas.xmlsoap.org/soap/envelope/"), cleanup);
476 NPT_CHECK_LABEL_SEVERE(res = envelope->SetAttribute("s", "encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"), cleanup);
478 body = new NPT_XmlElementNode("s", "Body");
479 NPT_CHECK_LABEL_SEVERE(res = envelope->AddChild(body), cleanup);
481 fault = new NPT_XmlElementNode("s", "Fault");
482 NPT_CHECK_LABEL_SEVERE(res = body->AddChild(fault), cleanup);
484 NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText(fault, "faultcode", "s:Client"), cleanup);
485 NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText(fault, "faultstring", "UPnPError"), cleanup);
487 detail = new NPT_XmlElementNode("detail");
488 NPT_CHECK_LABEL_SEVERE(res = fault->AddChild(detail), cleanup);
490 UPnPError = new NPT_XmlElementNode("UPnPError");
491 NPT_CHECK_LABEL_SEVERE(res = UPnPError->SetNamespaceUri("", "urn:schemas-upnp-org:control-1-0"), cleanup);
492 NPT_CHECK_LABEL_SEVERE(res = detail->AddChild(UPnPError), cleanup);
494 NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText(UPnPError, "errorCode", NPT_String::FromInteger(code)), cleanup);
495 NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText(UPnPError, "errorDescription", desc), cleanup);
497 NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::Serialize(*envelope, str), cleanup);
498 delete envelope;
500 return stream.Write((const char*)str, str.GetLength());
502 cleanup:
503 delete envelope;
504 return res;