📄 sdp_decode.c
字号:
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is MPEG4IP.
*
* The Initial Developer of the Original Code is Cisco Systems Inc.
* Portions created by Cisco Systems Inc. are
* Copyright (C) Cisco Systems Inc. 2000, 2001. All Rights Reserved.
*
* Contributor(s):
* Bill May wmay@cisco.com
*/
/*
* sdp_decode.c
*
* decode SDP format from file into session description structures
* defined in sdp.h
*
* October, 2000
* Bill May (wmay@cisco.com)
* Cisco Systems, Inc.
*/
/*#include "stddefs.h"
#if ((defined ST_7109 || defined ST_7100 )&& defined ST_OSLINUX)
#include "compat.h"
#endif*/
#include "sdp.h"
#include "sdp_decode_private.h"
#include "rtsp_private.h"
#define ADV_SPACE(a) {while (isspace(*(a)) && (*(a) != '\0'))(a)++;}
static const char *SPACES=" \t";
#define FREE_CHECK(a,b,c,d) if (a->b != NULL) { Rtsp_Free(a->b,c,d); a->b = NULL;}
/*****************************************************************************
* Memory free routines - frees memory associated with various structures
*****************************************************************************/
#if 1
static char *strsep (char **sptr, const char *delim)
{
char *start, *ret;
start = ret = *sptr;
if ((ret == NULL) || ret == '\0') {
return (NULL);
}
while (*ret != '\0' &&
strchr(delim, *ret) == NULL) {
ret++;
}
if (*ret == '\0') {
*sptr = NULL;
} else {
*ret = '\0';
ret++;
*sptr = ret;
}
return (start);
}
#endif
static void free_bandwidth_desc (bandwidth_t *bptr)
{
bandwidth_t *q;
while (bptr != NULL) {
q = bptr;
bptr = q->next;
FREE_CHECK(q, user_band,__LINE__,__FILE__);
Rtsp_Free(q,__LINE__,__FILE__);
}
}
static void free_category_list (category_list_t **cptr)
{
category_list_t *p;
if (*cptr == NULL) return;
while (*cptr != NULL) {
p = *cptr;
*cptr = p->next;
Rtsp_Free(p,__LINE__,__FILE__);
}
}
static void free_connect_desc (connect_desc_t *cptr)
{
FREE_CHECK(cptr, conn_type,__LINE__,__FILE__);
FREE_CHECK(cptr, conn_addr,__LINE__,__FILE__);
}
/*
* free_media_desc()
* Frees all memory associated with a media descriptor(mptr)
*/
static void free_media_desc (media_desc_t *mptr)
{
free_bandwidth_desc(mptr->media_bandwidth);
mptr->media_bandwidth = NULL;
free_connect_desc(&mptr->media_connect);
sdp_free_format_list(&mptr->fmt);
sdp_free_string_list(&mptr->unparsed_a_lines);
FREE_CHECK(mptr, media,__LINE__,__FILE__);
FREE_CHECK(mptr, media_desc,__LINE__,__FILE__);
FREE_CHECK(mptr, proto,__LINE__,__FILE__);
FREE_CHECK(mptr, sdplang,__LINE__,__FILE__);
FREE_CHECK(mptr, lang,__LINE__,__FILE__);
FREE_CHECK(mptr, orient_user_type,__LINE__,__FILE__);
FREE_CHECK(mptr, control_string,__LINE__,__FILE__);
FREE_CHECK(mptr, key.key,__LINE__,__FILE__);
mptr->parent = NULL;
Rtsp_Free(mptr,__LINE__,__FILE__);
}
static void free_time_desc (session_time_desc_t *time)
{
time_repeat_desc_t *rptr;
if (time->next != NULL) {
free_time_desc(time->next);
time->next = NULL;
}
while (time->repeat != NULL) {
rptr = time->repeat;
time->repeat = rptr->next;
Rtsp_Free(rptr,__LINE__,__FILE__);
}
Rtsp_Free(time,__LINE__,__FILE__);
}
/*
* sdp_free_session_desc()
* Inputs - sptr - pointer to session_description list to free
*/
void sdp_free_session_desc (session_desc_t *sptr)
{
session_desc_t *p;
media_desc_t *mptr, *q;
p = sptr;
while (p != NULL) {
sptr = p;
p = p->next;
sptr->next = NULL;
mptr = sptr->media;
sptr->media = NULL;
while (mptr != NULL) {
q = mptr;
mptr = q->next;
free_media_desc(q);
}
FREE_CHECK(sptr, etag,__LINE__,__FILE__);
FREE_CHECK(sptr, orig_username,__LINE__,__FILE__);
FREE_CHECK(sptr, control_string,__LINE__,__FILE__);
FREE_CHECK(sptr, create_addr_type,__LINE__,__FILE__);
FREE_CHECK(sptr, create_addr,__LINE__,__FILE__);
FREE_CHECK(sptr, session_name,__LINE__,__FILE__);
FREE_CHECK(sptr, session_desc,__LINE__,__FILE__);
FREE_CHECK(sptr, uri,__LINE__,__FILE__);
FREE_CHECK(sptr, key.key,__LINE__,__FILE__);
FREE_CHECK(sptr, keywds,__LINE__,__FILE__);
FREE_CHECK(sptr, lang,__LINE__,__FILE__);
FREE_CHECK(sptr, tool,__LINE__,__FILE__);
FREE_CHECK(sptr, charset,__LINE__,__FILE__);
FREE_CHECK(sptr, sdplang,__LINE__,__FILE__);
FREE_CHECK(sptr, conf_type_user,__LINE__,__FILE__);
if (sptr->time_desc != NULL) {
free_time_desc(sptr->time_desc);
sptr->time_desc = NULL;
}
free_bandwidth_desc(sptr->session_bandwidth);
sptr->session_bandwidth = NULL;
free_category_list(&sptr->category_list);
free_connect_desc(&sptr->session_connect);
sdp_free_string_list(&sptr->admin_phone);
sdp_free_string_list(&sptr->admin_email);
sdp_free_string_list(&sptr->unparsed_a_lines);
while (sptr->time_adj_desc != NULL) {
time_adj_desc_t *aptr;
aptr = sptr->time_adj_desc;
sptr->time_adj_desc = aptr->next;
Rtsp_Free(aptr,__LINE__,__FILE__);
}
Rtsp_Free(sptr,__LINE__,__FILE__);
}
}
/*****************************************************************************
* Utility routines - string manipulation, etc
*****************************************************************************/
/*
* get_next_line will get the next line to process, and stick it in
* lptr.
*
* Inputs:
* lptr - buffer to store into
* decode - pointer to where to get next line
* buflen - max length of buffer
*
* Outputs:
* TRUE - have a new line.
* FALSE - all done.
*/
static int get_next_line (char **polptr,
sdp_decode_info_t *decode,
uint32_t *buflen)
{
char *fret;
int len;
uint32_t buflen_left;
const char *cptr;
if (decode->isMem) {
cptr = decode->memptr;
if (*cptr == '\0') return FALSE;
while (*cptr != '\0' && *cptr != '\n' && *cptr != '\r') cptr++;
len = cptr - decode->memptr;
if (*buflen <= len + 1) {
if (len > 65535) {
Rtsp_Printf( "Max line length of 65535 exceeded %u\n",
len);
return (FALSE);
}
*polptr = realloc(*polptr, len + 1);
*buflen = len + 1;
}
memcpy(*polptr, decode->memptr, len);
(*polptr)[len] = '\0';
decode->memptr += len;
while (*decode->memptr == '\n' || *decode->memptr == '\r')
decode->memptr++;
} else {
char *ptr;
/* File reads...*/
if (decode->ifile == NULL)
return FALSE;
if (*buflen == 0) {
*polptr = (char *)Rtsp_Malloc(1024,__LINE__,__FILE__);
*buflen = 1024;
}
/* Read file until we hit the end, or a non-blank line read*/
ptr = *polptr;
buflen_left = *buflen;
len = 0;
while (1) {
fret = fgets(ptr, buflen_left, decode->ifile);
if (fret == NULL) {
if (len > 0) {
/* Rtsp_Printf( "Unterminated last line\n");
*/
(*polptr)[len] = '\0'; /* make sure*/
return (TRUE);
}
return (FALSE);
}
len = strlen(ptr);
if (ptr[len - 1] == '\n' || ptr[len - 1] == '\r') {
/* we have an end of line*/
len--;
while (len >= 0 &&
(ptr[len] == '\n' || ptr[len] == '\r')) {
ptr[len] = '\0';
len--;
}
return (TRUE);
}
/* too long...*/
buflen_left -= len;
if (*buflen + 1024 > 65535) {
Rtsp_Printf( "Max line length of 65535 exceeded %u\n",
*buflen);
return (FALSE);
}
*buflen += 1024;
buflen_left += 1024;
*polptr = realloc(*polptr, *buflen);
ptr = *polptr + *buflen - buflen_left;
}
}
return TRUE;
}
/*
* strtou64()
* Converts string to uint32_t number up to next space, with error checking.
* Inputs:
* lptr - pointer to pointer to string. *lptr will be modified
* num - return value
* Outputs - TRUE - sucess, FALSE, failure
*/
static int strtou64 (char **lptr, uint32_t *num)
{
char *sep;
*num = 0;
ADV_SPACE((*lptr));
sep = (char*)strsep(lptr, SPACES);
if (sep == NULL || *lptr == NULL) {
return (FALSE);
}
*num = 0;
while (*sep != '\0') {
if (isdigit(*sep)) {
*num *= 10;
*num += *sep - '0';
sep++;
} else {
return (FALSE);
}
}
return (TRUE);
}
/*
* str_to_time_offset()
* converts typed-time field (number or [#d][#h][#m][#s])
*
* Inputs -
* str - \0 terminated string to translate
* retval - pointer to return value
* Returns -
* TRUE - valid string processed;
* FALSE - invalid string
*/
static int str_to_time_offset (const char *str, uint32_t *retval)
{
uint32_t value;
uint32_t accum;
char temp;
value = 0;
accum = 0;
if (!isdigit(*str)) return (FALSE);
while (*str != '\0') {
if (isdigit(*str)) {
accum *= 10;
accum += (*str - '0');
} else {
temp = tolower(*str);
if (temp == 'd') {
value += accum * SEC_PER_DAY;
accum = 0;
} else if (temp == 'h') {
value += accum * SEC_PER_HOUR;
accum = 0;
} else if (temp == 'm') {
value += accum * SEC_PER_MINUTE;
accum = 0;
} else if (temp == 's') {
value += accum;
accum = 0;
} else {
Rtsp_Printf( "Illegal character %c in time offset\n", temp);
return (FALSE);
}
}
str++;
}
value += accum;
*retval = value;
return (TRUE);
}
/*
* time_adj_order_in_list()
* order linked list by adj_time values. We don't allow 2 items in the
* list - "new" value might be free'd at end
* Inputs:
* start - pointer to start of list
* new - pointer to new value
* Returns:
* pointer to head of list - new value might be free'd.
*/
static time_adj_desc_t *time_adj_order_in_list (time_adj_desc_t *start,
time_adj_desc_t *new)
{
time_adj_desc_t *p, *q;
if (start == NULL)
return (new);
p = start;
q = NULL;
while (p != NULL) {
if (new->adj_time == p->adj_time) {
Rtsp_Printf( "Duplicate time %ld in adj description\n", p->adj_time);
Rtsp_Free(new,__LINE__,__FILE__);
return (start);
}
if (new->adj_time < p->adj_time) {
new->next = p;
if (q == NULL) {
return (new);
} else {
q->next = new;
return (start);
}
}
q = p;
p = p->next;
}
q->next = new;
return (start);
}
/*****************************************************************************
* Line parsing routines
*****************************************************************************/
/*
* sdp_decode_parse_a_bool()
* parses a boolean field.
*/
static int sdp_decode_parse_a_bool (int arg,
char *lptr,
session_desc_t *sptr,
media_desc_t *mptr)
{
switch (arg) {
case 0:
if (mptr != NULL) mptr->recvonly = TRUE;
else sptr->recvonly = TRUE;
break;
case 1:
if (mptr != NULL) mptr->sendrecv = TRUE;
else sptr->sendrecv = TRUE;
break;
case 2:
if (mptr != NULL) mptr->sendonly = TRUE;
else sptr->sendonly = TRUE;
break;
}
return (0);
}
/*
* sdp_decode_parse_a_rtpmap()
* parses a=rtpmap:<fmt> <name>/<clockrate>[/<enc_param>]
*/
static int sdp_decode_parse_a_fmtp (int arg,
char *lptr,
session_desc_t *sptr,
media_desc_t *mptr)
{
format_list_t *fptr;
int len;
if (mptr == NULL)
return (-1);
/*
* See our format matches a value in the media's format list.
*/
fptr = sdp_find_format_in_line(mptr->fmt,lptr) ;
if (fptr == NULL) {
Rtsp_Printf( "Can't find fmtp format %s in media format list\n", lptr);
return (-1);
}
len = strlen(fptr->fmt);
lptr += len;
lptr++;
ADV_SPACE(lptr);
fptr->fmt_param = strdup(lptr);
if (fptr->fmt_param == NULL) {
return (-1);
}
return (0);
}
/*
* sdp_decode_parse_a_rtpmap()
* parses a=rtpmap:<fmt> <name>/<clockrate>[/<enc_param>]
*/
static int sdp_decode_parse_a_rtpmap (int arg,
char *lptr,
session_desc_t *sptr,
media_desc_t *mptr)
{
char *enc, *slash, *temp;
format_list_t *fptr;
int len;
uint32_t a, b;
if (mptr == NULL)
return (-1);
/*
* See our format matches a value in the media's format list.
*/
fptr = sdp_find_format_in_line(mptr->fmt,lptr) ;
if (fptr == NULL) {
Rtsp_Printf( "Can't find rtpmap format %s in media list\n", lptr);
return (-1);
}
len = strlen(fptr->fmt);
/*
* Matches entry left in fptr. Decode rest of line
*/
enc = lptr + len;
ADV_SPACE(enc);
slash = strchr(enc, '/');
if (slash != NULL) {
*slash++ = '\0';
temp = enc;
while ((!(isspace(*temp))) && *temp != '\0') temp++;
*temp = '\0';
/* enc points to encode name*/
ADV_SPACE(slash);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -