From a08b589d09d5197f9a76d549a189e4686bd2ca8c Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Sun, 13 Nov 2005 19:40:44 +0000 Subject: Applying license to pjproject git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@49 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib-util/include/pjlib-util.h | 21 + pjlib-util/include/pjlib-util/md5.h | 209 +++--- pjlib-util/include/pjlib-util/scanner.h | 877 +++++++++++++------------ pjlib-util/include/pjlib-util/stun.h | 267 ++++---- pjlib-util/include/pjlib-util/xml.h | 335 +++++----- pjlib-util/src/pjlib-util-test/main.c | 21 + pjlib-util/src/pjlib-util-test/test.c | 21 + pjlib-util/src/pjlib-util-test/test.h | 21 + pjlib-util/src/pjlib-util-test/xml.c | 279 ++++---- pjlib-util/src/pjlib-util/md5.c | 833 ++++++++++++------------ pjlib-util/src/pjlib-util/scanner.c | 1085 ++++++++++++++++--------------- pjlib-util/src/pjlib-util/stun.c | 247 +++---- pjlib-util/src/pjlib-util/stun_client.c | 543 ++++++++-------- pjlib-util/src/pjlib-util/symbols.c | 21 + pjlib-util/src/pjlib-util/xml.c | 781 +++++++++++----------- 15 files changed, 2938 insertions(+), 2623 deletions(-) (limited to 'pjlib-util') diff --git a/pjlib-util/include/pjlib-util.h b/pjlib-util/include/pjlib-util.h index 69989ca0..8efac78b 100644 --- a/pjlib-util/include/pjlib-util.h +++ b/pjlib-util/include/pjlib-util.h @@ -1,3 +1,24 @@ +/* + * PJLIB - PJ Foundation Library + * (C)2003-2005 Benny Prijono + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ #include #include #include diff --git a/pjlib-util/include/pjlib-util/md5.h b/pjlib-util/include/pjlib-util/md5.h index 8f3f6145..ce27b6a2 100644 --- a/pjlib-util/include/pjlib-util/md5.h +++ b/pjlib-util/include/pjlib-util/md5.h @@ -1,94 +1,115 @@ -/* $Id$ - * - */ -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id$ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.h is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . - 1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -# define md5_INCLUDED - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned long md5_word_t; /* 32-bit word */ - -/** Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /**< message length in bits, lsw first */ - md5_word_t abcd[4]; /**< digest buffer */ - md5_byte_t buf[64]; /**< accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** Initialize the algorithm. */ -void md5_init(md5_state_t *pms); - -/** Append a string to the message. */ -void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); - -/** Finish the message and return the digest. */ -void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */ +/* $Id$ + * + */ +/* + * PJLIB - PJ Foundation Library + * (C)2003-2005 Benny Prijono + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id$ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned long md5_word_t; /* 32-bit word */ + +/** Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /**< message length in bits, lsw first */ + md5_word_t abcd[4]; /**< digest buffer */ + md5_byte_t buf[64]; /**< accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/** Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/** Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/pjlib-util/include/pjlib-util/scanner.h b/pjlib-util/include/pjlib-util/scanner.h index 711eeed7..a9491431 100644 --- a/pjlib-util/include/pjlib-util/scanner.h +++ b/pjlib-util/include/pjlib-util/scanner.h @@ -1,26 +1,47 @@ -/* $Id$ - */ -#ifndef __PJ_SCANNER_H__ -#define __PJ_SCANNER_H__ - -/** - * @file scanner.h - * @brief Text Scanning. - */ - -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_SCAN Text Scanning - * @ingroup PJ_MISC - * @brief +/* $Id$ + */ +/* + * PJLIB - PJ Foundation Library + * (C)2003-2005 Benny Prijono + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __PJ_SCANNER_H__ +#define __PJ_SCANNER_H__ + +/** + * @file scanner.h + * @brief Text Scanning. + */ + +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_SCAN Text Scanning + * @ingroup PJ_MISC + * @brief * Text scanning utility. * - * @{ - */ - + * @{ + */ + /** * This describes the type of individual character specification in * #pj_cis_buf_t. Basicly the number of bits here @@ -28,28 +49,28 @@ PJ_BEGIN_DECL #ifndef PJ_CIS_ELEM_TYPE # define PJ_CIS_ELEM_TYPE pj_uint32_t #endif - -/** - * This describes the type of individual character specification in - * #pj_cis_buf_t. - */ -typedef PJ_CIS_ELEM_TYPE pj_cis_elem_t; + +/** + * This describes the type of individual character specification in + * #pj_cis_buf_t. + */ +typedef PJ_CIS_ELEM_TYPE pj_cis_elem_t; /** * Maximum number of input specification in a buffer. * Effectively this means the number of bits in pj_cis_elem_t. */ #define PJ_CIS_MAX_INDEX (sizeof(pj_cis_elem_t) << 3) - -/** - * The scanner input specification buffer. - */ + +/** + * The scanner input specification buffer. + */ typedef struct pj_cis_buf_t { pj_cis_elem_t cis_buf[256]; /**< Must be 256 (not 128)! */ pj_cis_elem_t use_mask; /**< To keep used indexes. */ } pj_cis_buf_t; - + /** * Character input specification. */ @@ -58,13 +79,13 @@ typedef struct pj_cis_t pj_cis_elem_t *cis_buf; /**< Pointer to buffer. */ int cis_id; /**< Id. */ } pj_cis_t; - -/** + +/** * Initialize scanner input specification buffer. - * - * @param cs_buf The scanner character specification. - */ -PJ_DECL(void) pj_cis_buf_init(pj_cis_buf_t *cs_buf); + * + * @param cs_buf The scanner character specification. + */ +PJ_DECL(void) pj_cis_buf_init(pj_cis_buf_t *cs_buf); /** * Create a new input specification. @@ -90,15 +111,15 @@ PJ_DECL(pj_status_t) pj_cis_init(pj_cis_buf_t *cs_buf, pj_cis_t *cis); * specifications in the buffer. */ PJ_DECL(pj_status_t) pj_cis_dup(pj_cis_t *new_cis, pj_cis_t *existing); - -/** + +/** * Set the membership of the specified character. * Note that this is a macro, and arguments may be evaluated more than once. - * - * @param cis Pointer to character input specification. - * @param c The character. - */ -#define PJ_CIS_SET(cis,c) ((cis)->cis_buf[(c)] |= (1 << (cis)->cis_id)) + * + * @param cis Pointer to character input specification. + * @param c The character. + */ +#define PJ_CIS_SET(cis,c) ((cis)->cis_buf[(c)] |= (1 << (cis)->cis_id)) /** * Remove the membership of the specified character. @@ -117,395 +138,395 @@ PJ_DECL(pj_status_t) pj_cis_dup(pj_cis_t *new_cis, pj_cis_t *existing); * @param c The character. */ #define PJ_CIS_ISSET(cis,c) ((cis)->cis_buf[c] & (1 << (cis)->cis_id)) - -/** - * Add the characters in the specified range '[cstart, cend)' to the + +/** + * Add the characters in the specified range '[cstart, cend)' to the * specification (the last character itself ('cend') is not added). - * - * @param cis The scanner character specification. - * @param cstart The first character in the range. - * @param cend The next character after the last character in the range. - */ -PJ_DECL(void) pj_cis_add_range( pj_cis_t *cis, int cstart, int cend); - -/** + * + * @param cis The scanner character specification. + * @param cstart The first character in the range. + * @param cend The next character after the last character in the range. + */ +PJ_DECL(void) pj_cis_add_range( pj_cis_t *cis, int cstart, int cend); + +/** * Add alphabetic characters to the specification. - * - * @param cis The scanner character specification. - */ -PJ_DECL(void) pj_cis_add_alpha( pj_cis_t *cis); - -/** + * + * @param cis The scanner character specification. + */ +PJ_DECL(void) pj_cis_add_alpha( pj_cis_t *cis); + +/** * Add numeric characters to the specification. - * - * @param cis The scanner character specification. - */ -PJ_DECL(void) pj_cis_add_num( pj_cis_t *cis); - -/** + * + * @param cis The scanner character specification. + */ +PJ_DECL(void) pj_cis_add_num( pj_cis_t *cis); + +/** * Add the characters in the string to the specification. - * - * @param cis The scanner character specification. - * @param str The string. - */ -PJ_DECL(void) pj_cis_add_str( pj_cis_t *cis, const char *str); - -/** + * + * @param cis The scanner character specification. + * @param str The string. + */ +PJ_DECL(void) pj_cis_add_str( pj_cis_t *cis, const char *str); + +/** * Delete characters in the specified range from the specification. - * - * @param cis The scanner character specification. - * @param cstart The first character in the range. - * @param cend The next character after the last character in the range. - */ -PJ_DECL(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend); - -/** + * + * @param cis The scanner character specification. + * @param cstart The first character in the range. + * @param cend The next character after the last character in the range. + */ +PJ_DECL(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend); + +/** * Delete characters in the specified string from the specification. - * - * @param cis The scanner character specification. - * @param str The string. - */ -PJ_DECL(void) pj_cis_del_str( pj_cis_t *cis, const char *str); - -/** + * + * @param cis The scanner character specification. + * @param str The string. + */ +PJ_DECL(void) pj_cis_del_str( pj_cis_t *cis, const char *str); + +/** * Invert specification. - * - * @param cis The scanner character specification. - */ -PJ_DECL(void) pj_cis_invert( pj_cis_t *cis ); - -/** + * + * @param cis The scanner character specification. + */ +PJ_DECL(void) pj_cis_invert( pj_cis_t *cis ); + +/** * Check whether the specified character belongs to the specification. - * - * @param cis The scanner character specification. - * @param c The character to check for matching. - */ -PJ_INLINE(int) pj_cis_match( const pj_cis_t *cis, int c ) -{ - return PJ_CIS_ISSET(cis, c); -} - - -/** - * Flags for scanner. - */ -enum -{ - /** This flags specifies that the scanner should automatically skip - whitespaces - */ - PJ_SCAN_AUTOSKIP_WS = 1, - - /** This flags specifies that the scanner should automatically skip - SIP header continuation. This flag implies PJ_SCAN_AUTOSKIP_WS. - */ - PJ_SCAN_AUTOSKIP_WS_HEADER = 3, - - /** Auto-skip new lines. - */ - PJ_SCAN_AUTOSKIP_NEWLINE = 4, -}; - - -/* Forward decl. */ -struct pj_scanner; - - -/** - * The callback function type to be called by the scanner when it encounters + * + * @param cis The scanner character specification. + * @param c The character to check for matching. + */ +PJ_INLINE(int) pj_cis_match( const pj_cis_t *cis, int c ) +{ + return PJ_CIS_ISSET(cis, c); +} + + +/** + * Flags for scanner. + */ +enum +{ + /** This flags specifies that the scanner should automatically skip + whitespaces + */ + PJ_SCAN_AUTOSKIP_WS = 1, + + /** This flags specifies that the scanner should automatically skip + SIP header continuation. This flag implies PJ_SCAN_AUTOSKIP_WS. + */ + PJ_SCAN_AUTOSKIP_WS_HEADER = 3, + + /** Auto-skip new lines. + */ + PJ_SCAN_AUTOSKIP_NEWLINE = 4, +}; + + +/* Forward decl. */ +struct pj_scanner; + + +/** + * The callback function type to be called by the scanner when it encounters * syntax error. - * - * @param scanner The scanner instance that calls the callback . - */ -typedef void (*pj_syn_err_func_ptr)(struct pj_scanner *scanner); - - -/** - * The text scanner structure. - */ -typedef struct pj_scanner -{ - char *begin; /**< Start of input buffer. */ - char *end; /**< End of input buffer. */ - char *curptr; /**< Current pointer. */ - int line; /**< Current line. */ - int col; /**< Current column. */ - int skip_ws; /**< Skip whitespace flag. */ - pj_syn_err_func_ptr callback; /**< Syntax error callback. */ -} pj_scanner; - - -/** - * This structure can be used by application to store the state of the parser, - * so that the scanner state can be rollback to this state when necessary. - */ -typedef struct pj_scan_state -{ - char *curptr; /**< Current scanner's pointer. */ - int line; /**< Current line. */ - int col; /**< Current column. */ -} pj_scan_state; - - -/** - * Initialize the scanner. Note that the input string buffer must have - * length at least buflen+1 because the scanner will NULL terminate the - * string during initialization. - * - * @param scanner The scanner to be initialized. - * @param bufstart The input buffer to scan. Note that buffer[buflen] will be - * filled with NULL char until scanner is destroyed, so - * the actual buffer length must be at least buflen+1. - * @param buflen The length of the input buffer, which normally is - * strlen(bufstart). - * @param options Zero, or combination of PJ_SCAN_AUTOSKIP_WS or - * PJ_SCAN_AUTOSKIP_WS_HEADER - * @param callback Callback to be called when the scanner encounters syntax - * error condition. - */ -PJ_DECL(void) pj_scan_init( pj_scanner *scanner, char *bufstart, int buflen, - unsigned options, - pj_syn_err_func_ptr callback ); - - -/** - * Call this function when application has finished using the scanner. - * - * @param scanner The scanner. - */ -PJ_DECL(void) pj_scan_fini( pj_scanner *scanner ); - - -/** - * Determine whether the EOF condition for the scanner has been met. - * - * @param scanner The scanner. - * - * @return Non-zero if scanner is EOF. - */ -PJ_INLINE(int) pj_scan_is_eof( const pj_scanner *scanner) -{ - return scanner->curptr >= scanner->end; -} - - -/** - * Peek strings in current position according to parameter spec, and return - * the strings in parameter out. The current scanner position will not be - * moved. If the scanner is already in EOF state, syntax error callback will - * be called thrown. - * - * @param scanner The scanner. - * @param spec The spec to match input string. - * @param out String to store the result. - * - * @return the character right after the peek-ed position or zero if there's - * no more characters. - */ -PJ_DECL(int) pj_scan_peek( pj_scanner *scanner, - const pj_cis_t *spec, pj_str_t *out); - - -/** - * Peek len characters in current position, and return them in out parameter. - * Note that whitespaces or newlines will be returned as it is, regardless - * of PJ_SCAN_AUTOSKIP_WS settings. If the character left is less than len, - * syntax error callback will be called. - * - * @param scanner The scanner. - * @param len Length to peek. - * @param out String to store the result. - * - * @return the character right after the peek-ed position or zero if there's - * no more characters. - */ -PJ_DECL(int) pj_scan_peek_n( pj_scanner *scanner, - pj_size_t len, pj_str_t *out); - - -/** - * Peek strings in current position until spec is matched, and return - * the strings in parameter out. The current scanner position will not be - * moved. If the scanner is already in EOF state, syntax error callback will - * be called. - * - * @param scanner The scanner. - * @param spec The peeking will stop when the input match this spec. - * @param out String to store the result. - * - * @return the character right after the peek-ed position. - */ -PJ_DECL(int) pj_scan_peek_until( pj_scanner *scanner, - const pj_cis_t *spec, - pj_str_t *out); - - -/** - * Get characters from the buffer according to the spec, and return them - * in out parameter. The scanner will attempt to get as many characters as - * possible as long as the spec matches. If the first character doesn't - * match the spec, or scanner is already in EOF when this function is called, - * an exception will be thrown. - * - * @param scanner The scanner. - * @param spec The spec to match input string. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get( pj_scanner *scanner, - const pj_cis_t *spec, pj_str_t *out); - - -/** - * Get characters between quotes. If current input doesn't match begin_quote, - * syntax error will be thrown. - * - * @param scanner The scanner. - * @param begin_quote The character to begin the quote. - * @param end_quote The character to end the quote. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get_quote( pj_scanner *scanner, - int begin_quote, int end_quote, - pj_str_t *out); - -/** - * Get N characters from the scanner. - * - * @param scanner The scanner. - * @param N Number of characters to get. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get_n( pj_scanner *scanner, - unsigned N, pj_str_t *out); - - -/** - * Get one character from the scanner. - * - * @param scanner The scanner. - * - * @return The character. - */ -PJ_DECL(int) pj_scan_get_char( pj_scanner *scanner ); - - -/** - * Get a newline from the scanner. A newline is defined as '\\n', or '\\r', or - * "\\r\\n". If current input is not newline, syntax error will be thrown. - * - * @param scanner The scanner. - */ -PJ_DECL(void) pj_scan_get_newline( pj_scanner *scanner ); - - -/** - * Get characters from the scanner and move the scanner position until the - * current character matches the spec. - * - * @param scanner The scanner. - * @param spec Get until the input match this spec. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get_until( pj_scanner *scanner, - const pj_cis_t *spec, pj_str_t *out); - - -/** - * Get characters from the scanner and move the scanner position until the - * current character matches until_char. - * - * @param scanner The scanner. - * @param until_char Get until the input match this character. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get_until_ch( pj_scanner *scanner, - int until_char, pj_str_t *out); - - -/** - * Get characters from the scanner and move the scanner position until the - * current character matches until_char. - * - * @param scanner The scanner. - * @param until_spec Get until the input match any of these characters. - * @param out String to store the result. - */ -PJ_DECL(void) pj_scan_get_until_chr( pj_scanner *scanner, - const char *until_spec, pj_str_t *out); - -/** - * Advance the scanner N characters, and skip whitespace - * if necessary. - * - * @param scanner The scanner. - * @param N Number of characters to skip. - * @param skip Flag to specify whether whitespace should be skipped - * after skipping the characters. - */ -PJ_DECL(void) pj_scan_advance_n( pj_scanner *scanner, - unsigned N, pj_bool_t skip); - - -/** - * Compare string in current position with the specified string. - * - * @param scanner The scanner. - * @param s The string to compare with. - * @param len Length of the string to compare. - * - * @return zero, <0, or >0 (just like strcmp()). - */ -PJ_DECL(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len); - - -/** - * Case-less string comparison of current position with the specified - * string. - * - * @param scanner The scanner. - * @param s The string to compare with. - * @param len Length of the string to compare with. - * - * @return zero, <0, or >0 (just like strcmp()). - */ -PJ_DECL(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len); - - -/** - * Manually skip whitespaces according to flag that was specified when - * the scanner was initialized. - * - * @param scanner The scanner. - */ -PJ_DECL(void) pj_scan_skip_whitespace( pj_scanner *scanner ); - - -/** - * Save the full scanner state. - * - * @param scanner The scanner. - * @param state Variable to store scanner's state. - */ -PJ_DECL(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state); - - -/** - * Restore the full scanner state. - * Note that this would not restore the string if application has modified - * it. This will only restore the scanner scanning position. - * - * @param scanner The scanner. - * @param state State of the scanner. - */ -PJ_DECL(void) pj_scan_restore_state( pj_scanner *scanner, - pj_scan_state *state); - -/** - * @} - */ - - -PJ_END_DECL - -#endif - + * + * @param scanner The scanner instance that calls the callback . + */ +typedef void (*pj_syn_err_func_ptr)(struct pj_scanner *scanner); + + +/** + * The text scanner structure. + */ +typedef struct pj_scanner +{ + char *begin; /**< Start of input buffer. */ + char *end; /**< End of input buffer. */ + char *curptr; /**< Current pointer. */ + int line; /**< Current line. */ + int col; /**< Current column. */ + int skip_ws; /**< Skip whitespace flag. */ + pj_syn_err_func_ptr callback; /**< Syntax error callback. */ +} pj_scanner; + + +/** + * This structure can be used by application to store the state of the parser, + * so that the scanner state can be rollback to this state when necessary. + */ +typedef struct pj_scan_state +{ + char *curptr; /**< Current scanner's pointer. */ + int line; /**< Current line. */ + int col; /**< Current column. */ +} pj_scan_state; + + +/** + * Initialize the scanner. Note that the input string buffer must have + * length at least buflen+1 because the scanner will NULL terminate the + * string during initialization. + * + * @param scanner The scanner to be initialized. + * @param bufstart The input buffer to scan. Note that buffer[buflen] will be + * filled with NULL char until scanner is destroyed, so + * the actual buffer length must be at least buflen+1. + * @param buflen The length of the input buffer, which normally is + * strlen(bufstart). + * @param options Zero, or combination of PJ_SCAN_AUTOSKIP_WS or + * PJ_SCAN_AUTOSKIP_WS_HEADER + * @param callback Callback to be called when the scanner encounters syntax + * error condition. + */ +PJ_DECL(void) pj_scan_init( pj_scanner *scanner, char *bufstart, int buflen, + unsigned options, + pj_syn_err_func_ptr callback ); + + +/** + * Call this function when application has finished using the scanner. + * + * @param scanner The scanner. + */ +PJ_DECL(void) pj_scan_fini( pj_scanner *scanner ); + + +/** + * Determine whether the EOF condition for the scanner has been met. + * + * @param scanner The scanner. + * + * @return Non-zero if scanner is EOF. + */ +PJ_INLINE(int) pj_scan_is_eof( const pj_scanner *scanner) +{ + return scanner->curptr >= scanner->end; +} + + +/** + * Peek strings in current position according to parameter spec, and return + * the strings in parameter out. The current scanner position will not be + * moved. If the scanner is already in EOF state, syntax error callback will + * be called thrown. + * + * @param scanner The scanner. + * @param spec The spec to match input string. + * @param out String to store the result. + * + * @return the character right after the peek-ed position or zero if there's + * no more characters. + */ +PJ_DECL(int) pj_scan_peek( pj_scanner *scanner, + const pj_cis_t *spec, pj_str_t *out); + + +/** + * Peek len characters in current position, and return them in out parameter. + * Note that whitespaces or newlines will be returned as it is, regardless + * of PJ_SCAN_AUTOSKIP_WS settings. If the character left is less than len, + * syntax error callback will be called. + * + * @param scanner The scanner. + * @param len Length to peek. + * @param out String to store the result. + * + * @return the character right after the peek-ed position or zero if there's + * no more characters. + */ +PJ_DECL(int) pj_scan_peek_n( pj_scanner *scanner, + pj_size_t len, pj_str_t *out); + + +/** + * Peek strings in current position until spec is matched, and return + * the strings in parameter out. The current scanner position will not be + * moved. If the scanner is already in EOF state, syntax error callback will + * be called. + * + * @param scanner The scanner. + * @param spec The peeking will stop when the input match this spec. + * @param out String to store the result. + * + * @return the character right after the peek-ed position. + */ +PJ_DECL(int) pj_scan_peek_until( pj_scanner *scanner, + const pj_cis_t *spec, + pj_str_t *out); + + +/** + * Get characters from the buffer according to the spec, and return them + * in out parameter. The scanner will attempt to get as many characters as + * possible as long as the spec matches. If the first character doesn't + * match the spec, or scanner is already in EOF when this function is called, + * an exception will be thrown. + * + * @param scanner The scanner. + * @param spec The spec to match input string. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get( pj_scanner *scanner, + const pj_cis_t *spec, pj_str_t *out); + + +/** + * Get characters between quotes. If current input doesn't match begin_quote, + * syntax error will be thrown. + * + * @param scanner The scanner. + * @param begin_quote The character to begin the quote. + * @param end_quote The character to end the quote. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get_quote( pj_scanner *scanner, + int begin_quote, int end_quote, + pj_str_t *out); + +/** + * Get N characters from the scanner. + * + * @param scanner The scanner. + * @param N Number of characters to get. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get_n( pj_scanner *scanner, + unsigned N, pj_str_t *out); + + +/** + * Get one character from the scanner. + * + * @param scanner The scanner. + * + * @return The character. + */ +PJ_DECL(int) pj_scan_get_char( pj_scanner *scanner ); + + +/** + * Get a newline from the scanner. A newline is defined as '\\n', or '\\r', or + * "\\r\\n". If current input is not newline, syntax error will be thrown. + * + * @param scanner The scanner. + */ +PJ_DECL(void) pj_scan_get_newline( pj_scanner *scanner ); + + +/** + * Get characters from the scanner and move the scanner position until the + * current character matches the spec. + * + * @param scanner The scanner. + * @param spec Get until the input match this spec. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get_until( pj_scanner *scanner, + const pj_cis_t *spec, pj_str_t *out); + + +/** + * Get characters from the scanner and move the scanner position until the + * current character matches until_char. + * + * @param scanner The scanner. + * @param until_char Get until the input match this character. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get_until_ch( pj_scanner *scanner, + int until_char, pj_str_t *out); + + +/** + * Get characters from the scanner and move the scanner position until the + * current character matches until_char. + * + * @param scanner The scanner. + * @param until_spec Get until the input match any of these characters. + * @param out String to store the result. + */ +PJ_DECL(void) pj_scan_get_until_chr( pj_scanner *scanner, + const char *until_spec, pj_str_t *out); + +/** + * Advance the scanner N characters, and skip whitespace + * if necessary. + * + * @param scanner The scanner. + * @param N Number of characters to skip. + * @param skip Flag to specify whether whitespace should be skipped + * after skipping the characters. + */ +PJ_DECL(void) pj_scan_advance_n( pj_scanner *scanner, + unsigned N, pj_bool_t skip); + + +/** + * Compare string in current position with the specified string. + * + * @param scanner The scanner. + * @param s The string to compare with. + * @param len Length of the string to compare. + * + * @return zero, <0, or >0 (just like strcmp()). + */ +PJ_DECL(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len); + + +/** + * Case-less string comparison of current position with the specified + * string. + * + * @param scanner The scanner. + * @param s The string to compare with. + * @param len Length of the string to compare with. + * + * @return zero, <0, or >0 (just like strcmp()). + */ +PJ_DECL(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len); + + +/** + * Manually skip whitespaces according to flag that was specified when + * the scanner was initialized. + * + * @param scanner The scanner. + */ +PJ_DECL(void) pj_scan_skip_whitespace( pj_scanner *scanner ); + + +/** + * Save the full scanner state. + * + * @param scanner The scanner. + * @param state Variable to store scanner's state. + */ +PJ_DECL(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state); + + +/** + * Restore the full scanner state. + * Note that this would not restore the string if application has modified + * it. This will only restore the scanner scanning position. + * + * @param scanner The scanner. + * @param state State of the scanner. + */ +PJ_DECL(void) pj_scan_restore_state( pj_scanner *scanner, + pj_scan_state *state); + +/** + * @} + */ + + +PJ_END_DECL + +#endif + diff --git a/pjlib-util/include/pjlib-util/stun.h b/pjlib-util/include/pjlib-util/stun.h index 90c20ec6..d2065e70 100644 --- a/pjlib-util/include/pjlib-util/stun.h +++ b/pjlib-util/include/pjlib-util/stun.h @@ -1,123 +1,144 @@ -#ifndef __PJ_STUN_H__ -#define __PJ_STUN_H__ - -#include -#include - -PJ_BEGIN_DECL - -#define PJ_STUN_MAX_ATTR 16 - -typedef enum pj_stun_msg_type -{ - PJ_STUN_BINDING_REQUEST = 0x0001, - PJ_STUN_BINDING_RESPONSE = 0x0101, - PJ_STUN_BINDING_ERROR_RESPONSE = 0x0111, - PJ_STUN_SHARED_SECRET_REQUEST = 0x0002, - PJ_STUN_SHARED_SECRET_RESPONSE = 0x0102, - PJ_STUN_SHARED_SECRET_ERROR_RESPONSE = 0x0112 -} pj_stun_msg_type; - -typedef enum pj_stun_attr_type -{ - PJ_STUN_ATTR_MAPPED_ADDR = 1, - PJ_STUN_ATTR_RESPONSE_ADDR, - PJ_STUN_ATTR_CHANGE_REQUEST, - PJ_STUN_ATTR_SOURCE_ADDR, - PJ_STUN_ATTR_CHANGED_ADDR, - PJ_STUN_ATTR_USERNAME, - PJ_STUN_ATTR_PASSWORD, - PJ_STUN_ATTR_MESSAGE_INTEGRITY, - PJ_STUN_ATTR_ERROR_CODE, - PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, - PJ_STUN_ATTR_REFLECTED_FORM -} pj_stun_attr_type; - -typedef struct pj_stun_msg_hdr -{ - pj_uint16_t type; - pj_uint16_t length; - pj_uint32_t tsx[4]; -} pj_stun_msg_hdr; - -typedef struct pj_stun_attr_hdr -{ - pj_uint16_t type; - pj_uint16_t length; -} pj_stun_attr_hdr; - -typedef struct pj_stun_mapped_addr_attr -{ - pj_stun_attr_hdr hdr; - pj_uint8_t ignored; - pj_uint8_t family; - pj_uint16_t port; - pj_uint32_t addr; -} pj_stun_mapped_addr_attr; - -typedef pj_stun_mapped_addr_attr pj_stun_response_addr_attr; -typedef pj_stun_mapped_addr_attr pj_stun_changed_addr_attr; -typedef pj_stun_mapped_addr_attr pj_stun_src_addr_attr; -typedef pj_stun_mapped_addr_attr pj_stun_reflected_form_attr; - -typedef struct pj_stun_change_request_attr -{ - pj_stun_attr_hdr hdr; - pj_uint32_t value; -} pj_stun_change_request_attr; - -typedef struct pj_stun_username_attr -{ - pj_stun_attr_hdr hdr; - pj_uint32_t value[1]; -} pj_stun_username_attr; - -typedef pj_stun_username_attr pj_stun_password_attr; - -typedef struct pj_stun_error_code_attr -{ - pj_stun_attr_hdr hdr; - pj_uint16_t ignored; - pj_uint8_t err_class; - pj_uint8_t number; - char reason[4]; -} pj_stun_error_code_attr; - -typedef struct pj_stun_msg -{ - pj_stun_msg_hdr *hdr; - int attr_count; - pj_stun_attr_hdr *attr[PJ_STUN_MAX_ATTR]; -} pj_stun_msg; - -/* STUN message API (stun.c). */ - -PJ_DECL(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, - void **msg, pj_size_t *len, - pj_uint32_t id_hi, - pj_uint32_t id_lo); -PJ_DECL(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, - pj_stun_msg *msg); -PJ_DECL(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t); - -/* STUN simple client API (stun_client.c) */ -enum pj_stun_err_code { - PJ_STUN_ERR_MEMORY = (-2), - PJ_STUN_ERR_RESOLVE = (-3), - PJ_STUN_ERR_TRANSPORT = (-4), - PJ_STUN_ERR_INVALID_MSG = (-5), - PJ_STUN_ERR_NO_RESPONSE = (-6), - PJ_STUN_ERR_SYMETRIC = (-7), -}; - -PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf, - int sock_cnt, pj_sock_t sock[], - const pj_str_t *srv1, int port1, - const pj_str_t *srv2, int port2, - pj_sockaddr_in mapped_addr[]); -PJ_DECL(const char*) pj_stun_get_err_msg(pj_status_t status); - -PJ_END_DECL - -#endif /* __PJ_STUN_H__ */ - +/* + * PJLIB - PJ Foundation Library + * (C)2003-2005 Benny Prijono + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __PJ_STUN_H__ +#define __PJ_STUN_H__ + +#include +#include + +PJ_BEGIN_DECL + +#define PJ_STUN_MAX_ATTR 16 + +typedef enum pj_stun_msg_type +{ + PJ_STUN_BINDING_REQUEST = 0x0001, + PJ_STUN_BINDING_RESPONSE = 0x0101, + PJ_STUN_BINDING_ERROR_RESPONSE = 0x0111, + PJ_STUN_SHARED_SECRET_REQUEST = 0x0002, + PJ_STUN_SHARED_SECRET_RESPONSE = 0x0102, + PJ_STUN_SHARED_SECRET_ERROR_RESPONSE = 0x0112 +} pj_stun_msg_type; + +typedef enum pj_stun_attr_type +{ + PJ_STUN_ATTR_MAPPED_ADDR = 1, + PJ_STUN_ATTR_RESPONSE_ADDR, + PJ_STUN_ATTR_CHANGE_REQUEST, + PJ_STUN_ATTR_SOURCE_ADDR, + PJ_STUN_ATTR_CHANGED_ADDR, + PJ_STUN_ATTR_USERNAME, + PJ_STUN_ATTR_PASSWORD, + PJ_STUN_ATTR_MESSAGE_INTEGRITY, + PJ_STUN_ATTR_ERROR_CODE, + PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, + PJ_STUN_ATTR_REFLECTED_FORM +} pj_stun_attr_type; + +typedef struct pj_stun_msg_hdr +{ + pj_uint16_t type; + pj_uint16_t length; + pj_uint32_t tsx[4]; +} pj_stun_msg_hdr; + +typedef struct pj_stun_attr_hdr +{ + pj_uint16_t type; + pj_uint16_t length; +} pj_stun_attr_hdr; + +typedef struct pj_stun_mapped_addr_attr +{ + pj_stun_attr_hdr hdr; + pj_uint8_t ignored; + pj_uint8_t family; + pj_uint16_t port; + pj_uint32_t addr; +} pj_stun_mapped_addr_attr; + +typedef pj_stun_mapped_addr_attr pj_stun_response_addr_attr; +typedef pj_stun_mapped_addr_attr pj_stun_changed_addr_attr; +typedef pj_stun_mapped_addr_attr pj_stun_src_addr_attr; +typedef pj_stun_mapped_addr_attr pj_stun_reflected_form_attr; + +typedef struct pj_stun_change_request_attr +{ + pj_stun_attr_hdr hdr; + pj_uint32_t value; +} pj_stun_change_request_attr; + +typedef struct pj_stun_username_attr +{ + pj_stun_attr_hdr hdr; + pj_uint32_t value[1]; +} pj_stun_username_attr; + +typedef pj_stun_username_attr pj_stun_password_attr; + +typedef struct pj_stun_error_code_attr +{ + pj_stun_attr_hdr hdr; + pj_uint16_t ignored; + pj_uint8_t err_class; + pj_uint8_t number; + char reason[4]; +} pj_stun_error_code_attr; + +typedef struct pj_stun_msg +{ + pj_stun_msg_hdr *hdr; + int attr_count; + pj_stun_attr_hdr *attr[PJ_STUN_MAX_ATTR]; +} pj_stun_msg; + +/* STUN message API (stun.c). */ + +PJ_DECL(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, + void **msg, pj_size_t *len, + pj_uint32_t id_hi, + pj_uint32_t id_lo); +PJ_DECL(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, + pj_stun_msg *msg); +PJ_DECL(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t); + +/* STUN simple client API (stun_client.c) */ +enum pj_stun_err_code { + PJ_STUN_ERR_MEMORY = (-2), + PJ_STUN_ERR_RESOLVE = (-3), + PJ_STUN_ERR_TRANSPORT = (-4), + PJ_STUN_ERR_INVALID_MSG = (-5), + PJ_STUN_ERR_NO_RESPONSE = (-6), + PJ_STUN_ERR_SYMETRIC = (-7), +}; + +PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf, + int sock_cnt, pj_sock_t sock[], + const pj_str_t *srv1, int port1, + const pj_str_t *srv2, int port2, + pj_sockaddr_in mapped_addr[]); +PJ_DECL(const char*) pj_stun_get_err_msg(pj_status_t status); + +PJ_END_DECL + +#endif /* __PJ_STUN_H__ */ + diff --git a/pjlib-util/include/pjlib-util/xml.h b/pjlib-util/include/pjlib-util/xml.h index fd7978ae..e0ebb4c7 100644 --- a/pjlib-util/include/pjlib-util/xml.h +++ b/pjlib-util/include/pjlib-util/xml.h @@ -1,157 +1,178 @@ -/* $Id$ - * - */ - -#ifndef __PJ_XML_H__ -#define __PJ_XML_H__ - -/** - * @file xml.h - * @brief PJLIB XML Parser/Helper. - */ - -#include -#include - -PJ_BEGIN_DECL - -/** - * @defgroup PJ_XML XML Parser/Helper. - * @ingroup PJ - * @{ - */ - -/** Typedef for XML attribute. */ -typedef struct pj_xml_attr pj_xml_attr; - -/** Typedef for XML nodes. */ -typedef struct pj_xml_node pj_xml_node; - -/** This structure declares XML attribute. */ -struct pj_xml_attr -{ - PJ_DECL_LIST_MEMBER(pj_xml_attr); /**< Standard list elements. */ - pj_str_t name; /**< Attribute name. */ - pj_str_t value; /**< Attribute value. */ -}; - -/** This structure describes XML node head inside XML node structure. - */ -typedef struct pj_xml_node_head -{ - PJ_DECL_LIST_MEMBER(pj_xml_node); /**< Standard list elements. */ -} pj_xml_node_head; - -/** This structure describes XML node. */ -struct pj_xml_node -{ - PJ_DECL_LIST_MEMBER(pj_xml_node); /**< List @a prev and @a next member */ - pj_str_t name; /**< Node name. */ - pj_xml_attr attr_head; /**< Attribute list. */ - pj_xml_node_head node_head; /**< Node list. */ - pj_str_t content; /**< Node content. */ -}; - -/** - * Parse XML message into XML document with a single root node. The parser - * is capable of parsing XML processing instruction construct (" + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PJ_XML_H__ +#define __PJ_XML_H__ + +/** + * @file xml.h + * @brief PJLIB XML Parser/Helper. + */ + +#include +#include + +PJ_BEGIN_DECL + +/** + * @defgroup PJ_XML XML Parser/Helper. + * @ingroup PJ + * @{ + */ + +/** Typedef for XML attribute. */ +typedef struct pj_xml_attr pj_xml_attr; + +/** Typedef for XML nodes. */ +typedef struct pj_xml_node pj_xml_node; + +/** This structure declares XML attribute. */ +struct pj_xml_attr +{ + PJ_DECL_LIST_MEMBER(pj_xml_attr); /**< Standard list elements. */ + pj_str_t name; /**< Attribute name. */ + pj_str_t value; /**< Attribute value. */ +}; + +/** This structure describes XML node head inside XML node structure. + */ +typedef struct pj_xml_node_head +{ + PJ_DECL_LIST_MEMBER(pj_xml_node); /**< Standard list elements. */ +} pj_xml_node_head; + +/** This structure describes XML node. */ +struct pj_xml_node +{ + PJ_DECL_LIST_MEMBER(pj_xml_node); /**< List @a prev and @a next member */ + pj_str_t name; /**< Node name. */ + pj_xml_attr attr_head; /**< Attribute list. */ + pj_xml_node_head node_head; /**< Node list. */ + pj_str_t content; /**< Node content. */ +}; + +/** + * Parse XML message into XML document with a single root node. The parser + * is capable of parsing XML processing instruction construct (" + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ #include "test.h" #if defined(PJ_SUNOS) && PJ_SUNOS!=0 diff --git a/pjlib-util/src/pjlib-util-test/test.c b/pjlib-util/src/pjlib-util-test/test.c index 45027280..06194ad0 100644 --- a/pjlib-util/src/pjlib-util-test/test.c +++ b/pjlib-util/src/pjlib-util-test/test.c @@ -1,3 +1,24 @@ +/* + * PJLIB - PJ Foundation Library + * (C)2003-2005 Benny Prijono + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ #include "test.h" #include diff --git a/pjlib-util/src/pjlib-util-test/test.h b/pjlib-util/src/pjlib-util-test/test.h index 2545bd7f..3b098dc0 100644 --- a/pjlib-util/src/pjlib-util-test/test.h +++ b/pjlib-util/src/pjlib-util-test/test.h @@ -1,3 +1,24 @@ +/* + * PJLIB - PJ Foundation Library + * (C)2003-2005 Benny Prijono + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ #include #define INCLUDE_XML_TEST 1 diff --git a/pjlib-util/src/pjlib-util-test/xml.c b/pjlib-util/src/pjlib-util-test/xml.c index d4e22746..440e0aef 100644 --- a/pjlib-util/src/pjlib-util-test/xml.c +++ b/pjlib-util/src/pjlib-util-test/xml.c @@ -1,129 +1,150 @@ -/* $Id$ - */ -#include "test.h" - - -#if INCLUDE_XML_TEST - -#include -#include - -#define THIS_FILE "xml_test" - -static const char *xml_doc[] = -{ -" \n" -" \n" -"\n" -" \n" -" \n" -" open\n" -" assistant\n" -" \n" -" \n" -" true\n" -" false\n" -" true\n" -" \n" -" tel:09012345678\n" -" \n" -"\n" -" \n" -" \n" -" open\n" -" \n" -" im:pep@example.com\n" -" \n" -"\n" -" \n" -" \n" -" closed\n" -" meeting\n" -" \n" -" http://example.com/~pep/\n" -" http://example.com/~pep/icon.gif\n" -" http://example.com/~pep/card.vcd\n" -" sip:pep@example.com\n" -" \n" -"\n" -" Full state presence document\n" -"\n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -"\n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -"\n" -" \n" -} -; - -static int xml_parse_print_test(const char *doc) -{ - pj_str_t msg; - pj_pool_t *pool; - pj_xml_node *root; - char *output; - int output_len; - - pool = pj_pool_create(mem, "xml", 4096, 1024, NULL); - pj_strdup2(pool, &msg, doc); - root = pj_xml_parse(pool, msg.ptr, msg.slen); - if (!root) { - PJ_LOG(1, (THIS_FILE, " Error: unable to parse XML")); - return -10; - } - - output = (char*)pj_pool_alloc(pool, msg.slen + 512); - pj_memset(output, 0, msg.slen+512); - output_len = pj_xml_print(root, output, msg.slen+512, PJ_TRUE); - if (output_len < 1) { - PJ_LOG(1, (THIS_FILE, " Error: buffer too small to print XML file")); - return -20; - } - output[output_len] = '\0'; - - - pj_pool_release(pool); - return 0; -} - -int xml_test() -{ - unsigned i; - for (i=0; i + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "test.h" + + +#if INCLUDE_XML_TEST + +#include +#include + +#define THIS_FILE "xml_test" + +static const char *xml_doc[] = +{ +" \n" +" \n" +"\n" +" \n" +" \n" +" open\n" +" assistant\n" +" \n" +" \n" +" true\n" +" false\n" +" true\n" +" \n" +" tel:09012345678\n" +" \n" +"\n" +" \n" +" \n" +" open\n" +" \n" +" im:pep@example.com\n" +" \n" +"\n" +" \n" +" \n" +" closed\n" +" meeting\n" +" \n" +" http://example.com/~pep/\n" +" http://example.com/~pep/icon.gif\n" +" http://example.com/~pep/card.vcd\n" +" sip:pep@example.com\n" +" \n" +"\n" +" Full state presence document\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +} +; + +static int xml_parse_print_test(const char *doc) +{ + pj_str_t msg; + pj_pool_t *pool; + pj_xml_node *root; + char *output; + int output_len; + + pool = pj_pool_create(mem, "xml", 4096, 1024, NULL); + pj_strdup2(pool, &msg, doc); + root = pj_xml_parse(pool, msg.ptr, msg.slen); + if (!root) { + PJ_LOG(1, (THIS_FILE, " Error: unable to parse XML")); + return -10; + } + + output = (char*)pj_pool_alloc(pool, msg.slen + 512); + pj_memset(output, 0, msg.slen+512); + output_len = pj_xml_print(root, output, msg.slen+512, PJ_TRUE); + if (output_len < 1) { + PJ_LOG(1, (THIS_FILE, " Error: buffer too small to print XML file")); + return -20; + } + output[output_len] = '\0'; + + + pj_pool_release(pool); + return 0; +} + +int xml_test() +{ + unsigned i; + for (i=0; i. Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -#include -#include -#include - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ - -/* -#ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -# define BYTE_ORDER 0 -#endif -*/ -/* pjlib: */ -#include -#if PJ_IS_LITTLE_ENDIAN -# define BYTE_ORDER -1 -#elif PJ_IS_BIG_ENDIAN -# define BYTE_ORDER 1 -#else -# error Endianess is not known! -#endif - - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; -#endif - - PJ_CHECK_STACK(); - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - PJ_CHECK_STACK(); - - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - PJ_CHECK_STACK(); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - PJ_CHECK_STACK(); - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} - +/* $Id$ + */ +/* + * PJLIB - PJ Foundation Library + * (C)2003-2005 Benny Prijono + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include +#include +#include + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ + +/* +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif +*/ +/* pjlib: */ +#include +#if PJ_IS_LITTLE_ENDIAN +# define BYTE_ORDER -1 +#elif PJ_IS_BIG_ENDIAN +# define BYTE_ORDER 1 +#else +# error Endianess is not known! +#endif + + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + PJ_CHECK_STACK(); + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + PJ_CHECK_STACK(); + + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + PJ_CHECK_STACK(); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + PJ_CHECK_STACK(); + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} + diff --git a/pjlib-util/src/pjlib-util/scanner.c b/pjlib-util/src/pjlib-util/scanner.c index 0e753dfb..edd8de54 100644 --- a/pjlib-util/src/pjlib-util/scanner.c +++ b/pjlib-util/src/pjlib-util/scanner.c @@ -1,26 +1,47 @@ -/* $Id$ - */ -#include -#include -#include -#include +/* $Id$ + */ +/* + * PJLIB - PJ Foundation Library + * (C)2003-2005 Benny Prijono + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include #include - -#define PJ_SCAN_IS_SPACE(c) ((c)==' ' || (c)=='\t') -#define PJ_SCAN_IS_NEWLINE(c) ((c)=='\r' || (c)=='\n') -#define PJ_SCAN_CHECK_EOF(s) (s != end) - - -static void pj_scan_syntax_err(pj_scanner *scanner) -{ - (*scanner->callback)(scanner); -} - -PJ_DEF(void) pj_cis_buf_init( pj_cis_buf_t *cis_buf) -{ + +#define PJ_SCAN_IS_SPACE(c) ((c)==' ' || (c)=='\t') +#define PJ_SCAN_IS_NEWLINE(c) ((c)=='\r' || (c)=='\n') +#define PJ_SCAN_CHECK_EOF(s) (s != end) + + +static void pj_scan_syntax_err(pj_scanner *scanner) +{ + (*scanner->callback)(scanner); +} + +PJ_DEF(void) pj_cis_buf_init( pj_cis_buf_t *cis_buf) +{ pj_memset(cis_buf->cis_buf, 0, sizeof(cis_buf->cis_buf)); - cis_buf->use_mask = 0; -} + cis_buf->use_mask = 0; +} PJ_DEF(pj_status_t) pj_cis_init(pj_cis_buf_t *cis_buf, pj_cis_t *cis) { @@ -57,521 +78,521 @@ PJ_DEF(pj_status_t) pj_cis_dup( pj_cis_t *new_cis, pj_cis_t *existing) return PJ_SUCCESS; } - -PJ_DEF(void) pj_cis_add_range(pj_cis_t *cis, int cstart, int cend) -{ + +PJ_DEF(void) pj_cis_add_range(pj_cis_t *cis, int cstart, int cend) +{ while (cstart != cend) { - PJ_CIS_SET(cis, cstart); + PJ_CIS_SET(cis, cstart); ++cstart; - } -} - -PJ_DEF(void) pj_cis_add_alpha(pj_cis_t *cis) -{ - pj_cis_add_range( cis, 'a', 'z'+1); - pj_cis_add_range( cis, 'A', 'Z'+1); -} - -PJ_DEF(void) pj_cis_add_num(pj_cis_t *cis) -{ - pj_cis_add_range( cis, '0', '9'+1); -} - -PJ_DEF(void) pj_cis_add_str( pj_cis_t *cis, const char *str) -{ - while (*str) { - PJ_CIS_SET(cis, *str); - ++str; - } -} - -PJ_DEF(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend) -{ - while (cstart != cend) { + } +} + +PJ_DEF(void) pj_cis_add_alpha(pj_cis_t *cis) +{ + pj_cis_add_range( cis, 'a', 'z'+1); + pj_cis_add_range( cis, 'A', 'Z'+1); +} + +PJ_DEF(void) pj_cis_add_num(pj_cis_t *cis) +{ + pj_cis_add_range( cis, '0', '9'+1); +} + +PJ_DEF(void) pj_cis_add_str( pj_cis_t *cis, const char *str) +{ + while (*str) { + PJ_CIS_SET(cis, *str); + ++str; + } +} + +PJ_DEF(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend) +{ + while (cstart != cend) { PJ_CIS_CLR(cis, cstart); cstart++; - } -} - -PJ_DEF(void) pj_cis_del_str( pj_cis_t *cis, const char *str) -{ - while (*str) { - PJ_CIS_CLR(cis, *str); - ++str; - } -} - -PJ_DEF(void) pj_cis_invert( pj_cis_t *cis ) -{ - unsigned i; - for (i=0; i<256; ++i) { + } +} + +PJ_DEF(void) pj_cis_del_str( pj_cis_t *cis, const char *str) +{ + while (*str) { + PJ_CIS_CLR(cis, *str); + ++str; + } +} + +PJ_DEF(void) pj_cis_invert( pj_cis_t *cis ) +{ + unsigned i; + for (i=0; i<256; ++i) { if (PJ_CIS_ISSET(cis,i)) PJ_CIS_CLR(cis,i); else - PJ_CIS_SET(cis,i); - } -} - -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->col = 1; - scanner->callback = callback; - scanner->skip_ws = options; - - if (scanner->skip_ws) - pj_scan_skip_whitespace(scanner); - - scanner->col = scanner->curptr - scanner->begin + 1; -} - - -PJ_DEF(void) pj_scan_fini( pj_scanner *scanner ) -{ - PJ_CHECK_STACK(); - PJ_UNUSED_ARG(scanner); -} - -PJ_DEF(void) pj_scan_skip_whitespace( pj_scanner *scanner ) -{ - register char *s = scanner->curptr; - - PJ_CHECK_STACK(); - - while (PJ_SCAN_IS_SPACE(*s)) { - ++s; - } - - if ((scanner->skip_ws & PJ_SCAN_AUTOSKIP_NEWLINE) && PJ_SCAN_IS_NEWLINE(*s)) { - for (;;) { - if (*s == '\r') { - ++s; - if (*s == '\n') ++s; - ++scanner->line; - scanner->col = 1; - scanner->curptr = s; - } else if (*s == '\n') { - ++s; - ++scanner->line; - scanner->col = 1; - scanner->curptr = s; - } else if (PJ_SCAN_IS_SPACE(*s)) { - do { - ++s; - } while (PJ_SCAN_IS_SPACE(*s)); - } else { - break; - } - } - } - - if (PJ_SCAN_IS_NEWLINE(*s) && (scanner->skip_ws & PJ_SCAN_AUTOSKIP_WS_HEADER)==PJ_SCAN_AUTOSKIP_WS_HEADER) { - /* Check for header continuation. */ - scanner->col += s - scanner->curptr; - scanner->curptr = s; - - if (*s == '\r') { - ++s; - } - if (*s == '\n') { - ++s; - } - if (PJ_SCAN_IS_SPACE(*s)) { - register char *t = s; - do { - ++t; - } while (PJ_SCAN_IS_SPACE(*t)); - - ++scanner->line; - scanner->col = t-s; - scanner->curptr = t; - } - } else { - scanner->col += s - scanner->curptr; - scanner->curptr = s; - } -} - -PJ_DEF(int) pj_scan_peek( pj_scanner *scanner, - const pj_cis_t *spec, pj_str_t *out) -{ - register char *s = scanner->curptr; - register char *end = scanner->end; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - pj_scan_syntax_err(scanner); - return -1; - } - - while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s)) - ++s; - - pj_strset3(out, scanner->curptr, s); - return s < scanner->end ? *s : 0; -} - - -PJ_DEF(int) pj_scan_peek_n( pj_scanner *scanner, - pj_size_t len, pj_str_t *out) -{ - char *endpos = scanner->curptr + len; - - PJ_CHECK_STACK(); - - if (endpos > scanner->end) { - pj_scan_syntax_err(scanner); - return -1; - } - - pj_strset(out, scanner->curptr, len); - return *endpos; -} - - -PJ_DEF(int) pj_scan_peek_until( pj_scanner *scanner, - const pj_cis_t *spec, - pj_str_t *out) -{ - register char *s = scanner->curptr; - register char *end = scanner->end; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - pj_scan_syntax_err(scanner); - return -1; - } - - while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match( spec, *s)) - ++s; - - pj_strset3(out, scanner->curptr, s); - return s!=scanner->end ? *s : 0; -} - - -PJ_DEF(void) pj_scan_get( pj_scanner *scanner, - const pj_cis_t *spec, pj_str_t *out) -{ - register char *s = scanner->curptr; - register char *end = scanner->end; - char *start = s; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner) || !pj_cis_match(spec, *s)) { - pj_scan_syntax_err(scanner); - return; - } - - do { - ++s; - } while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s)); - - pj_strset3(out, scanner->curptr, s); - - scanner->col += (s - start); - scanner->curptr = s; - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - - -PJ_DEF(void) pj_scan_get_quote( pj_scanner *scanner, - int begin_quote, int end_quote, - pj_str_t *out) -{ - register char *s = scanner->curptr; - register char *end = scanner->end; - char *start = s; - - PJ_CHECK_STACK(); - - /* Check and eat the begin_quote. */ - if (*s != begin_quote) { - pj_scan_syntax_err(scanner); - return; - } - ++s; - - /* Loop until end_quote is found. - */ - do { - /* loop until end_quote is found. */ - do { - ++s; - } while (s != end && *s != '\n' && *s != end_quote); - - /* check that no backslash character precedes the end_quote. */ - if (*s == end_quote) { - if (*(s-1) == '\\') { - if (s-2 == scanner->begin) { - break; - } else { - 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; - } - } - } 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) { - pj_scan_syntax_err(scanner); - return; - } - ++s; - - pj_strset3(out, scanner->curptr, s); - - scanner->col += (s - start); - scanner->curptr = s; - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - -PJ_DEF(void) pj_scan_get_n( pj_scanner *scanner, - unsigned N, pj_str_t *out) -{ - register char *s = scanner->curptr; - char *start = scanner->curptr; - - PJ_CHECK_STACK(); - - if (scanner->curptr + N > scanner->end) { - pj_scan_syntax_err(scanner); - return; - } - - pj_strset(out, s, N); - - s += N; - scanner->col += (s - start); - scanner->curptr = s; - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - - -PJ_DEF(int) pj_scan_get_char( pj_scanner *scanner ) -{ - char *start = scanner->curptr; - int chr = *start; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - pj_scan_syntax_err(scanner); - return 0; - } - - ++scanner->curptr; - scanner->col += (scanner->curptr - start); - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } - return chr; -} - - -PJ_DEF(void) pj_scan_get_newline( pj_scanner *scanner ) -{ - PJ_CHECK_STACK(); - - if (!PJ_SCAN_IS_NEWLINE(*scanner->curptr)) { - pj_scan_syntax_err(scanner); - return; - } - - if (*scanner->curptr == '\r') { - ++scanner->curptr; - } - if (*scanner->curptr == '\n') { - ++scanner->curptr; - } - - ++scanner->line; - scanner->col = 1; - - if (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; - register char *end = scanner->end; - char *start = s; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - 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->col += (s - start); - scanner->curptr = s; - - if (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; - register char *end = scanner->end; - char *start = s; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - pj_scan_syntax_err(scanner); - return; - } - - while (PJ_SCAN_CHECK_EOF(s) && *s != until_char) { - ++s; - } - - pj_strset3(out, scanner->curptr, s); - - scanner->col += (s - start); - scanner->curptr = s; - - if (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; - register char *end = scanner->end; - char *start = scanner->curptr; - - PJ_CHECK_STACK(); - - if (pj_scan_is_eof(scanner)) { - pj_scan_syntax_err(scanner); - return; - } - - while (PJ_SCAN_CHECK_EOF(s) && !strchr(until_spec, *s)) { - ++s; - } - - pj_strset3(out, scanner->curptr, s); - - scanner->col += (s - start); - scanner->curptr = s; - - if (scanner->skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - -PJ_DEF(void) pj_scan_advance_n( pj_scanner *scanner, - unsigned N, pj_bool_t skip_ws) -{ - char *start = scanner->curptr; - - PJ_CHECK_STACK(); - - if (scanner->curptr + N > scanner->end) { - pj_scan_syntax_err(scanner); - return; - } - - scanner->curptr += N; - scanner->col += (scanner->curptr - start); - - if (skip_ws) { - pj_scan_skip_whitespace(scanner); - } -} - - -PJ_DEF(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len) -{ - if (scanner->curptr + len > scanner->end) { - pj_scan_syntax_err(scanner); - return -1; - } - return strncmp(scanner->curptr, s, len); -} - - -PJ_DEF(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len) -{ - if (scanner->curptr + len > scanner->end) { - pj_scan_syntax_err(scanner); - return -1; - } - return strnicmp(scanner->curptr, s, len); -} - - -PJ_DEF(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state) -{ - PJ_CHECK_STACK(); - - state->curptr = scanner->curptr; - state->line = scanner->line; - state->col = scanner->col; -} - - -PJ_DEF(void) pj_scan_restore_state( pj_scanner *scanner, - pj_scan_state *state) -{ - PJ_CHECK_STACK(); - - scanner->curptr = state->curptr; - scanner->line = state->line; - scanner->col = state->col; -} - - + PJ_CIS_SET(cis,i); + } +} + +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->col = 1; + scanner->callback = callback; + scanner->skip_ws = options; + + if (scanner->skip_ws) + pj_scan_skip_whitespace(scanner); + + scanner->col = scanner->curptr - scanner->begin + 1; +} + + +PJ_DEF(void) pj_scan_fini( pj_scanner *scanner ) +{ + PJ_CHECK_STACK(); + PJ_UNUSED_ARG(scanner); +} + +PJ_DEF(void) pj_scan_skip_whitespace( pj_scanner *scanner ) +{ + register char *s = scanner->curptr; + + PJ_CHECK_STACK(); + + while (PJ_SCAN_IS_SPACE(*s)) { + ++s; + } + + if ((scanner->skip_ws & PJ_SCAN_AUTOSKIP_NEWLINE) && PJ_SCAN_IS_NEWLINE(*s)) { + for (;;) { + if (*s == '\r') { + ++s; + if (*s == '\n') ++s; + ++scanner->line; + scanner->col = 1; + scanner->curptr = s; + } else if (*s == '\n') { + ++s; + ++scanner->line; + scanner->col = 1; + scanner->curptr = s; + } else if (PJ_SCAN_IS_SPACE(*s)) { + do { + ++s; + } while (PJ_SCAN_IS_SPACE(*s)); + } else { + break; + } + } + } + + if (PJ_SCAN_IS_NEWLINE(*s) && (scanner->skip_ws & PJ_SCAN_AUTOSKIP_WS_HEADER)==PJ_SCAN_AUTOSKIP_WS_HEADER) { + /* Check for header continuation. */ + scanner->col += s - scanner->curptr; + scanner->curptr = s; + + if (*s == '\r') { + ++s; + } + if (*s == '\n') { + ++s; + } + if (PJ_SCAN_IS_SPACE(*s)) { + register char *t = s; + do { + ++t; + } while (PJ_SCAN_IS_SPACE(*t)); + + ++scanner->line; + scanner->col = t-s; + scanner->curptr = t; + } + } else { + scanner->col += s - scanner->curptr; + scanner->curptr = s; + } +} + +PJ_DEF(int) pj_scan_peek( pj_scanner *scanner, + const pj_cis_t *spec, pj_str_t *out) +{ + register char *s = scanner->curptr; + register char *end = scanner->end; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + pj_scan_syntax_err(scanner); + return -1; + } + + while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s)) + ++s; + + pj_strset3(out, scanner->curptr, s); + return s < scanner->end ? *s : 0; +} + + +PJ_DEF(int) pj_scan_peek_n( pj_scanner *scanner, + pj_size_t len, pj_str_t *out) +{ + char *endpos = scanner->curptr + len; + + PJ_CHECK_STACK(); + + if (endpos > scanner->end) { + pj_scan_syntax_err(scanner); + return -1; + } + + pj_strset(out, scanner->curptr, len); + return *endpos; +} + + +PJ_DEF(int) pj_scan_peek_until( pj_scanner *scanner, + const pj_cis_t *spec, + pj_str_t *out) +{ + register char *s = scanner->curptr; + register char *end = scanner->end; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + pj_scan_syntax_err(scanner); + return -1; + } + + while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match( spec, *s)) + ++s; + + pj_strset3(out, scanner->curptr, s); + return s!=scanner->end ? *s : 0; +} + + +PJ_DEF(void) pj_scan_get( pj_scanner *scanner, + const pj_cis_t *spec, pj_str_t *out) +{ + register char *s = scanner->curptr; + register char *end = scanner->end; + char *start = s; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner) || !pj_cis_match(spec, *s)) { + pj_scan_syntax_err(scanner); + return; + } + + do { + ++s; + } while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s)); + + pj_strset3(out, scanner->curptr, s); + + scanner->col += (s - start); + scanner->curptr = s; + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + + +PJ_DEF(void) pj_scan_get_quote( pj_scanner *scanner, + int begin_quote, int end_quote, + pj_str_t *out) +{ + register char *s = scanner->curptr; + register char *end = scanner->end; + char *start = s; + + PJ_CHECK_STACK(); + + /* Check and eat the begin_quote. */ + if (*s != begin_quote) { + pj_scan_syntax_err(scanner); + return; + } + ++s; + + /* Loop until end_quote is found. + */ + do { + /* loop until end_quote is found. */ + do { + ++s; + } while (s != end && *s != '\n' && *s != end_quote); + + /* check that no backslash character precedes the end_quote. */ + if (*s == end_quote) { + if (*(s-1) == '\\') { + if (s-2 == scanner->begin) { + break; + } else { + 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; + } + } + } 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) { + pj_scan_syntax_err(scanner); + return; + } + ++s; + + pj_strset3(out, scanner->curptr, s); + + scanner->col += (s - start); + scanner->curptr = s; + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + +PJ_DEF(void) pj_scan_get_n( pj_scanner *scanner, + unsigned N, pj_str_t *out) +{ + register char *s = scanner->curptr; + char *start = scanner->curptr; + + PJ_CHECK_STACK(); + + if (scanner->curptr + N > scanner->end) { + pj_scan_syntax_err(scanner); + return; + } + + pj_strset(out, s, N); + + s += N; + scanner->col += (s - start); + scanner->curptr = s; + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + + +PJ_DEF(int) pj_scan_get_char( pj_scanner *scanner ) +{ + char *start = scanner->curptr; + int chr = *start; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + pj_scan_syntax_err(scanner); + return 0; + } + + ++scanner->curptr; + scanner->col += (scanner->curptr - start); + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } + return chr; +} + + +PJ_DEF(void) pj_scan_get_newline( pj_scanner *scanner ) +{ + PJ_CHECK_STACK(); + + if (!PJ_SCAN_IS_NEWLINE(*scanner->curptr)) { + pj_scan_syntax_err(scanner); + return; + } + + if (*scanner->curptr == '\r') { + ++scanner->curptr; + } + if (*scanner->curptr == '\n') { + ++scanner->curptr; + } + + ++scanner->line; + scanner->col = 1; + + if (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; + register char *end = scanner->end; + char *start = s; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + 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->col += (s - start); + scanner->curptr = s; + + if (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; + register char *end = scanner->end; + char *start = s; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + pj_scan_syntax_err(scanner); + return; + } + + while (PJ_SCAN_CHECK_EOF(s) && *s != until_char) { + ++s; + } + + pj_strset3(out, scanner->curptr, s); + + scanner->col += (s - start); + scanner->curptr = s; + + if (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; + register char *end = scanner->end; + char *start = scanner->curptr; + + PJ_CHECK_STACK(); + + if (pj_scan_is_eof(scanner)) { + pj_scan_syntax_err(scanner); + return; + } + + while (PJ_SCAN_CHECK_EOF(s) && !strchr(until_spec, *s)) { + ++s; + } + + pj_strset3(out, scanner->curptr, s); + + scanner->col += (s - start); + scanner->curptr = s; + + if (scanner->skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + +PJ_DEF(void) pj_scan_advance_n( pj_scanner *scanner, + unsigned N, pj_bool_t skip_ws) +{ + char *start = scanner->curptr; + + PJ_CHECK_STACK(); + + if (scanner->curptr + N > scanner->end) { + pj_scan_syntax_err(scanner); + return; + } + + scanner->curptr += N; + scanner->col += (scanner->curptr - start); + + if (skip_ws) { + pj_scan_skip_whitespace(scanner); + } +} + + +PJ_DEF(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len) +{ + if (scanner->curptr + len > scanner->end) { + pj_scan_syntax_err(scanner); + return -1; + } + return strncmp(scanner->curptr, s, len); +} + + +PJ_DEF(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len) +{ + if (scanner->curptr + len > scanner->end) { + pj_scan_syntax_err(scanner); + return -1; + } + return strnicmp(scanner->curptr, s, len); +} + + +PJ_DEF(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state) +{ + PJ_CHECK_STACK(); + + state->curptr = scanner->curptr; + state->line = scanner->line; + state->col = scanner->col; +} + + +PJ_DEF(void) pj_scan_restore_state( pj_scanner *scanner, + pj_scan_state *state) +{ + PJ_CHECK_STACK(); + + scanner->curptr = state->curptr; + scanner->line = state->line; + scanner->col = state->col; +} + + diff --git a/pjlib-util/src/pjlib-util/stun.c b/pjlib-util/src/pjlib-util/stun.c index 4b417533..40566a69 100644 --- a/pjlib-util/src/pjlib-util/stun.c +++ b/pjlib-util/src/pjlib-util/stun.c @@ -1,113 +1,134 @@ -/* $Id$ - */ -#include -#include -#include -#include -#include - -#define THIS_FILE "stun" - -PJ_DEF(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, - void **msg, pj_size_t *len, - pj_uint32_t id_hi, - pj_uint32_t id_lo) -{ - pj_stun_msg_hdr *hdr; - - PJ_CHECK_STACK(); - - PJ_LOG(5,(THIS_FILE, "pj_stun_create_bind_req")); - - hdr = pj_pool_calloc(pool, 1, sizeof(pj_stun_msg_hdr)); - if (!hdr) { - PJ_LOG(5,(THIS_FILE, "Error allocating memory!")); - return -1; - } - - hdr->type = pj_htons(PJ_STUN_BINDING_REQUEST); - hdr->tsx[2] = pj_htonl(id_hi); - hdr->tsx[3] = pj_htonl(id_lo); - *msg = hdr; - *len = sizeof(pj_stun_msg_hdr); - - return 0; -} - -PJ_DEF(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, - pj_stun_msg *msg) -{ - pj_uint16_t msg_type, msg_len; - char *p_attr; - - PJ_CHECK_STACK(); - - PJ_LOG(5,(THIS_FILE, "pj_stun_parse_msg %p, len=%d", buf, len)); - - msg->hdr = (pj_stun_msg_hdr*)buf; - msg_type = pj_ntohs(msg->hdr->type); - - switch (msg_type) { - case PJ_STUN_BINDING_REQUEST: - case PJ_STUN_BINDING_RESPONSE: - case PJ_STUN_BINDING_ERROR_RESPONSE: - case PJ_STUN_SHARED_SECRET_REQUEST: - case PJ_STUN_SHARED_SECRET_RESPONSE: - case PJ_STUN_SHARED_SECRET_ERROR_RESPONSE: - break; - default: - PJ_LOG(5,(THIS_FILE, "Error: unknown msg type %d", msg_type)); - return -1; - } - - msg_len = pj_ntohs(msg->hdr->length); - if (msg_len != len - sizeof(pj_stun_msg_hdr)) { - PJ_LOG(5,(THIS_FILE, "Error: invalid msg_len %d (expecting %d)", - msg_len, len - sizeof(pj_stun_msg_hdr))); - return -1; - } - - msg->attr_count = 0; - p_attr = (char*)buf + sizeof(pj_stun_msg_hdr); - - while (msg_len > 0) { - pj_stun_attr_hdr **attr = &msg->attr[msg->attr_count]; - pj_uint32_t len; - - *attr = (pj_stun_attr_hdr*)p_attr; - len = pj_ntohs((pj_uint16_t) ((*attr)->length)) + sizeof(pj_stun_attr_hdr); - - if (msg_len < len) { - PJ_LOG(5,(THIS_FILE, "Error: length mismatch in attr %d", - msg->attr_count)); - return -1; - } - - if (pj_ntohs((*attr)->type) > PJ_STUN_ATTR_REFLECTED_FORM) { - PJ_LOG(5,(THIS_FILE, "Error: invalid attr type %d in attr %d", - pj_ntohs((*attr)->type), msg->attr_count)); - return -1; - } - - msg_len = (pj_uint16_t)(msg_len - len); - p_attr += len; - ++msg->attr_count; - } - - return 0; -} - -PJ_DEF(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t) -{ - int i; - - PJ_CHECK_STACK(); - - for (i=0; iattr_count; ++i) { - pj_stun_attr_hdr *attr = msg->attr[i]; - if (pj_ntohs(attr->type) == t) - return attr; - } - - return 0; -} +/* $Id$ + */ +/* + * PJLIB - PJ Foundation Library + * (C)2003-2005 Benny Prijono + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#define THIS_FILE "stun" + +PJ_DEF(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, + void **msg, pj_size_t *len, + pj_uint32_t id_hi, + pj_uint32_t id_lo) +{ + pj_stun_msg_hdr *hdr; + + PJ_CHECK_STACK(); + + PJ_LOG(5,(THIS_FILE, "pj_stun_create_bind_req")); + + hdr = pj_pool_calloc(pool, 1, sizeof(pj_stun_msg_hdr)); + if (!hdr) { + PJ_LOG(5,(THIS_FILE, "Error allocating memory!")); + return -1; + } + + hdr->type = pj_htons(PJ_STUN_BINDING_REQUEST); + hdr->tsx[2] = pj_htonl(id_hi); + hdr->tsx[3] = pj_htonl(id_lo); + *msg = hdr; + *len = sizeof(pj_stun_msg_hdr); + + return 0; +} + +PJ_DEF(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, + pj_stun_msg *msg) +{ + pj_uint16_t msg_type, msg_len; + char *p_attr; + + PJ_CHECK_STACK(); + + PJ_LOG(5,(THIS_FILE, "pj_stun_parse_msg %p, len=%d", buf, len)); + + msg->hdr = (pj_stun_msg_hdr*)buf; + msg_type = pj_ntohs(msg->hdr->type); + + switch (msg_type) { + case PJ_STUN_BINDING_REQUEST: + case PJ_STUN_BINDING_RESPONSE: + case PJ_STUN_BINDING_ERROR_RESPONSE: + case PJ_STUN_SHARED_SECRET_REQUEST: + case PJ_STUN_SHARED_SECRET_RESPONSE: + case PJ_STUN_SHARED_SECRET_ERROR_RESPONSE: + break; + default: + PJ_LOG(5,(THIS_FILE, "Error: unknown msg type %d", msg_type)); + return -1; + } + + msg_len = pj_ntohs(msg->hdr->length); + if (msg_len != len - sizeof(pj_stun_msg_hdr)) { + PJ_LOG(5,(THIS_FILE, "Error: invalid msg_len %d (expecting %d)", + msg_len, len - sizeof(pj_stun_msg_hdr))); + return -1; + } + + msg->attr_count = 0; + p_attr = (char*)buf + sizeof(pj_stun_msg_hdr); + + while (msg_len > 0) { + pj_stun_attr_hdr **attr = &msg->attr[msg->attr_count]; + pj_uint32_t len; + + *attr = (pj_stun_attr_hdr*)p_attr; + len = pj_ntohs((pj_uint16_t) ((*attr)->length)) + sizeof(pj_stun_attr_hdr); + + if (msg_len < len) { + PJ_LOG(5,(THIS_FILE, "Error: length mismatch in attr %d", + msg->attr_count)); + return -1; + } + + if (pj_ntohs((*attr)->type) > PJ_STUN_ATTR_REFLECTED_FORM) { + PJ_LOG(5,(THIS_FILE, "Error: invalid attr type %d in attr %d", + pj_ntohs((*attr)->type), msg->attr_count)); + return -1; + } + + msg_len = (pj_uint16_t)(msg_len - len); + p_attr += len; + ++msg->attr_count; + } + + return 0; +} + +PJ_DEF(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t) +{ + int i; + + PJ_CHECK_STACK(); + + for (i=0; iattr_count; ++i) { + pj_stun_attr_hdr *attr = msg->attr[i]; + if (pj_ntohs(attr->type) == t) + return attr; + } + + return 0; +} diff --git a/pjlib-util/src/pjlib-util/stun_client.c b/pjlib-util/src/pjlib-util/stun_client.c index 6bfca13f..57185321 100644 --- a/pjlib-util/src/pjlib-util/stun_client.c +++ b/pjlib-util/src/pjlib-util/stun_client.c @@ -1,261 +1,282 @@ -/* $Id$ - */ -#include -#include -#include -#include -#include -#include - -enum { MAX_REQUEST = 3 }; -static int stun_timer[] = {1600, 1600, 1600 }; - -#define THIS_FILE "stunclient" -#define LOG_ADDR(addr) pj_inet_ntoa(addr.sin_addr), pj_ntohs(addr.sin_port) - - -PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf, - int sock_cnt, pj_sock_t sock[], - const pj_str_t *srv1, int port1, - const pj_str_t *srv2, int port2, - pj_sockaddr_in mapped_addr[]) -{ - pj_sockaddr_in srv_addr[2]; - int i, j, rc, send_cnt = 0; - pj_pool_t *pool; - struct { - struct { - pj_uint32_t mapped_addr; - pj_uint32_t mapped_port; - } srv[2]; - } *rec; - void *out_msg; - pj_size_t out_msg_len; - int wait_resp = 0; - int mapped_status = 0; - - PJ_CHECK_STACK(); - - /* Create pool. */ - pool = pj_pool_create(pf, "stun%p", 1024, 1024, NULL); - if (!pool) { - mapped_status = PJ_STUN_ERR_MEMORY; - return -1; - } - - /* Allocate client records */ - rec = pj_pool_calloc(pool, sock_cnt, sizeof(*rec)); - if (!rec) { - mapped_status = PJ_STUN_ERR_MEMORY; - goto on_error; - } - - /* Create the outgoing BIND REQUEST message template */ - rc = pj_stun_create_bind_req( pool, &out_msg, &out_msg_len, 0, 0); - if (rc != 0) { - mapped_status = -1; - goto on_error; - } - - /* Resolve servers. */ - if (pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1) != 0) { - mapped_status = PJ_STUN_ERR_RESOLVE; - goto on_error; - } - if (pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2) != 0) { - mapped_status = PJ_STUN_ERR_RESOLVE; - goto on_error; - } - - /* Init mapped addresses to zero */ - pj_memset(mapped_addr, 0, sock_cnt * sizeof(pj_sockaddr_in)); - - /* Main retransmission loop. */ - for (send_cnt=0; send_cnttsx[2] = pj_htonl(i); - msg_hdr->tsx[3] = pj_htonl(j); - - /* Send! */ - sent_len = out_msg_len; - rc = pj_sock_sendto(sock[i], out_msg, &sent_len, 0, - (pj_sockaddr_t*)&srv_addr[j], - sizeof(pj_sockaddr_in)); - if (sent_len != (int)out_msg_len) { - PJ_LOG(4,(THIS_FILE, - "Error sending STUN request to %s:%d", - LOG_ADDR(srv_addr[j]))); - mapped_status = PJ_STUN_ERR_TRANSPORT; - } else { - ++wait_resp; - } - } - } - - /* All requests sent. - * The loop below will wait for responses until all responses have - * been received (i.e. wait_resp==0) or timeout occurs, which then - * we'll go to the next retransmission iteration. - */ - - /* Calculate time of next retransmission. */ - pj_gettimeofday(&next_tx); - next_tx.sec += (stun_timer[send_cnt]/1000); - next_tx.msec += (stun_timer[send_cnt]%1000); - pj_time_val_normalize(&next_tx); - - for (pj_gettimeofday(&now), select_rc=1; - mapped_status==0 && select_rc==1 && wait_resp>0 && PJ_TIME_VAL_LT(now, next_tx); - pj_gettimeofday(&now)) - { - pj_time_val timeout; - - timeout = next_tx; - PJ_TIME_VAL_SUB(timeout, now); - - for (i=0; itsx[2]); - srv_idx = pj_ntohl(msg.hdr->tsx[3]); - - if (sock_idx<0 || sock_idx>=sock_cnt || srv_idx<0 || srv_idx>=2) { - PJ_LOG(4,(THIS_FILE, - "Invalid transaction ID from %s:%d", - LOG_ADDR(addr))); - mapped_status = PJ_STUN_ERR_INVALID_MSG; - continue; - } - - if (pj_ntohs(msg.hdr->type) != PJ_STUN_BINDING_RESPONSE) { - PJ_LOG(4,(THIS_FILE, - "Non binding response %d from %s:%d", - pj_ntohs(msg.hdr->type), LOG_ADDR(addr))); - mapped_status = PJ_STUN_ERR_INVALID_MSG; - continue; - } - - if (pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_ERROR_CODE) != NULL) { - PJ_LOG(4,(THIS_FILE, - "Got STUN error attribute from %s:%d", - LOG_ADDR(addr))); - mapped_status = PJ_STUN_ERR_INVALID_MSG; - continue; - } - - attr = (void*)pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_MAPPED_ADDR); - if (!attr) { - PJ_LOG(4,(THIS_FILE, - "No mapped address in response from %s:%d", - LOG_ADDR(addr))); - mapped_status = PJ_STUN_ERR_INVALID_MSG; - continue; - } - - rec[sock_idx].srv[srv_idx].mapped_addr = attr->addr; - rec[sock_idx].srv[srv_idx].mapped_port = attr->port; - } - } - - /* The best scenario is if all requests have been replied. - * Then we don't need to go to the next retransmission iteration. - */ - if (wait_resp <= 0) - break; - } - - for (i=0; i + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +enum { MAX_REQUEST = 3 }; +static int stun_timer[] = {1600, 1600, 1600 }; + +#define THIS_FILE "stunclient" +#define LOG_ADDR(addr) pj_inet_ntoa(addr.sin_addr), pj_ntohs(addr.sin_port) + + +PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf, + int sock_cnt, pj_sock_t sock[], + const pj_str_t *srv1, int port1, + const pj_str_t *srv2, int port2, + pj_sockaddr_in mapped_addr[]) +{ + pj_sockaddr_in srv_addr[2]; + int i, j, rc, send_cnt = 0; + pj_pool_t *pool; + struct { + struct { + pj_uint32_t mapped_addr; + pj_uint32_t mapped_port; + } srv[2]; + } *rec; + void *out_msg; + pj_size_t out_msg_len; + int wait_resp = 0; + int mapped_status = 0; + + PJ_CHECK_STACK(); + + /* Create pool. */ + pool = pj_pool_create(pf, "stun%p", 1024, 1024, NULL); + if (!pool) { + mapped_status = PJ_STUN_ERR_MEMORY; + return -1; + } + + /* Allocate client records */ + rec = pj_pool_calloc(pool, sock_cnt, sizeof(*rec)); + if (!rec) { + mapped_status = PJ_STUN_ERR_MEMORY; + goto on_error; + } + + /* Create the outgoing BIND REQUEST message template */ + rc = pj_stun_create_bind_req( pool, &out_msg, &out_msg_len, 0, 0); + if (rc != 0) { + mapped_status = -1; + goto on_error; + } + + /* Resolve servers. */ + if (pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1) != 0) { + mapped_status = PJ_STUN_ERR_RESOLVE; + goto on_error; + } + if (pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2) != 0) { + mapped_status = PJ_STUN_ERR_RESOLVE; + goto on_error; + } + + /* Init mapped addresses to zero */ + pj_memset(mapped_addr, 0, sock_cnt * sizeof(pj_sockaddr_in)); + + /* Main retransmission loop. */ + for (send_cnt=0; send_cnttsx[2] = pj_htonl(i); + msg_hdr->tsx[3] = pj_htonl(j); + + /* Send! */ + sent_len = out_msg_len; + rc = pj_sock_sendto(sock[i], out_msg, &sent_len, 0, + (pj_sockaddr_t*)&srv_addr[j], + sizeof(pj_sockaddr_in)); + if (sent_len != (int)out_msg_len) { + PJ_LOG(4,(THIS_FILE, + "Error sending STUN request to %s:%d", + LOG_ADDR(srv_addr[j]))); + mapped_status = PJ_STUN_ERR_TRANSPORT; + } else { + ++wait_resp; + } + } + } + + /* All requests sent. + * The loop below will wait for responses until all responses have + * been received (i.e. wait_resp==0) or timeout occurs, which then + * we'll go to the next retransmission iteration. + */ + + /* Calculate time of next retransmission. */ + pj_gettimeofday(&next_tx); + next_tx.sec += (stun_timer[send_cnt]/1000); + next_tx.msec += (stun_timer[send_cnt]%1000); + pj_time_val_normalize(&next_tx); + + for (pj_gettimeofday(&now), select_rc=1; + mapped_status==0 && select_rc==1 && wait_resp>0 && PJ_TIME_VAL_LT(now, next_tx); + pj_gettimeofday(&now)) + { + pj_time_val timeout; + + timeout = next_tx; + PJ_TIME_VAL_SUB(timeout, now); + + for (i=0; itsx[2]); + srv_idx = pj_ntohl(msg.hdr->tsx[3]); + + if (sock_idx<0 || sock_idx>=sock_cnt || srv_idx<0 || srv_idx>=2) { + PJ_LOG(4,(THIS_FILE, + "Invalid transaction ID from %s:%d", + LOG_ADDR(addr))); + mapped_status = PJ_STUN_ERR_INVALID_MSG; + continue; + } + + if (pj_ntohs(msg.hdr->type) != PJ_STUN_BINDING_RESPONSE) { + PJ_LOG(4,(THIS_FILE, + "Non binding response %d from %s:%d", + pj_ntohs(msg.hdr->type), LOG_ADDR(addr))); + mapped_status = PJ_STUN_ERR_INVALID_MSG; + continue; + } + + if (pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_ERROR_CODE) != NULL) { + PJ_LOG(4,(THIS_FILE, + "Got STUN error attribute from %s:%d", + LOG_ADDR(addr))); + mapped_status = PJ_STUN_ERR_INVALID_MSG; + continue; + } + + attr = (void*)pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_MAPPED_ADDR); + if (!attr) { + PJ_LOG(4,(THIS_FILE, + "No mapped address in response from %s:%d", + LOG_ADDR(addr))); + mapped_status = PJ_STUN_ERR_INVALID_MSG; + continue; + } + + rec[sock_idx].srv[srv_idx].mapped_addr = attr->addr; + rec[sock_idx].srv[srv_idx].mapped_port = attr->port; + } + } + + /* The best scenario is if all requests have been replied. + * Then we don't need to go to the next retransmission iteration. + */ + if (wait_resp <= 0) + break; + } + + for (i=0; i + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ #include #include diff --git a/pjlib-util/src/pjlib-util/xml.c b/pjlib-util/src/pjlib-util/xml.c index 600666d6..dd9fb4df 100644 --- a/pjlib-util/src/pjlib-util/xml.c +++ b/pjlib-util/src/pjlib-util/xml.c @@ -1,380 +1,401 @@ -/* $Id$ - */ -#include -#include -#include -#include -#include -#include -#include - -#define EX_SYNTAX_ERROR 12 -#define THIS_FILE "xml.c" - -static void on_syntax_error(struct pj_scanner *scanner) -{ - PJ_UNUSED_ARG(scanner); - PJ_THROW(EX_SYNTAX_ERROR); -} - -static pj_xml_node *alloc_node( pj_pool_t *pool ) -{ - pj_xml_node *node; - - node = pj_pool_calloc(pool, 1, sizeof(pj_xml_node)); - pj_list_init( &node->attr_head ); - pj_list_init( &node->node_head ); - - return node; -} - -static pj_xml_attr *alloc_attr( pj_pool_t *pool ) -{ - return pj_pool_calloc(pool, 1, sizeof(pj_xml_attr)); -} - -/* This is a recursive function! */ -static pj_xml_node *xml_parse_node( pj_pool_t *pool, pj_scanner *scanner) -{ - pj_xml_node *node; - pj_str_t end_name; - - PJ_CHECK_STACK(); - - if (*scanner->curptr != '<') - on_syntax_error(scanner); - - /* Handle Processing Instructino (PI) construct (i.e. "curptr == '<' && *(scanner->curptr+1) == '?') { - pj_scan_advance_n(scanner, 2, PJ_FALSE); - for (;;) { - pj_str_t dummy; - pj_scan_get_until_ch(scanner, '?', &dummy); - if (*scanner->curptr=='?' && *(scanner->curptr+1)=='>') { - pj_scan_advance_n(scanner, 2, PJ_TRUE); - break; - } else { - pj_scan_advance_n(scanner, 1, PJ_FALSE); - } - } - return xml_parse_node(pool, scanner); - } - - /* Handle comments construct (i.e. "", 3) == 0) { - pj_scan_advance_n(scanner, 3, PJ_TRUE); - break; - } else { - pj_scan_advance_n(scanner, 1, PJ_FALSE); - } - } - return xml_parse_node(pool, scanner); - } - - /* Alloc node. */ - node = alloc_node(pool); - - /* Get '<' */ - pj_scan_get_char(scanner); - - /* Get node name. */ - pj_scan_get_until_chr( scanner, " />\t", &node->name); - - /* Get attributes. */ - while (*scanner->curptr != '>' && *scanner->curptr != '/') { - pj_xml_attr *attr = alloc_attr(pool); - - pj_scan_get_until_chr( scanner, "=> \t", &attr->name); - if (*scanner->curptr == '=') { - pj_scan_get_char( scanner ); - pj_scan_get_quote(scanner, '"', '"', &attr->value); - /* remove quote characters */ - ++attr->value.ptr; - attr->value.slen -= 2; - } - - pj_list_insert_before( &node->attr_head, attr ); - } - - if (*scanner->curptr == '/') { - pj_scan_get_char(scanner); - if (pj_scan_get_char(scanner) != '>') - on_syntax_error(scanner); - return node; - } - - /* Enclosing bracket. */ - if (pj_scan_get_char(scanner) != '>') - on_syntax_error(scanner); - - /* Sub nodes. */ - while (*scanner->curptr == '<' && *(scanner->curptr+1) != '/') { - pj_xml_node *sub_node = xml_parse_node(pool, scanner); - pj_list_insert_before( &node->node_head, sub_node ); - } - - /* Content. */ - if (!pj_scan_is_eof(scanner) && *scanner->curptr != '<') { - pj_scan_get_until_ch(scanner, '<', &node->content); - } - - /* Enclosing node. */ - if (pj_scan_get_char(scanner) != '<' || pj_scan_get_char(scanner) != '/') - on_syntax_error(scanner); - - pj_scan_get_until_chr(scanner, " \t>", &end_name); - - /* Compare name. */ - if (pj_stricmp(&node->name, &end_name) != 0) - on_syntax_error(scanner); - - /* Enclosing '>' */ - if (pj_scan_get_char(scanner) != '>') - on_syntax_error(scanner); - - return node; -} - -PJ_DEF(pj_xml_node*) pj_xml_parse( pj_pool_t *pool, char *msg, pj_size_t len) -{ - pj_xml_node *node = NULL; - pj_scanner scanner; - PJ_USE_EXCEPTION; - - if (!msg || !len || !pool) - return NULL; - - pj_scan_init( &scanner, msg, len, - PJ_SCAN_AUTOSKIP_WS|PJ_SCAN_AUTOSKIP_NEWLINE, - &on_syntax_error); - PJ_TRY { - node = xml_parse_node(pool, &scanner); - } - PJ_DEFAULT { - PJ_LOG(4,(THIS_FILE, "Syntax error parsing XML in line %d column %d", - scanner.line, scanner.col)); - } - PJ_END; - pj_scan_fini( &scanner ); - return node; -} - -/* This is a recursive function. */ -static int xml_print_node( const pj_xml_node *node, int indent, - char *buf, pj_size_t len ) -{ - int i; - char *p = buf; - pj_xml_attr *attr; - pj_xml_node *sub_node; - -#define SIZE_LEFT() ((int)(len - (p-buf))) - - PJ_CHECK_STACK(); - - /* Print name. */ - if (SIZE_LEFT() < node->name.slen + indent + 5) - return -1; - for (i=0; iname.ptr, node->name.slen); - p += node->name.slen; - - /* Print attributes. */ - attr = node->attr_head.next; - while (attr != &node->attr_head) { - - if (SIZE_LEFT() < attr->name.slen + attr->value.slen + 4) - return -1; - - *p++ = ' '; - - /* Attribute name. */ - pj_memcpy(p, attr->name.ptr, attr->name.slen); - p += attr->name.slen; - - /* Attribute value. */ - if (attr->value.slen) { - *p++ = '='; - *p++ = '"'; - pj_memcpy(p, attr->value.ptr, attr->value.slen); - p += attr->value.slen; - *p++ = '"'; - } - - attr = attr->next; - } - - /* Check for empty node. */ - if (node->content.slen==0 && - node->node_head.next==(pj_xml_node*)&node->node_head) - { - *p++ = ' '; - *p++ = '/'; - *p++ = '>'; - return p-buf; - } - - /* Enclosing '>' */ - if (SIZE_LEFT() < 1) return -1; - *p++ = '>'; - - /* Print sub nodes. */ - sub_node = node->node_head.next; - while (sub_node != (pj_xml_node*)&node->node_head) { - int printed; - - if (SIZE_LEFT() < indent + 3) - return -1; - //*p++ = '\r'; - *p++ = '\n'; - - printed = xml_print_node(sub_node, indent + 1, p, SIZE_LEFT()); - if (printed < 0) - return -1; - - p += printed; - sub_node = sub_node->next; - } - - /* Content. */ - if (node->content.slen) { - if (SIZE_LEFT() < node->content.slen) return -1; - pj_memcpy(p, node->content.ptr, node->content.slen); - p += node->content.slen; - } - - /* Enclosing node. */ - if (node->node_head.next != (pj_xml_node*)&node->node_head) { - if (SIZE_LEFT() < node->name.slen + 5 + indent) - return -1; - //*p++ = '\r'; - *p++ = '\n'; - for (i=0; iname.slen + 3) - return -1; - } - *p++ = '<'; - *p++ = '/'; - pj_memcpy(p, node->name.ptr, node->name.slen); - p += node->name.slen; - *p++ = '>'; - -#undef SIZE_LEFT - - return p - buf; -} - -PJ_DEF(int) pj_xml_print(const pj_xml_node *node, char *buf, pj_size_t len, - pj_bool_t include_prolog) -{ - int prolog_len = 0; - int printed; - - if (!node || !buf || !len) - return 0; - - if (include_prolog) { - pj_str_t prolog = {"\n", 39}; - if ((int)len < prolog.slen) - return -1; - pj_memcpy(buf, prolog.ptr, prolog.slen); - prolog_len = prolog.slen; - } - - printed = xml_print_node(node, 0, buf+prolog_len, len-prolog_len) + prolog_len; - if (printed > 0 && len-printed >= 1) { - buf[printed++] = '\n'; - } - return printed; -} - - -PJ_DEF(void) pj_xml_add_node( pj_xml_node *parent, pj_xml_node *node ) -{ - pj_list_insert_before(&parent->node_head, node); -} - -PJ_DEF(void) pj_xml_add_attr( pj_xml_node *node, pj_xml_attr *attr ) -{ - pj_list_insert_before(&node->attr_head, attr); -} - -PJ_DEF(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name) -{ - pj_xml_node *node = parent->node_head.next; - - PJ_CHECK_STACK(); - - while (node != (void*)&parent->node_head) { - if (pj_stricmp(&node->name, name) == 0) - return node; - node = node->next; - } - return NULL; -} - - -PJ_DEF(pj_xml_node*) pj_xml_find_next_node( pj_xml_node *parent, pj_xml_node *node, - const pj_str_t *name) -{ - PJ_CHECK_STACK(); - - node = node->next; - while (node != (void*)&parent->node_head) { - if (pj_stricmp(&node->name, name) == 0) - return node; - node = node->next; - } - return NULL; -} - - -PJ_DEF(pj_xml_attr*) pj_xml_find_attr( pj_xml_node *node, const pj_str_t *name, - const pj_str_t *value) -{ - pj_xml_attr *attr = node->attr_head.next; - while (attr != (void*)&node->attr_head) { - if (pj_stricmp(&attr->name, name)==0) { - if (value) { - if (pj_stricmp(&attr->value, value)==0) - return attr; - } else { - return attr; - } - } - attr = attr->next; - } - return NULL; -} - - - -PJ_DEF(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name, - const void *data, - pj_bool_t (*match)(pj_xml_node *, const void*)) -{ - pj_xml_node *head = (void*)&parent->node_head, *node = head->next; - - while (node != (void*)head) { - if (name && pj_stricmp(&node->name, name)==0) { - if (match) { - if (match(node, data)) - return node; - } else { - return node; - } - } - node = node->next; - } - return NULL; -} - +/* $Id$ + */ +/* + * PJLIB - PJ Foundation Library + * (C)2003-2005 Benny Prijono + * + * Author: + * Benny Prijono + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include + +#define EX_SYNTAX_ERROR 12 +#define THIS_FILE "xml.c" + +static void on_syntax_error(struct pj_scanner *scanner) +{ + PJ_UNUSED_ARG(scanner); + PJ_THROW(EX_SYNTAX_ERROR); +} + +static pj_xml_node *alloc_node( pj_pool_t *pool ) +{ + pj_xml_node *node; + + node = pj_pool_calloc(pool, 1, sizeof(pj_xml_node)); + pj_list_init( &node->attr_head ); + pj_list_init( &node->node_head ); + + return node; +} + +static pj_xml_attr *alloc_attr( pj_pool_t *pool ) +{ + return pj_pool_calloc(pool, 1, sizeof(pj_xml_attr)); +} + +/* This is a recursive function! */ +static pj_xml_node *xml_parse_node( pj_pool_t *pool, pj_scanner *scanner) +{ + pj_xml_node *node; + pj_str_t end_name; + + PJ_CHECK_STACK(); + + if (*scanner->curptr != '<') + on_syntax_error(scanner); + + /* Handle Processing Instructino (PI) construct (i.e. "curptr == '<' && *(scanner->curptr+1) == '?') { + pj_scan_advance_n(scanner, 2, PJ_FALSE); + for (;;) { + pj_str_t dummy; + pj_scan_get_until_ch(scanner, '?', &dummy); + if (*scanner->curptr=='?' && *(scanner->curptr+1)=='>') { + pj_scan_advance_n(scanner, 2, PJ_TRUE); + break; + } else { + pj_scan_advance_n(scanner, 1, PJ_FALSE); + } + } + return xml_parse_node(pool, scanner); + } + + /* Handle comments construct (i.e. "", 3) == 0) { + pj_scan_advance_n(scanner, 3, PJ_TRUE); + break; + } else { + pj_scan_advance_n(scanner, 1, PJ_FALSE); + } + } + return xml_parse_node(pool, scanner); + } + + /* Alloc node. */ + node = alloc_node(pool); + + /* Get '<' */ + pj_scan_get_char(scanner); + + /* Get node name. */ + pj_scan_get_until_chr( scanner, " />\t", &node->name); + + /* Get attributes. */ + while (*scanner->curptr != '>' && *scanner->curptr != '/') { + pj_xml_attr *attr = alloc_attr(pool); + + pj_scan_get_until_chr( scanner, "=> \t", &attr->name); + if (*scanner->curptr == '=') { + pj_scan_get_char( scanner ); + pj_scan_get_quote(scanner, '"', '"', &attr->value); + /* remove quote characters */ + ++attr->value.ptr; + attr->value.slen -= 2; + } + + pj_list_insert_before( &node->attr_head, attr ); + } + + if (*scanner->curptr == '/') { + pj_scan_get_char(scanner); + if (pj_scan_get_char(scanner) != '>') + on_syntax_error(scanner); + return node; + } + + /* Enclosing bracket. */ + if (pj_scan_get_char(scanner) != '>') + on_syntax_error(scanner); + + /* Sub nodes. */ + while (*scanner->curptr == '<' && *(scanner->curptr+1) != '/') { + pj_xml_node *sub_node = xml_parse_node(pool, scanner); + pj_list_insert_before( &node->node_head, sub_node ); + } + + /* Content. */ + if (!pj_scan_is_eof(scanner) && *scanner->curptr != '<') { + pj_scan_get_until_ch(scanner, '<', &node->content); + } + + /* Enclosing node. */ + if (pj_scan_get_char(scanner) != '<' || pj_scan_get_char(scanner) != '/') + on_syntax_error(scanner); + + pj_scan_get_until_chr(scanner, " \t>", &end_name); + + /* Compare name. */ + if (pj_stricmp(&node->name, &end_name) != 0) + on_syntax_error(scanner); + + /* Enclosing '>' */ + if (pj_scan_get_char(scanner) != '>') + on_syntax_error(scanner); + + return node; +} + +PJ_DEF(pj_xml_node*) pj_xml_parse( pj_pool_t *pool, char *msg, pj_size_t len) +{ + pj_xml_node *node = NULL; + pj_scanner scanner; + PJ_USE_EXCEPTION; + + if (!msg || !len || !pool) + return NULL; + + pj_scan_init( &scanner, msg, len, + PJ_SCAN_AUTOSKIP_WS|PJ_SCAN_AUTOSKIP_NEWLINE, + &on_syntax_error); + PJ_TRY { + node = xml_parse_node(pool, &scanner); + } + PJ_DEFAULT { + PJ_LOG(4,(THIS_FILE, "Syntax error parsing XML in line %d column %d", + scanner.line, scanner.col)); + } + PJ_END; + pj_scan_fini( &scanner ); + return node; +} + +/* This is a recursive function. */ +static int xml_print_node( const pj_xml_node *node, int indent, + char *buf, pj_size_t len ) +{ + int i; + char *p = buf; + pj_xml_attr *attr; + pj_xml_node *sub_node; + +#define SIZE_LEFT() ((int)(len - (p-buf))) + + PJ_CHECK_STACK(); + + /* Print name. */ + if (SIZE_LEFT() < node->name.slen + indent + 5) + return -1; + for (i=0; iname.ptr, node->name.slen); + p += node->name.slen; + + /* Print attributes. */ + attr = node->attr_head.next; + while (attr != &node->attr_head) { + + if (SIZE_LEFT() < attr->name.slen + attr->value.slen + 4) + return -1; + + *p++ = ' '; + + /* Attribute name. */ + pj_memcpy(p, attr->name.ptr, attr->name.slen); + p += attr->name.slen; + + /* Attribute value. */ + if (attr->value.slen) { + *p++ = '='; + *p++ = '"'; + pj_memcpy(p, attr->value.ptr, attr->value.slen); + p += attr->value.slen; + *p++ = '"'; + } + + attr = attr->next; + } + + /* Check for empty node. */ + if (node->content.slen==0 && + node->node_head.next==(pj_xml_node*)&node->node_head) + { + *p++ = ' '; + *p++ = '/'; + *p++ = '>'; + return p-buf; + } + + /* Enclosing '>' */ + if (SIZE_LEFT() < 1) return -1; + *p++ = '>'; + + /* Print sub nodes. */ + sub_node = node->node_head.next; + while (sub_node != (pj_xml_node*)&node->node_head) { + int printed; + + if (SIZE_LEFT() < indent + 3) + return -1; + //*p++ = '\r'; + *p++ = '\n'; + + printed = xml_print_node(sub_node, indent + 1, p, SIZE_LEFT()); + if (printed < 0) + return -1; + + p += printed; + sub_node = sub_node->next; + } + + /* Content. */ + if (node->content.slen) { + if (SIZE_LEFT() < node->content.slen) return -1; + pj_memcpy(p, node->content.ptr, node->content.slen); + p += node->content.slen; + } + + /* Enclosing node. */ + if (node->node_head.next != (pj_xml_node*)&node->node_head) { + if (SIZE_LEFT() < node->name.slen + 5 + indent) + return -1; + //*p++ = '\r'; + *p++ = '\n'; + for (i=0; iname.slen + 3) + return -1; + } + *p++ = '<'; + *p++ = '/'; + pj_memcpy(p, node->name.ptr, node->name.slen); + p += node->name.slen; + *p++ = '>'; + +#undef SIZE_LEFT + + return p - buf; +} + +PJ_DEF(int) pj_xml_print(const pj_xml_node *node, char *buf, pj_size_t len, + pj_bool_t include_prolog) +{ + int prolog_len = 0; + int printed; + + if (!node || !buf || !len) + return 0; + + if (include_prolog) { + pj_str_t prolog = {"\n", 39}; + if ((int)len < prolog.slen) + return -1; + pj_memcpy(buf, prolog.ptr, prolog.slen); + prolog_len = prolog.slen; + } + + printed = xml_print_node(node, 0, buf+prolog_len, len-prolog_len) + prolog_len; + if (printed > 0 && len-printed >= 1) { + buf[printed++] = '\n'; + } + return printed; +} + + +PJ_DEF(void) pj_xml_add_node( pj_xml_node *parent, pj_xml_node *node ) +{ + pj_list_insert_before(&parent->node_head, node); +} + +PJ_DEF(void) pj_xml_add_attr( pj_xml_node *node, pj_xml_attr *attr ) +{ + pj_list_insert_before(&node->attr_head, attr); +} + +PJ_DEF(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name) +{ + pj_xml_node *node = parent->node_head.next; + + PJ_CHECK_STACK(); + + while (node != (void*)&parent->node_head) { + if (pj_stricmp(&node->name, name) == 0) + return node; + node = node->next; + } + return NULL; +} + + +PJ_DEF(pj_xml_node*) pj_xml_find_next_node( pj_xml_node *parent, pj_xml_node *node, + const pj_str_t *name) +{ + PJ_CHECK_STACK(); + + node = node->next; + while (node != (void*)&parent->node_head) { + if (pj_stricmp(&node->name, name) == 0) + return node; + node = node->next; + } + return NULL; +} + + +PJ_DEF(pj_xml_attr*) pj_xml_find_attr( pj_xml_node *node, const pj_str_t *name, + const pj_str_t *value) +{ + pj_xml_attr *attr = node->attr_head.next; + while (attr != (void*)&node->attr_head) { + if (pj_stricmp(&attr->name, name)==0) { + if (value) { + if (pj_stricmp(&attr->value, value)==0) + return attr; + } else { + return attr; + } + } + attr = attr->next; + } + return NULL; +} + + + +PJ_DEF(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name, + const void *data, + pj_bool_t (*match)(pj_xml_node *, const void*)) +{ + pj_xml_node *head = (void*)&parent->node_head, *node = head->next; + + while (node != (void*)head) { + if (name && pj_stricmp(&node->name, name)==0) { + if (match) { + if (match(node, data)) + return node; + } else { + return node; + } + } + node = node->next; + } + return NULL; +} + -- cgit v1.2.3