diff options
author | Mamadou DIOP <bossiel@yahoo.fr> | 2015-08-17 01:56:35 +0200 |
---|---|---|
committer | Mamadou DIOP <bossiel@yahoo.fr> | 2015-08-17 01:56:35 +0200 |
commit | 631fffee8a28b1bec5ed1f1d26a20e0135967f99 (patch) | |
tree | 74afe3bf3efe15aa82bcd0272b2b0f4d48c2d837 /tinySDP/ragel | |
parent | 7908865936604036e6f200f1b5e069f8752f3a3a (diff) | |
download | doubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.zip doubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.tar.gz |
-
Diffstat (limited to 'tinySDP/ragel')
-rw-r--r-- | tinySDP/ragel/tsdp_machine_utils.rl | 72 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_A.rl | 229 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_B.rl | 186 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_C.rl | 193 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_Dummy.rl | 183 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_E.rl | 175 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_I.rl | 176 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_K.rl | 175 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_M.rl | 723 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_O.rl | 223 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_P.rl | 174 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_R.rl | 215 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_S.rl | 172 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_T.rl | 226 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_U.rl | 176 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_V.rl | 173 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_header_Z.rl | 277 | ||||
-rw-r--r-- | tinySDP/ragel/tsdp_parser_message.rl | 288 |
18 files changed, 4036 insertions, 0 deletions
diff --git a/tinySDP/ragel/tsdp_machine_utils.rl b/tinySDP/ragel/tsdp_machine_utils.rl new file mode 100644 index 0000000..ed2b2b9 --- /dev/null +++ b/tinySDP/ragel/tsdp_machine_utils.rl @@ -0,0 +1,72 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +/**@file tsdp_machine_utils.rl + * @brief Ragel file. + */ +%%{ + + machine tsdp_machine_utils; + + OCTET = "0x"[0-9A-Fa-f]+; + CHAR = 0x01..0x7f; + VCHAR = 0x21..0x7e; + ALPHA = 0x41..0x5a | 0x61..0x7a; + DIGIT = 0x30..0x39; + CTL = 0x00..0x1f | 0x7f; + HTAB = "\t"; + LF = "\n"; + CR = "\r"; + SP = " "; + DQUOTE = "\""; + BIT = "0" | "1"; + HEXDIG = DIGIT | "A"i | "B"i | "C"i | "D"i | "E"i | "F"i; + CRLF = CR LF; + WSP = SP | HTAB; + LWSP = ( WSP | ( CRLF WSP ) )*; + LWS = ( WSP* CRLF )? WSP+; + SWS = LWS?; + EQUAL = SWS "=" SWS; + LHEX = DIGIT | 0x61..0x66; + HCOLON = ( SP | HTAB )* ":" SWS; + separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | DQUOTE | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HTAB; + STAR = SWS "*" SWS; + SLASH = SWS "/" SWS; + LPAREN = SWS "(" SWS; + RPAREN = SWS ")" SWS; + COMMA = SWS "," SWS; + SEMI = SWS ";" SWS; + COLON = SWS ":" SWS; + LAQUOT = SWS "<"; + LDQUOT = SWS DQUOTE; + RAQUOT = ">" SWS; + RDQUOT = DQUOTE SWS; + UTF8_CONT = 0x80..0xbf; + ##### FIXME: UTF8_NONASCII up to 2bytes will fail on Android + UTF8_NONASCII = ( 0x80..0xff ); + #UTF8_NONASCII = ( 0xc0..0xdf UTF8_CONT ) | ( 0xe0..0xef UTF8_CONT{2} ) | ( 0xf0..0xf7 UTF8_CONT{3} ) | ( 0xf8..0xfb UTF8_CONT{4} ) | ( 0xfc..0xfd UTF8_CONT{5} ); ctext = 0x21..0x27 | 0x2a..0x5b | 0x5d..0x7e | UTF8_NONASCII | LWS; + qvalue = ( "0" ( "." DIGIT{,3} )? ) | ( "1" ( "." "0"{,3} )? ); + alphanum = ALPHA | DIGIT; + token = ( alphanum | "-" | "." | "!" | "%" | "*" | "_" | "+" | "`" | "'" | "~" )+; + ietf_token = token; + x_token = "x-"i token; + iana_token = token; + token_nodot = ( alphanum | "-" | "!" | "%" | "*" | "_" | "+" | "`" | "'" | "~" )+; + word = ( alphanum | "-" | "." | "!" | "%" | "*" | "_" | "+" | "`" | "'" | "~" | "(" | ")" | "<" | ">" | ":" | "\\" | DQUOTE | "/" | "[" | "]" | "?" | "{" | "}" )+; +}%% diff --git a/tinySDP/ragel/tsdp_parser_header_A.rl b/tinySDP/ragel/tsdp_parser_header_A.rl new file mode 100644 index 0000000..29f7a20 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_A.rl @@ -0,0 +1,229 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + +/**@file tsdp_header_A.c + * @brief SDP "a=" header (Attributes). + * + */ +#include "tinysdp/headers/tsdp_header_A.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_A; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_field{ + TSK_PARSER_SET_STRING(hdr_A->field); + } + + action parse_value{ + TSK_PARSER_SET_STRING(hdr_A->value); + } + + field = token>tag %parse_field; + value = any*>tag %parse_value; + + A = 'a' SP* "=" SP*<: ((field ":" value) | (field)); + + # Entry point + main := A :>CRLF?; + +}%% + + + +tsdp_header_A_t* tsdp_header_A_create(const char* field, const char* value) +{ + return tsk_object_new(TSDP_HEADER_A_VA_ARGS(field, value)); +} + +tsdp_header_A_t* tsdp_header_A_create_null() +{ + return tsdp_header_A_create(tsk_null, tsk_null); +} + + +int tsdp_header_A_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header){ + const tsdp_header_A_t *A = (const tsdp_header_A_t *)header; + + return tsk_buffer_append_2(output, "%s%s%s", + A->field, + + A->value ? ":" : "", + A->value ? A->value : "" + ); + } + + return -1; +} + +tsdp_header_t* tsdp_header_A_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_A_t *A = (const tsdp_header_A_t *)header; + return (tsdp_header_t*)tsdp_header_A_create(A->field, A->value); + } + return tsk_null; +} + +tsdp_header_A_t *tsdp_header_A_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_A_t *hdr_A = tsdp_header_A_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + %%write init; + (void)(tsdp_machine_parser_header_A_first_final); + (void)(tsdp_machine_parser_header_A_error); + (void)(tsdp_machine_parser_header_A_en_main); + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"a=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_A); + } + + return hdr_A; +} + + +int tsdp_header_A_removeAll_by_field(tsdp_headers_A_L_t *attributes, const char* field) +{ + tsk_list_item_t* item; + const tsdp_header_A_t* A; + + if(!attributes || !field){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + +again: + tsk_list_foreach(item, attributes){ + if(!(A = item->data) || TSDP_HEADER(A)->type != tsdp_htype_A){ + continue; + } + if(tsk_striequals(field, A->field)){ + tsk_list_remove_item(attributes, item); + goto again; + } + } + + return 0; +} + +int tsdp_header_A_removeAll_by_fields(tsdp_headers_A_L_t *attributes, const char** fields, tsk_size_t fields_count) +{ + tsk_size_t i; + + if(!attributes || !fields){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + for(i = 0; i < fields_count; ++i){ + if(!fields[i]){ + continue; + } + tsdp_header_A_removeAll_by_field(attributes, fields[i]); + } + return 0; +} + + + + +//======================================================== +// A header object definition +// + +static tsk_object_t* tsdp_header_A_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_A_t *A = self; + if(A) + { + TSDP_HEADER(A)->type = tsdp_htype_A; + TSDP_HEADER(A)->tostring = tsdp_header_A_tostring; + TSDP_HEADER(A)->clone = tsdp_header_A_clone; + TSDP_HEADER(A)->rank = TSDP_HTYPE_A_RANK; + + A->field = tsk_strdup(va_arg(*app, const char*)); + A->value = tsk_strdup(va_arg(*app, const char*)); + } + else{ + TSK_DEBUG_ERROR("Failed to create new A header."); + } + return self; +} + +static tsk_object_t* tsdp_header_A_dtor(tsk_object_t *self) +{ + tsdp_header_A_t *A = self; + if(A){ + TSK_FREE(A->field); + TSK_FREE(A->value); + } + else{ + TSK_DEBUG_ERROR("Null A header."); + } + + return self; +} +static int tsdp_header_A_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_A_def_s = +{ + sizeof(tsdp_header_A_t), + tsdp_header_A_ctor, + tsdp_header_A_dtor, + tsdp_header_A_cmp +}; + +const tsk_object_def_t *tsdp_header_A_def_t = &tsdp_header_A_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_B.rl b/tinySDP/ragel/tsdp_parser_header_B.rl new file mode 100644 index 0000000..63500b7 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_B.rl @@ -0,0 +1,186 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + + +/**@file tsdp_header_B.c + * @brief SDP "b=" header (Bandwidth). + * + */ +#include "tinysdp/headers/tsdp_header_B.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_B; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_bwtype{ + TSK_PARSER_SET_STRING(hdr_B->bwtype); + } + + action parse_bandwidth{ + TSK_PARSER_SET_UINT(hdr_B->bandwidth); + } + + bwtype = token>tag %parse_bwtype; + bandwidth = DIGIT+>tag %parse_bandwidth; + + B = 'b' SP* "=" SP*<: bwtype ":" bandwidth; + + # Entry point + main := B :>CRLF?; + +}%% + + + + +tsdp_header_B_t* tsdp_header_B_create(const char* bwtype, uint32_t bandwidth) +{ + return tsk_object_new(TSDP_HEADER_B_VA_ARGS(bwtype, bandwidth)); +} + +tsdp_header_B_t* tsdp_header_B_create_null() +{ + return tsdp_header_B_create(tsk_null, 0); +} + +int tsdp_header_B_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header){ + const tsdp_header_B_t *B = (const tsdp_header_B_t *)header; + + return tsk_buffer_append_2(output, "%s:%u", + B->bwtype, + B->bandwidth + ); + } + + return -1; +} + +tsdp_header_t* tsdp_header_B_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_B_t *B = (const tsdp_header_B_t *)header; + return (tsdp_header_t*)tsdp_header_B_create(B->bwtype, B->bandwidth); + } + return tsk_null; +} + +tsdp_header_B_t *tsdp_header_B_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_B_t *hdr_B = tsdp_header_B_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_B_first_final); + (void)(tsdp_machine_parser_header_B_error); + (void)(tsdp_machine_parser_header_B_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"b=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_B); + } + + return hdr_B; +} + + + + + + + +//======================================================== +// B header object definition +// + +static tsk_object_t* tsdp_header_B_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_B_t *B = self; + if(B){ + TSDP_HEADER(B)->type = tsdp_htype_B; + TSDP_HEADER(B)->tostring = tsdp_header_B_tostring; + TSDP_HEADER(B)->clone = tsdp_header_B_clone; + TSDP_HEADER(B)->rank = TSDP_HTYPE_B_RANK; + + B->bwtype = tsk_strdup(va_arg(*app, const char*)); + B->bandwidth = va_arg(*app, uint32_t); + } + else{ + TSK_DEBUG_ERROR("Failed to create new B header."); + } + return self; +} + +static tsk_object_t* tsdp_header_B_dtor(tsk_object_t *self) +{ + tsdp_header_B_t *B = self; + if(B){ + TSK_FREE(B->bwtype); + } + else{ + TSK_DEBUG_ERROR("Null B header."); + } + + return self; +} +static int tsdp_header_B_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_B_def_s = +{ + sizeof(tsdp_header_B_t), + tsdp_header_B_ctor, + tsdp_header_B_dtor, + tsdp_header_B_cmp +}; + +const tsk_object_def_t *tsdp_header_B_def_t = &tsdp_header_B_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_C.rl b/tinySDP/ragel/tsdp_parser_header_C.rl new file mode 100644 index 0000000..ff87043 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_C.rl @@ -0,0 +1,193 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + + +/**@file tsdp_header_C.c + * @brief "c=" header (Connection Data). + */ +#include "tinysdp/headers/tsdp_header_C.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_C; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_nettype{ + TSK_PARSER_SET_STRING(hdr_C->nettype); + } + + action parse_addrtype{ + TSK_PARSER_SET_STRING(hdr_C->addrtype); + } + + action parse_addr{ + TSK_PARSER_SET_STRING(hdr_C->addr); + } + + nettype = any* >tag %parse_nettype; + addrtype = any* >tag %parse_addrtype; + addr = any* >tag %parse_addr; + C = 'c' SP* "=" SP*<: nettype :>SP addrtype :>SP addr; + + # Entry point + main := C :>CRLF?; + +}%% + + +tsdp_header_C_t* tsdp_header_c_create(const char* nettype, const char* addrtype, const char* addr) +{ + return tsk_object_new(TSDP_HEADER_C_VA_ARGS(nettype, addrtype, addr)); +} + +tsdp_header_C_t* tsdp_header_c_create_null() +{ + return tsdp_header_c_create(tsk_null, tsk_null, tsk_null); +} + +int tsdp_header_C_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header){ + const tsdp_header_C_t *C = (const tsdp_header_C_t *)header; + + return tsk_buffer_append_2(output, "%s %s %s", + C->nettype, + C->addrtype, + C->addr + ); + + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_C_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_C_t *C = (const tsdp_header_C_t *)header; + return (tsdp_header_t*)tsdp_header_c_create(C->nettype, C->addrtype, C->addr); + } + return tsk_null; +} + +tsdp_header_C_t *tsdp_header_C_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_C_t *hdr_C = tsdp_header_c_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_C_first_final); + (void)(tsdp_machine_parser_header_C_error); + (void)(tsdp_machine_parser_header_C_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"c=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_C); + } + + return hdr_C; +} + + + + + + + +//======================================================== +// E header object definition +// + +static tsk_object_t* tsdp_header_C_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_C_t *C = self; + if(C){ + TSDP_HEADER(C)->type = tsdp_htype_C; + TSDP_HEADER(C)->tostring = tsdp_header_C_tostring; + TSDP_HEADER(C)->clone = tsdp_header_C_clone; + TSDP_HEADER(C)->rank = TSDP_HTYPE_C_RANK; + + C->nettype = tsk_strdup(va_arg(*app, const char*)); + C->addrtype = tsk_strdup(va_arg(*app, const char*)); + C->addr = tsk_strdup(va_arg(*app, const char*)); + } + else{ + TSK_DEBUG_ERROR("Failed to create new C header."); + } + return self; +} + +static tsk_object_t* tsdp_header_C_dtor(tsk_object_t *self) +{ + tsdp_header_C_t *C = self; + if(C){ + TSK_FREE(C->nettype); + TSK_FREE(C->addrtype); + TSK_FREE(C->addr); + } + else{ + TSK_DEBUG_ERROR("Null PC header."); + } + + return self; +} +static int tsdp_header_C_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_C_def_s = +{ + sizeof(tsdp_header_C_t), + tsdp_header_C_ctor, + tsdp_header_C_dtor, + tsdp_header_C_cmp +}; + +const tsk_object_def_t *tsdp_header_C_def_t = &tsdp_header_C_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_Dummy.rl b/tinySDP/ragel/tsdp_parser_header_Dummy.rl new file mode 100644 index 0000000..61c27f4 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_Dummy.rl @@ -0,0 +1,183 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + +/**@file tsdp_header_Dummy.c + * @brief SDP Dummy header. + */ +#include "tinysdp/headers/tsdp_header_Dummy.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_Dummy; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_name{ + hdr_Dummy->name = *tag_start; + } + + action parse_value{ + TSK_PARSER_SET_STRING(hdr_Dummy->value); + } + + Dummy = alpha>tag %parse_name SP* "=" SP*<: any*>tag %parse_value; + + # Entry point + main := Dummy :>CRLF?; + +}%% + + + +tsdp_header_Dummy_t* tsdp_header_dummy_create(char name, const char* value) +{ + return tsk_object_new(TSDP_HEADER_DUMMY_VA_ARGS(name, value)); +} + +tsdp_header_Dummy_t* tsdp_header_dummy_create_null() +{ + return tsdp_header_dummy_create(0, tsk_null); +} + +int tsdp_header_Dummy_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header) + { + const tsdp_header_Dummy_t *Dummy = (const tsdp_header_Dummy_t *)header; + if(Dummy->value){ + return tsk_buffer_append(output, Dummy->value, tsk_strlen(Dummy->value)); + } + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_Dummy_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_Dummy_t *Dummy = (const tsdp_header_Dummy_t *)header; + return (tsdp_header_t*)tsdp_header_dummy_create(Dummy->name, Dummy->value); + } + return tsk_null; +} + +tsdp_header_Dummy_t *tsdp_header_Dummy_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_Dummy_t *hdr_Dummy = tsdp_header_dummy_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_Dummy_first_final); + (void)(tsdp_machine_parser_header_Dummy_error); + (void)(tsdp_machine_parser_header_Dummy_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse dummy header."); + TSK_OBJECT_SAFE_FREE(hdr_Dummy); + } + + return hdr_Dummy; +} + + + + + + + +//======================================================== +// Dummy header object definition +// + +static tsk_object_t* tsdp_header_Dummy_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_Dummy_t *Dummy = self; + if(Dummy){ + TSDP_HEADER(Dummy)->type = tsdp_htype_Dummy; + TSDP_HEADER(Dummy)->tostring = tsdp_header_Dummy_tostring; + TSDP_HEADER(Dummy)->clone = tsdp_header_Dummy_clone; + TSDP_HEADER(Dummy)->rank = TSDP_HTYPE_DUMMY_RANK; +#if defined(__GNUC__) + Dummy->name = va_arg(*app, const int); +#else + Dummy->name = va_arg(*app, const char); +#endif + Dummy->value = tsk_strdup(va_arg(*app, const char*)); + } + else{ + TSK_DEBUG_ERROR("Failed to create new Dummy header."); + } + return self; +} + +static tsk_object_t* tsdp_header_Dummy_dtor(tsk_object_t *self) +{ + tsdp_header_Dummy_t *Dummy = self; + if(Dummy){ + TSK_FREE(Dummy->value); + } + else{ + TSK_DEBUG_ERROR("Null Dummy header."); + } + + return self; +} +static int tsdp_header_Dummy_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_Dummy_def_s = +{ + sizeof(tsdp_header_Dummy_t), + tsdp_header_Dummy_ctor, + tsdp_header_Dummy_dtor, + tsdp_header_Dummy_cmp +}; + +const tsk_object_def_t *tsdp_header_Dummy_def_t = &tsdp_header_Dummy_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_E.rl b/tinySDP/ragel/tsdp_parser_header_E.rl new file mode 100644 index 0000000..60ca08d --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_E.rl @@ -0,0 +1,175 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + + +/**@file tsdp_header_E.c + * @brief SDP "e=" header (Session Information). + */ +#include "tinysdp/headers/tsdp_header_E.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_E; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_value{ + TSK_PARSER_SET_STRING(hdr_E->value); + } + + E = 'e' SP* "=" SP*<: any*>tag %parse_value; + + # Entry point + main := E :>CRLF?; + +}%% + + + +tsdp_header_E_t* tsdp_header_E_create(const char* value) +{ + return tsk_object_new(TSDP_HEADER_E_VA_ARGS(value)); +} + +tsdp_header_E_t* tsdp_header_E_create_null() +{ + return tsdp_header_E_create(tsk_null); +} + +int tsdp_header_E_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header){ + const tsdp_header_E_t *E = (const tsdp_header_E_t *)header; + if(E->value){ + tsk_buffer_append(output, E->value, tsk_strlen(E->value)); + } + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_E_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_E_t *E = (const tsdp_header_E_t *)header; + return (tsdp_header_t*)tsdp_header_E_create(E->value); + } + return tsk_null; +} + +tsdp_header_E_t *tsdp_header_E_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_E_t *hdr_E = tsdp_header_E_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_E_first_final); + (void)(tsdp_machine_parser_header_E_error); + (void)(tsdp_machine_parser_header_E_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"e=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_E); + } + + return hdr_E; +} + + + + + + + +//======================================================== +// E header object definition +// + +static tsk_object_t* tsdp_header_E_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_E_t *E = self; + if(E){ + TSDP_HEADER(E)->type = tsdp_htype_E; + TSDP_HEADER(E)->tostring = tsdp_header_E_tostring; + TSDP_HEADER(E)->clone = tsdp_header_E_clone; + TSDP_HEADER(E)->rank = TSDP_HTYPE_E_RANK; + + E->value = tsk_strdup(va_arg(*app, const char*)); + } + else{ + TSK_DEBUG_ERROR("Failed to create new E header."); + } + return self; +} + +static tsk_object_t* tsdp_header_E_dtor(tsk_object_t *self) +{ + tsdp_header_E_t *E = self; + if(E){ + TSK_FREE(E->value); + } + else{ + TSK_DEBUG_ERROR("Null E header."); + } + + return self; +} +static int tsdp_header_E_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_E_def_s = +{ + sizeof(tsdp_header_E_t), + tsdp_header_E_ctor, + tsdp_header_E_dtor, + tsdp_header_E_cmp +}; + +const tsk_object_def_t *tsdp_header_E_def_t = &tsdp_header_E_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_I.rl b/tinySDP/ragel/tsdp_parser_header_I.rl new file mode 100644 index 0000000..7804ba7 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_I.rl @@ -0,0 +1,176 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + + +/**@file tsdp_header_I.c + * @brief SDP "i=" header (Session Information). + */ +#include "tinysdp/headers/tsdp_header_I.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_I; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_value{ + TSK_PARSER_SET_STRING(hdr_I->value); + } + + I = 'i' SP* "=" SP*<: any*>tag %parse_value; + + # Entry point + main := I :>CRLF?; + +}%% + + +tsdp_header_I_t* tsdp_header_I_create(const char* value) +{ + return tsk_object_new(TSDP_HEADER_I_VA_ARGS(value)); +} + +tsdp_header_I_t* tsdp_header_I_create_null() +{ + return tsdp_header_I_create(tsk_null); +} + +int tsdp_header_I_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header) + { + const tsdp_header_I_t *I = (const tsdp_header_I_t *)header; + if(I->value){ + tsk_buffer_append(output, I->value, tsk_strlen(I->value)); + } + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_I_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_I_t *I = (const tsdp_header_I_t *)header; + return (tsdp_header_t*)tsdp_header_I_create(I->value); + } + return tsk_null; +} + +tsdp_header_I_t *tsdp_header_I_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_I_t *hdr_I = tsdp_header_I_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_I_first_final); + (void)(tsdp_machine_parser_header_I_error); + (void)(tsdp_machine_parser_header_I_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"i=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_I); + } + + return hdr_I; +} + + + + + + + +//======================================================== +// I header object definition +// + +static tsk_object_t* tsdp_header_I_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_I_t *I = self; + if(I) + { + TSDP_HEADER(I)->type = tsdp_htype_I; + TSDP_HEADER(I)->tostring = tsdp_header_I_tostring; + TSDP_HEADER(I)->clone = tsdp_header_I_clone; + TSDP_HEADER(I)->rank = TSDP_HTYPE_I_RANK; + + I->value = tsk_strdup(va_arg(*app, const char*)); + } + else{ + TSK_DEBUG_ERROR("Failed to create new I header."); + } + return self; +} + +static tsk_object_t* tsdp_header_I_dtor(tsk_object_t *self) +{ + tsdp_header_I_t *I = self; + if(I){ + TSK_FREE(I->value); + } + else{ + TSK_DEBUG_ERROR("Null I header."); + } + + return self; +} +static int tsdp_header_I_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_I_def_s = +{ + sizeof(tsdp_header_I_t), + tsdp_header_I_ctor, + tsdp_header_I_dtor, + tsdp_header_I_cmp +}; + +const tsk_object_def_t *tsdp_header_I_def_t = &tsdp_header_I_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_K.rl b/tinySDP/ragel/tsdp_parser_header_K.rl new file mode 100644 index 0000000..5514d20 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_K.rl @@ -0,0 +1,175 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + + +/**@file tsdp_header_K.c + * @brief SDP "k=" header (Encryption Key). + */ +#include "tinysdp/headers/tsdp_header_K.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_K; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_value{ + TSK_PARSER_SET_STRING(hdr_K->value); + } + + K = 'k' SP* "=" SP*<: any*>tag %parse_value; + + # Entry point + main := K :>CRLF?; + +}%% + + + +tsdp_header_K_t* tsdp_header_K_create(const char* value) +{ + return tsk_object_new(TSDP_HEADER_K_VA_ARGS(value)); +} + +tsdp_header_K_t* tsdp_header_K_create_null() +{ + return tsdp_header_K_create(tsk_null); +} + +int tsdp_header_K_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header){ + const tsdp_header_K_t *K = (const tsdp_header_K_t *)header; + if(K->value){ + tsk_buffer_append(output, K->value, tsk_strlen(K->value)); + } + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_K_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_K_t *K = (const tsdp_header_K_t *)header; + return (tsdp_header_t*)tsdp_header_K_create(K->value); + } + return tsk_null; +} + +tsdp_header_K_t *tsdp_header_K_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_K_t *hdr_K = tsdp_header_K_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_K_first_final); + (void)(tsdp_machine_parser_header_K_error); + (void)(tsdp_machine_parser_header_K_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"k=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_K); + } + + return hdr_K; +} + + + + + + + +//======================================================== +// K header object definition +// + +static tsk_object_t* tsdp_header_K_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_K_t *K = self; + if(K){ + TSDP_HEADER(K)->type = tsdp_htype_K; + TSDP_HEADER(K)->tostring = tsdp_header_K_tostring; + TSDP_HEADER(K)->clone = tsdp_header_K_clone; + TSDP_HEADER(K)->rank = TSDP_HTYPE_P_RANK; + + K->value = tsk_strdup(va_arg(*app, const char*)); + } + else{ + TSK_DEBUG_ERROR("Failed to create new K header."); + } + return self; +} + +static tsk_object_t* tsdp_header_K_dtor(tsk_object_t *self) +{ + tsdp_header_K_t *K = self; + if(K){ + TSK_FREE(K->value); + } + else{ + TSK_DEBUG_ERROR("Null K header."); + } + + return self; +} +static int tsdp_header_K_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_K_def_s = +{ + sizeof(tsdp_header_K_t), + tsdp_header_K_ctor, + tsdp_header_K_dtor, + tsdp_header_K_cmp +}; + +const tsk_object_def_t *tsdp_header_K_def_t = &tsdp_header_K_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_M.rl b/tinySDP/ragel/tsdp_parser_header_M.rl new file mode 100644 index 0000000..02b2fe4 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_M.rl @@ -0,0 +1,723 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + + +/**@file tsdp_header_M.c + * @brief SDP "m=" header (Media Descriptions). + * + */ +#include "tinysdp/headers/tsdp_header_M.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_M; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_media{ + TSK_PARSER_SET_STRING(hdr_M->media); + } + + action parse_port{ + TSK_PARSER_SET_UINT(hdr_M->port); + } + + action parse_nports{ + TSK_PARSER_SET_UINT(hdr_M->nports); + } + + action parse_proto{ + TSK_PARSER_SET_STRING(hdr_M->proto); + } + + action parse_fmt{ + TSK_PARSER_ADD_STRING(hdr_M->FMTs); + } + + media = token>tag %parse_media; + port = DIGIT+>tag %parse_port; + nports = DIGIT+>tag %parse_port; + proto = (token ("/" token)*)>tag %parse_proto; + fmt = token>tag %parse_fmt; + + #// media SP port ["/" integer] SP proto 1*(SP fmt) + 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") + + # Entry point + main := M :>CRLF?; +}%% + + + +tsdp_header_M_t* tsdp_header_M_create(const char* media, uint32_t port, const char* proto) +{ + return tsk_object_new(TSDP_HEADER_M_VA_ARGS(media, port, proto)); +} + +tsdp_header_M_t* tsdp_header_M_create_null() +{ + return tsdp_header_M_create(tsk_null, 0, tsk_null); +} + +tsdp_fmt_t* tsdp_fmt_create(const char* fmt) +{ + return tsk_object_new(TSDP_FMT_VA_ARGS(fmt)); +} + + +int tsdp_header_M_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header){ + const tsdp_header_M_t *M = (const tsdp_header_M_t *)header; + const tsk_list_item_t* item; + tsk_istr_t nports; + + tsk_itoa(M->nports, &nports); + + /* IMPORTANT: Keep the order. + + m= (media name and transport address) + i=* (media title) + c=* (connection information -- optional if included at + session level) + b=* (zero or more bandwidth information lines) + k=* (encryption key) + a=* (zero or more media attribute lines) + */ + tsk_buffer_append_2(output, "%s %u%s%s %s", + M->media, + M->port, + + M->nports ? "/" : "", + M->nports ? nports : "", + + M->proto + ); + // FMTs + tsk_list_foreach(item, M->FMTs){ + tsk_buffer_append_2(output, " %s", TSDP_FMT_STR(item->data)); + } + tsk_buffer_append(output, "\r\n", 2); // close the "m=" line. + // i=* (media title) + if(M->I){ + tsdp_header_serialize(TSDP_HEADER(M->I), output); + } + // c=* (connection information -- optional if included at session level) + if(M->C){ + tsdp_header_serialize(TSDP_HEADER(M->C), output); + } + // b=* (zero or more bandwidth information lines) + if(M->Bandwidths){ + tsk_list_foreach(item, M->Bandwidths){ + tsdp_header_serialize(TSDP_HEADER(item->data), output); + } + } + // k=* (encryption key) + if(M->K){ + tsdp_header_serialize(TSDP_HEADER(M->K), output); + } + // a=* (zero or more media attribute lines) + if(M->Attributes){ + tsk_list_foreach(item, M->Attributes){ + tsdp_header_serialize(TSDP_HEADER(item->data), output); + } + } + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_M_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_M_t *M = (const tsdp_header_M_t *)header; + tsdp_header_M_t* clone; + const tsk_list_item_t* item; + + if((clone = tsdp_header_M_create(M->media, M->port, M->proto))){ + clone->nports = M->nports; + + // Formats + tsk_list_foreach(item, M->FMTs){ + tsk_string_t* string = tsk_string_create(TSK_STRING_STR(item->data)); + tsk_list_push_back_data(clone->FMTs, (void**)&string); + } + + // I + clone->I = (tsdp_header_I_t*) (M->I ? TSDP_HEADER(M->I)->clone(TSDP_HEADER(M->I)) : tsk_null); + // C + clone->C = (tsdp_header_C_t*) (M->C ? TSDP_HEADER(M->C)->clone(TSDP_HEADER(M->C)) : tsk_null); + // Bandwidths + tsk_list_foreach(item, M->Bandwidths){ + tsdp_header_t* B; + if(!clone->Bandwidths){ + clone->Bandwidths = tsk_list_create(); + } + B = ((tsdp_header_t*)item->data)->clone((tsdp_header_t*)item->data); + tsk_list_push_back_data(clone->Bandwidths, (void**)&B); + } + // K + clone->K = (tsdp_header_K_t*) (M->K ? TSDP_HEADER(M->K)->clone(TSDP_HEADER(M->K)) : tsk_null); + // Attributes + tsk_list_foreach(item, M->Attributes){ + tsdp_header_t* A; + if(!clone->Attributes){ + clone->Attributes = tsk_list_create(); + } + A = ((tsdp_header_t*)item->data)->clone((tsdp_header_t*)item->data); + tsk_list_push_back_data(clone->Attributes, (void**)&A); + } + } + + return TSDP_HEADER(clone); + } + return tsk_null; +} + +tsdp_header_M_t *tsdp_header_M_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_M_t *hdr_M = tsdp_header_M_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_M_first_final); + (void)(tsdp_machine_parser_header_M_error); + (void)(tsdp_machine_parser_header_M_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"m=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_M); + } + + return hdr_M; +} + + +// for A headers, use "tsdp_header_A_removeAll_by_field()" +int tsdp_header_M_remove(tsdp_header_M_t* self, tsdp_header_type_t type) +{ + switch(type){ + case tsdp_htype_I: + { + TSK_OBJECT_SAFE_FREE(self->I); + break; + } + case tsdp_htype_C: + { + TSK_OBJECT_SAFE_FREE(self->C); + break; + } + case tsdp_htype_B: + { + if(self->Bandwidths){ + tsk_list_clear_items(self->Bandwidths); + } + break; + } + case tsdp_htype_K: + { + TSK_OBJECT_SAFE_FREE(self->K); + break; + } + } + return 0; +} + +int tsdp_header_M_add(tsdp_header_M_t* self, const tsdp_header_t* header) +{ + if(!self || !header){ + return -1; + } + + switch(header->type){ + case tsdp_htype_I: + { + TSK_OBJECT_SAFE_FREE(self->I); + self->I = tsk_object_ref((void*)header); + break; + } + case tsdp_htype_C: + { + TSK_OBJECT_SAFE_FREE(self->C); + self->C = tsk_object_ref((void*)header); + break; + } + case tsdp_htype_B: + { + tsdp_header_t* B = tsk_object_ref((void*)header); + if(!self->Bandwidths){ + self->Bandwidths = tsk_list_create(); + } + tsk_list_push_back_data(self->Bandwidths, (void**)&B); + break; + } + case tsdp_htype_K: + { + TSK_OBJECT_SAFE_FREE(self->K); + self->K = tsk_object_ref((void*)header); + break; + } + case tsdp_htype_A: + { + tsdp_header_t* A = tsk_object_ref((void*)header); + if(!self->Attributes){ + self->Attributes = tsk_list_create(); + } + tsk_list_push_back_data(self->Attributes, (void**)&A); + break; + } + } + + return 0; +} + +int tsdp_header_M_add_headers(tsdp_header_M_t* self, ...) +{ + const tsk_object_def_t* objdef; + tsdp_header_t *header; + tsdp_fmt_t* fmt; + va_list ap; + + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + va_start(ap, self); + while((objdef = va_arg(ap, const tsk_object_def_t*))){ + if(objdef == tsdp_fmt_def_t){ + if((fmt = tsk_object_new_2(objdef, &ap))){ + tsk_list_push_back_data(self->FMTs, (void**)&fmt); + } + } + else{ + if((header = tsk_object_new_2(objdef, &ap))){ + tsdp_header_M_add(self, header); + TSK_OBJECT_SAFE_FREE(header); + } + } + } + va_end(ap); + + return 0; +} + +int tsdp_header_M_add_headers_2(tsdp_header_M_t* self, const tsdp_headers_L_t* headers) +{ + const tsk_list_item_t* item; + + if(!self || !headers){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + tsk_list_foreach(item, headers){ + tsdp_header_M_add(self, item->data); + } + + return 0; +} + +int tsdp_header_M_add_fmt(tsdp_header_M_t* self, const char* fmt) +{ + tsdp_fmt_t* _fmt; + if(!self || tsk_strnullORempty(fmt)){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if((_fmt = tsdp_fmt_create(fmt))){ + tsk_list_push_back_data(self->FMTs, (void**)&_fmt); + return 0; + } + else{ + TSK_DEBUG_ERROR("Failed to create fmt object"); + return -2; + } +} + +int tsdp_header_M_remove_fmt(tsdp_header_M_t* self, const char* fmt) +{ + const tsk_list_item_t* itemM; + const tsdp_fmt_t* _fmt; + char* fmt_plus_space = tsk_null; + tsk_size_t fmt_plus_space_len; + if(!self || tsk_strnullORempty(fmt)){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + tsk_sprintf(&fmt_plus_space, "%s ", fmt); + if((fmt_plus_space_len = tsk_strlen(fmt_plus_space))){ + tsk_list_foreach(itemM, self->FMTs){ + if(!(_fmt = (const tsdp_fmt_t*)itemM->data)){ + continue; + } + if(tsk_striequals(_fmt->value, fmt)){ + // remove all A headers using this attribute + const tsdp_header_A_t* A; + const tsk_list_item_t* itemA; +removeAttributes: + tsk_list_foreach(itemA, self->Attributes){ + if(!(A = (const tsdp_header_A_t*)itemA->data)){ + continue; + } + if(tsk_strindexOf(A->value, fmt_plus_space_len, fmt_plus_space) == 0){ + // Guard to be sure we know what to remove. For example: + // tsdp_header_M_remove_fmt(self, 0) would remove both + // a=rtpmap:0 PCMU/8000/1 + // a=crypto:0 AES_CM_128_HMAC_SHA1_32 inline:Gi8s25tDKDnd/xORJ/ZtRWWC1drVbax5Ve4ftCWd + // and cause issue 115: https://code.google.com/p/webrtc2sip/issues/detail?id=115 + if(!tsk_striequals(A->field, "crypto")){ + tsk_list_remove_item(self->Attributes, (tsk_list_item_t*)itemA); + goto removeAttributes; + } + } + } + tsk_list_remove_item(self->FMTs, (tsk_list_item_t*)itemM); + break; + } + } + } + TSK_FREE(fmt_plus_space); + return 0; +} + +tsk_bool_t tsdp_header_M_have_fmt(tsdp_header_M_t* self, const char* fmt) +{ + if(self &&! tsk_strnullORempty(fmt)){ + const tsk_list_item_t* item; + const tsdp_fmt_t* _fmt; + tsk_list_foreach(item, self->FMTs){ + if(!(_fmt = (const tsdp_fmt_t*)item->data)){ + continue; + } + if(tsk_striequals(_fmt->value, fmt)){ + return tsk_true; + } + } + } + + return tsk_false; +} + +const tsdp_header_A_t* tsdp_header_M_findA_at(const tsdp_header_M_t* self, const char* field, tsk_size_t index) +{ + const tsk_list_item_t *item; + tsk_size_t pos = 0; + const tsdp_header_A_t* A; + + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + tsk_list_foreach(item, self->Attributes){ + if(!(A = item->data)){ + continue; + } + + if(tsk_strequals(A->field, field)){ + if(pos++ >= index){ + return A; + } + } + } + + return tsk_null; +} + +const tsdp_header_A_t* tsdp_header_M_findA(const tsdp_header_M_t* self, const char* field) +{ + return tsdp_header_M_findA_at(self, field, 0); +} + +char* tsdp_header_M_getAValue(const tsdp_header_M_t* self, const char* field, const char* fmt) +{ + char *value = tsk_null; /* e.g. AMR-WB/16000 */ + tsk_size_t i = 0, fmt_len, A_len; + int indexof; + const tsdp_header_A_t* A; + + fmt_len = tsk_strlen(fmt); + if(!self || !fmt_len || fmt_len > 3/*'0-255' or '*'*/){ + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + /* find "a=rtpmap" */ + while((A = tsdp_header_M_findA_at(self, field, i++))){ + /* A->value would be: "98 AMR-WB/16000" */ + if((A_len = tsk_strlen(A->value)) < (fmt_len + 1/*space*/)){ + continue; + } + if((indexof = tsk_strindexOf(A->value, A_len, fmt)) == 0 && (A->value[fmt_len] == ' ')){ + value = tsk_strndup(&A->value[fmt_len+1], (A_len-(fmt_len+1))); + break; + } + } + return value; +} + +/* as per 3GPP TS 34.610 */ +int tsdp_header_M_hold(tsdp_header_M_t* self, tsk_bool_t local) +{ + const tsdp_header_A_t* a; + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if((a = tsdp_header_M_findA(self, local ? "recvonly" : "sendonly"))){ + // an "inactive" SDP attribute if the stream was previously set to "recvonly" media stream + tsk_strupdate(&(TSDP_HEADER_A(a)->field), local ? "inactive" : "recvonly"); + } + else if((a = tsdp_header_M_findA(self, "sendrecv"))){ + // a "sendonly" SDP attribute if the stream was previously set to "sendrecv" media stream + tsk_strupdate(&(TSDP_HEADER_A(a)->field), local ? "sendonly" : "recvonly"); + } + else{ + // default value is sendrecv. hold on default --> sendonly + if(!(a = tsdp_header_M_findA(self, local ? "sendonly" : "recvonly")) && !(a = tsdp_header_M_findA(self, "inactive"))){ + tsdp_header_A_t* newA; + if((newA = tsdp_header_A_create(local ? "sendonly" : "recvonly", tsk_null))){ + tsdp_header_M_add(self, TSDP_HEADER_CONST(newA)); + TSK_OBJECT_SAFE_FREE(newA); + } + } + } + return 0; +} + +/* as per 3GPP TS 34.610 */ +int tsdp_header_M_set_holdresume_att(tsdp_header_M_t* self, tsk_bool_t lo_held, tsk_bool_t ro_held) +{ + const tsdp_header_A_t* A; + static const char* hold_resume_atts[2][2] = + { + {"sendrecv", "recvonly"}, + {"sendonly", "inactive"}, + }; + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + 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"))){ + tsk_strupdate(&(TSDP_HEADER_A(A)->field), hold_resume_atts[lo_held & 1][ro_held & 1]); + } + else{ + tsdp_header_A_t* newA; + if((newA = tsdp_header_A_create(hold_resume_atts[lo_held & 1][ro_held & 1], tsk_null))){ + tsdp_header_M_add(self, TSDP_HEADER_CONST(newA)); + TSK_OBJECT_SAFE_FREE(newA); + } + } + + return 0; +} + +const char* tsdp_header_M_get_holdresume_att(const tsdp_header_M_t* self) +{ + static const char* hold_resume_atts[4] = {"sendrecv"/*first because most likely to be present*/, "recvonly", "sendonly", "inactive"}; + static tsk_size_t hold_resume_atts_count = sizeof(hold_resume_atts)/sizeof(hold_resume_atts[0]); + tsk_size_t i; + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return hold_resume_atts[0]; + } + for(i = 0; i < hold_resume_atts_count; ++i){ + if(tsdp_header_M_findA(self, hold_resume_atts[i])){ + return hold_resume_atts[i]; + } + } + return hold_resume_atts[0]; +} + +tsk_bool_t tsdp_header_M_is_held(const tsdp_header_M_t* self, tsk_bool_t local) +{ + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_false; + } + + /* both cases */ + if(tsdp_header_M_findA(self, "inactive")){ + return tsk_true; + } + + if(local){ + return tsdp_header_M_findA(self, "recvonly") ? tsk_true : tsk_false; + } + else{ + return tsdp_header_M_findA(self, "sendonly") ? tsk_true : tsk_false; + } +} + +/* as per 3GPP TS 34.610 */ +int tsdp_header_M_resume(tsdp_header_M_t* self, tsk_bool_t local) +{ + const tsdp_header_A_t* a; + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if((a = tsdp_header_M_findA(self, "inactive"))){ + // a "recvonly" SDP attribute if the stream was previously an inactive media stream + tsk_strupdate(&(TSDP_HEADER_A(a)->field), local ? "recvonly" : "sendonly"); + } + else if((a = tsdp_header_M_findA(self, local ? "sendonly" : "recvonly"))){ + // a "sendrecv" SDP attribute if the stream was previously a sendonly media stream, or the attribute may be omitted, since sendrecv is the default + tsk_strupdate(&(TSDP_HEADER_A(a)->field), "sendrecv"); + } + return 0; +} + +// +//int tsdp_header_M_set(tsdp_header_M_t* self, ...) +//{ +// int ret = -1; +// va_list params; +// int type; +// +// va_start(params, self); +// +// if(!m){ +// goto bail; +// } +// +// while((type=va_arg(params, int))){ +// switch(type){ +// case 0x01: /* FMT */ +// { +// tsk_string_t* fmt = tsk_string_create(va_arg(values, const char *)); +// if(fmt){ +// tsk_list_push_back_data(sefl->FMTs, (void**)&fmt); +// } +// break; +// } +// case 0x02: /* A */ +// { +// tsdp_header_A_t* A = tsdp_header_A_create(va_arg(values, const char *), va_arg(values, const char *)); +// if(A){ +// if(!M->Attributes){ +// M->Attributes = tsk_list_create(); +// } +// tsk_list_push_back_data(M->Attributes, (void**)&A); +// } +// break; +// } +// } +// } +// +//bail: +// va_end(params); +// return ret; +//} + + + +//======================================================== +// M header object definition +// + +static tsk_object_t* tsdp_header_M_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_M_t *M = self; + if(M){ + TSDP_HEADER(M)->type = tsdp_htype_M; + TSDP_HEADER(M)->tostring = tsdp_header_M_tostring; + TSDP_HEADER(M)->clone = tsdp_header_M_clone; + TSDP_HEADER(M)->rank = TSDP_HTYPE_M_RANK; + + M->FMTs = tsk_list_create(); // Because there is at least one fmt. + + M->media = tsk_strdup(va_arg(*app, const char*)); + M->port = va_arg(*app, uint32_t); + M->proto = tsk_strdup(va_arg(*app, const char*)); + } + else{ + TSK_DEBUG_ERROR("Failed to create new M header."); + } + return self; +} + +static tsk_object_t* tsdp_header_M_dtor(tsk_object_t *self) +{ + tsdp_header_M_t *M = self; + if(M){ + TSK_FREE(M->media); + TSK_FREE(M->proto); + TSK_OBJECT_SAFE_FREE(M->FMTs); + + TSK_OBJECT_SAFE_FREE(M->I); + TSK_OBJECT_SAFE_FREE(M->C); + TSK_OBJECT_SAFE_FREE(M->Bandwidths); + TSK_OBJECT_SAFE_FREE(M->K); + TSK_OBJECT_SAFE_FREE(M->Attributes); + } + else{ + TSK_DEBUG_ERROR("Null M header."); + } + + return self; +} +static int tsdp_header_M_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_M_def_s = +{ + sizeof(tsdp_header_M_t), + tsdp_header_M_ctor, + tsdp_header_M_dtor, + tsdp_header_M_cmp +}; + +const tsk_object_def_t *tsdp_header_M_def_t = &tsdp_header_M_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_O.rl b/tinySDP/ragel/tsdp_parser_header_O.rl new file mode 100644 index 0000000..405676e --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_O.rl @@ -0,0 +1,223 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + +/**@file tsdp_header_O.c + * @brief SDP "o=" header (Origin). + */ +#include "tinysdp/headers/tsdp_header_O.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_O; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_username{ + TSK_PARSER_SET_STRING(hdr_O->username); + } + + action parse_sess_id{ + TSK_PARSER_SET_UINT(hdr_O->sess_id); + } + + action parse_sess_version{ + TSK_PARSER_SET_UINT(hdr_O->sess_version); + } + + action parse_nettype{ + TSK_PARSER_SET_STRING(hdr_O->nettype); + } + + action parse_addrtype{ + TSK_PARSER_SET_STRING(hdr_O->addrtype); + } + + action parse_addr{ + TSK_PARSER_SET_STRING(hdr_O->addr); + } + + username = any*>tag %parse_username; + sess_id = DIGIT+>tag %parse_sess_id; + sess_version = DIGIT+>tag %parse_sess_version; + nettype = any*>tag %parse_nettype; + addrtype = any*>tag %parse_addrtype; + addr = any*>tag %parse_addr; + O = 'o' SP* "=" SP*<: username :>SP sess_id :>SP sess_version :>SP nettype :>SP addrtype :>SP addr; + + # Entry point + main := O :>CRLF?; + +}%% + + + + +tsdp_header_O_t* tsdp_header_O_create(const char* username, uint32_t sess_id, uint32_t sess_version, const char* nettype, const char* addrtype, const char* addr) +{ + return tsk_object_new(TSDP_HEADER_O_VA_ARGS(username, sess_id, sess_version, nettype, addrtype, addr)); +} + +tsdp_header_O_t* tsdp_header_O_create_null() +{ + return tsdp_header_O_create(tsk_null, 0, 0, tsk_null, tsk_null, tsk_null); +} + +tsdp_header_O_t* tsdp_header_O_create_default(const char* username, const char* nettype, const char* addrtype, const char* addr) +{ + return tsdp_header_O_create(username, TSDP_HEADER_O_SESS_ID_DEFAULT, TSDP_HEADER_O_SESS_VERSION_DEFAULT, nettype, addrtype, addr); +} + + +int tsdp_header_O_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header){ + const tsdp_header_O_t *O = (const tsdp_header_O_t *)header; + + // o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com + return tsk_buffer_append_2(output, "%s %u %u %s %s %s", + O->username, + O->sess_id, + O->sess_version, + O->nettype, + O->addrtype, + O->addr + ); + + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_O_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_O_t *O = (const tsdp_header_O_t *)header; + return (tsdp_header_t*)tsdp_header_O_create(O->username, O->sess_id, O->sess_version, O->nettype, O->addrtype, O->addr); + } + return tsk_null; +} + +tsdp_header_O_t *tsdp_header_O_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_O_t *hdr_O = tsdp_header_O_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_O_first_final); + (void)(tsdp_machine_parser_header_O_error); + (void)(tsdp_machine_parser_header_O_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"o=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_O); + } + + return hdr_O; +} + + + + + + + +//======================================================== +// O header object definition +// + +static tsk_object_t* tsdp_header_O_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_O_t *O = self; + if(O){ + TSDP_HEADER(O)->type = tsdp_htype_O; + TSDP_HEADER(O)->tostring = tsdp_header_O_tostring; + TSDP_HEADER(O)->clone = tsdp_header_O_clone; + TSDP_HEADER(O)->rank = TSDP_HTYPE_O_RANK; + + O->username = tsk_strdup(va_arg(*app, const char*)); + O->sess_id = va_arg(*app, uint32_t); + O->sess_version = va_arg(*app, uint32_t); + O->nettype = tsk_strdup(va_arg(*app, const char*)); + O->addrtype = tsk_strdup(va_arg(*app, const char*)); + O->addr = tsk_strdup(va_arg(*app, const char*)); + } + else{ + TSK_DEBUG_ERROR("Failed to create new O header."); + } + return self; +} + +static tsk_object_t* tsdp_header_O_dtor(tsk_object_t *self) +{ + tsdp_header_O_t *O = self; + if(O){ + TSK_FREE(O->username); + TSK_FREE(O->nettype); + TSK_FREE(O->addrtype); + TSK_FREE(O->addr); + } + else{ + TSK_DEBUG_ERROR("Null O header."); + } + + return self; +} +static int tsdp_header_O_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_O_def_s = +{ + sizeof(tsdp_header_O_t), + tsdp_header_O_ctor, + tsdp_header_O_dtor, + tsdp_header_O_cmp +}; + +const tsk_object_def_t *tsdp_header_O_def_t = &tsdp_header_O_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_P.rl b/tinySDP/ragel/tsdp_parser_header_P.rl new file mode 100644 index 0000000..949c892 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_P.rl @@ -0,0 +1,174 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + + +/**@file tsdp_header_P.c + * @brief SDP "p=" header (Phone Number). + */ +#include "tinysdp/headers/tsdp_header_P.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_P; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_value{ + TSK_PARSER_SET_STRING(hdr_P->value); + } + + P = 'p' SP* "=" SP*<: any*>tag %parse_value; + + # Entry point + main := P :>CRLF?; + +}%% + + +tsdp_header_P_t* tsdp_header_P_create(const char* value) +{ + return tsk_object_new(TSDP_HEADER_P_VA_ARGS(value)); +} + +tsdp_header_P_t* tsdp_header_P_create_null() +{ + return tsdp_header_P_create(tsk_null); +} + +int tsdp_header_P_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header){ + const tsdp_header_P_t *P = (const tsdp_header_P_t *)header; + if(P->value){ + tsk_buffer_append(output, P->value, tsk_strlen(P->value)); + } + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_P_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_P_t *P = (const tsdp_header_P_t *)header; + return (tsdp_header_t*)tsdp_header_P_create(P->value); + } + return tsk_null; +} + +tsdp_header_P_t *tsdp_header_P_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_P_t *hdr_P = tsdp_header_P_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_P_first_final); + (void)(tsdp_machine_parser_header_P_error); + (void)(tsdp_machine_parser_header_P_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"p=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_P); + } + + return hdr_P; +} + + + + + + + +//======================================================== +// P header object definition +// + +static tsk_object_t* tsdp_header_P_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_P_t *P = self; + if(P){ + TSDP_HEADER(P)->type = tsdp_htype_P; + TSDP_HEADER(P)->tostring = tsdp_header_P_tostring; + TSDP_HEADER(P)->clone = tsdp_header_P_clone; + TSDP_HEADER(P)->rank = TSDP_HTYPE_P_RANK; + + P->value = tsk_strdup(va_arg(*app, const char*)); + } + else{ + TSK_DEBUG_ERROR("Failed to create new P header."); + } + return self; +} + +static tsk_object_t* tsdp_header_P_dtor(tsk_object_t *self) +{ + tsdp_header_P_t *P = self; + if(P){ + TSK_FREE(P->value); + } + else{ + TSK_DEBUG_ERROR("Null P header."); + } + + return self; +} +static int tsdp_header_P_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_P_def_s = +{ + sizeof(tsdp_header_P_t), + tsdp_header_P_ctor, + tsdp_header_P_dtor, + tsdp_header_P_cmp +}; + +const tsk_object_def_t *tsdp_header_P_def_t = &tsdp_header_P_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_R.rl b/tinySDP/ragel/tsdp_parser_header_R.rl new file mode 100644 index 0000000..22507b3 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_R.rl @@ -0,0 +1,215 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + + +/**@file tsdp_header_R.c + * @brief SDP "r=" header (Repeat Times). + * + */ +#include "tinysdp/headers/tsdp_header_R.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_R; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_repeat_interval{ + TSK_PARSER_SET_STRING(hdr_R->repeat_interval); + } + + action parse_typed_time{ + if(!hdr_R->typed_time){ + TSK_PARSER_SET_STRING(hdr_R->typed_time); + } + else{ + TSK_PARSER_ADD_STRING(hdr_R->typed_times); + } + } + + fixed_len_time_unit = "d" | "h" | "m" | "s"; + + repeat_interval = (DIGIT+ fixed_len_time_unit?) >tag %parse_repeat_interval; + typed_time = (DIGIT+ fixed_len_time_unit?) >tag %parse_typed_time; + + R = 'r' SP* "=" SP*<: repeat_interval :>SP typed_time (SP<: typed_time)+; + + # Entry point + main := R :>CRLF?; + +}%% + + + +tsdp_header_R_t* tsdp_header_R_create() +{ + return tsk_object_new(TSDP_HEADER_R_VA_ARGS()); +} + +tsdp_header_R_t* tsdp_header_R_create_null() +{ + return tsdp_header_R_create(); +} + +int tsdp_header_R_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header){ + const tsdp_header_R_t *R = (const tsdp_header_R_t *)header; + const tsk_list_item_t* item; + + // r=7d 1h 0 25h + tsk_buffer_append_2(output, "%s %s", + R->repeat_interval, + R->typed_time + ); + tsk_list_foreach(item, R->typed_times){ + tsk_string_t* string = item->data; + tsk_buffer_append_2(output, " %s", TSK_STRING_STR(string)); + } + + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_R_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_R_t *R = (const tsdp_header_R_t *)header; + tsdp_header_R_t* clone; + const tsk_list_item_t* item; + + if((clone = tsdp_header_R_create_null())){ + clone->repeat_interval = tsk_strdup(R->repeat_interval); + clone->typed_time = tsk_strdup(R->typed_time); + + if(R->typed_times){ + clone->typed_times = tsk_list_create(); + } + + tsk_list_foreach(item, R->typed_times){ + tsk_string_t* string = tsk_string_create(TSK_STRING_STR(item->data)); + tsk_list_push_back_data(clone->typed_times, (void**)&string); + } + } + return TSDP_HEADER(clone); + } + return tsk_null; +} + +tsdp_header_R_t *tsdp_header_R_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_R_t *hdr_R = tsdp_header_R_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_R_first_final); + (void)(tsdp_machine_parser_header_R_error); + (void)(tsdp_machine_parser_header_R_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"r=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_R); + } + + return hdr_R; +} + + + + + + + +//======================================================== +// E header object definition +// + +static tsk_object_t* tsdp_header_R_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_R_t *R = self; + if(R){ + TSDP_HEADER(R)->type = tsdp_htype_R; + TSDP_HEADER(R)->tostring = tsdp_header_R_tostring; + TSDP_HEADER(R)->clone = tsdp_header_R_clone; + TSDP_HEADER(R)->rank = TSDP_HTYPE_R_RANK; + } + else{ + TSK_DEBUG_ERROR("Failed to create new E header."); + } + return self; +} + +static tsk_object_t* tsdp_header_R_dtor(tsk_object_t *self) +{ + tsdp_header_R_t *R = self; + if(R){ + TSK_FREE(R->repeat_interval); + TSK_FREE(R->typed_time); + TSK_OBJECT_SAFE_FREE(R->typed_times); + } + else{ + TSK_DEBUG_ERROR("Null R header."); + } + + return self; +} +static int tsdp_header_R_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_R_def_s = +{ + sizeof(tsdp_header_R_t), + tsdp_header_R_ctor, + tsdp_header_R_dtor, + tsdp_header_R_cmp +}; + +const tsk_object_def_t *tsdp_header_R_def_t = &tsdp_header_R_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_S.rl b/tinySDP/ragel/tsdp_parser_header_S.rl new file mode 100644 index 0000000..1b7e562 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_S.rl @@ -0,0 +1,172 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + +/**@file tsdp_header_S.c + * @brief SDP "s=" header (Session Name). + */ +#include "tinysdp/headers/tsdp_header_S.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_S; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_value{ + TSK_PARSER_SET_STRING(hdr_S->value); + } + + S = 's' SP* "=" SP*<: any*>tag %parse_value; + + # Entry point + main := S :>CRLF?; + +}%% + + +tsdp_header_S_t* tsdp_header_S_create(const char* value) +{ + return tsk_object_new(TSDP_HEADER_S_VA_ARGS(value)); +} +tsdp_header_S_t* tsdp_header_S_create_null() +{ + return tsdp_header_S_create(tsk_null); +} + +int tsdp_header_S_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header) + { + const tsdp_header_S_t *S = (const tsdp_header_S_t *)header; + if(S->value){ + tsk_buffer_append(output, S->value, tsk_strlen(S->value)); + } + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_S_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_S_t *S = (const tsdp_header_S_t *)header; + return (tsdp_header_t*)tsdp_header_S_create(S->value); + } + return tsk_null; +} + +tsdp_header_S_t *tsdp_header_S_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_S_t *hdr_S = tsdp_header_S_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_S_first_final); + (void)(tsdp_machine_parser_header_S_error); + (void)(tsdp_machine_parser_header_S_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_OBJECT_SAFE_FREE(hdr_S); + } + + return hdr_S; +} + + + + + + + +//======================================================== +// S header object definition +// + +static tsk_object_t* tsdp_header_S_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_S_t *S = self; + if(S){ + TSDP_HEADER(S)->type = tsdp_htype_S; + TSDP_HEADER(S)->tostring = tsdp_header_S_tostring; + TSDP_HEADER(S)->clone = tsdp_header_S_clone; + TSDP_HEADER(S)->rank = TSDP_HTYPE_S_RANK; + + S->value = tsk_strdup(va_arg(*app, const char*)); + } + else{ + TSK_DEBUG_ERROR("Failed to create new S header."); + } + return self; +} + +static tsk_object_t* tsdp_header_S_dtor(tsk_object_t *self) +{ + tsdp_header_S_t *S = self; + if(S){ + TSK_FREE(S->value); + } + else{ + TSK_DEBUG_ERROR("Null S header."); + } + + return self; +} +static int tsdp_header_S_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_S_def_s = +{ + sizeof(tsdp_header_S_t), + tsdp_header_S_ctor, + tsdp_header_S_dtor, + tsdp_header_S_cmp +}; + +const tsk_object_def_t *tsdp_header_S_def_t = &tsdp_header_S_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_T.rl b/tinySDP/ragel/tsdp_parser_header_T.rl new file mode 100644 index 0000000..044178d --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_T.rl @@ -0,0 +1,226 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + +/**@file tsdp_header_T.c + * @brief SDP "t=" header (Timing). + */ +#include "tinysdp/headers/tsdp_header_T.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_T; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_start_time{ + TSK_PARSER_SET_INTEGER_EX(hdr_T->start, uint64_t, atoi64); + } + + action parse_stop_time{ + TSK_PARSER_SET_INTEGER_EX(hdr_T->stop, uint64_t, atoi64); + } + + action parse_repeat_fields{ + tsdp_header_R_t* header_R; + if((header_R = tsdp_header_R_parse(tag_start, (p - tag_start)))){ + if(!hdr_T->repeat_fields){ + hdr_T->repeat_fields = tsk_list_create(); + } + tsk_list_push_back_data(hdr_T->repeat_fields, (void**)&header_R); + } + } + + start_time = DIGIT+ >tag %parse_start_time; + stop_time = DIGIT+ >tag %parse_stop_time; + repeat_fields = any+ >tag %parse_repeat_fields; + + T = 't' SP* "=" SP*<: start_time :>SP stop_time (CRLF <:repeat_fields)?; + + # Entry point + main := T :>CRLF?; + +}%% + + +tsdp_header_T_t* tsdp_header_T_create(uint64_t start, uint64_t stop) +{ + return tsk_object_new(TSDP_HEADER_T_VA_ARGS(start, stop)); +} + +tsdp_header_T_t* tsdp_header_T_create_null() +{ + return tsdp_header_T_create(0, 0); +} + +int tsdp_header_T_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header) + { + const tsdp_header_T_t *T = (const tsdp_header_T_t *)header; + const tsk_list_item_t *item; + + //"t=3034423619 3042462419\r\n" + //"r=7d 1h 0 25h\r\n" + // IMPORTANT: Do not append the last CRLF (because we only print the header value). + tsk_buffer_append_2(output, "%llu %llu", + T->start, + T->stop + ); + + tsk_list_foreach(item, T->repeat_fields) + { + if(TSK_LIST_IS_FIRST(T->repeat_fields, item)){ + tsk_buffer_append(output, "\r\n", 2); + } + tsk_buffer_append_2(output, "%c=", tsdp_header_get_nameex(TSDP_HEADER(item->data))); + TSDP_HEADER(item->data)->tostring(TSDP_HEADER(item->data), output); + //tsdp_header_tostring(TSDP_HEADER(item->data), output); + + if(!TSK_LIST_IS_LAST(T->repeat_fields, item)){ + tsk_buffer_append(output, "\r\n", 2); + } + } + + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_T_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_T_t *T = (const tsdp_header_T_t *)header; + tsdp_header_T_t* clone; + const tsk_list_item_t *item; + + if((clone = tsdp_header_T_create(T->start, T->stop))){ + + if(T->repeat_fields){ + clone->repeat_fields = tsk_list_create(); + } + + tsk_list_foreach(item, T->repeat_fields){ + const tsdp_header_t* curr = item->data; + tsdp_header_t* hdr_clone = curr->clone(curr); + tsk_list_push_back_data(clone->repeat_fields, (void**)&hdr_clone); + } + } + return TSDP_HEADER(clone); + } + return tsk_null; +} + +tsdp_header_T_t *tsdp_header_T_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_T_t *hdr_T = tsdp_header_T_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_T_first_final); + (void)(tsdp_machine_parser_header_T_error); + (void)(tsdp_machine_parser_header_T_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"t=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_T); + } + + return hdr_T; +} + + + + + + + +//======================================================== +// T header object definition +// + +static tsk_object_t* tsdp_header_T_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_T_t *T = self; + if(T){ + TSDP_HEADER(T)->type = tsdp_htype_T; + TSDP_HEADER(T)->tostring = tsdp_header_T_tostring; + TSDP_HEADER(T)->clone = tsdp_header_T_clone; + TSDP_HEADER(T)->rank = TSDP_HTYPE_T_RANK; + } + else{ + TSK_DEBUG_ERROR("Failed to create new U header."); + } + return self; +} + +static tsk_object_t* tsdp_header_T_dtor(tsk_object_t *self) +{ + tsdp_header_T_t *T = self; + if(T){ + TSK_OBJECT_SAFE_FREE(T->repeat_fields); + } + else{ + TSK_DEBUG_ERROR("Null U header."); + } + + return self; +} +static int tsdp_header_T_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_T_def_s = +{ + sizeof(tsdp_header_T_t), + tsdp_header_T_ctor, + tsdp_header_T_dtor, + tsdp_header_T_cmp +}; + +const tsk_object_def_t *tsdp_header_T_def_t = &tsdp_header_T_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_U.rl b/tinySDP/ragel/tsdp_parser_header_U.rl new file mode 100644 index 0000000..026754b --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_U.rl @@ -0,0 +1,176 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + +/**@file tsdp_header_U.c + * @brief SDP "u=" header (URI). + */ +#include "tinysdp/headers/tsdp_header_U.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_U; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_value{ + TSK_PARSER_SET_STRING(hdr_U->value); + } + + U = 'u' SP* "=" SP*<: any*>tag %parse_value; + + # Entry point + main := U :>CRLF?; + +}%% + + + +tsdp_header_U_t* tsdp_header_U_create(const char* value) +{ + return tsk_object_new(TSDP_HEADER_U_VA_ARGS(value)); +} + +tsdp_header_U_t* tsdp_header_U_create_null() +{ + return tsdp_header_U_create(tsk_null); +} + +int tsdp_header_U_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header) + { + const tsdp_header_U_t *U = (const tsdp_header_U_t *)header; + if(U->value){ + tsk_buffer_append(output, U->value, tsk_strlen(U->value)); + } + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_U_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_U_t *U = (const tsdp_header_U_t *)header; + return (tsdp_header_t*)tsdp_header_U_create(U->value); + } + return tsk_null; +} + +tsdp_header_U_t *tsdp_header_U_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_U_t *hdr_U = tsdp_header_U_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_U_first_final); + (void)(tsdp_machine_parser_header_U_error); + (void)(tsdp_machine_parser_header_U_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"u=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_U); + } + + return hdr_U; +} + + + + + + + +//======================================================== +// U header object definition +// + +static tsk_object_t* tsdp_header_U_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_U_t *U = self; + if(U) + { + TSDP_HEADER(U)->type = tsdp_htype_U; + TSDP_HEADER(U)->tostring = tsdp_header_U_tostring; + TSDP_HEADER(U)->clone = tsdp_header_U_clone; + TSDP_HEADER(U)->rank = TSDP_HTYPE_U_RANK; + + U->value = tsk_strdup(va_arg(*app, const char*)); + } + else{ + TSK_DEBUG_ERROR("Failed to create new U header."); + } + return self; +} + +static tsk_object_t* tsdp_header_U_dtor(tsk_object_t *self) +{ + tsdp_header_U_t *U = self; + if(U){ + TSK_FREE(U->value); + } + else{ + TSK_DEBUG_ERROR("Null U header."); + } + + return self; +} +static int tsdp_header_U_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_U_def_s = +{ + sizeof(tsdp_header_U_t), + tsdp_header_U_ctor, + tsdp_header_U_dtor, + tsdp_header_U_cmp +}; + +const tsk_object_def_t *tsdp_header_U_def_t = &tsdp_header_U_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_V.rl b/tinySDP/ragel/tsdp_parser_header_V.rl new file mode 100644 index 0000000..6b66963 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_V.rl @@ -0,0 +1,173 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + +/**@file tsdp_header_V.c + * @brief SDP "v=" header (Protocol Version). + */ +#include "tinysdp/headers/tsdp_header_V.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_V; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action parse_version{ + TSK_PARSER_SET_INT(hdr_V->version); + } + + V = 'v' SP* "=" SP*<: DIGIT+>tag %parse_version; + + # Entry point + main := V :>CRLF?; + +}%% + + +tsdp_header_V_t* tsdp_header_V_create(int32_t version) +{ + return tsk_object_new(TSDP_HEADER_V_VA_ARGS(version)); +} + +tsdp_header_V_t* tsdp_header_V_create_null() +{ + return tsdp_header_V_create(TSDP_HEADER_V_DEFAULT); +} + +int tsdp_header_V_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header) + { + const tsdp_header_V_t *V = (const tsdp_header_V_t *)header; + if(V->version >=0){ + tsk_buffer_append_2(output, "%d", V->version); + } + return 0; + } + + return -1; +} + +tsdp_header_t* tsdp_header_V_clone(const tsdp_header_t* header) +{ + if(header){ + const tsdp_header_V_t *V = (const tsdp_header_V_t *)header; + return (tsdp_header_t*)tsdp_header_V_create(V->version); + } + return tsk_null; +} + +tsdp_header_V_t *tsdp_header_V_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_V_t *hdr_V = tsdp_header_V_create_null(); + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_V_first_final); + (void)(tsdp_machine_parser_header_V_error); + (void)(tsdp_machine_parser_header_V_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"v=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_V); + } + + return hdr_V; +} + + + + + + + +//======================================================== +// V header object definition +// + +static tsk_object_t* tsdp_header_V_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_V_t *V = self; + if(V){ + TSDP_HEADER(V)->type = tsdp_htype_V; + TSDP_HEADER(V)->tostring = tsdp_header_V_tostring; + TSDP_HEADER(V)->clone = tsdp_header_V_clone; + TSDP_HEADER(V)->rank = TSDP_HTYPE_V_RANK; + + V->version = va_arg(*app, int32_t); + } + else{ + TSK_DEBUG_ERROR("Failed to create new V header."); + } + return self; +} + +static tsk_object_t* tsdp_header_V_dtor(tsk_object_t *self) +{ + tsdp_header_V_t *V = self; + if(V){ + } + else{ + TSK_DEBUG_ERROR("Null V header."); + } + + return self; +} +static int tsdp_header_V_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_V_def_s = +{ + sizeof(tsdp_header_V_t), + tsdp_header_V_ctor, + tsdp_header_V_dtor, + tsdp_header_V_cmp +}; + +const tsk_object_def_t *tsdp_header_V_def_t = &tsdp_header_V_def_s; diff --git a/tinySDP/ragel/tsdp_parser_header_Z.rl b/tinySDP/ragel/tsdp_parser_header_Z.rl new file mode 100644 index 0000000..85c90b9 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_header_Z.rl @@ -0,0 +1,277 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + + +/**@file tsdp_header_Z.c + * @brief SDP "z=" header (Time Zones). + * + */ +#include "tinysdp/headers/tsdp_header_Z.h" + +#include "tsk_debug.h" +#include "tsk_memory.h" +#include "tsk_string.h" + +#include <string.h> + +/*********************************** +* Ragel state machine. +*/ +%%{ + machine tsdp_machine_parser_header_Z; + + # Includes + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + action create_zone{ + if(!zone){ + zone = tsdp_zone_create_null(); + } + } + + action add_zone{ + if(zone){ + tsk_list_push_back_data(hdr_Z->zones,(void**)&zone); + } + } + + action parse_time{ + if(zone){ + TSK_PARSER_SET_INTEGER_EX(zone->time, uint64_t, atoi64); + } + } + + action parse_typed_time{ + if(zone){ + TSK_PARSER_SET_STRING(zone->typed_time); + } + } + + action shifted{ + if(zone){ + zone->shifted_back = tsk_true; + } + } + + fixed_len_time_unit = "d" | "h" | "m" | "s"; + + time = DIGIT+ >tag %parse_time; + typed_time = (DIGIT+ fixed_len_time_unit?) >tag %parse_typed_time; + + Z = 'z' SP* "=" (time SP ("-"%shifted)? typed_time) >create_zone %add_zone + (SP time SP ("-"%shifted)? typed_time)* >create_zone %add_zone; + + # Entry point + main := Z :>CRLF?; + +}%% + + +tsdp_header_Z_t* tsdp_header_Z_create(uint64_t time, tsk_bool_t shifted_back, const char* typed_time) +{ + return tsk_object_new(TSDP_HEADER_Z_VA_ARGS(time, shifted_back, typed_time)); +} + +tsdp_header_Z_t* tsdp_header_Z_create_null() +{ + return tsdp_header_Z_create(0L, tsk_false, tsk_null); +} + + +tsdp_zone_t* tsdp_zone_create(uint64_t time, tsk_bool_t shifted_back, const char* typed_time) +{ + return tsk_object_new(tsdp_zone_def_t, time, shifted_back, typed_time); +} + +tsdp_zone_t* tsdp_zone_create_null() +{ + return tsdp_zone_create(0L, tsk_false, tsk_null); +} + +int tsdp_header_Z_tostring(const tsdp_header_t* header, tsk_buffer_t* output) +{ + if(header){ + const tsdp_header_Z_t *Z = (const tsdp_header_Z_t *)header; + const tsk_list_item_t *item; + const tsdp_zone_t* zone; + + tsk_list_foreach(item, Z->zones){ + zone = (const tsdp_zone_t*)item->data; + // time SP ["-"] typed-time + tsk_buffer_append_2(output, "%s%llu %s%s", + TSK_LIST_IS_FIRST(Z->zones, item) ? "" : " ", + zone->time, + zone->shifted_back ? "-" : "", + zone->typed_time + ); + } + } + + return -1; +} + +tsdp_header_Z_t *tsdp_header_Z_parse(const char *data, tsk_size_t size) +{ + int cs = 0; + const char *p = data; + const char *pe = p + size; + const char *eof = pe; + tsdp_header_Z_t *hdr_Z = tsdp_header_Z_create_null(); + tsdp_zone_t* zone = tsk_null; + + const char *tag_start = tsk_null; + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + %%write data; + (void)(tsdp_machine_parser_header_Z_first_final); + (void)(tsdp_machine_parser_header_Z_error); + (void)(tsdp_machine_parser_header_Z_en_main); + %%write init; + %%write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + if(zone){ + TSK_OBJECT_SAFE_FREE(zone); + } + + if( cs < %%{ write first_final; }%% ){ + TSK_DEBUG_ERROR("Failed to parse \"z=\" header."); + TSK_OBJECT_SAFE_FREE(hdr_Z); + } + + return hdr_Z; +} + + + + + + + +//======================================================== +// Z header object definition +// + +static tsk_object_t* tsdp_header_Z_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_header_Z_t *Z = self; + if(Z){ + TSDP_HEADER(Z)->type = tsdp_htype_Z; + TSDP_HEADER(Z)->tostring = tsdp_header_Z_tostring; + TSDP_HEADER(Z)->rank = TSDP_HTYPE_Z_RANK; + + if((Z->zones = tsk_list_create())){ + uint64_t time = va_arg(*app, uint64_t); + unsigned shifted_back = va_arg(*app, unsigned); + const char* typed_time = va_arg(*app, const char*); + + if(typed_time){ + tsdp_zone_t *zone; + if((zone = tsdp_zone_create(time, shifted_back, typed_time))){ + tsk_list_push_back_data(Z->zones,(void**)&zone); + } + } + } + } + else{ + TSK_DEBUG_ERROR("Failed to create new Z header."); + } + return self; +} + +static tsk_object_t* tsdp_header_Z_dtor(tsk_object_t *self) +{ + tsdp_header_Z_t *Z = self; + if(Z){ + TSK_OBJECT_SAFE_FREE(Z->zones); + } + else{ + TSK_DEBUG_ERROR("Null Z header."); + } + + return self; +} +static int tsdp_header_Z_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2) +{ + if(obj1 && obj2){ + return tsdp_header_rank_cmp(obj1, obj2); + } + else{ + return -1; + } +} + +static const tsk_object_def_t tsdp_header_Z_def_s = +{ + sizeof(tsdp_header_Z_t), + tsdp_header_Z_ctor, + tsdp_header_Z_dtor, + tsdp_header_Z_cmp +}; + +const tsk_object_def_t *tsdp_header_Z_def_t = &tsdp_header_Z_def_s; + + + + +//======================================================== +// Zone object definition +// + +static tsk_object_t* tsdp_zone_ctor(tsk_object_t *self, va_list * app) +{ + tsdp_zone_t *zone = self; + if(zone){ + zone->time = va_arg(*app, uint64_t); + zone->shifted_back = va_arg(*app, tsk_bool_t); + zone->typed_time = tsk_strdup( va_arg(*app, const char*) ); + } + else{ + TSK_DEBUG_ERROR("Failed to create new zone object."); + } + return self; +} + +static tsk_object_t* tsdp_zone_dtor(tsk_object_t *self) +{ + tsdp_zone_t *zone = self; + if(zone){ + TSK_FREE(zone->typed_time); + } + else{ + TSK_DEBUG_ERROR("Null zone object."); + } + + return self; +} + +static const tsk_object_def_t tsdp_zone_def_s = +{ + sizeof(tsdp_zone_t), + tsdp_zone_ctor, + tsdp_zone_dtor, + tsk_null +}; + +const tsk_object_def_t *tsdp_zone_def_t = &tsdp_zone_def_s; diff --git a/tinySDP/ragel/tsdp_parser_message.rl b/tinySDP/ragel/tsdp_parser_message.rl new file mode 100644 index 0000000..b09a743 --- /dev/null +++ b/tinySDP/ragel/tsdp_parser_message.rl @@ -0,0 +1,288 @@ +/* +* Copyright (C) 2010-2015 Mamadou Diop. +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +/**@file tsdp_machine_message.rl + * @brief Ragel file. + */ +#include "tinysdp/parsers/tsdp_parser_message.h" + +#include "tinysdp/headers/tsdp_header_A.h" +#include "tinysdp/headers/tsdp_header_B.h" +#include "tinysdp/headers/tsdp_header_C.h" +#include "tinysdp/headers/tsdp_header_Dummy.h" +#include "tinysdp/headers/tsdp_header_E.h" +#include "tinysdp/headers/tsdp_header_I.h" +#include "tinysdp/headers/tsdp_header_K.h" +#include "tinysdp/headers/tsdp_header_M.h" +#include "tinysdp/headers/tsdp_header_O.h" +#include "tinysdp/headers/tsdp_header_P.h" +#include "tinysdp/headers/tsdp_header_R.h" +#include "tinysdp/headers/tsdp_header_S.h" +#include "tinysdp/headers/tsdp_header_T.h" +#include "tinysdp/headers/tsdp_header_U.h" +#include "tinysdp/headers/tsdp_header_V.h" +#include "tinysdp/headers/tsdp_header_Z.h" + +#include "tsk_debug.h" + +%%{ + machine tsdp_machine_message; + + ########################################### + # Includes + ########################################### + include tsdp_machine_utils "./ragel/tsdp_machine_utils.rl"; + + action tag{ + tag_start = p; + } + + ########################################### + # Actions + ########################################### + action parse_header_A{ + if(hdr_M){ + if(!hdr_M->Attributes){ + hdr_M->Attributes = tsk_list_create(); + } + if((header = (tsdp_header_t*)tsdp_header_A_parse(tag_start, (p - tag_start)))){ + tsk_list_push_back_data(hdr_M->Attributes, (void**)&header); + } + } + else if((header = (tsdp_header_t*)tsdp_header_A_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_B{ + if(hdr_M){ + if(!hdr_M->Bandwidths){ + hdr_M->Bandwidths = tsk_list_create(); + } + if((header = (tsdp_header_t*)tsdp_header_B_parse(tag_start, (p - tag_start)))){ + tsk_list_push_back_data(hdr_M->Bandwidths, (void**)&header); + } + } + else if((header = (tsdp_header_t*)tsdp_header_B_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_C{ + if(hdr_M && !hdr_M->C){ + hdr_M->C = tsdp_header_C_parse(tag_start, (p - tag_start)); + } + else if((header = (tsdp_header_t*)tsdp_header_C_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_Dummy{ + if((header = (tsdp_header_t*)tsdp_header_Dummy_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_E{ + if((header = (tsdp_header_t*)tsdp_header_E_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_I{ + if(hdr_M && !hdr_M->I){ + hdr_M->I = tsdp_header_I_parse(tag_start, (p - tag_start)); + } + else if((header = (tsdp_header_t*)tsdp_header_I_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_K{ + if(hdr_M && !hdr_M->K){ + hdr_M->K = tsdp_header_K_parse(tag_start, (p - tag_start)); + } + else if((header = (tsdp_header_t*)tsdp_header_K_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_M{ + if((hdr_M = tsdp_header_M_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, TSDP_HEADER(hdr_M)); + hdr_M = tsk_object_unref(hdr_M); + } + } + + action parse_header_O{ + if((header = (tsdp_header_t*)tsdp_header_O_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_P{ + if((header = (tsdp_header_t*)tsdp_header_P_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_R{ + if((header = (tsdp_header_t*)tsdp_header_R_parse(tag_start, (p - tag_start)))){ + if(hdr_T){ + if(!hdr_T->repeat_fields){ + hdr_T->repeat_fields = tsk_list_create(); + } + tsk_list_push_back_data(hdr_T->repeat_fields, (void**)&header); + } + else{ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + } + + action parse_header_S{ + if((header = (tsdp_header_t*)tsdp_header_S_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_T{ + if((hdr_T = tsdp_header_T_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, TSDP_HEADER(hdr_T)); + hdr_T = tsk_object_unref(hdr_T); + } + } + + action parse_header_U{ + if((header = (tsdp_header_t*)tsdp_header_U_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_V{ + if((header = (tsdp_header_t*)tsdp_header_V_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + action parse_header_Z{ + if((header = (tsdp_header_t*)tsdp_header_Z_parse(tag_start, (p - tag_start)))){ + tsdp_message_add_header(sdp_msg, header); + tsk_object_unref(header); + } + } + + ########################################### + # Headers + ########################################### + + A = "a"i SP* "=" SP*<: any* %parse_header_A :>CRLF; + B = "b"i SP* "=" SP*<: any* %parse_header_B :>CRLF; + C = "c"i SP* "=" SP*<: any* %parse_header_C :>CRLF; + E = "e"i SP* "=" SP*<: any* %parse_header_E :>CRLF; + I = "i"i SP* "=" SP*<: any* %parse_header_I :>CRLF; + K = "k"i SP* "=" SP*<: any* %parse_header_K :>CRLF; + M = "m"i SP* "=" SP*<: any* %parse_header_M :>CRLF; + O = "o"i SP* "=" SP*<: any* %parse_header_O :>CRLF; + P = "p"i SP* "=" SP*<: any* %parse_header_P :>CRLF; + R = "r"i SP* "=" SP*<: any* %parse_header_R :>CRLF; + S = "s"i SP* "=" SP*<: any* %parse_header_S :>CRLF; + T = "t"i SP* "=" SP*<: any* %parse_header_T :>CRLF; + U = "u"i SP* "=" SP*<: any* %parse_header_U :>CRLF; + V = "v"i SP* "=" SP*<: any* %parse_header_V :>CRLF; + Z = "z"i SP* "=" SP*<: any* %parse_header_Z :>CRLF; + + Dummy = alpha SP* "=" SP*<: any* %parse_header_Dummy :>CRLF; + + Header = (A | B | C | E | I | K | M | O | P | R | S | T | U | V | Z)>tag >1 | (Dummy>tag) >0; + + + ########################################### + # Message + ########################################### + SDP_message = Header*; + + ########################################### + # Entry Point + ########################################### + main := SDP_message; +}%% + +TSK_RAGEL_DISABLE_WARNINGS_BEGIN() +/* Ragel data */ +%% write data; +TSK_RAGEL_DISABLE_WARNINGS_END() + +tsdp_message_t* tsdp_message_parse(const void *input, tsk_size_t size) +{ + tsdp_message_t* sdp_msg = tsk_null; + const char* tag_start = tsk_null; + tsdp_header_t *header = tsk_null; + tsdp_header_T_t *hdr_T = tsk_null; + tsdp_header_M_t *hdr_M = tsk_null; + + /* Ragel variables */ + int cs = 0; + const char* p = input; + const char* pe = p + size; + const char* eof = tsk_null; + + (void)(eof); + + if(!input || !size){ + TSK_DEBUG_ERROR("Null or empty buffer."); + goto bail; + } + + if(!(sdp_msg = tsdp_message_create())){ + goto bail; + } + + TSK_RAGEL_DISABLE_WARNINGS_BEGIN() + /* Ragel init */ + %% write init; + + /* Ragel execute */ + %% write exec; + TSK_RAGEL_DISABLE_WARNINGS_END() + + /* Check result */ + if( cs < %%{ write first_final; }%% ) + { + TSK_DEBUG_ERROR("Failed to parse SDP message."); + TSK_OBJECT_SAFE_FREE(sdp_msg); + goto bail; + } + +bail: + return sdp_msg; +} |