minidlna support now Samsung TV C550/C650 (thx amir909)
[tomato.git] / release / src / router / minidlna / upnpdescgen.c
blob4111dab6d6f96c2d0d47d1c5289e62dbf9b2b106
1 /* $Id: upnpdescgen.c,v 1.18 2011/05/02 23:50:52 jmaggard Exp $ */
2 /* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
5 * Copyright (c) 2006-2008, Thomas Bernard
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
34 #include "config.h"
35 #include "getifaddr.h"
36 #include "upnpdescgen.h"
37 #include "minidlnapath.h"
38 #include "upnpglobalvars.h"
39 #include "upnpdescstrings.h"
41 #undef DESC_DEBUG
43 static const char * const upnptypes[] =
45 "string",
46 "boolean",
47 "ui2",
48 "ui4",
49 "i4",
50 "uri",
51 "int",
52 "bin.base64"
55 static const char * const upnpdefaultvalues[] =
58 "Unconfigured"
61 static const char * const upnpallowedvalues[] =
63 0, /* 0 */
64 "DSL", /* 1 */
65 "POTS",
66 "Cable",
67 "Ethernet",
69 "Up", /* 6 */
70 "Down",
71 "Initializing",
72 "Unavailable",
74 "TCP", /* 11 */
75 "UDP",
77 "Unconfigured", /* 14 */
78 "IP_Routed",
79 "IP_Bridged",
81 "Unconfigured", /* 18 */
82 "Connecting",
83 "Connected",
84 "PendingDisconnect",
85 "Disconnecting",
86 "Disconnected",
88 "ERROR_NONE", /* 25 */
90 "OK", /* 27 */
91 "ContentFormatMismatch",
92 "InsufficientBandwidth",
93 "UnreliableChannel",
94 "Unknown",
96 "Input", /* 33 */
97 "Output",
99 "BrowseMetadata", /* 36 */
100 "BrowseDirectChildren",
102 "COMPLETED", /* 39 */
103 "ERROR",
104 "IN_PROGRESS",
105 "STOPPED",
107 RESOURCE_PROTOCOL_INFO_VALUES, /* 44 */
109 "0", /* 46 */
111 "", /* 48 */
115 static const char xmlver[] =
116 "<?xml version=\"1.0\"?>\r\n";
117 static const char root_service[] =
118 "scpd xmlns=\"urn:schemas-upnp-org:service-1-0\"";
119 static const char root_device[] =
120 "root xmlns=\"urn:schemas-upnp-org:device-1-0\""
121 #if PNPX
122 " xmlns:pnpx=\"http://schemas.microsoft.com/windows/pnpx/2005/11\""
123 " xmlns:df=\"http://schemas.microsoft.com/windows/2008/09/devicefoundation\""
124 #endif
127 /* root Description of the UPnP Device */
128 static const struct XMLElt rootDesc[] =
130 {root_device, INITHELPER(1,2)},
131 {"specVersion", INITHELPER(3,2)},
132 {"device", INITHELPER(5,(16+PNPX))},
133 {"/major", "1"},
134 {"/minor", "0"},
135 {"/deviceType", "urn:schemas-upnp-org:device:MediaServer:1"},
136 #if PNPX == 5
137 {"/pnpx:X_hardwareId", pnpx_hwid},
138 {"/pnpx:X_compatibleId", "MS_DigitalMediaDeviceClass_DMS_V001"},
139 {"/pnpx:X_deviceCategory", "MediaDevices"},
140 {"/df:X_deviceCategory", "Multimedia.DMS"},
141 {"/microsoft:magicPacketWakeSupported xmlns:microsoft=\"urn:schemas-microsoft-com:WMPNSS-1-0\"", "0"},
142 #endif
143 {"/friendlyName", friendly_name}, /* required */
144 {"/manufacturer", ROOTDEV_MANUFACTURER}, /* required */
145 {"/manufacturerURL", ROOTDEV_MANUFACTURERURL}, /* optional */
146 {"/modelDescription", ROOTDEV_MODELDESCRIPTION}, /* recommended */
147 {"/modelName", modelname}, /* required */
148 {"/modelNumber", modelnumber},
149 {"/modelURL", ROOTDEV_MODELURL},
150 {"/serialNumber", serialnumber},
151 {"/sec:ProductCap", "smi,DCM10,getMediaInfo.sec,getCaptionInfo.sec"},
152 {"/sec:X_ProductCap", "smi,DCM10,getMediaInfo.sec,getCaptionInfo.sec"},
153 {"/UDN", uuidvalue}, /* required */
154 {"/dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\"", "DMS-1.50"},
155 {"/presentationURL", presentationurl}, /* recommended */
156 {"iconList", INITHELPER((21+PNPX),4)},
157 {"serviceList", INITHELPER((45+PNPX),3)},
158 {"icon", INITHELPER((25+PNPX),5)},
159 {"icon", INITHELPER((30+PNPX),5)},
160 {"icon", INITHELPER((35+PNPX),5)},
161 {"icon", INITHELPER((40+PNPX),5)},
162 {"/mimetype", "image/png"},
163 {"/width", "48"},
164 {"/height", "48"},
165 {"/depth", "24"},
166 {"/url", "/icons/sm.png"},
167 {"/mimetype", "image/png"},
168 {"/width", "120"},
169 {"/height", "120"},
170 {"/depth", "24"},
171 {"/url", "/icons/lrg.png"},
172 {"/mimetype", "image/jpeg"},
173 {"/width", "48"},
174 {"/height", "48"},
175 {"/depth", "24"},
176 {"/url", "/icons/sm.jpg"},
177 {"/mimetype", "image/jpeg"},
178 {"/width", "120"},
179 {"/height", "120"},
180 {"/depth", "24"},
181 {"/url", "/icons/lrg.jpg"},
182 {"service", INITHELPER((48+PNPX),5)},
183 {"service", INITHELPER((53+PNPX),5)},
184 {"service", INITHELPER((58+PNPX),5)},
185 {"/serviceType", "urn:schemas-upnp-org:service:ContentDirectory:1"},
186 {"/serviceId", "urn:upnp-org:serviceId:ContentDirectory"},
187 {"/controlURL", CONTENTDIRECTORY_CONTROLURL},
188 {"/eventSubURL", CONTENTDIRECTORY_EVENTURL},
189 {"/SCPDURL", CONTENTDIRECTORY_PATH},
190 {"/serviceType", "urn:schemas-upnp-org:service:ConnectionManager:1"},
191 {"/serviceId", "urn:upnp-org:serviceId:ConnectionManager"},
192 {"/controlURL", CONNECTIONMGR_CONTROLURL},
193 {"/eventSubURL", CONNECTIONMGR_EVENTURL},
194 {"/SCPDURL", CONNECTIONMGR_PATH},
195 {"/serviceType", "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"},
196 {"/serviceId", "urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar"},
197 {"/controlURL", X_MS_MEDIARECEIVERREGISTRAR_CONTROLURL},
198 {"/eventSubURL", X_MS_MEDIARECEIVERREGISTRAR_EVENTURL},
199 {"/SCPDURL", X_MS_MEDIARECEIVERREGISTRAR_PATH},
200 {0, 0}
203 static const struct argument AddPortMappingArgs[] =
205 {NULL, 1, 11},
206 {NULL, 1, 12},
207 {NULL, 1, 14},
208 {NULL, 1, 13},
209 {NULL, 1, 15},
210 {NULL, 1, 9},
211 {NULL, 1, 16},
212 {NULL, 1, 10},
213 {NULL, 0, 0}
216 static const struct argument DeletePortMappingArgs[] =
218 {NULL, 1, 11},
219 {NULL, 1, 12},
220 {NULL, 1, 14},
221 {NULL, 0, 0}
224 static const struct argument SetConnectionTypeArgs[] =
226 {NULL, 1, 0},
227 {NULL, 0, 0}
230 static const struct argument GetConnectionTypeInfoArgs[] =
232 {NULL, 2, 0},
233 {NULL, 2, 1},
234 {NULL, 0, 0}
237 static const struct argument GetNATRSIPStatusArgs[] =
239 {NULL, 2, 5},
240 {NULL, 2, 6},
241 {NULL, 0, 0}
244 static const struct argument GetGenericPortMappingEntryArgs[] =
246 {NULL, 1, 8},
247 {NULL, 2, 11},
248 {NULL, 2, 12},
249 {NULL, 2, 14},
250 {NULL, 2, 13},
251 {NULL, 2, 15},
252 {NULL, 2, 9},
253 {NULL, 2, 16},
254 {NULL, 2, 10},
255 {NULL, 0, 0}
258 static const struct argument GetSpecificPortMappingEntryArgs[] =
260 {NULL, 1, 11},
261 {NULL, 1, 12},
262 {NULL, 1, 14},
263 {NULL, 2, 13},
264 {NULL, 2, 15},
265 {NULL, 2, 9},
266 {NULL, 2, 16},
267 {NULL, 2, 10},
268 {NULL, 0, 0}
271 /* For ConnectionManager */
272 static const struct argument GetProtocolInfoArgs[] =
274 {"Source", 2, 0},
275 {"Sink", 2, 1},
276 {NULL, 0, 0}
279 static const struct argument PrepareForConnectionArgs[] =
281 {"RemoteProtocolInfo", 1, 6},
282 {"PeerConnectionManager", 1, 4},
283 {"PeerConnectionID", 1, 7},
284 {"Direction", 1, 5},
285 {"ConnectionID", 2, 7},
286 {"AVTransportID", 2, 8},
287 {"RcsID", 2, 9},
288 {NULL, 0, 0}
291 static const struct argument ConnectionCompleteArgs[] =
293 {"ConnectionID", 1, 7},
294 {NULL, 0, 0}
297 static const struct argument GetCurrentConnectionIDsArgs[] =
299 {"ConnectionIDs", 2, 2},
300 {NULL, 0, 0}
303 static const struct argument GetCurrentConnectionInfoArgs[] =
305 {"ConnectionID", 1, 7},
306 {"RcsID", 2, 9},
307 {"AVTransportID", 2, 8},
308 {"ProtocolInfo", 2, 6},
309 {"PeerConnectionManager", 2, 4},
310 {"PeerConnectionID", 2, 7},
311 {"Direction", 2, 5},
312 {"Status", 2, 3},
313 {NULL, 0, 0}
316 static const struct action ConnectionManagerActions[] =
318 {"GetProtocolInfo", GetProtocolInfoArgs}, /* R */
319 //OPTIONAL {"PrepareForConnection", PrepareForConnectionArgs}, /* R */
320 //OPTIONAL {"ConnectionComplete", ConnectionCompleteArgs}, /* R */
321 {"GetCurrentConnectionIDs", GetCurrentConnectionIDsArgs}, /* R */
322 {"GetCurrentConnectionInfo", GetCurrentConnectionInfoArgs}, /* R */
323 {0, 0}
326 static const struct stateVar ConnectionManagerVars[] =
328 {"SourceProtocolInfo", 1<<7, 0, 0, 44}, /* required */
329 {"SinkProtocolInfo", 1<<7, 0, 0, 48}, /* required */
330 {"CurrentConnectionIDs", 1<<7, 0, 0, 46}, /* required */
331 {"A_ARG_TYPE_ConnectionStatus", 0, 0, 27}, /* required */
332 {"A_ARG_TYPE_ConnectionManager", 0, 0}, /* required */
333 {"A_ARG_TYPE_Direction", 0, 0, 33}, /* required */
334 {"A_ARG_TYPE_ProtocolInfo", 0, 0}, /* required */
335 {"A_ARG_TYPE_ConnectionID", 4, 0}, /* required */
336 {"A_ARG_TYPE_AVTransportID", 4, 0}, /* required */
337 {"A_ARG_TYPE_RcsID", 4, 0}, /* required */
338 {0, 0}
341 static const struct argument GetSearchCapabilitiesArgs[] =
343 {"SearchCaps", 2, 10},
344 {0, 0}
347 static const struct argument GetSortCapabilitiesArgs[] =
349 {"SortCaps", 2, 11},
350 {0, 0}
353 static const struct argument GetSystemUpdateIDArgs[] =
355 {"Id", 2, 12},
356 {0, 0}
359 static const struct argument BrowseArgs[] =
361 {"ObjectID", 1, 1},
362 {"BrowseFlag", 1, 4},
363 {"Filter", 1, 5},
364 {"StartingIndex", 1, 7},
365 {"RequestedCount", 1, 8},
366 {"SortCriteria", 1, 6},
367 {"Result", 2, 2},
368 {"NumberReturned", 2, 8},
369 {"TotalMatches", 2, 8},
370 {"UpdateID", 2, 9},
371 {0, 0}
374 static const struct argument SearchArgs[] =
376 {"ContainerID", 1, 1},
377 {"SearchCriteria", 1, 3},
378 {"Filter", 1, 5},
379 {"StartingIndex", 1, 7},
380 {"RequestedCount", 1, 8},
381 {"SortCriteria", 1, 6},
382 {"Result", 2, 2},
383 {"NumberReturned", 2, 8},
384 {"TotalMatches", 2, 8},
385 {"UpdateID", 2, 9},
386 {0, 0}
389 static const struct action ContentDirectoryActions[] =
391 {"GetSearchCapabilities", GetSearchCapabilitiesArgs}, /* R */
392 {"GetSortCapabilities", GetSortCapabilitiesArgs}, /* R */
393 {"GetSystemUpdateID", GetSystemUpdateIDArgs}, /* R */
394 {"Browse", BrowseArgs}, /* R */
395 {"Search", SearchArgs}, /* O */
396 #if 0 // Not implementing optional features yet...
397 {"CreateObject", CreateObjectArgs}, /* O */
398 {"DestroyObject", DestroyObjectArgs}, /* O */
399 {"UpdateObject", UpdateObjectArgs}, /* O */
400 {"ImportResource", ImportResourceArgs}, /* O */
401 {"ExportResource", ExportResourceArgs}, /* O */
402 {"StopTransferResource", StopTransferResourceArgs}, /* O */
403 {"GetTransferProgress", GetTransferProgressArgs}, /* O */
404 {"DeleteResource", DeleteResourceArgs}, /* O */
405 {"CreateReference", CreateReferenceArgs}, /* O */
406 #endif
407 {0, 0}
410 static const struct stateVar ContentDirectoryVars[] =
412 {"TransferIDs", 1<<7, 0, 0, 48}, /* 0 */
413 {"A_ARG_TYPE_ObjectID", 0, 0},
414 {"A_ARG_TYPE_Result", 0, 0},
415 {"A_ARG_TYPE_SearchCriteria", 0, 0},
416 {"A_ARG_TYPE_BrowseFlag", 0, 0, 36},
417 /* Allowed Values : BrowseMetadata / BrowseDirectChildren */
418 {"A_ARG_TYPE_Filter", 0, 0}, /* 5 */
419 {"A_ARG_TYPE_SortCriteria", 0, 0},
420 {"A_ARG_TYPE_Index", 3, 0},
421 {"A_ARG_TYPE_Count", 3, 0},
422 {"A_ARG_TYPE_UpdateID", 3, 0},
423 //JM{"A_ARG_TYPE_TransferID", 3, 0}, /* 10 */
424 //JM{"A_ARG_TYPE_TransferStatus", 0, 0, 39},
425 /* Allowed Values : COMPLETED / ERROR / IN_PROGRESS / STOPPED */
426 //JM{"A_ARG_TYPE_TransferLength", 0, 0},
427 //JM{"A_ARG_TYPE_TransferTotal", 0, 0},
428 //JM{"A_ARG_TYPE_TagValueList", 0, 0},
429 //JM{"A_ARG_TYPE_URI", 5, 0}, /* 15 */
430 {"SearchCapabilities", 0, 0},
431 {"SortCapabilities", 0, 0},
432 {"SystemUpdateID", 3|0x80, 0, 0, 255},
433 //{"ContainerUpdateIDs", 0, 0},
434 {0, 0}
437 static const struct argument GetIsAuthorizedArgs[] =
439 {"DeviceID", 1, 0},
440 {"Result", 2, 3},
441 {NULL, 0, 0}
444 static const struct argument GetIsValidatedArgs[] =
446 {"DeviceID", 1, 0},
447 {"Result", 2, 3},
448 {NULL, 0, 0}
451 static const struct argument GetRegisterDeviceArgs[] =
453 {"RegistrationReqMsg", 1, 1},
454 {"RegistrationRespMsg", 2, 2},
455 {NULL, 0, 0}
458 static const struct action X_MS_MediaReceiverRegistrarActions[] =
460 {"IsAuthorized", GetIsAuthorizedArgs}, /* R */
461 {"IsValidated", GetIsValidatedArgs}, /* R */
462 #if 0 // Not needed? WMP12 still works. Need to check with 360 and WMP11.
463 {"RegisterDevice", GetRegisterDeviceArgs}, /* R */
464 #endif
465 {0, 0}
468 static const struct stateVar X_MS_MediaReceiverRegistrarVars[] =
470 {"A_ARG_TYPE_DeviceID", 0, 0},
471 {"A_ARG_TYPE_RegistrationReqMsg", 7, 0},
472 {"A_ARG_TYPE_RegistrationRespMsg", 7, 0},
473 {"A_ARG_TYPE_Result", 6, 0},
474 {"AuthorizationDeniedUpdateID", 3, 0},
475 {"AuthorizationGrantedUpdateID", 3, 0},
476 {"ValidationRevokedUpdateID", 3, 0},
477 {"ValidationSucceededUpdateID", 3, 0},
478 {0, 0}
481 /* WANCfg.xml */
482 /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
484 static const struct argument GetCommonLinkPropertiesArgs[] =
486 {NULL, 2, 0},
487 {NULL, 2, 1},
488 {NULL, 2, 2},
489 {NULL, 2, 3},
490 {NULL, 0, 0}
493 static const struct argument GetTotalBytesSentArgs[] =
495 {NULL, 2, 4},
496 {NULL, 0, 0}
499 static const struct argument GetTotalBytesReceivedArgs[] =
501 {NULL, 2, 5},
502 {NULL, 0, 0}
505 static const struct argument GetTotalPacketsSentArgs[] =
507 {NULL, 2, 6},
508 {NULL, 0, 0}
511 static const struct argument GetTotalPacketsReceivedArgs[] =
513 {NULL, 2, 7},
514 {NULL, 0, 0}
517 static const struct serviceDesc scpdContentDirectory =
518 { ContentDirectoryActions, ContentDirectoryVars };
520 static const struct serviceDesc scpdConnectionManager =
521 { ConnectionManagerActions, ConnectionManagerVars };
523 static const struct serviceDesc scpdX_MS_MediaReceiverRegistrar =
524 { X_MS_MediaReceiverRegistrarActions, X_MS_MediaReceiverRegistrarVars };
526 /* strcat_str()
527 * concatenate the string and use realloc to increase the
528 * memory buffer if needed. */
529 static char *
530 strcat_str(char * str, int * len, int * tmplen, const char * s2)
532 char *p;
533 int s2len;
534 s2len = (int)strlen(s2);
535 if(*tmplen <= (*len + s2len))
537 if(s2len < 256)
538 *tmplen += 256;
539 else
540 *tmplen += s2len + 1;
541 p = realloc(str, *tmplen);
542 if (!p)
544 if(s2len < 256)
545 *tmplen -= 256;
546 else
547 *tmplen -= s2len + 1;
548 return str;
550 else
551 str = p;
553 /*strcpy(str + *len, s2); */
554 memcpy(str + *len, s2, s2len + 1);
555 *len += s2len;
556 return str;
559 /* strcat_char() :
560 * concatenate a character and use realloc to increase the
561 * size of the memory buffer if needed */
562 static char *
563 strcat_char(char * str, int * len, int * tmplen, char c)
565 char *p;
566 if(*tmplen <= (*len + 1))
568 *tmplen += 256;
569 p = (char *)realloc(str, *tmplen);
570 if (!p)
572 *tmplen -= 256;
573 return str;
575 else
576 str = p;
578 str[*len] = c;
579 (*len)++;
580 return str;
583 /* iterative subroutine using a small stack
584 * This way, the progam stack usage is kept low */
585 static char *
586 genXML(char * str, int * len, int * tmplen,
587 const struct XMLElt * p)
589 u_int16_t i, j, k;
590 int top;
591 const char * eltname, *s;
592 char c;
593 char element[64];
594 struct {
595 unsigned short i;
596 unsigned short j;
597 const char * eltname;
598 } pile[16]; /* stack */
599 top = -1;
600 i = 0; /* current node */
601 j = 1; /* i + number of nodes*/
602 for(;;)
604 eltname = p[i].eltname;
605 if(!eltname)
606 return str;
607 if(eltname[0] == '/')
609 #ifdef DESC_DEBUG
610 printf("DBG: <%s>%s<%s>\n", eltname+1, p[i].data, eltname);
611 #endif
612 str = strcat_char(str, len, tmplen, '<');
613 str = strcat_str(str, len, tmplen, eltname+1);
614 str = strcat_char(str, len, tmplen, '>');
615 str = strcat_str(str, len, tmplen, p[i].data);
616 str = strcat_char(str, len, tmplen, '<');
617 sscanf(eltname, "%s", element);
618 str = strcat_str(str, len, tmplen, element);
619 str = strcat_char(str, len, tmplen, '>');
620 for(;;)
622 if(top < 0)
623 return str;
624 i = ++(pile[top].i);
625 j = pile[top].j;
626 #ifdef DESC_DEBUG
627 printf("DBG: pile[%d]\t%d %d\n", top, i, j);
628 #endif
629 if(i==j)
631 #ifdef DESC_DEBUG
632 printf("DBG: i==j, </%s>\n", pile[top].eltname);
633 #endif
634 str = strcat_char(str, len, tmplen, '<');
635 str = strcat_char(str, len, tmplen, '/');
636 s = pile[top].eltname;
637 for(c = *s; c > ' '; c = *(++s))
638 str = strcat_char(str, len, tmplen, c);
639 str = strcat_char(str, len, tmplen, '>');
640 top--;
642 else
643 break;
646 else
648 #ifdef DESC_DEBUG
649 printf("DBG: [%d] <%s>\n", i, eltname);
650 #endif
651 str = strcat_char(str, len, tmplen, '<');
652 str = strcat_str(str, len, tmplen, eltname);
653 str = strcat_char(str, len, tmplen, '>');
654 k = i;
655 /*i = p[k].index; */
656 /*j = i + p[k].nchild; */
657 i = (unsigned long)p[k].data & 0xffff;
658 j = i + ((unsigned long)p[k].data >> 16);
659 top++;
660 #ifdef DESC_DEBUG
661 printf("DBG: +pile[%d]\t%d %d\n", top, i, j);
662 #endif
663 pile[top].i = i;
664 pile[top].j = j;
665 pile[top].eltname = eltname;
670 /* genRootDesc() :
671 * - Generate the root description of the UPnP device.
672 * - the len argument is used to return the length of
673 * the returned string.
674 * - tmp_uuid argument is used to build the uuid string */
675 char *
676 genRootDesc(int * len)
678 char * str;
679 int tmplen;
680 tmplen = 2048;
681 str = (char *)malloc(tmplen);
682 if(str == NULL)
683 return NULL;
684 * len = strlen(xmlver);
685 /*strcpy(str, xmlver); */
686 memcpy(str, xmlver, *len + 1);
687 str = genXML(str, len, &tmplen, rootDesc);
688 str[*len] = '\0';
689 return str;
692 /* genServiceDesc() :
693 * Generate service description with allowed methods and
694 * related variables. */
695 static char *
696 genServiceDesc(int * len, const struct serviceDesc * s)
698 int i, j;
699 const struct action * acts;
700 const struct stateVar * vars;
701 const struct argument * args;
702 const char * p;
703 char * str;
704 int tmplen;
705 tmplen = 2048;
706 str = (char *)malloc(tmplen);
707 if(str == NULL)
708 return NULL;
709 /*strcpy(str, xmlver); */
710 *len = strlen(xmlver);
711 memcpy(str, xmlver, *len + 1);
713 acts = s->actionList;
714 vars = s->serviceStateTable;
716 str = strcat_char(str, len, &tmplen, '<');
717 str = strcat_str(str, len, &tmplen, root_service);
718 str = strcat_char(str, len, &tmplen, '>');
720 str = strcat_str(str, len, &tmplen,
721 "<specVersion><major>1</major><minor>0</minor></specVersion>");
723 i = 0;
724 str = strcat_str(str, len, &tmplen, "<actionList>");
725 while(acts[i].name)
727 str = strcat_str(str, len, &tmplen, "<action><name>");
728 str = strcat_str(str, len, &tmplen, acts[i].name);
729 str = strcat_str(str, len, &tmplen, "</name>");
730 /* argument List */
731 args = acts[i].args;
732 if(args)
734 str = strcat_str(str, len, &tmplen, "<argumentList>");
735 j = 0;
736 while(args[j].dir)
738 str = strcat_str(str, len, &tmplen, "<argument><name>");
739 p = vars[args[j].relatedVar].name;
740 str = strcat_str(str, len, &tmplen, (args[j].name ? args[j].name : p));
741 str = strcat_str(str, len, &tmplen, "</name><direction>");
742 str = strcat_str(str, len, &tmplen, args[j].dir==1?"in":"out");
743 str = strcat_str(str, len, &tmplen,
744 "</direction><relatedStateVariable>");
745 str = strcat_str(str, len, &tmplen, p);
746 str = strcat_str(str, len, &tmplen,
747 "</relatedStateVariable></argument>");
748 j++;
750 str = strcat_str(str, len, &tmplen,"</argumentList>");
752 str = strcat_str(str, len, &tmplen, "</action>");
753 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
754 i++;
756 str = strcat_str(str, len, &tmplen, "</actionList><serviceStateTable>");
757 i = 0;
758 while(vars[i].name)
760 str = strcat_str(str, len, &tmplen,
761 "<stateVariable sendEvents=\"");
762 str = strcat_str(str, len, &tmplen, (vars[i].itype & 0x80)?"yes":"no");
763 str = strcat_str(str, len, &tmplen, "\"><name>");
764 str = strcat_str(str, len, &tmplen, vars[i].name);
765 str = strcat_str(str, len, &tmplen, "</name><dataType>");
766 str = strcat_str(str, len, &tmplen, upnptypes[vars[i].itype & 0x0f]);
767 str = strcat_str(str, len, &tmplen, "</dataType>");
768 if(vars[i].iallowedlist)
770 str = strcat_str(str, len, &tmplen, "<allowedValueList>");
771 for(j=vars[i].iallowedlist; upnpallowedvalues[j]; j++)
773 str = strcat_str(str, len, &tmplen, "<allowedValue>");
774 str = strcat_str(str, len, &tmplen, upnpallowedvalues[j]);
775 str = strcat_str(str, len, &tmplen, "</allowedValue>");
777 str = strcat_str(str, len, &tmplen, "</allowedValueList>");
779 /*if(vars[i].defaultValue) */
780 if(vars[i].idefault)
782 str = strcat_str(str, len, &tmplen, "<defaultValue>");
783 /*str = strcat_str(str, len, &tmplen, vars[i].defaultValue); */
784 str = strcat_str(str, len, &tmplen, upnpdefaultvalues[vars[i].idefault]);
785 str = strcat_str(str, len, &tmplen, "</defaultValue>");
787 str = strcat_str(str, len, &tmplen, "</stateVariable>");
788 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
789 i++;
791 str = strcat_str(str, len, &tmplen, "</serviceStateTable></scpd>");
792 str[*len] = '\0';
793 return str;
796 /* genContentDirectory() :
797 * Generate the ContentDirectory xml description */
798 char *
799 genContentDirectory(int * len)
801 return genServiceDesc(len, &scpdContentDirectory);
804 /* genConnectionManager() :
805 * Generate the ConnectionManager xml description */
806 char *
807 genConnectionManager(int * len)
809 return genServiceDesc(len, &scpdConnectionManager);
812 /* genX_MS_MediaReceiverRegistrar() :
813 * Generate the X_MS_MediaReceiverRegistrar xml description */
814 char *
815 genX_MS_MediaReceiverRegistrar(int * len)
817 return genServiceDesc(len, &scpdX_MS_MediaReceiverRegistrar);
820 static char *
821 genEventVars(int * len, const struct serviceDesc * s, const char * servns)
823 const struct stateVar * v;
824 char * str;
825 int tmplen;
826 char buf[512];
827 tmplen = 512;
828 str = (char *)malloc(tmplen);
829 if(str == NULL)
830 return NULL;
831 *len = 0;
832 v = s->serviceStateTable;
833 snprintf(buf, sizeof(buf), "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\" xmlns:s=\"%s\">", servns);
834 str = strcat_str(str, len, &tmplen, buf);
835 while(v->name) {
836 if(v->itype & 0x80) {
837 snprintf(buf, sizeof(buf), "<e:property><%s>", v->name);
838 str = strcat_str(str, len, &tmplen, buf);
839 //printf("<e:property><s:%s>", v->name);
840 switch(v->ieventvalue) {
841 case 0:
842 break;
843 case 255: /* Magical values should go around here */
844 if( strcmp(v->name, "SystemUpdateID") == 0 )
846 snprintf(buf, sizeof(buf), "%d", updateID);
847 str = strcat_str(str, len, &tmplen, buf);
849 break;
850 default:
851 str = strcat_str(str, len, &tmplen, upnpallowedvalues[v->ieventvalue]);
852 //printf("%s", upnpallowedvalues[v->ieventvalue]);
854 snprintf(buf, sizeof(buf), "</%s></e:property>", v->name);
855 str = strcat_str(str, len, &tmplen, buf);
856 //printf("</s:%s></e:property>\n", v->name);
858 v++;
860 str = strcat_str(str, len, &tmplen, "</e:propertyset>");
861 //printf("</e:propertyset>\n");
862 //printf("\n");
863 //printf("%d\n", tmplen);
864 str[*len] = '\0';
865 return str;
868 char *
869 getVarsContentDirectory(int * l)
871 return genEventVars(l,
872 &scpdContentDirectory,
873 "urn:schemas-upnp-org:service:ContentDirectory:1");
876 char *
877 getVarsConnectionManager(int * l)
879 return genEventVars(l,
880 &scpdConnectionManager,
881 "urn:schemas-upnp-org:service:ConnectionManager:1");
884 char *
885 getVarsX_MS_MediaReceiverRegistrar(int * l)
887 return genEventVars(l,
888 &scpdX_MS_MediaReceiverRegistrar,
889 "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1");