pjsip_hdr* parse_hdr_session_expires(pjsip_parse_ctx* ctx) { pj_pool_t* pool = ctx->pool; pj_scanner* scanner = ctx->scanner; pjsip_session_expires_hdr* hdr = pjsip_session_expires_hdr_create(pool); const pjsip_parser_const_t* pc = pjsip_parser_const(); // Parse the expiry number pj_str_t int_str; pj_scan_get(scanner, &pc->pjsip_DIGIT_SPEC, &int_str); hdr->expires = pj_strtoul(&int_str); pj_scan_skip_whitespace(scanner); // Parse the rest of the params, looking for the refresher param while (*scanner->curptr == ';') { // Consume the ';'. pj_scan_get_char(scanner); pj_scan_skip_whitespace(scanner); // Parse the param. pj_str_t name; pj_str_t value; pjsip_parse_param_imp(scanner, pool, &name, &value, PJSIP_PARSE_REMOVE_QUOTE); if (!pj_stricmp2(&name, "refresher")) { if (!pj_stricmp2(&value, "uac")) { hdr->refresher = SESSION_REFRESHER_UAC; } else if (!pj_stricmp2(&value, "uas")) { hdr->refresher = SESSION_REFRESHER_UAS; } else { PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); // LCOV_EXCL_LINE } } else { pjsip_param* param = PJ_POOL_ALLOC_T(pool, pjsip_param); param->name = name; param->value = value; pj_list_insert_before(&hdr->other_param, param); } } // We're done parsing this header. pjsip_parse_end_hdr_imp(scanner); return (pjsip_hdr*)hdr; }
PJ_DEF(void) pj_scan_get( pj_scanner *scanner, const pj_cis_t *spec, pj_str_t *out) { register char *s = scanner->curptr; pj_assert(pj_cis_match(spec,0)==0); /* EOF is detected implicitly */ if (!pj_cis_match(spec, *s)) { pj_scan_syntax_err(scanner); return; } do { ++s; } while (pj_cis_match(spec, *s)); /* No need to check EOF here (PJ_SCAN_CHECK_EOF(s)) because * buffer is NULL terminated and pj_cis_match(spec,0) should be * false. */ pj_strset3(out, scanner->curptr, s); scanner->curptr = s; if (PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws) { pj_scan_skip_whitespace(scanner); } }
pjsip_hdr* parse_hdr_p_charging_function_addresses(pjsip_parse_ctx* ctx) { // The P-Charging-Function-Addresses header has the following ABNF: // // P-Charging-Addr = "P-Charging-Function-Addresses" HCOLON // charge-addr-params // *(SEMI charge-addr-params) // charge-addr-params = ccf / ecf / generic-param // ccf = "ccf" EQUAL gen-value // ecf = "ecf" EQUAL gen-value // // Where the ccf and ecf elements may be repeated to specify backup CDFs // for redundancy. pj_pool_t* pool = ctx->pool; pj_scanner* scanner = ctx->scanner; pjsip_p_c_f_a_hdr* hdr = pjsip_p_c_f_a_hdr_create(pool); pj_str_t name; pj_str_t value; pjsip_param *param; for (;;) { pjsip_parse_param_imp(scanner, pool, &name, &value, PJSIP_PARSE_REMOVE_QUOTE); param = PJ_POOL_ALLOC_T(pool, pjsip_param); param->name = name; param->value = value; if (!pj_stricmp2(&name, "ccf")) { pj_list_insert_before(&hdr->ccf, param); } else if (!pj_stricmp2(&name, "ecf")) { pj_list_insert_before(&hdr->ecf, param); } else { pj_list_insert_before(&hdr->other_param, param); } // We might need to swallow the ';'. if (!pj_scan_is_eof(scanner) && *scanner->curptr == ';') { pj_scan_get_char(scanner); } // If we're EOF or looking at a newline, we're done. pj_scan_skip_whitespace(scanner); if (pj_scan_is_eof(scanner) || (*scanner->curptr == '\r') || (*scanner->curptr == '\n')) { break; } } // We're done parsing this header. pjsip_parse_end_hdr_imp(scanner); return (pjsip_hdr*)hdr; }
PJ_DEF(void) pj_scan_get_unescape( pj_scanner *scanner, const pj_cis_t *spec, pj_str_t *out) { register char *s = scanner->curptr; char *dst = s; pj_assert(pj_cis_match(spec,0)==0); /* Must not match character '%' */ pj_assert(pj_cis_match(spec,'%')==0); /* EOF is detected implicitly */ if (!pj_cis_match(spec, *s) && *s != '%') { pj_scan_syntax_err(scanner); return; } out->ptr = s; do { if (*s == '%') { if (s+3 <= scanner->end && pj_isxdigit(*(s+1)) && pj_isxdigit(*(s+2))) { *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(s+1)) << 4) + pj_hex_digit_to_val(*(s+2))); ++dst; s += 3; } else { *dst++ = *s++; *dst++ = *s++; break; } } if (pj_cis_match(spec, *s)) { char *start = s; do { ++s; } while (pj_cis_match(spec, *s)); if (dst != start) pj_memmove(dst, start, s-start); dst += (s-start); } } while (*s == '%'); scanner->curptr = s; out->slen = (dst - out->ptr); if (PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws) { pj_scan_skip_whitespace(scanner); } }
pjsip_hdr* parse_hdr_reject_contact(pjsip_parse_ctx* ctx) { // The Reject-Contact header has the following ABNF: // // Reject-Contact = ("Reject-Contact" / "j") HCOLON rc-value // *(COMMA rc-value) // rc-value = "*" *(SEMI rc-params) // rc-params = feature-param / generic-param // // But we allow any value for the header (not just *). pj_pool_t* pool = ctx->pool; pj_scanner* scanner = ctx->scanner; const pjsip_parser_const_t* pc = pjsip_parser_const(); pjsip_reject_contact_hdr* hdr = pjsip_reject_contact_hdr_create(pool); pj_str_t name; pj_str_t value; pjsip_param *param; // Read and ignore the value. pj_str_t header_value; pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &header_value); for (;;) { // We might need to swallow the ';'. if (!pj_scan_is_eof(scanner) && *scanner->curptr == ';') { pj_scan_get_char(scanner); } pjsip_parse_param_imp(scanner, pool, &name, &value, 0); param = PJ_POOL_ALLOC_T(pool, pjsip_param); param->name = name; param->value = value; pj_list_insert_before(&hdr->feature_set, param); // If we're EOF or looking at a newline, we're done. pj_scan_skip_whitespace(scanner); if (pj_scan_is_eof(scanner) || (*scanner->curptr == '\r') || (*scanner->curptr == '\n')) { break; } } // We're done parsing this header. pjsip_parse_end_hdr_imp(scanner); return (pjsip_hdr*)hdr; }
PJ_DEF(void) pj_scan_advance_n( pj_scanner *scanner, unsigned N, pj_bool_t skip_ws) { if (scanner->curptr + N > scanner->end) { pj_scan_syntax_err(scanner); return; } scanner->curptr += N; if (PJ_SCAN_IS_PROBABLY_SPACE(*scanner->curptr) && skip_ws) { pj_scan_skip_whitespace(scanner); } }
PJ_DEF(void) pj_scan_init( pj_scanner *scanner, char *bufstart, int buflen, unsigned options, pj_syn_err_func_ptr callback ) { PJ_CHECK_STACK(); scanner->begin = scanner->curptr = bufstart; scanner->end = bufstart + buflen; scanner->line = 1; scanner->start_line = scanner->begin; scanner->callback = callback; scanner->skip_ws = options; if (scanner->skip_ws) pj_scan_skip_whitespace(scanner); }
PJ_DEF(int) pj_scan_get_char( pj_scanner *scanner ) { int chr = *scanner->curptr; if (!chr) { pj_scan_syntax_err(scanner); return 0; } ++scanner->curptr; if (PJ_SCAN_IS_PROBABLY_SPACE(*scanner->curptr) && scanner->skip_ws) { pj_scan_skip_whitespace(scanner); } return chr; }
PJ_DEF(void) pj_scan_get_n( pj_scanner *scanner, unsigned N, pj_str_t *out) { if (scanner->curptr + N > scanner->end) { pj_scan_syntax_err(scanner); return; } pj_strset(out, scanner->curptr, N); scanner->curptr += N; if (PJ_SCAN_IS_PROBABLY_SPACE(*scanner->curptr) && scanner->skip_ws) { pj_scan_skip_whitespace(scanner); } }
PJ_DEF(void) pj_scan_get_until_ch( pj_scanner *scanner, int until_char, pj_str_t *out) { register char *s = scanner->curptr; if (s >= scanner->end) { pj_scan_syntax_err(scanner); return; } while (PJ_SCAN_CHECK_EOF(s) && *s != until_char) { ++s; } pj_strset3(out, scanner->curptr, s); scanner->curptr = s; if (PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws) { pj_scan_skip_whitespace(scanner); } }
PJ_DEF(void) pj_scan_get_until( pj_scanner *scanner, const pj_cis_t *spec, pj_str_t *out) { register char *s = scanner->curptr; if (s >= scanner->end) { pj_scan_syntax_err(scanner); return; } while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match(spec, *s)) { ++s; } pj_strset3(out, scanner->curptr, s); scanner->curptr = s; if (PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws) { pj_scan_skip_whitespace(scanner); } }
PJ_DEF(void) pj_scan_get_until_chr( pj_scanner *scanner, const char *until_spec, pj_str_t *out) { register char *s = scanner->curptr; pj_size_t speclen; if (s >= scanner->end) { pj_scan_syntax_err(scanner); return; } speclen = strlen(until_spec); while (PJ_SCAN_CHECK_EOF(s) && !memchr(until_spec, *s, speclen)) { ++s; } pj_strset3(out, scanner->curptr, s); scanner->curptr = s; if (PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws) { pj_scan_skip_whitespace(scanner); } }
pjsip_hdr* parse_hdr_p_charging_vector(pjsip_parse_ctx* ctx) { // The P-Charging-Vector header has the following ABNF: // // P-Charging-Vector = "P-Charging-Vector" HCOLON icid-value // *(SEMI charge-params) // charge-params = icid-gen-addr / orig-ioi / // term-ioi / generic-param // icid-value = "icid-value" EQUAL gen-value // icid-gen-addr = "icid-generated-at" EQUAL host // orig-ioi = "orig-ioi" EQUAL gen-value // term-ioi = "term-ioi" EQUAL gen-value pj_pool_t* pool = ctx->pool; pj_scanner* scanner = ctx->scanner; pjsip_p_c_v_hdr* hdr = pjsip_p_c_v_hdr_create(pool); pj_str_t name; pj_str_t value; // Parse the required icid-value parameter first. pjsip_parse_param_imp(scanner, pool, &name, &value, PJSIP_PARSE_REMOVE_QUOTE); if (!pj_stricmp2(&name, "icid-value")) { hdr->icid = value; } else { PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); // LCOV_EXCL_LINE } for (;;) { pj_scan_skip_whitespace(scanner); // If we just parsed the last parameter we will have reached the end of the // header and have nothing more to do. if (pj_scan_is_eof(scanner) || (*scanner->curptr == '\r') || (*scanner->curptr == '\n')) { break; } // There's more content in the header so the next character must be the ";" // separator. if (*scanner->curptr == ';') { pj_scan_get_char(scanner); } else { PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); // LCOV_EXCL_LINE } pjsip_parse_param_imp(scanner, pool, &name, &value, PJSIP_PARSE_REMOVE_QUOTE); if (!pj_stricmp2(&name, "orig-ioi")) { hdr->orig_ioi = value; } else if (!pj_stricmp2(&name, "term-ioi")) { hdr->term_ioi = value; } else if (!pj_stricmp2(&name, "icid-generated-at")) { hdr->icid_gen_addr = value; } else { pjsip_param *param = PJ_POOL_ALLOC_T(pool, pjsip_param); param->name = name; param->value = value; pj_list_insert_before(&hdr->other_param, param); } } // We're done parsing this header. pjsip_parse_end_hdr_imp(scanner); return (pjsip_hdr*)hdr; }
PJ_DEF(void) pj_scan_get_quotes(pj_scanner *scanner, const char *begin_quote, const char *end_quote, int qsize, pj_str_t *out) { register char *s = scanner->curptr; int qpair = -1; int i; pj_assert(qsize > 0); /* Check and eat the begin_quote. */ for (i = 0; i < qsize; ++i) { if (*s == begin_quote[i]) { qpair = i; break; } } if (qpair == -1) { pj_scan_syntax_err(scanner); return; } ++s; /* Loop until end_quote is found. */ do { /* loop until end_quote is found. */ while (PJ_SCAN_CHECK_EOF(s) && *s != '\n' && *s != end_quote[qpair]) { ++s; } /* check that no backslash character precedes the end_quote. */ if (*s == end_quote[qpair]) { if (*(s-1) == '\\') { char *q = s-2; char *r = s-2; while (r != scanner->begin && *r == '\\') { --r; } /* break from main loop if we have odd number of backslashes */ if (((unsigned)(q-r) & 0x01) == 1) { break; } ++s; } else { /* end_quote is not preceeded by backslash. break now. */ break; } } else { /* loop ended by non-end_quote character. break now. */ break; } } while (1); /* Check and eat the end quote. */ if (*s != end_quote[qpair]) { pj_scan_syntax_err(scanner); return; } ++s; pj_strset3(out, scanner->curptr, s); scanner->curptr = s; if (PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws) { pj_scan_skip_whitespace(scanner); } }
/* Parse tel: URI * THis actually returns (pjsip_tel_uri *) type. */ static void* tel_uri_parse( pj_scanner *scanner, pj_pool_t *pool, pj_bool_t parse_params) { pjsip_tel_uri *uri; pj_str_t token; int skip_ws = scanner->skip_ws; const pjsip_parser_const_t *pc = pjsip_parser_const(); scanner->skip_ws = 0; /* Parse scheme. */ pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &token); if (pj_scan_get_char(scanner) != ':') PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); if (pj_stricmp_alnum(&token, &pc->pjsip_TEL_STR) != 0) PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); /* Create URI */ uri = pjsip_tel_uri_create(pool); /* Get the phone number. */ #if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0 pj_scan_get_unescape(scanner, &pjsip_TEL_NUMBER_SPEC, &uri->number); #else pj_scan_get(scanner, &pjsip_TEL_NUMBER_SPEC, &uri->number); uri->number = pj_str_unescape(pool, &uri->number); #endif /* Get all parameters. */ if (parse_params && *scanner->curptr==';') { pj_str_t pname, pvalue; const pjsip_parser_const_t *pc = pjsip_parser_const(); do { /* Eat the ';' separator. */ pj_scan_get_char(scanner); /* Get pname. */ pj_scan_get(scanner, &pc->pjsip_PARAM_CHAR_SPEC, &pname); if (*scanner->curptr == '=') { pj_scan_get_char(scanner); # if defined(PJSIP_UNESCAPE_IN_PLACE) && PJSIP_UNESCAPE_IN_PLACE!=0 pj_scan_get_unescape(scanner, &pjsip_TEL_PARSING_PVALUE_SPEC_ESC, &pvalue); # else pj_scan_get(scanner, &pjsip_TEL_PARSING_PVALUE_SPEC, &pvalue); pvalue = pj_str_unescape(pool, &pvalue); # endif } else { pvalue.slen = 0; pvalue.ptr = NULL; } /* Save the parameters. */ if (pj_stricmp_alnum(&pname, &pjsip_ISUB_STR)==0) { uri->isub_param = pvalue; } else if (pj_stricmp_alnum(&pname, &pjsip_EXT_STR)==0) { uri->ext_param = pvalue; } else if (pj_stricmp_alnum(&pname, &pjsip_PH_CTX_STR)==0) { uri->context = pvalue; } else { pjsip_param *param = PJ_POOL_ALLOC_T(pool, pjsip_param); param->name = pname; param->value = pvalue; pj_list_insert_before(&uri->other_param, param); } } while (*scanner->curptr==';'); } scanner->skip_ws = skip_ws; pj_scan_skip_whitespace(scanner); return uri; }
void skip_ws() { pj_scan_skip_whitespace(&scanner_); }