📄 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 int 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; int 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. */int msg_token_d(char **ss, char const **return_token) { char *s = *ss; int n = span_token(s); if (n) { for (; IS_LWS(s[n]); n++) s[n] = '\0'; *return_token = s; *ss = s + n; return 0; } 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. */int 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 -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. * * A pointer to the resulting list is returned in the return-value parameter * @a return_list. If there already is a list in @a return_list, new items * are appended. Empty list items are ignored, and are not included in the * list. * * The function 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. The scanning function returns the * length of the scanned item, including any linear whitespace after it. * * @param home memory home used to allocate memory for list pointers [IN] * @param ss pointer to pointer to string to be parsed [IN/OUT] * @param return_list return-value parameter for parsed list [IN/OUT] * @param sep separator character [IN] * @param scanner pointer to function scanning a single item (optional) [IN] * * @retval 0 if successful. * @retval -1 upon an error. */int msg_any_list_d(su_home_t *home, char **ss, msg_param_t **return_list, int (*scanner)(char *s), int sep){ char const *auto_list[MSG_N_PARAMS]; char const **list = auto_list, **re_list; int N = MSG_N_PARAMS, n = 0, tlen; char *s = *ss; char const **start; if (!scanner) return -1; if (*return_list) { list = *return_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 == auto_list || list == *return_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 && list == auto_list) { int size = sizeof(*list) * MSG_PARAMS_NUM(n + 1); list = su_alloc(home, size); if (!list) return -1; memcpy((void *)list, auto_list, n * sizeof(*list)); } list[n] = NULL; if (n == 0) list = NULL; *return_list = list; return 0; error: *start = NULL; if (list != auto_list && list != *return_list) su_free(home, list); return -1;}/** Scan an attribute [= value] pair */int msg_attribute_value_scanner(char *s){ char *p = s; unsigned 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 == '"') { int 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 home pointer to a memory home [IN] * @param ss pointer to string at the start of parameter list [IN/OUT] * @param return_list return-value parameter for parsed list [IN/OUT] * * @retval 0 if successful * @retval -1 upon an error */int msg_avlist_d(su_home_t *home, char **ss, msg_param_t const **return_list){ char const *stack[MSG_N_PARAMS]; int N; char const **params; int n = 0; char *s = *ss; if (!*s) return -1; if (*return_list) { params = (char const **)*return_list; for (n = 0; params[n]; n++) ; N = MSG_PARAMS_NUM(n + 1); } else { params = stack; N = MSG_PARAMS_NUM(1); } for (;;) { char *p; int 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 == '"') { int 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) { int 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; *return_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 home pointer to a memory home [IN] * @param ss pointer to string at the start of parameter list [IN/OUT] * @param return_list return-value parameter for the parsed list [IN/OUT] * * @retval 0 if successful * @retval -1 upon an error * * @sa msg_avlist_d() */int msg_params_d(su_home_t *home, char **ss, msg_param_t const **return_list){ if (**ss == ';') { *(*ss)++ = '\0'; *return_list = NULL; return msg_avlist_d(home, ss, return_list); } if (IS_LWS(**ss)) { *(*ss)++ = '\0'; skip_lws(ss); } return 0;}/** Encode a list of parameters */int msg_params_e(char b[], int bsiz, msg_param_t const pparams[]){ int i; char *end = b + bsiz, *b0 = b; msg_param_t p; if (pparams) for (i = 0; (p = pparams[i]); i++) { if (p[0]) { MSG_CHAR_E(b, end, ';'); MSG_STRING_E(b, end, p); } } return b - b0;}/** Duplicate a parameter list */char *msg_params_dup(msg_param_t const **d, msg_param_t const s[], char *b, int xtra){ char *end = b + xtra; char **pp; int i, n; n = msg_params_count(s); if (n == 0) { *d = NULL; return b; } MSG_STRUCT_ALIGN(b); pp = (char **)b; b += sizeof(*pp) * MSG_PARAMS_NUM(n + 1); for (i = 0; s[i]; i++) { MSG_STRING_DUP(b, pp[i], s[i]); } pp[i] = NULL; assert(b <= end); *d = (msg_param_t const *)pp; return b;} /** Parse a comma-separated list. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -