diff options
author | Benny Prijono <bennylp@teluu.com> | 2005-11-21 01:55:47 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2005-11-21 01:55:47 +0000 |
commit | 5f1de1bbb341ea1dc1d27d9bf35764b643ef904a (patch) | |
tree | d18b0365b69b8b488a0b2b2bd715e9f14f77b505 /pjlib-util/src | |
parent | 9f4da35e676737f830a90a18de08440cf0f6cdf9 (diff) |
Set svn:eol-style property
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@65 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjlib-util/src')
-rw-r--r-- | pjlib-util/src/pjlib-util-test/main.c | 106 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util-test/test.c | 172 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util-test/test.h | 56 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util-test/xml.c | 290 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/md5.c | 558 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/scanner.c | 1190 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/string.c | 206 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/stun.c | 258 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/stun_client.c | 554 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/symbols.c | 164 | ||||
-rw-r--r-- | pjlib-util/src/pjlib-util/xml.c | 792 |
11 files changed, 2177 insertions, 2169 deletions
diff --git a/pjlib-util/src/pjlib-util-test/main.c b/pjlib-util/src/pjlib-util-test/main.c index 2fc23a79..9925b710 100644 --- a/pjlib-util/src/pjlib-util-test/main.c +++ b/pjlib-util/src/pjlib-util-test/main.c @@ -1,53 +1,53 @@ -/* $Id */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; 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
-#include <signal.h>
-static void init_signals()
-{
- struct sigaction act;
-
- memset(&act, 0, sizeof(act));
- act.sa_handler = SIG_IGN;
-
- sigaction(SIGALRM, &act, NULL);
-}
-
-#else
-#define init_signals()
-#endif
-
-#define boost()
-
-int main(int argc, char *argv[])
-{
- int rc;
-
- PJ_UNUSED_ARG(argc);
- PJ_UNUSED_ARG(argv);
-
- boost();
- init_signals();
-
- rc = test_main();
-
- return rc;
-}
-
+/* $Id */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; 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 +#include <signal.h> +static void init_signals() +{ + struct sigaction act; + + memset(&act, 0, sizeof(act)); + act.sa_handler = SIG_IGN; + + sigaction(SIGALRM, &act, NULL); +} + +#else +#define init_signals() +#endif + +#define boost() + +int main(int argc, char *argv[]) +{ + int rc; + + PJ_UNUSED_ARG(argc); + PJ_UNUSED_ARG(argv); + + boost(); + init_signals(); + + rc = test_main(); + + return rc; +} + diff --git a/pjlib-util/src/pjlib-util-test/test.c b/pjlib-util/src/pjlib-util-test/test.c index 511e7a12..991c1c39 100644 --- a/pjlib-util/src/pjlib-util-test/test.c +++ b/pjlib-util/src/pjlib-util-test/test.c @@ -1,86 +1,86 @@ -/* $Id */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include "test.h"
-#include <pjlib.h>
-
-void app_perror(const char *msg, pj_status_t rc)
-{
- char errbuf[256];
-
- PJ_CHECK_STACK();
-
- pj_strerror(rc, errbuf, sizeof(errbuf));
- PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf));
-}
-
-#define DO_TEST(test) do { \
- PJ_LOG(3, ("test", "Running %s...", #test)); \
- rc = test; \
- PJ_LOG(3, ("test", \
- "%s(%d)", \
- (char*)(rc ? "..ERROR" : "..success"), rc)); \
- if (rc!=0) goto on_return; \
- } while (0)
-
-
-pj_pool_factory *mem;
-
-
-static int test_inner(void)
-{
- pj_caching_pool caching_pool;
- int rc = 0;
-
- mem = &caching_pool.factory;
-
- pj_log_set_level(3);
- pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME |
- PJ_LOG_HAS_MICRO_SEC);
-
- rc = pj_init();
- if (rc != 0) {
- app_perror("pj_init() error!!", rc);
- return rc;
- }
-
- pj_dump_config();
- pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 );
- DO_TEST(xml_test());
-
-on_return:
- return rc;
-}
-
-int test_main(void)
-{
- PJ_USE_EXCEPTION;
-
- PJ_TRY {
- return test_inner();
- }
- PJ_DEFAULT {
- int id = PJ_GET_EXCEPTION();
- PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)",
- id, pj_exception_id_name(id)));
- }
- PJ_END;
-
- return -1;
-}
-
+/* $Id */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "test.h" +#include <pjlib.h> + +void app_perror(const char *msg, pj_status_t rc) +{ + char errbuf[256]; + + PJ_CHECK_STACK(); + + pj_strerror(rc, errbuf, sizeof(errbuf)); + PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf)); +} + +#define DO_TEST(test) do { \ + PJ_LOG(3, ("test", "Running %s...", #test)); \ + rc = test; \ + PJ_LOG(3, ("test", \ + "%s(%d)", \ + (char*)(rc ? "..ERROR" : "..success"), rc)); \ + if (rc!=0) goto on_return; \ + } while (0) + + +pj_pool_factory *mem; + + +static int test_inner(void) +{ + pj_caching_pool caching_pool; + int rc = 0; + + mem = &caching_pool.factory; + + pj_log_set_level(3); + pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | + PJ_LOG_HAS_MICRO_SEC); + + rc = pj_init(); + if (rc != 0) { + app_perror("pj_init() error!!", rc); + return rc; + } + + pj_dump_config(); + pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 ); + DO_TEST(xml_test()); + +on_return: + return rc; +} + +int test_main(void) +{ + PJ_USE_EXCEPTION; + + PJ_TRY { + return test_inner(); + } + PJ_DEFAULT { + int id = PJ_GET_EXCEPTION(); + PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)", + id, pj_exception_id_name(id))); + } + PJ_END; + + return -1; +} + diff --git a/pjlib-util/src/pjlib-util-test/test.h b/pjlib-util/src/pjlib-util-test/test.h index c4467290..c3ef3e4c 100644 --- a/pjlib-util/src/pjlib-util-test/test.h +++ b/pjlib-util/src/pjlib-util-test/test.h @@ -1,28 +1,28 @@ -/* $Id */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pj/types.h>
-
-#define INCLUDE_XML_TEST 1
-
-extern int xml_test(void);
-extern int test_main(void);
-
-extern void app_perror(const char *title, pj_status_t rc);
-extern pj_pool_factory *mem;
-
+/* $Id */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pj/types.h> + +#define INCLUDE_XML_TEST 1 + +extern int xml_test(void); +extern int test_main(void); + +extern void app_perror(const char *title, pj_status_t rc); +extern pj_pool_factory *mem; + diff --git a/pjlib-util/src/pjlib-util-test/xml.c b/pjlib-util/src/pjlib-util-test/xml.c index 9ad4a73e..e20a68ff 100644 --- a/pjlib-util/src/pjlib-util-test/xml.c +++ b/pjlib-util/src/pjlib-util-test/xml.c @@ -1,145 +1,145 @@ -/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; 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 <pjlib-util/xml.h>
-#include <pjlib.h>
-
-#define THIS_FILE "xml_test"
-
-static const char *xml_doc[] =
-{
-" <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-" <p:pidf-full xmlns=\"urn:ietf:params:xml:ns:pidf\"\n"
-" xmlns:p=\"urn:ietf:params:xml:ns:pidf-diff\"\n"
-" xmlns:r=\"urn:ietf:params:xml:ns:pidf:rpid\"\n"
-" xmlns:c=\"urn:ietf:params:xml:ns:pidf:caps\"\n"
-" entity=\"pres:someone@example.com\"\n"
-" version=\"567\">\n"
-"\n"
-" <tuple id=\"sg89ae\">\n"
-" <status>\n"
-" <basic>open</basic>\n"
-" <r:relationship>assistant</r:relationship>\n"
-" </status>\n"
-" <c:servcaps>\n"
-" <c:audio>true</c:audio>\n"
-" <c:video>false</c:video>\n"
-" <c:message>true</c:message>\n"
-" </c:servcaps>\n"
-" <contact priority=\"0.8\">tel:09012345678</contact>\n"
-" </tuple>\n"
-"\n"
-" <tuple id=\"cg231jcr\">\n"
-" <status>\n"
-" <basic>open</basic>\n"
-" </status>\n"
-" <contact priority=\"1.0\">im:pep@example.com</contact>\n"
-" </tuple>\n"
-"\n"
-" <tuple id=\"r1230d\">\n"
-" <status>\n"
-" <basic>closed</basic>\n"
-" <r:activity>meeting</r:activity>\n"
-" </status>\n"
-" <r:homepage>http://example.com/~pep/</r:homepage>\n"
-" <r:icon>http://example.com/~pep/icon.gif</r:icon>\n"
-" <r:card>http://example.com/~pep/card.vcd</r:card>\n"
-" <contact priority=\"0.9\">sip:pep@example.com</contact>\n"
-" </tuple>\n"
-"\n"
-" <note xml:lang=\"en\">Full state presence document</note>\n"
-"\n"
-" <r:person>\n"
-" <r:status>\n"
-" <r:activities>\n"
-" <r:on-the-phone/>\n"
-" <r:busy/>\n"
-" </r:activities>\n"
-" </r:status>\n"
-" </r:person>\n"
-"\n"
-" <r:device id=\"urn:esn:600b40c7\">\n"
-" <r:status>\n"
-" <c:devcaps>\n"
-" <c:mobility>\n"
-" <c:supported>\n"
-" <c:mobile/>\n"
-" </c:supported>\n"
-" </c:mobility>\n"
-" </c:devcaps>\n"
-" </r:status>\n"
-" </r:device>\n"
-"\n"
-" </p:pidf-full>\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<sizeof(xml_doc)/sizeof(xml_doc[0]); ++i) {
- int status;
- if ((status=xml_parse_print_test(xml_doc[i])) != 0)
- return status;
- }
- return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled.
- */
-int dummy_xml_test;
-#endif /* INCLUDE_XML_TEST */
-
-
+/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; 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 <pjlib-util/xml.h> +#include <pjlib.h> + +#define THIS_FILE "xml_test" + +static const char *xml_doc[] = +{ +" <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +" <p:pidf-full xmlns=\"urn:ietf:params:xml:ns:pidf\"\n" +" xmlns:p=\"urn:ietf:params:xml:ns:pidf-diff\"\n" +" xmlns:r=\"urn:ietf:params:xml:ns:pidf:rpid\"\n" +" xmlns:c=\"urn:ietf:params:xml:ns:pidf:caps\"\n" +" entity=\"pres:someone@example.com\"\n" +" version=\"567\">\n" +"\n" +" <tuple id=\"sg89ae\">\n" +" <status>\n" +" <basic>open</basic>\n" +" <r:relationship>assistant</r:relationship>\n" +" </status>\n" +" <c:servcaps>\n" +" <c:audio>true</c:audio>\n" +" <c:video>false</c:video>\n" +" <c:message>true</c:message>\n" +" </c:servcaps>\n" +" <contact priority=\"0.8\">tel:09012345678</contact>\n" +" </tuple>\n" +"\n" +" <tuple id=\"cg231jcr\">\n" +" <status>\n" +" <basic>open</basic>\n" +" </status>\n" +" <contact priority=\"1.0\">im:pep@example.com</contact>\n" +" </tuple>\n" +"\n" +" <tuple id=\"r1230d\">\n" +" <status>\n" +" <basic>closed</basic>\n" +" <r:activity>meeting</r:activity>\n" +" </status>\n" +" <r:homepage>http://example.com/~pep/</r:homepage>\n" +" <r:icon>http://example.com/~pep/icon.gif</r:icon>\n" +" <r:card>http://example.com/~pep/card.vcd</r:card>\n" +" <contact priority=\"0.9\">sip:pep@example.com</contact>\n" +" </tuple>\n" +"\n" +" <note xml:lang=\"en\">Full state presence document</note>\n" +"\n" +" <r:person>\n" +" <r:status>\n" +" <r:activities>\n" +" <r:on-the-phone/>\n" +" <r:busy/>\n" +" </r:activities>\n" +" </r:status>\n" +" </r:person>\n" +"\n" +" <r:device id=\"urn:esn:600b40c7\">\n" +" <r:status>\n" +" <c:devcaps>\n" +" <c:mobility>\n" +" <c:supported>\n" +" <c:mobile/>\n" +" </c:supported>\n" +" </c:mobility>\n" +" </c:devcaps>\n" +" </r:status>\n" +" </r:device>\n" +"\n" +" </p:pidf-full>\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<sizeof(xml_doc)/sizeof(xml_doc[0]); ++i) { + int status; + if ((status=xml_parse_print_test(xml_doc[i])) != 0) + return status; + } + return 0; +} + +#else +/* To prevent warning about "translation unit is empty" + * when this test is disabled. + */ +int dummy_xml_test; +#endif /* INCLUDE_XML_TEST */ + + diff --git a/pjlib-util/src/pjlib-util/md5.c b/pjlib-util/src/pjlib-util/md5.c index 80aed531..233a1da9 100644 --- a/pjlib-util/src/pjlib-util/md5.c +++ b/pjlib-util/src/pjlib-util/md5.c @@ -1,279 +1,279 @@ -/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjlib-util/md5.h>
-#include <pj/string.h> /* pj_memcpy */
-/*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest. This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MD5Init, call MD5Update as
- * needed on buffers full of bytes, and then call MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- */
-
-#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN != 0
-#define HIGHFIRST 1
-#endif
-
-#ifndef HIGHFIRST
-#define byteReverse(buf, len) /* Nothing */
-#else
-void byteReverse(unsigned char *buf, unsigned longs);
-
-#ifndef ASM_MD5
-/*
- * Note: this code is harmless on little-endian machines.
- */
-void byteReverse(unsigned char *buf, unsigned longs)
-{
- pj_uint32_t t;
- do {
- t = (pj_uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
- ((unsigned) buf[1] << 8 | buf[0]);
- *(pj_uint32_t *) buf = t;
- buf += 4;
- } while (--longs);
-}
-#endif
-#endif
-
-static void MD5Transform(pj_uint32_t buf[4], pj_uint32_t const in[16]);
-
-
-/*
- * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-PJ_DEF(void) pj_md5_init(pj_md5_context *ctx)
-{
- ctx->buf[0] = 0x67452301;
- ctx->buf[1] = 0xefcdab89;
- ctx->buf[2] = 0x98badcfe;
- ctx->buf[3] = 0x10325476;
-
- ctx->bits[0] = 0;
- ctx->bits[1] = 0;
-}
-
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-PJ_DEF(void) pj_md5_update( pj_md5_context *ctx,
- unsigned char const *buf, unsigned len)
-{
- pj_uint32_t t;
-
- /* Update bitcount */
-
- t = ctx->bits[0];
- if ((ctx->bits[0] = t + ((pj_uint32_t) len << 3)) < t)
- ctx->bits[1]++; /* Carry from low to high */
- ctx->bits[1] += len >> 29;
-
- t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
-
- /* Handle any leading odd-sized chunks */
-
- if (t) {
- unsigned char *p = (unsigned char *) ctx->in + t;
-
- t = 64 - t;
- if (len < t) {
- pj_memcpy(p, buf, len);
- return;
- }
- pj_memcpy(p, buf, t);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);
- buf += t;
- len -= t;
- }
- /* Process data in 64-byte chunks */
-
- while (len >= 64) {
- pj_memcpy(ctx->in, buf, 64);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);
- buf += 64;
- len -= 64;
- }
-
- /* Handle any remaining bytes of data. */
-
- pj_memcpy(ctx->in, buf, len);
-}
-
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-PJ_DEF(void) pj_md5_final(pj_md5_context *ctx, unsigned char digest[16])
-{
- unsigned count;
- unsigned char *p;
-
- /* Compute number of bytes mod 64 */
- count = (ctx->bits[0] >> 3) & 0x3F;
-
- /* Set the first char of padding to 0x80. This is safe since there is
- always at least one byte free */
- p = ctx->in + count;
- *p++ = 0x80;
-
- /* Bytes of padding needed to make 64 bytes */
- count = 64 - 1 - count;
-
- /* Pad out to 56 mod 64 */
- if (count < 8) {
- /* Two lots of padding: Pad the first block to 64 bytes */
- pj_memset(p, 0, count);
- byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);
-
- /* Now fill the next block with 56 bytes */
- pj_memset(ctx->in, 0, 56);
- } else {
- /* Pad block to 56 bytes */
- pj_memset(p, 0, count - 8);
- }
- byteReverse(ctx->in, 14);
-
- /* Append length in bits and transform */
- ((pj_uint32_t *) ctx->in)[14] = ctx->bits[0];
- ((pj_uint32_t *) ctx->in)[15] = ctx->bits[1];
-
- MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in);
- byteReverse((unsigned char *) ctx->buf, 4);
- pj_memcpy(digest, ctx->buf, 16);
- pj_memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
-}
-
-#ifndef ASM_MD5
-
-/* The four core functions - F1 is optimized somewhat */
-
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f, w, x, y, z, data, s) \
- ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
-
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data. MD5Update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void MD5Transform(pj_uint32_t buf[4], pj_uint32_t const in[16])
-{
- register pj_uint32_t a, b, c, d;
-
- a = buf[0];
- b = buf[1];
- c = buf[2];
- d = buf[3];
-
- MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
- MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
- MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
- MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
- MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
- MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
- MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
- MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
- MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
- MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
- MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
- MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
- MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
- MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
- MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
- MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
- MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
- MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
- MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
- MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
- MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
- MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
- MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
- MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
- MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
- MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
- MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
- MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
- MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
- MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
- MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
- MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
- MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
- MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
- MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
- MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
- MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
- MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
- MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
- MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
- MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
- MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
- MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
- MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
- MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
- MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
- MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
- MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
- MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
- MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
- MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
- MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
- MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
- MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
- MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
- MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
- MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
- MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
- MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
- MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
- MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
- MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
- MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
- MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
- buf[0] += a;
- buf[1] += b;
- buf[2] += c;
- buf[3] += d;
-}
-
-#endif
-
+/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjlib-util/md5.h> +#include <pj/string.h> /* pj_memcpy */ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN != 0 +#define HIGHFIRST 1 +#endif + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +void byteReverse(unsigned char *buf, unsigned longs); + +#ifndef ASM_MD5 +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(unsigned char *buf, unsigned longs) +{ + pj_uint32_t t; + do { + t = (pj_uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(pj_uint32_t *) buf = t; + buf += 4; + } while (--longs); +} +#endif +#endif + +static void MD5Transform(pj_uint32_t buf[4], pj_uint32_t const in[16]); + + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +PJ_DEF(void) pj_md5_init(pj_md5_context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +PJ_DEF(void) pj_md5_update( pj_md5_context *ctx, + unsigned char const *buf, unsigned len) +{ + pj_uint32_t t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((pj_uint32_t) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + pj_memcpy(p, buf, len); + return; + } + pj_memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + pj_memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + pj_memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +PJ_DEF(void) pj_md5_final(pj_md5_context *ctx, unsigned char digest[16]) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + pj_memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in); + + /* Now fill the next block with 56 bytes */ + pj_memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + pj_memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((pj_uint32_t *) ctx->in)[14] = ctx->bits[0]; + ((pj_uint32_t *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (pj_uint32_t *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + pj_memcpy(digest, ctx->buf, 16); + pj_memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(pj_uint32_t buf[4], pj_uint32_t const in[16]) +{ + register pj_uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + diff --git a/pjlib-util/src/pjlib-util/scanner.c b/pjlib-util/src/pjlib-util/scanner.c index 27a1d4d0..3a19e9fd 100644 --- a/pjlib-util/src/pjlib-util/scanner.c +++ b/pjlib-util/src/pjlib-util/scanner.c @@ -1,595 +1,595 @@ -/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjlib-util/scanner.h>
-#include <pj/string.h>
-#include <pj/except.h>
-#include <pj/os.h>
-#include <pj/errno.h>
-
-#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;
-}
-
-PJ_DEF(pj_status_t) pj_cis_init(pj_cis_buf_t *cis_buf, pj_cis_t *cis)
-{
- unsigned i;
-
- cis->cis_buf = cis_buf->cis_buf;
-
- for (i=0; i<PJ_CIS_MAX_INDEX; ++i) {
- if ((cis_buf->use_mask & (1 << i)) == 0) {
- cis->cis_id = i;
- cis_buf->use_mask |= (1 << i);
- return PJ_SUCCESS;
- }
- }
-
- cis->cis_id = PJ_CIS_MAX_INDEX;
- return PJ_ETOOMANY;
-}
-
-PJ_DEF(pj_status_t) pj_cis_dup( pj_cis_t *new_cis, pj_cis_t *existing)
-{
- pj_status_t status;
- unsigned i;
-
- /* Warning: typecasting here! */
- status = pj_cis_init((pj_cis_buf_t*)existing->cis_buf, new_cis);
- if (status != PJ_SUCCESS)
- return status;
-
- for (i=0; i<256; ++i) {
- if (PJ_CIS_ISSET(existing, i))
- PJ_CIS_SET(new_cis, i);
- else
- PJ_CIS_CLR(new_cis, i);
- }
-
- return PJ_SUCCESS;
-}
-
-PJ_DEF(void) pj_cis_add_range(pj_cis_t *cis, int cstart, int cend)
-{
- while (cstart != cend) {
- 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_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) {
- 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;
-}
-
-
+/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjlib-util/scanner.h> +#include <pj/string.h> +#include <pj/except.h> +#include <pj/os.h> +#include <pj/errno.h> + +#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; +} + +PJ_DEF(pj_status_t) pj_cis_init(pj_cis_buf_t *cis_buf, pj_cis_t *cis) +{ + unsigned i; + + cis->cis_buf = cis_buf->cis_buf; + + for (i=0; i<PJ_CIS_MAX_INDEX; ++i) { + if ((cis_buf->use_mask & (1 << i)) == 0) { + cis->cis_id = i; + cis_buf->use_mask |= (1 << i); + return PJ_SUCCESS; + } + } + + cis->cis_id = PJ_CIS_MAX_INDEX; + return PJ_ETOOMANY; +} + +PJ_DEF(pj_status_t) pj_cis_dup( pj_cis_t *new_cis, pj_cis_t *existing) +{ + pj_status_t status; + unsigned i; + + /* Warning: typecasting here! */ + status = pj_cis_init((pj_cis_buf_t*)existing->cis_buf, new_cis); + if (status != PJ_SUCCESS) + return status; + + for (i=0; i<256; ++i) { + if (PJ_CIS_ISSET(existing, i)) + PJ_CIS_SET(new_cis, i); + else + PJ_CIS_CLR(new_cis, i); + } + + return PJ_SUCCESS; +} + +PJ_DEF(void) pj_cis_add_range(pj_cis_t *cis, int cstart, int cend) +{ + while (cstart != cend) { + 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_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) { + 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; +} + + diff --git a/pjlib-util/src/pjlib-util/string.c b/pjlib-util/src/pjlib-util/string.c index 55859eb6..8115bc8f 100644 --- a/pjlib-util/src/pjlib-util/string.c +++ b/pjlib-util/src/pjlib-util/string.c @@ -1,99 +1,107 @@ -/* $Id: $ */
-/*
- * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjlib-util/string.h>
-#include <pj/ctype.h>
-
-PJ_DEF(void) pj_str_unescape(pj_str_t *str)
-{
- char *src = str->ptr;
- char *dst = str->ptr;
- char *end = src + str->slen;
-
- while (src != end) {
- if (*src == '%' && src < end-2) {
- *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(src+1)) << 4) +
- pj_hex_digit_to_val(*(src+2)));
- ++dst;
- src += 3;
- } else {
- ++src;
- ++dst;
- }
- }
- str->slen = dst - str->ptr;
-}
-
-PJ_DEF(pj_str_t*) pj_strcpy_unescape(pj_str_t *dst_str,
- const pj_str_t *src_str)
-{
- const char *src = src_str->ptr;
- const char *end = src + src_str->slen;
- char *dst = dst_str->ptr;
-
- while (src != end) {
- if (*src == '%' && src < end-2) {
- *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(src+1)) << 4) +
- pj_hex_digit_to_val(*(src+2)));
- ++dst;
- src += 3;
- } else {
- *dst++ = *src++;
- }
- }
- dst_str->slen = dst - dst_str->ptr;
- return dst_str;
-}
-
-PJ_DEF(pj_ssize_t) pj_strncpy2_escape( char *dst_str, const pj_str_t *src_str,
- pj_ssize_t max, const pj_cis_t *unres)
-{
- const char *src = src_str->ptr;
- const char *src_end = src + src_str->slen;
- char *dst = dst_str;
- char *dst_end = dst + max;
-
- if (max < src_str->slen)
- return -1;
-
- while (src != src_end && dst != dst_end) {
- if (pj_cis_match(unres, *src)) {
- *dst++ = *src++;
- } else {
- if (dst < dst_end-2) {
- *dst++ = '%';
- pj_val_to_hex_digit(*src, dst);
- dst+=2;
- ++src;
- } else {
- break;
- }
- }
- }
-
- return src==src_end ? dst-dst_str : -1;
-}
-
-PJ_DEF(pj_str_t*) pj_strncpy_escape(pj_str_t *dst_str,
- const pj_str_t *src_str,
- pj_ssize_t max, const pj_cis_t *unres)
-{
- dst_str->slen = pj_strncpy2_escape(dst_str->ptr, src_str, max, unres);
- return dst_str->slen < 0 ? NULL : dst_str;
-}
-
+/* $Id$ */ +/* + * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjlib-util/string.h> +#include <pj/ctype.h> +#include <pj/string.h> +#include <pj/pool.h> + +PJ_DEF(pj_str_t) pj_str_unescape( pj_pool_t *pool, const pj_str_t *src_str) +{ + char *src = src_str->ptr; + char *end = src + src_str->slen; + pj_str_t dst_str; + char *dst; + + if (pj_strchr(src_str, '%')==NULL) + return *src_str; + + dst = dst_str.ptr = pj_pool_alloc(pool, src_str->slen); + + while (src != end) { + if (*src == '%' && src < end-2) { + *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(src+1)) << 4) + + pj_hex_digit_to_val(*(src+2))); + ++dst; + src += 3; + } else { + *dst++ = *src++; + } + } + dst_str.slen = dst - dst_str.ptr; + return dst_str; +} + +PJ_DEF(pj_str_t*) pj_strcpy_unescape(pj_str_t *dst_str, + const pj_str_t *src_str) +{ + const char *src = src_str->ptr; + const char *end = src + src_str->slen; + char *dst = dst_str->ptr; + + while (src != end) { + if (*src == '%' && src < end-2) { + *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(src+1)) << 4) + + pj_hex_digit_to_val(*(src+2))); + ++dst; + src += 3; + } else { + *dst++ = *src++; + } + } + dst_str->slen = dst - dst_str->ptr; + return dst_str; +} + +PJ_DEF(pj_ssize_t) pj_strncpy2_escape( char *dst_str, const pj_str_t *src_str, + pj_ssize_t max, const pj_cis_t *unres) +{ + const char *src = src_str->ptr; + const char *src_end = src + src_str->slen; + char *dst = dst_str; + char *dst_end = dst + max; + + if (max < src_str->slen) + return -1; + + while (src != src_end && dst != dst_end) { + if (pj_cis_match(unres, *src)) { + *dst++ = *src++; + } else { + if (dst < dst_end-2) { + *dst++ = '%'; + pj_val_to_hex_digit(*src, dst); + dst+=2; + ++src; + } else { + break; + } + } + } + + return src==src_end ? dst-dst_str : -1; +} + +PJ_DEF(pj_str_t*) pj_strncpy_escape(pj_str_t *dst_str, + const pj_str_t *src_str, + pj_ssize_t max, const pj_cis_t *unres) +{ + dst_str->slen = pj_strncpy2_escape(dst_str->ptr, src_str, max, unres); + return dst_str->slen < 0 ? NULL : dst_str; +} + diff --git a/pjlib-util/src/pjlib-util/stun.c b/pjlib-util/src/pjlib-util/stun.c index f4287691..52c5bf55 100644 --- a/pjlib-util/src/pjlib-util/stun.c +++ b/pjlib-util/src/pjlib-util/stun.c @@ -1,129 +1,129 @@ -/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjlib-util/stun.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/sock.h>
-#include <pj/os.h>
-
-#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; i<msg->attr_count; ++i) {
- pj_stun_attr_hdr *attr = msg->attr[i];
- if (pj_ntohs(attr->type) == t)
- return attr;
- }
-
- return 0;
-}
+/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjlib-util/stun.h> +#include <pj/pool.h> +#include <pj/log.h> +#include <pj/sock.h> +#include <pj/os.h> + +#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; i<msg->attr_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 e0633ccc..69153f6d 100644 --- a/pjlib-util/src/pjlib-util/stun_client.c +++ b/pjlib-util/src/pjlib-util/stun_client.c @@ -1,277 +1,277 @@ -/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjlib-util/stun.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/os.h>
-#include <pj/sock_select.h>
-
-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_cnt<MAX_REQUEST; ++send_cnt) {
- pj_time_val next_tx, now;
- pj_fd_set_t r;
- int select_rc;
-
- PJ_LOG(4,(THIS_FILE, "STUN retransmit %d, wait_resp=%d",
- send_cnt, wait_resp));
-
- PJ_FD_ZERO(&r);
-
- /* Send messages to servers that has not given us response. */
- for (i=0; i<sock_cnt && mapped_status==0; ++i) {
- for (j=0; j<2 && mapped_status==0; ++j) {
- pj_stun_msg_hdr *msg_hdr = out_msg;
- pj_ssize_t sent_len;
-
- if (rec[i].srv[j].mapped_port != 0)
- continue;
-
- /* Modify message so that we can distinguish response. */
- msg_hdr->tsx[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; i<sock_cnt; ++i) {
- PJ_FD_SET(sock[i], &r);
- }
-
- select_rc = pj_sock_select(FD_SETSIZE, &r, NULL, NULL, &timeout);
- if (select_rc < 1)
- continue;
-
- for (i=0; i<sock_cnt; ++i) {
- int sock_idx, srv_idx;
- pj_ssize_t len;
- pj_stun_msg msg;
- pj_sockaddr_in addr;
- int addrlen = sizeof(addr);
- pj_stun_mapped_addr_attr *attr;
- char recv_buf[128];
-
- if (!PJ_FD_ISSET(sock[i], &r))
- continue;
-
- len = sizeof(recv_buf);
- pj_sock_recvfrom( sock[i], recv_buf,
- &len, 0,
- (pj_sockaddr_t*)&addr,
- &addrlen);
-
- --wait_resp;
-
- if (len < 1) {
- mapped_status = PJ_STUN_ERR_TRANSPORT;
- continue;
- }
-
- if (pj_stun_parse_msg(recv_buf, len, &msg) != 0) {
- PJ_LOG(4,(THIS_FILE,
- "Error parsing STUN response from %s:%d",
- LOG_ADDR(addr)));
- mapped_status = PJ_STUN_ERR_INVALID_MSG;
- continue;
- }
-
- sock_idx = pj_ntohl(msg.hdr->tsx[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<sock_cnt && mapped_status==0; ++i) {
- if (rec[i].srv[0].mapped_addr == rec[i].srv[1].mapped_addr &&
- rec[i].srv[0].mapped_port == rec[i].srv[1].mapped_port)
- {
- mapped_addr[i].sin_family = PJ_AF_INET;
- mapped_addr[i].sin_addr.s_addr = rec[i].srv[0].mapped_addr;
- mapped_addr[i].sin_port = (pj_uint16_t)rec[i].srv[0].mapped_port;
-
- if (rec[i].srv[0].mapped_addr == 0 || rec[i].srv[0].mapped_port == 0) {
- mapped_status = PJ_STUN_ERR_NO_RESPONSE;
- }
- } else {
- mapped_status = PJ_STUN_ERR_SYMETRIC;
- }
- }
-
- pj_pool_release(pool);
-
- return mapped_status;
-
-on_error:
- if (pool) pj_pool_release(pool);
- return -1;
-}
-
-PJ_DEF(const char*) pj_stun_get_err_msg(pj_status_t status)
-{
- switch (status) {
- case 0: return "No error";
- case -1: return "General error";
- case PJ_STUN_ERR_MEMORY: return "Memory allocation failed";
- case PJ_STUN_ERR_RESOLVE: return "Invalid IP or unable to resolve STUN server";
- case PJ_STUN_ERR_TRANSPORT: return "Unable to contact STUN server";
- case PJ_STUN_ERR_INVALID_MSG: return "Invalid response from STUN server";
- case PJ_STUN_ERR_NO_RESPONSE: return "No response from STUN server";
- case PJ_STUN_ERR_SYMETRIC: return "Different mappings are returned from servers";
- }
- return "Unknown error";
-}
+/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjlib-util/stun.h> +#include <pj/pool.h> +#include <pj/log.h> +#include <pj/string.h> +#include <pj/os.h> +#include <pj/sock_select.h> + +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_cnt<MAX_REQUEST; ++send_cnt) { + pj_time_val next_tx, now; + pj_fd_set_t r; + int select_rc; + + PJ_LOG(4,(THIS_FILE, "STUN retransmit %d, wait_resp=%d", + send_cnt, wait_resp)); + + PJ_FD_ZERO(&r); + + /* Send messages to servers that has not given us response. */ + for (i=0; i<sock_cnt && mapped_status==0; ++i) { + for (j=0; j<2 && mapped_status==0; ++j) { + pj_stun_msg_hdr *msg_hdr = out_msg; + pj_ssize_t sent_len; + + if (rec[i].srv[j].mapped_port != 0) + continue; + + /* Modify message so that we can distinguish response. */ + msg_hdr->tsx[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; i<sock_cnt; ++i) { + PJ_FD_SET(sock[i], &r); + } + + select_rc = pj_sock_select(FD_SETSIZE, &r, NULL, NULL, &timeout); + if (select_rc < 1) + continue; + + for (i=0; i<sock_cnt; ++i) { + int sock_idx, srv_idx; + pj_ssize_t len; + pj_stun_msg msg; + pj_sockaddr_in addr; + int addrlen = sizeof(addr); + pj_stun_mapped_addr_attr *attr; + char recv_buf[128]; + + if (!PJ_FD_ISSET(sock[i], &r)) + continue; + + len = sizeof(recv_buf); + pj_sock_recvfrom( sock[i], recv_buf, + &len, 0, + (pj_sockaddr_t*)&addr, + &addrlen); + + --wait_resp; + + if (len < 1) { + mapped_status = PJ_STUN_ERR_TRANSPORT; + continue; + } + + if (pj_stun_parse_msg(recv_buf, len, &msg) != 0) { + PJ_LOG(4,(THIS_FILE, + "Error parsing STUN response from %s:%d", + LOG_ADDR(addr))); + mapped_status = PJ_STUN_ERR_INVALID_MSG; + continue; + } + + sock_idx = pj_ntohl(msg.hdr->tsx[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<sock_cnt && mapped_status==0; ++i) { + if (rec[i].srv[0].mapped_addr == rec[i].srv[1].mapped_addr && + rec[i].srv[0].mapped_port == rec[i].srv[1].mapped_port) + { + mapped_addr[i].sin_family = PJ_AF_INET; + mapped_addr[i].sin_addr.s_addr = rec[i].srv[0].mapped_addr; + mapped_addr[i].sin_port = (pj_uint16_t)rec[i].srv[0].mapped_port; + + if (rec[i].srv[0].mapped_addr == 0 || rec[i].srv[0].mapped_port == 0) { + mapped_status = PJ_STUN_ERR_NO_RESPONSE; + } + } else { + mapped_status = PJ_STUN_ERR_SYMETRIC; + } + } + + pj_pool_release(pool); + + return mapped_status; + +on_error: + if (pool) pj_pool_release(pool); + return -1; +} + +PJ_DEF(const char*) pj_stun_get_err_msg(pj_status_t status) +{ + switch (status) { + case 0: return "No error"; + case -1: return "General error"; + case PJ_STUN_ERR_MEMORY: return "Memory allocation failed"; + case PJ_STUN_ERR_RESOLVE: return "Invalid IP or unable to resolve STUN server"; + case PJ_STUN_ERR_TRANSPORT: return "Unable to contact STUN server"; + case PJ_STUN_ERR_INVALID_MSG: return "Invalid response from STUN server"; + case PJ_STUN_ERR_NO_RESPONSE: return "No response from STUN server"; + case PJ_STUN_ERR_SYMETRIC: return "Different mappings are returned from servers"; + } + return "Unknown error"; +} diff --git a/pjlib-util/src/pjlib-util/symbols.c b/pjlib-util/src/pjlib-util/symbols.c index 123d401c..00558a04 100644 --- a/pjlib-util/src/pjlib-util/symbols.c +++ b/pjlib-util/src/pjlib-util/symbols.c @@ -1,82 +1,82 @@ -/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjlib.h>
-#include <pjlib-util.h>
-
-/*
- * md5.h
- */
-PJ_EXPORT_SYMBOL(md5_init)
-PJ_EXPORT_SYMBOL(md5_append)
-PJ_EXPORT_SYMBOL(md5_finish)
-
-/*
- * scanner.h
- */
-PJ_EXPORT_SYMBOL(pj_cs_init)
-PJ_EXPORT_SYMBOL(pj_cs_set)
-PJ_EXPORT_SYMBOL(pj_cs_add_range)
-PJ_EXPORT_SYMBOL(pj_cs_add_alpha)
-PJ_EXPORT_SYMBOL(pj_cs_add_num)
-PJ_EXPORT_SYMBOL(pj_cs_add_str)
-PJ_EXPORT_SYMBOL(pj_cs_del_range)
-PJ_EXPORT_SYMBOL(pj_cs_del_str)
-PJ_EXPORT_SYMBOL(pj_cs_invert)
-PJ_EXPORT_SYMBOL(pj_scan_init)
-PJ_EXPORT_SYMBOL(pj_scan_fini)
-PJ_EXPORT_SYMBOL(pj_scan_peek)
-PJ_EXPORT_SYMBOL(pj_scan_peek_n)
-PJ_EXPORT_SYMBOL(pj_scan_peek_until)
-PJ_EXPORT_SYMBOL(pj_scan_get)
-PJ_EXPORT_SYMBOL(pj_scan_get_quote)
-PJ_EXPORT_SYMBOL(pj_scan_get_n)
-PJ_EXPORT_SYMBOL(pj_scan_get_char)
-PJ_EXPORT_SYMBOL(pj_scan_get_newline)
-PJ_EXPORT_SYMBOL(pj_scan_get_until)
-PJ_EXPORT_SYMBOL(pj_scan_get_until_ch)
-PJ_EXPORT_SYMBOL(pj_scan_get_until_chr)
-PJ_EXPORT_SYMBOL(pj_scan_advance_n)
-PJ_EXPORT_SYMBOL(pj_scan_strcmp)
-PJ_EXPORT_SYMBOL(pj_scan_stricmp)
-PJ_EXPORT_SYMBOL(pj_scan_skip_whitespace)
-PJ_EXPORT_SYMBOL(pj_scan_save_state)
-PJ_EXPORT_SYMBOL(pj_scan_restore_state)
-
-/*
- * stun.h
- */
-PJ_EXPORT_SYMBOL(pj_stun_create_bind_req)
-PJ_EXPORT_SYMBOL(pj_stun_parse_msg)
-PJ_EXPORT_SYMBOL(pj_stun_msg_find_attr)
-PJ_EXPORT_SYMBOL(pj_stun_get_mapped_addr)
-PJ_EXPORT_SYMBOL(pj_stun_get_err_msg)
-
-/*
- * xml.h
- */
-PJ_EXPORT_SYMBOL(pj_xml_parse)
-PJ_EXPORT_SYMBOL(pj_xml_print)
-PJ_EXPORT_SYMBOL(pj_xml_add_node)
-PJ_EXPORT_SYMBOL(pj_xml_add_attr)
-PJ_EXPORT_SYMBOL(pj_xml_find_node)
-PJ_EXPORT_SYMBOL(pj_xml_find_next_node)
-PJ_EXPORT_SYMBOL(pj_xml_find_attr)
-PJ_EXPORT_SYMBOL(pj_xml_find)
-
-
+/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjlib.h> +#include <pjlib-util.h> + +/* + * md5.h + */ +PJ_EXPORT_SYMBOL(md5_init) +PJ_EXPORT_SYMBOL(md5_append) +PJ_EXPORT_SYMBOL(md5_finish) + +/* + * scanner.h + */ +PJ_EXPORT_SYMBOL(pj_cs_init) +PJ_EXPORT_SYMBOL(pj_cs_set) +PJ_EXPORT_SYMBOL(pj_cs_add_range) +PJ_EXPORT_SYMBOL(pj_cs_add_alpha) +PJ_EXPORT_SYMBOL(pj_cs_add_num) +PJ_EXPORT_SYMBOL(pj_cs_add_str) +PJ_EXPORT_SYMBOL(pj_cs_del_range) +PJ_EXPORT_SYMBOL(pj_cs_del_str) +PJ_EXPORT_SYMBOL(pj_cs_invert) +PJ_EXPORT_SYMBOL(pj_scan_init) +PJ_EXPORT_SYMBOL(pj_scan_fini) +PJ_EXPORT_SYMBOL(pj_scan_peek) +PJ_EXPORT_SYMBOL(pj_scan_peek_n) +PJ_EXPORT_SYMBOL(pj_scan_peek_until) +PJ_EXPORT_SYMBOL(pj_scan_get) +PJ_EXPORT_SYMBOL(pj_scan_get_quote) +PJ_EXPORT_SYMBOL(pj_scan_get_n) +PJ_EXPORT_SYMBOL(pj_scan_get_char) +PJ_EXPORT_SYMBOL(pj_scan_get_newline) +PJ_EXPORT_SYMBOL(pj_scan_get_until) +PJ_EXPORT_SYMBOL(pj_scan_get_until_ch) +PJ_EXPORT_SYMBOL(pj_scan_get_until_chr) +PJ_EXPORT_SYMBOL(pj_scan_advance_n) +PJ_EXPORT_SYMBOL(pj_scan_strcmp) +PJ_EXPORT_SYMBOL(pj_scan_stricmp) +PJ_EXPORT_SYMBOL(pj_scan_skip_whitespace) +PJ_EXPORT_SYMBOL(pj_scan_save_state) +PJ_EXPORT_SYMBOL(pj_scan_restore_state) + +/* + * stun.h + */ +PJ_EXPORT_SYMBOL(pj_stun_create_bind_req) +PJ_EXPORT_SYMBOL(pj_stun_parse_msg) +PJ_EXPORT_SYMBOL(pj_stun_msg_find_attr) +PJ_EXPORT_SYMBOL(pj_stun_get_mapped_addr) +PJ_EXPORT_SYMBOL(pj_stun_get_err_msg) + +/* + * xml.h + */ +PJ_EXPORT_SYMBOL(pj_xml_parse) +PJ_EXPORT_SYMBOL(pj_xml_print) +PJ_EXPORT_SYMBOL(pj_xml_add_node) +PJ_EXPORT_SYMBOL(pj_xml_add_attr) +PJ_EXPORT_SYMBOL(pj_xml_find_node) +PJ_EXPORT_SYMBOL(pj_xml_find_next_node) +PJ_EXPORT_SYMBOL(pj_xml_find_attr) +PJ_EXPORT_SYMBOL(pj_xml_find) + + diff --git a/pjlib-util/src/pjlib-util/xml.c b/pjlib-util/src/pjlib-util/xml.c index 3be7bee4..140c64c7 100644 --- a/pjlib-util/src/pjlib-util/xml.c +++ b/pjlib-util/src/pjlib-util/xml.c @@ -1,396 +1,396 @@ -/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjlib-util/xml.h>
-#include <pjlib-util/scanner.h>
-#include <pj/except.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/log.h>
-#include <pj/os.h>
-
-#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. "<?") */
- if (*scanner->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. "<!--") */
- if (pj_scan_strcmp(scanner, "<!--", 4) == 0) {
- pj_scan_advance_n(scanner, 4, PJ_FALSE);
- for (;;) {
- pj_str_t dummy;
- pj_scan_get_until_ch(scanner, '-', &dummy);
- if (pj_scan_strcmp(scanner, "-->", 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; i<indent; ++i)
- *p++ = ' ';
- *p++ = '<';
- pj_memcpy(p, node->name.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; i<indent; ++i)
- *p++ = ' ';
- } else {
- if (SIZE_LEFT() < node->name.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 = {"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjlib-util/xml.h> +#include <pjlib-util/scanner.h> +#include <pj/except.h> +#include <pj/pool.h> +#include <pj/string.h> +#include <pj/log.h> +#include <pj/os.h> + +#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. "<?") */ + if (*scanner->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. "<!--") */ + if (pj_scan_strcmp(scanner, "<!--", 4) == 0) { + pj_scan_advance_n(scanner, 4, PJ_FALSE); + for (;;) { + pj_str_t dummy; + pj_scan_get_until_ch(scanner, '-', &dummy); + if (pj_scan_strcmp(scanner, "-->", 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; i<indent; ++i) + *p++ = ' '; + *p++ = '<'; + pj_memcpy(p, node->name.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; i<indent; ++i) + *p++ = ' '; + } else { + if (SIZE_LEFT() < node->name.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 = {"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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; +} + |