tsdp_parser_header_M.rl 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. /*
  2. * Copyright (C) 2010-2015 Mamadou Diop.
  3. *
  4. * This file is part of Open Source Doubango Framework.
  5. *
  6. * DOUBANGO is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * DOUBANGO is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with DOUBANGO.
  18. *
  19. */
  20. /**@file tsdp_header_M.c
  21. * @brief SDP "m=" header (Media Descriptions).
  22. *
  23. */
  24. #include "tinysdp/headers/tsdp_header_M.h"
  25. #include "tsk_debug.h"
  26. #include "tsk_memory.h"
  27. #include "tsk_string.h"
  28. #include <string.h>
  29. /***********************************
  30. * Ragel state machine.
  31. */
  32. %%{
  33. machine tsdp_machine_parser_header_M;
  34. # Includes
  35. include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl";
  36. action tag{
  37. tag_start = p;
  38. }
  39. action parse_media{
  40. TSK_PARSER_SET_STRING(hdr_M->media);
  41. }
  42. action parse_port{
  43. TSK_PARSER_SET_UINT(hdr_M->port);
  44. }
  45. action parse_nports{
  46. TSK_PARSER_SET_UINT(hdr_M->nports);
  47. }
  48. action parse_proto{
  49. TSK_PARSER_SET_STRING(hdr_M->proto);
  50. }
  51. action parse_fmt{
  52. TSK_PARSER_ADD_STRING(hdr_M->FMTs);
  53. }
  54. media = token>tag %parse_media;
  55. port = DIGIT+>tag %parse_port;
  56. nports = DIGIT+>tag %parse_port;
  57. proto = (token ("/" token)*)>tag %parse_proto;
  58. fmt = token>tag %parse_fmt;
  59. #// media SP port ["/" integer] SP proto 1*(SP fmt)
  60. M = 'm' SP* "=" SP*<: media SP port ("/" nports)? SP proto (SP fmt)* (SP{1})?; # The last SP is for buggy browsers (e.g. Nightly 20.0a1 => "m=application 51713 SCTP/DTLS 5000 \r\n")
  61. # Entry point
  62. main := M :>CRLF?;
  63. }%%
  64. tsdp_header_M_t* tsdp_header_M_create(const char* media, uint32_t port, const char* proto)
  65. {
  66. return tsk_object_new(TSDP_HEADER_M_VA_ARGS(media, port, proto));
  67. }
  68. tsdp_header_M_t* tsdp_header_M_create_null()
  69. {
  70. return tsdp_header_M_create(tsk_null, 0, tsk_null);
  71. }
  72. tsdp_fmt_t* tsdp_fmt_create(const char* fmt)
  73. {
  74. return tsk_object_new(TSDP_FMT_VA_ARGS(fmt));
  75. }
  76. int tsdp_header_M_tostring(const tsdp_header_t* header, tsk_buffer_t* output)
  77. {
  78. if(header){
  79. const tsdp_header_M_t *M = (const tsdp_header_M_t *)header;
  80. const tsk_list_item_t* item;
  81. tsk_istr_t nports;
  82. tsk_itoa(M->nports, &nports);
  83. /* IMPORTANT: Keep the order.
  84. m= (media name and transport address)
  85. i=* (media title)
  86. c=* (connection information -- optional if included at
  87. session level)
  88. b=* (zero or more bandwidth information lines)
  89. k=* (encryption key)
  90. a=* (zero or more media attribute lines)
  91. */
  92. tsk_buffer_append_2(output, "%s %u%s%s %s",
  93. M->media,
  94. M->port,
  95. M->nports ? "/" : "",
  96. M->nports ? nports : "",
  97. M->proto
  98. );
  99. // FMTs
  100. tsk_list_foreach(item, M->FMTs){
  101. tsk_buffer_append_2(output, " %s", TSDP_FMT_STR(item->data));
  102. }
  103. tsk_buffer_append(output, "\r\n", 2); // close the "m=" line.
  104. // i=* (media title)
  105. if(M->I){
  106. tsdp_header_serialize(TSDP_HEADER(M->I), output);
  107. }
  108. // c=* (connection information -- optional if included at session level)
  109. if(M->C){
  110. tsdp_header_serialize(TSDP_HEADER(M->C), output);
  111. }
  112. // b=* (zero or more bandwidth information lines)
  113. if(M->Bandwidths){
  114. tsk_list_foreach(item, M->Bandwidths){
  115. tsdp_header_serialize(TSDP_HEADER(item->data), output);
  116. }
  117. }
  118. // k=* (encryption key)
  119. if(M->K){
  120. tsdp_header_serialize(TSDP_HEADER(M->K), output);
  121. }
  122. // a=* (zero or more media attribute lines)
  123. if(M->Attributes){
  124. tsk_list_foreach(item, M->Attributes){
  125. tsdp_header_serialize(TSDP_HEADER(item->data), output);
  126. }
  127. }
  128. return 0;
  129. }
  130. return -1;
  131. }
  132. tsdp_header_t* tsdp_header_M_clone(const tsdp_header_t* header)
  133. {
  134. if(header){
  135. const tsdp_header_M_t *M = (const tsdp_header_M_t *)header;
  136. tsdp_header_M_t* clone;
  137. const tsk_list_item_t* item;
  138. if((clone = tsdp_header_M_create(M->media, M->port, M->proto))){
  139. clone->nports = M->nports;
  140. // Formats
  141. tsk_list_foreach(item, M->FMTs){
  142. tsk_string_t* string = tsk_string_create(TSK_STRING_STR(item->data));
  143. tsk_list_push_back_data(clone->FMTs, (void**)&string);
  144. }
  145. // I
  146. clone->I = (tsdp_header_I_t*) (M->I ? TSDP_HEADER(M->I)->clone(TSDP_HEADER(M->I)) : tsk_null);
  147. // C
  148. clone->C = (tsdp_header_C_t*) (M->C ? TSDP_HEADER(M->C)->clone(TSDP_HEADER(M->C)) : tsk_null);
  149. // Bandwidths
  150. tsk_list_foreach(item, M->Bandwidths){
  151. tsdp_header_t* B;
  152. if(!clone->Bandwidths){
  153. clone->Bandwidths = tsk_list_create();
  154. }
  155. B = ((tsdp_header_t*)item->data)->clone((tsdp_header_t*)item->data);
  156. tsk_list_push_back_data(clone->Bandwidths, (void**)&B);
  157. }
  158. // K
  159. clone->K = (tsdp_header_K_t*) (M->K ? TSDP_HEADER(M->K)->clone(TSDP_HEADER(M->K)) : tsk_null);
  160. // Attributes
  161. tsk_list_foreach(item, M->Attributes){
  162. tsdp_header_t* A;
  163. if(!clone->Attributes){
  164. clone->Attributes = tsk_list_create();
  165. }
  166. A = ((tsdp_header_t*)item->data)->clone((tsdp_header_t*)item->data);
  167. tsk_list_push_back_data(clone->Attributes, (void**)&A);
  168. }
  169. }
  170. return TSDP_HEADER(clone);
  171. }
  172. return tsk_null;
  173. }
  174. tsdp_header_M_t *tsdp_header_M_parse(const char *data, tsk_size_t size)
  175. {
  176. int cs = 0;
  177. const char *p = data;
  178. const char *pe = p + size;
  179. const char *eof = pe;
  180. tsdp_header_M_t *hdr_M = tsdp_header_M_create_null();
  181. const char *tag_start = tsk_null;
  182. TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
  183. %%write data;
  184. (void)(tsdp_machine_parser_header_M_first_final);
  185. (void)(tsdp_machine_parser_header_M_error);
  186. (void)(tsdp_machine_parser_header_M_en_main);
  187. %%write init;
  188. %%write exec;
  189. TSK_RAGEL_DISABLE_WARNINGS_END()
  190. if( cs < %%{ write first_final; }%% ){
  191. TSK_DEBUG_ERROR("Failed to parse \"m=\" header.");
  192. TSK_OBJECT_SAFE_FREE(hdr_M);
  193. }
  194. return hdr_M;
  195. }
  196. // for A headers, use "tsdp_header_A_removeAll_by_field()"
  197. int tsdp_header_M_remove(tsdp_header_M_t* self, tsdp_header_type_t type)
  198. {
  199. switch(type){
  200. case tsdp_htype_I:
  201. {
  202. TSK_OBJECT_SAFE_FREE(self->I);
  203. break;
  204. }
  205. case tsdp_htype_C:
  206. {
  207. TSK_OBJECT_SAFE_FREE(self->C);
  208. break;
  209. }
  210. case tsdp_htype_B:
  211. {
  212. if(self->Bandwidths){
  213. tsk_list_clear_items(self->Bandwidths);
  214. }
  215. break;
  216. }
  217. case tsdp_htype_K:
  218. {
  219. TSK_OBJECT_SAFE_FREE(self->K);
  220. break;
  221. }
  222. }
  223. return 0;
  224. }
  225. int tsdp_header_M_add(tsdp_header_M_t* self, const tsdp_header_t* header)
  226. {
  227. if(!self || !header){
  228. return -1;
  229. }
  230. switch(header->type){
  231. case tsdp_htype_I:
  232. {
  233. TSK_OBJECT_SAFE_FREE(self->I);
  234. self->I = tsk_object_ref((void*)header);
  235. break;
  236. }
  237. case tsdp_htype_C:
  238. {
  239. TSK_OBJECT_SAFE_FREE(self->C);
  240. self->C = tsk_object_ref((void*)header);
  241. break;
  242. }
  243. case tsdp_htype_B:
  244. {
  245. tsdp_header_t* B = tsk_object_ref((void*)header);
  246. if(!self->Bandwidths){
  247. self->Bandwidths = tsk_list_create();
  248. }
  249. tsk_list_push_back_data(self->Bandwidths, (void**)&B);
  250. break;
  251. }
  252. case tsdp_htype_K:
  253. {
  254. TSK_OBJECT_SAFE_FREE(self->K);
  255. self->K = tsk_object_ref((void*)header);
  256. break;
  257. }
  258. case tsdp_htype_A:
  259. {
  260. tsdp_header_t* A = tsk_object_ref((void*)header);
  261. if(!self->Attributes){
  262. self->Attributes = tsk_list_create();
  263. }
  264. tsk_list_push_back_data(self->Attributes, (void**)&A);
  265. break;
  266. }
  267. }
  268. return 0;
  269. }
  270. int tsdp_header_M_add_headers(tsdp_header_M_t* self, ...)
  271. {
  272. const tsk_object_def_t* objdef;
  273. tsdp_header_t *header;
  274. tsdp_fmt_t* fmt;
  275. va_list ap;
  276. if(!self){
  277. TSK_DEBUG_ERROR("Invalid parameter");
  278. return -1;
  279. }
  280. va_start(ap, self);
  281. while((objdef = va_arg(ap, const tsk_object_def_t*))){
  282. if(objdef == tsdp_fmt_def_t){
  283. if((fmt = tsk_object_new_2(objdef, &ap))){
  284. tsk_list_push_back_data(self->FMTs, (void**)&fmt);
  285. }
  286. }
  287. else{
  288. if((header = tsk_object_new_2(objdef, &ap))){
  289. tsdp_header_M_add(self, header);
  290. TSK_OBJECT_SAFE_FREE(header);
  291. }
  292. }
  293. }
  294. va_end(ap);
  295. return 0;
  296. }
  297. int tsdp_header_M_add_headers_2(tsdp_header_M_t* self, const tsdp_headers_L_t* headers)
  298. {
  299. const tsk_list_item_t* item;
  300. if(!self || !headers){
  301. TSK_DEBUG_ERROR("Invalid parameter");
  302. return -1;
  303. }
  304. tsk_list_foreach(item, headers){
  305. tsdp_header_M_add(self, item->data);
  306. }
  307. return 0;
  308. }
  309. int tsdp_header_M_add_fmt(tsdp_header_M_t* self, const char* fmt)
  310. {
  311. tsdp_fmt_t* _fmt;
  312. if(!self || tsk_strnullORempty(fmt)){
  313. TSK_DEBUG_ERROR("Invalid parameter");
  314. return -1;
  315. }
  316. if((_fmt = tsdp_fmt_create(fmt))){
  317. tsk_list_push_back_data(self->FMTs, (void**)&_fmt);
  318. return 0;
  319. }
  320. else{
  321. TSK_DEBUG_ERROR("Failed to create fmt object");
  322. return -2;
  323. }
  324. }
  325. int tsdp_header_M_remove_fmt(tsdp_header_M_t* self, const char* fmt)
  326. {
  327. const tsk_list_item_t* itemM;
  328. const tsdp_fmt_t* _fmt;
  329. char* fmt_plus_space = tsk_null;
  330. tsk_size_t fmt_plus_space_len;
  331. if(!self || tsk_strnullORempty(fmt)){
  332. TSK_DEBUG_ERROR("Invalid parameter");
  333. return -1;
  334. }
  335. tsk_sprintf(&fmt_plus_space, "%s ", fmt);
  336. if((fmt_plus_space_len = tsk_strlen(fmt_plus_space))){
  337. tsk_list_foreach(itemM, self->FMTs){
  338. if(!(_fmt = (const tsdp_fmt_t*)itemM->data)){
  339. continue;
  340. }
  341. if(tsk_striequals(_fmt->value, fmt)){
  342. // remove all A headers using this attribute
  343. const tsdp_header_A_t* A;
  344. const tsk_list_item_t* itemA;
  345. removeAttributes:
  346. tsk_list_foreach(itemA, self->Attributes){
  347. if(!(A = (const tsdp_header_A_t*)itemA->data)){
  348. continue;
  349. }
  350. if(tsk_strindexOf(A->value, fmt_plus_space_len, fmt_plus_space) == 0){
  351. // Guard to be sure we know what to remove. For example:
  352. // tsdp_header_M_remove_fmt(self, 0) would remove both
  353. // a=rtpmap:0 PCMU/8000/1
  354. // a=crypto:0 AES_CM_128_HMAC_SHA1_32 inline:Gi8s25tDKDnd/xORJ/ZtRWWC1drVbax5Ve4ftCWd
  355. // and cause issue 115: https://code.google.com/p/webrtc2sip/issues/detail?id=115
  356. if(!tsk_striequals(A->field, "crypto")){
  357. tsk_list_remove_item(self->Attributes, (tsk_list_item_t*)itemA);
  358. goto removeAttributes;
  359. }
  360. }
  361. }
  362. tsk_list_remove_item(self->FMTs, (tsk_list_item_t*)itemM);
  363. break;
  364. }
  365. }
  366. }
  367. TSK_FREE(fmt_plus_space);
  368. return 0;
  369. }
  370. tsk_bool_t tsdp_header_M_have_fmt(tsdp_header_M_t* self, const char* fmt)
  371. {
  372. if(self &&! tsk_strnullORempty(fmt)){
  373. const tsk_list_item_t* item;
  374. const tsdp_fmt_t* _fmt;
  375. tsk_list_foreach(item, self->FMTs){
  376. if(!(_fmt = (const tsdp_fmt_t*)item->data)){
  377. continue;
  378. }
  379. if(tsk_striequals(_fmt->value, fmt)){
  380. return tsk_true;
  381. }
  382. }
  383. }
  384. return tsk_false;
  385. }
  386. const tsdp_header_A_t* tsdp_header_M_findA_at(const tsdp_header_M_t* self, const char* field, tsk_size_t index)
  387. {
  388. const tsk_list_item_t *item;
  389. tsk_size_t pos = 0;
  390. const tsdp_header_A_t* A;
  391. if(!self){
  392. TSK_DEBUG_ERROR("Invalid parameter");
  393. return tsk_null;
  394. }
  395. tsk_list_foreach(item, self->Attributes){
  396. if(!(A = item->data)){
  397. continue;
  398. }
  399. if(tsk_strequals(A->field, field)){
  400. if(pos++ >= index){
  401. return A;
  402. }
  403. }
  404. }
  405. return tsk_null;
  406. }
  407. const tsdp_header_A_t* tsdp_header_M_findA(const tsdp_header_M_t* self, const char* field)
  408. {
  409. return tsdp_header_M_findA_at(self, field, 0);
  410. }
  411. char* tsdp_header_M_getAValue(const tsdp_header_M_t* self, const char* field, const char* fmt)
  412. {
  413. char *value = tsk_null; /* e.g. AMR-WB/16000 */
  414. tsk_size_t i = 0, fmt_len, A_len;
  415. int indexof;
  416. const tsdp_header_A_t* A;
  417. fmt_len = tsk_strlen(fmt);
  418. if(!self || !fmt_len || fmt_len > 3/*'0-255' or '*'*/){
  419. TSK_DEBUG_ERROR("Invalid parameter");
  420. return tsk_null;
  421. }
  422. /* find "a=rtpmap" */
  423. while((A = tsdp_header_M_findA_at(self, field, i++))){
  424. /* A->value would be: "98 AMR-WB/16000" */
  425. if((A_len = tsk_strlen(A->value)) < (fmt_len + 1/*space*/)){
  426. continue;
  427. }
  428. if((indexof = tsk_strindexOf(A->value, A_len, fmt)) == 0 && (A->value[fmt_len] == ' ')){
  429. value = tsk_strndup(&A->value[fmt_len+1], (A_len-(fmt_len+1)));
  430. break;
  431. }
  432. }
  433. return value;
  434. }
  435. /* as per 3GPP TS 34.610 */
  436. int tsdp_header_M_hold(tsdp_header_M_t* self, tsk_bool_t local)
  437. {
  438. const tsdp_header_A_t* a;
  439. if(!self){
  440. TSK_DEBUG_ERROR("Invalid parameter");
  441. return -1;
  442. }
  443. if((a = tsdp_header_M_findA(self, local ? "recvonly" : "sendonly"))){
  444. // an "inactive" SDP attribute if the stream was previously set to "recvonly" media stream
  445. tsk_strupdate(&(TSDP_HEADER_A(a)->field), local ? "inactive" : "recvonly");
  446. }
  447. else if((a = tsdp_header_M_findA(self, "sendrecv"))){
  448. // a "sendonly" SDP attribute if the stream was previously set to "sendrecv" media stream
  449. tsk_strupdate(&(TSDP_HEADER_A(a)->field), local ? "sendonly" : "recvonly");
  450. }
  451. else{
  452. // default value is sendrecv. hold on default --> sendonly
  453. if(!(a = tsdp_header_M_findA(self, local ? "sendonly" : "recvonly")) && !(a = tsdp_header_M_findA(self, "inactive"))){
  454. tsdp_header_A_t* newA;
  455. if((newA = tsdp_header_A_create(local ? "sendonly" : "recvonly", tsk_null))){
  456. tsdp_header_M_add(self, TSDP_HEADER_CONST(newA));
  457. TSK_OBJECT_SAFE_FREE(newA);
  458. }
  459. }
  460. }
  461. return 0;
  462. }
  463. /* as per 3GPP TS 34.610 */
  464. int tsdp_header_M_set_holdresume_att(tsdp_header_M_t* self, tsk_bool_t lo_held, tsk_bool_t ro_held)
  465. {
  466. const tsdp_header_A_t* A;
  467. static const char* hold_resume_atts[2][2] =
  468. {
  469. {"sendrecv", "recvonly"},
  470. {"sendonly", "inactive"},
  471. };
  472. if(!self){
  473. TSK_DEBUG_ERROR("Invalid parameter");
  474. return -1;
  475. }
  476. if((A = tsdp_header_M_findA(self, "sendrecv")) || (A = tsdp_header_M_findA(self, "sendonly")) || (A = tsdp_header_M_findA(self, "recvonly")) || (A = tsdp_header_M_findA(self, "inactive"))){
  477. tsk_strupdate(&(TSDP_HEADER_A(A)->field), hold_resume_atts[lo_held & 1][ro_held & 1]);
  478. }
  479. else{
  480. tsdp_header_A_t* newA;
  481. if((newA = tsdp_header_A_create(hold_resume_atts[lo_held & 1][ro_held & 1], tsk_null))){
  482. tsdp_header_M_add(self, TSDP_HEADER_CONST(newA));
  483. TSK_OBJECT_SAFE_FREE(newA);
  484. }
  485. }
  486. return 0;
  487. }
  488. const char* tsdp_header_M_get_holdresume_att(const tsdp_header_M_t* self)
  489. {
  490. static const char* hold_resume_atts[4] = {"sendrecv"/*first because most likely to be present*/, "recvonly", "sendonly", "inactive"};
  491. static tsk_size_t hold_resume_atts_count = sizeof(hold_resume_atts)/sizeof(hold_resume_atts[0]);
  492. tsk_size_t i;
  493. if(!self){
  494. TSK_DEBUG_ERROR("Invalid parameter");
  495. return hold_resume_atts[0];
  496. }
  497. for(i = 0; i < hold_resume_atts_count; ++i){
  498. if(tsdp_header_M_findA(self, hold_resume_atts[i])){
  499. return hold_resume_atts[i];
  500. }
  501. }
  502. return hold_resume_atts[0];
  503. }
  504. tsk_bool_t tsdp_header_M_is_held(const tsdp_header_M_t* self, tsk_bool_t local)
  505. {
  506. if(!self){
  507. TSK_DEBUG_ERROR("Invalid parameter");
  508. return tsk_false;
  509. }
  510. /* both cases */
  511. if(tsdp_header_M_findA(self, "inactive")){
  512. return tsk_true;
  513. }
  514. if(local){
  515. return tsdp_header_M_findA(self, "recvonly") ? tsk_true : tsk_false;
  516. }
  517. else{
  518. return tsdp_header_M_findA(self, "sendonly") ? tsk_true : tsk_false;
  519. }
  520. }
  521. /* as per 3GPP TS 34.610 */
  522. int tsdp_header_M_resume(tsdp_header_M_t* self, tsk_bool_t local)
  523. {
  524. const tsdp_header_A_t* a;
  525. if(!self){
  526. TSK_DEBUG_ERROR("Invalid parameter");
  527. return -1;
  528. }
  529. if((a = tsdp_header_M_findA(self, "inactive"))){
  530. // a "recvonly" SDP attribute if the stream was previously an inactive media stream
  531. tsk_strupdate(&(TSDP_HEADER_A(a)->field), local ? "recvonly" : "sendonly");
  532. }
  533. else if((a = tsdp_header_M_findA(self, local ? "sendonly" : "recvonly"))){
  534. // a "sendrecv" SDP attribute if the stream was previously a sendonly media stream, or the attribute may be omitted, since sendrecv is the default
  535. tsk_strupdate(&(TSDP_HEADER_A(a)->field), "sendrecv");
  536. }
  537. return 0;
  538. }
  539. //
  540. //int tsdp_header_M_set(tsdp_header_M_t* self, ...)
  541. //{
  542. // int ret = -1;
  543. // va_list params;
  544. // int type;
  545. //
  546. // va_start(params, self);
  547. //
  548. // if(!m){
  549. // goto bail;
  550. // }
  551. //
  552. // while((type=va_arg(params, int))){
  553. // switch(type){
  554. // case 0x01: /* FMT */
  555. // {
  556. // tsk_string_t* fmt = tsk_string_create(va_arg(values, const char *));
  557. // if(fmt){
  558. // tsk_list_push_back_data(sefl->FMTs, (void**)&fmt);
  559. // }
  560. // break;
  561. // }
  562. // case 0x02: /* A */
  563. // {
  564. // tsdp_header_A_t* A = tsdp_header_A_create(va_arg(values, const char *), va_arg(values, const char *));
  565. // if(A){
  566. // if(!M->Attributes){
  567. // M->Attributes = tsk_list_create();
  568. // }
  569. // tsk_list_push_back_data(M->Attributes, (void**)&A);
  570. // }
  571. // break;
  572. // }
  573. // }
  574. // }
  575. //
  576. //bail:
  577. // va_end(params);
  578. // return ret;
  579. //}
  580. //========================================================
  581. // M header object definition
  582. //
  583. static tsk_object_t* tsdp_header_M_ctor(tsk_object_t *self, va_list * app)
  584. {
  585. tsdp_header_M_t *M = self;
  586. if(M){
  587. TSDP_HEADER(M)->type = tsdp_htype_M;
  588. TSDP_HEADER(M)->tostring = tsdp_header_M_tostring;
  589. TSDP_HEADER(M)->clone = tsdp_header_M_clone;
  590. TSDP_HEADER(M)->rank = TSDP_HTYPE_M_RANK;
  591. M->FMTs = tsk_list_create(); // Because there is at least one fmt.
  592. M->media = tsk_strdup(va_arg(*app, const char*));
  593. M->port = va_arg(*app, uint32_t);
  594. M->proto = tsk_strdup(va_arg(*app, const char*));
  595. }
  596. else{
  597. TSK_DEBUG_ERROR("Failed to create new M header.");
  598. }
  599. return self;
  600. }
  601. static tsk_object_t* tsdp_header_M_dtor(tsk_object_t *self)
  602. {
  603. tsdp_header_M_t *M = self;
  604. if(M){
  605. TSK_FREE(M->media);
  606. TSK_FREE(M->proto);
  607. TSK_OBJECT_SAFE_FREE(M->FMTs);
  608. TSK_OBJECT_SAFE_FREE(M->I);
  609. TSK_OBJECT_SAFE_FREE(M->C);
  610. TSK_OBJECT_SAFE_FREE(M->Bandwidths);
  611. TSK_OBJECT_SAFE_FREE(M->K);
  612. TSK_OBJECT_SAFE_FREE(M->Attributes);
  613. }
  614. else{
  615. TSK_DEBUG_ERROR("Null M header.");
  616. }
  617. return self;
  618. }
  619. static int tsdp_header_M_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2)
  620. {
  621. if(obj1 && obj2){
  622. return tsdp_header_rank_cmp(obj1, obj2);
  623. }
  624. else{
  625. return -1;
  626. }
  627. }
  628. static const tsk_object_def_t tsdp_header_M_def_s =
  629. {
  630. sizeof(tsdp_header_M_t),
  631. tsdp_header_M_ctor,
  632. tsdp_header_M_dtor,
  633. tsdp_header_M_cmp
  634. };
  635. const tsk_object_def_t *tsdp_header_M_def_t = &tsdp_header_M_def_s;