📄 msg_parser_util.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@ingroup msg_parser * @CFILE msg_parser_util.c * * Text-message parser helper functions. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Tue Aug 28 16:26:34 2001 ppessi * */#include "config.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <assert.h>#include <limits.h>#include <stdarg.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/su.h>#include <sofia-sip/su_alloc.h>#include "msg_internal.h"#include "sofia-sip/msg_parser.h"#include "sofia-sip/bnf.h"#include "sofia-sip/url.h"static issize_t msg_comma_scanner(char *start);/** * Parse first line. * * Splits the first line from a message into three whitespace-separated * parts. */int msg_firstline_d(char *s, char **return_part2, char **return_part3){ char *s1 = s, *s2, *s3; size_t n; /* Split line into three segments separated by whitespace */ if (s1[n = span_non_ws(s1)]) { s1[n] = '\0'; s2 = s1 + n + 1; while (IS_WS(*s2)) s2++; } else { /* Hopeless - no WS in first line */ return -1; } n = span_non_ws(s2); if (s2[n]) { s2[n++] = '\0'; while (IS_WS(s2[n])) n++; } s3 = s2 + n; *return_part2 = s2; *return_part3 = s3; return 0;}/**Parse a token. * * Parses a token from string pointed by @a *ss. It stores the token value * in @a return_token, and updates the @a ss to the end of token and * possible whitespace. */issize_t msg_token_d(char **ss, char const **return_token) { char *s = *ss; size_t n = span_token(s); if (n) { for (; IS_LWS(s[n]); n++) s[n] = '\0'; *return_token = s; *ss = s + n; return n; } else return -1;}/** Parse a 32-bit unsigned int. * * The function msg_uint32_d() parses a 32-bit unsigned integer in string * pointed by @a *ss. It stores the value in @a return_token and updates the * @a ss to the end of integer and possible whitespace. * * @retval length of parsed integer, or -1 upon an error. */issize_t msg_uint32_d(char **ss, uint32_t *return_value){ char const *s = *ss, *s0 = s; uint32_t value; unsigned digit; if (!IS_DIGIT(*s)) return -1; for (value = 0; IS_DIGIT(*s); s++) { digit = *s - '0'; if (value > 429496729U) return -1; else if (value == 429496729U && digit > 5) return -1; value = 10 * value + digit; } if (*s) { if (!IS_LWS(*s)) return (issize_t)-1; skip_lws(&s); } *ss = (char *)s; *return_value = value; return s - s0;}/** Parse any list. * * Parses a list of items, separated by @a sep. The parsed string is passed * in @a *ss, which is updated to point to the first non-linear-whitespace * character after the list. The function modifies the string as it parses * it. * * The parsed items are appended to the list @a *append_list. If there the * list in @a *append_list is NULL, allocate a new list and return it in @a * *append_list. Empty list items are ignored, and are not appended to the * list. * * The function @b must be passed a scanning function @a scanner. The * scanning function scans for a legitimate list item, for example, a token. * It should also compact the list item, for instance, if the item consists * of @c name=value parameter definitions it should remove whitespace around * "=" sign. The scanning function returns the length of the scanned item, * including any linear whitespace after it. * * @param[in] home memory home for allocating list pointers * @param[in,out] ss pointer to pointer to string to be parsed * @param[in,out] append_list pointer to list * where parsed list items are appended * @param[in] sep separator character * @param[in] scanner pointer to function for scanning a single item * * @retval 0 if successful. * @retval -1 upon an error. */issize_t msg_any_list_d(su_home_t *home, char **ss, msg_param_t **append_list, issize_t (*scanner)(char *s), int sep){ char const *stack[MSG_N_PARAMS]; char const **list = stack, **re_list; size_t N = MSG_N_PARAMS, n = 0; issize_t tlen; char *s = *ss; char const **start; if (!scanner) return -1; if (*append_list) { list = *append_list; while (list[n]) n++; N = MSG_PARAMS_NUM(n + 1); } start = &list[n]; skip_lws(&s); while (*s) { tlen = scanner(s); if (tlen < 0 || (s[tlen] && s[tlen] != sep && s[tlen] != ',')) goto error; if (tlen > 0) { if (n + 1 == N) { /* Reallocate list? */ N = MSG_PARAMS_NUM(N + 1); if (list == stack || list == *append_list) { re_list = su_alloc(home, N * sizeof(*list)); if (re_list) memcpy(re_list, list, n * sizeof(*list)); } else re_list = su_realloc(home, list, N * sizeof(*list)); if (!re_list) goto error; list = re_list; } list[n++] = s; s += tlen; } if (*s == sep) { *s++ = '\0'; skip_lws(&s); } else if (*s) break; } *ss = s; if (n == 0) { *append_list = NULL; return 0; } if (list == stack) { size_t size = sizeof(*list) * MSG_PARAMS_NUM(n + 1); list = su_alloc(home, size); if (!list) return -1; memcpy((void *)list, stack, n * sizeof(*list)); } list[n] = NULL; *append_list = list; return 0; error: *start = NULL; if (list != stack && list != *append_list) su_free(home, list); return -1;}/** Scan an attribute (name [= value]) pair. * * The attribute consists of name (a token) and optional value, separated by * equal sign. The value can be a token or quoted string. * * This function compacts the scanned value. It removes the * whitespace around equal sign "=" by moving the equal sign character and * value towards name. * * If there is whitespace within the scanned value or after it, * NUL-terminates the scanned attribute. * * @retval > 0 number of characters scanned, * including the whitespace within the value * @retval -1 upon an error */issize_t msg_attribute_value_scanner(char *s){ char *p = s; size_t tlen; skip_token(&s); if (s == p) /* invalid parameter name */ return -1; tlen = s - p; if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); } if (*s == '=') { char *v; s++; skip_lws(&s); /* get value */ if (*s == '"') { size_t qlen = span_quoted(s); if (!qlen) return -1; v = s; s += qlen; } else { v = s; skip_param(&s); if (s == v) return -1; } if (p + tlen + 1 != v) { memmove(p + tlen + 1, v, s - v); p[tlen] = '='; p[tlen + 1 + (s - v)] = '\0'; } } if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); } return s - p;}/**Parse an attribute-value list. * * Parses an attribute-value list, which has syntax as follows: * @code * av-list = (av-pair *(";" av-pair) * av-pair = token ["=" ( value / quoted-string) ] ; optional value * @endcode * * @param[in] home pointer to a memory home * @param[in,out] ss pointer to string at the start of parameter list * @param[in,out] append_list pointer to list * where parsed list items are appended * * @retval >= 0 if successful * @retval -1 upon an error */issize_t msg_avlist_d(su_home_t *home, char **ss, msg_param_t const **append_list){ char const *stack[MSG_N_PARAMS]; char const **params; size_t n = 0, N; char *s = *ss; if (!*s) return -1; if (*append_list) { params = (char const **)*append_list; for (n = 0; params[n]; n++) ; N = MSG_PARAMS_NUM(n + 1); } else { params = stack; N = MSG_PARAMS_NUM(1); } for (;;) { char *p; size_t tlen; /* XXX - we should handle also quoted parameters */ skip_lws(&s); p = s; skip_token(&s); tlen = s - p; if (!tlen) /* invalid parameter name */ goto error; if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); } if (*s == '=') { char *v; s++; skip_lws(&s); /* get value */ if (*s == '"') { size_t qlen = span_quoted(s); if (!qlen) goto error; v = s; s += qlen; } else { v = s; skip_param(&s); if (s == v) goto error; } if (p + tlen + 1 != v) { p = memmove(v - tlen - 1, p, tlen); p[tlen] = '='; } } if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); } if (n == N) { /* Reallocate params */ char **nparams = su_alloc(home, (N = MSG_PARAMS_NUM(N + 1)) * sizeof(*params)); if (!nparams) { goto error; } params = memcpy(nparams, params, n * sizeof(*params)); } params[n++] = p; if (*s != ';') break; *s++ = '\0'; } *ss = s; if (params == stack) { size_t size = sizeof(*params) * MSG_PARAMS_NUM(n + 1); params = su_alloc(home, size); if (!params) return -1; memcpy((void *)params, stack, n * sizeof(*params)); } else if (n == N) { /* Reallocate params */ char **nparams = su_alloc(home, (N = MSG_PARAMS_NUM(N + 1)) * sizeof(*params)); if (!nparams) { goto error; } params = memcpy(nparams, params, n * sizeof(*params)); } params[n] = NULL; *append_list = params; return 0; error: if (params != stack) su_free(home, params); return -1;}/**Parse a semicolon-separated parameter list starting with semicolon. * * Parse a parameter list, which has syntax as follows: * @code * *(";" token [ "=" (token | quoted-string)]). * @endcode * * @param[in] home pointer to a memory home * @param[in,out] ss pointer to string at the start of parameter list * @param[in,out] append_list pointer to list * where parsed list items are appended * * @retval >= 0 if successful * @retval -1 upon an error * * @sa msg_avlist_d() */issize_t msg_params_d(su_home_t *home, char **ss, msg_param_t const **append_list){ if (**ss == ';') { *(*ss)++ = '\0'; *append_list = NULL; return msg_avlist_d(home, ss, append_list); } if (IS_LWS(**ss)) { *(*ss)++ = '\0'; skip_lws(ss); } return 0;}/** Encode a list of parameters */isize_t msg_params_e(char b[], isize_t bsiz, msg_param_t const pparams[]){ int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -