├── README ├── doc ├── Makefile.am ├── man3 │ ├── metalink_parse_fd.3 │ ├── metalink_parse_fp.3 │ ├── metalink_parse_final.3 │ ├── metalink_parse_memory.3 │ ├── metalink_parser_context_delete.3 │ ├── metalink_parser_context_new.3 │ ├── Makefile.am │ ├── metalink_delete.3 │ ├── metalink_piece_hash_t.3 │ ├── metalink_checksum_t.3 │ ├── metalink_resource_t.3 │ ├── metalink_t.3 │ ├── metalink_chunk_checksum_t.3 │ ├── metalink_file_t.3 │ ├── metalink_parse_file.3 │ └── metalink_parse_update.3 └── examples │ ├── Makefile.am │ └── metalinkcat.c ├── m4 ├── Makefile.am ├── libexpat.m4 └── ax_check_compile_flag.m4 ├── Makefile.am ├── AUTHORS ├── lib ├── includes │ ├── Makefile.am │ └── metalink │ │ ├── metalinkver.h.in │ │ ├── metalink.h │ │ ├── metalink_error.h │ │ └── metalink_parser.h ├── strptime.h ├── libmetalink.pc.in ├── Makefile.am ├── timegm.h ├── metalink_helper.h ├── metalink_session_data.h ├── metalink_config.h ├── metalink_parser_common.c ├── metalink_stack.h ├── metalink_string_buffer.h ├── metalink_parser_common.h ├── metalink_session_data.c ├── metalink_list.h ├── metalink_stack.c ├── timegm.c ├── metalink_string_buffer.c ├── metalink_list.c ├── metalink_pstate_v3.h ├── metalink_pstm.h ├── metalink_helper.c ├── metalink_pstate_v4.h ├── metalink_pstate.h ├── libexpat_metalink_parser.c ├── metalink_pstm.c └── metalink_pctrl.h ├── .gitignore ├── mingw └── mingw-config.sh ├── test ├── Makefile.am ├── metalink_list_test.h ├── metalink_parser_test_v4.h ├── metalink_helper_test.h ├── metalink_parser_test.h ├── metalink_pctrl_test.h ├── metalink_list_test.c ├── test2.xml ├── test1.xml ├── main.c ├── metalink_helper_test.c ├── metalink_parser_test_v4.c ├── metalink_pctrl_test.c └── metalink_parser_test.c ├── NEWS ├── COPYING ├── README.rst ├── genlibattrtokenlookup.py ├── genlibtokenlookup.py ├── .clang-format ├── ChangeLog └── configure.ac /README: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = examples man3 2 | -------------------------------------------------------------------------------- /m4/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = libexpat.m4 2 | -------------------------------------------------------------------------------- /doc/man3/metalink_parse_fd.3: -------------------------------------------------------------------------------- 1 | .so man3/metalink_parse_file.3 2 | -------------------------------------------------------------------------------- /doc/man3/metalink_parse_fp.3: -------------------------------------------------------------------------------- 1 | .so man3/metalink_parse_file.3 2 | -------------------------------------------------------------------------------- /doc/man3/metalink_parse_final.3: -------------------------------------------------------------------------------- 1 | .so man3/metalink_parse_update.3 2 | -------------------------------------------------------------------------------- /doc/man3/metalink_parse_memory.3: -------------------------------------------------------------------------------- 1 | .so man3/metalink_parse_file.3 2 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = lib test doc m4 2 | ACLOCAL_AMFLAGS = -I m4 3 | 4 | -------------------------------------------------------------------------------- /doc/man3/metalink_parser_context_delete.3: -------------------------------------------------------------------------------- 1 | .so man3/metalink_parse_update.3 2 | -------------------------------------------------------------------------------- /doc/man3/metalink_parser_context_new.3: -------------------------------------------------------------------------------- 1 | .so man3/metalink_parse_update.3 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Tatsuhiro Tsujikawa 2 | Quentin Stievenart (Metalink 4.0/RFC 5854 support) 3 | -------------------------------------------------------------------------------- /lib/includes/Makefile.am: -------------------------------------------------------------------------------- 1 | nobase_include_HEADERS = metalink/metalink.h \ 2 | metalink/metalink_parser.h \ 3 | metalink/metalink_types.h \ 4 | metalink/metalink_error.h \ 5 | metalink/metalinkver.h 6 | -------------------------------------------------------------------------------- /doc/examples/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/lib/includes -I$(top_builddir)/lib/includes \ 2 | $(WARNCFLAGS) $(ADDCFLAGS) 3 | LDADD = $(top_builddir)/lib/libmetalink.la 4 | 5 | noinst_PROGRAMS = metalinkcat 6 | metalinkcat_SOURCES = metalinkcat.c 7 | 8 | EXTRA_DIST = LibO_3.5.4_Win_x86_install_multi.msi.meta4 \ 9 | ubuntu-12.04-server-amd64.metalink 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # emacs backup file 2 | *~ 3 | 4 | # autotools 5 | *.la 6 | *.lo 7 | *.m4 8 | *.o 9 | .deps/ 10 | .libs/ 11 | INSTALL 12 | Makefile 13 | Makefile.in 14 | autom4te.cache/ 15 | compile 16 | config.guess 17 | config.h 18 | config.h.in 19 | config.log 20 | config.status 21 | config.sub 22 | configure 23 | depcomp 24 | install-sh 25 | libtool 26 | ltmain.sh 27 | missing 28 | stamp-h1 29 | test-driver 30 | 31 | # test logs generated by `make check` 32 | *.log 33 | *.trs 34 | -------------------------------------------------------------------------------- /m4/libexpat.m4: -------------------------------------------------------------------------------- 1 | AC_DEFUN([AM_PATH_LIBEXPAT], 2 | [ 3 | LIBS_save=$LIBS 4 | CPPFLAGS_save=$CPPFLAGS 5 | 6 | LIBS="-lexpat $LIBS" 7 | AC_CHECK_LIB([expat], [XML_ParserCreate], [have_libexpat=yes]) 8 | if test "x$have_libexpat" = "xyes"; then 9 | AC_DEFINE([HAVE_LIBEXPAT], [1], [Define to 1 if you have libexpat.]) 10 | EXPAT_LIBS=-lexpat 11 | EXPAT_CFLAGS= 12 | AC_SUBST([EXPAT_LIBS]) 13 | AC_SUBST([EXPAT_CFLAGS]) 14 | fi 15 | 16 | LIBS=$LIBS_save 17 | CPPFLAGS=$CPPFLAGS_save 18 | 19 | ]) 20 | -------------------------------------------------------------------------------- /doc/man3/Makefile.am: -------------------------------------------------------------------------------- 1 | man_MANS = \ 2 | metalink_checksum_t.3 \ 3 | metalink_chunk_checksum_t.3 \ 4 | metalink_delete.3 \ 5 | metalink_file_t.3 \ 6 | metalink_parse_fd.3 \ 7 | metalink_parse_file.3 \ 8 | metalink_parse_final.3 \ 9 | metalink_parse_fp.3 \ 10 | metalink_parse_memory.3 \ 11 | metalink_parse_update.3 \ 12 | metalink_parser_context_delete.3 \ 13 | metalink_parser_context_new.3 \ 14 | metalink_piece_hash_t.3 \ 15 | metalink_resource_t.3 \ 16 | metalink_t.3 17 | 18 | EXTRA_DIST = $(man_MANS) 19 | -------------------------------------------------------------------------------- /mingw/mingw-config.sh: -------------------------------------------------------------------------------- 1 | # Define _USE_32BIT_TIME_T because 32bit library of MinGW-w64 does not 2 | # implement many 64bit version function. 3 | HOST=i686-w64-mingw32 4 | ./configure \ 5 | --prefix=/usr/local/$HOST \ 6 | --host=$HOST \ 7 | --build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \ 8 | --with-libexpat \ 9 | --enable-maintainer-mode \ 10 | CPPFLAGS="-I/usr/local/$HOST/include -D_USE_32BIT_TIME_T" \ 11 | LDFLAGS="-L/usr/local/$HOST/lib" \ 12 | PKG_CONFIG_LIBDIR="/usr/local/$HOST/lib/pkgconfig" 13 | -------------------------------------------------------------------------------- /doc/man3/metalink_delete.3: -------------------------------------------------------------------------------- 1 | .TH "METALINK_DELETE" "3" "July 2012" "libmetalink 0.1.0" "libmetalink Manual" 2 | .SH "NAME" 3 | metalink_delete \- Free the allocated resources for metalink_t structure. 4 | .SH "SYNOPSIS" 5 | .B #include 6 | .sp 7 | .BI "void metalink_delete(metalink_t *" metalink ); 8 | 9 | .SH "DESCRIPTION" 10 | \fBmetalink_delete\fP() frees the allocated resources for \fImetalink\fP. 11 | Passing NULL is legal: \fBmetalink_delete\fP() does nothing in this case. 12 | 13 | .SH "RETURN VALUE" 14 | \fBmetalink_delete\fP() returns no value. 15 | 16 | .SH "SEE ALSO" 17 | .BR metalink_t (3) 18 | -------------------------------------------------------------------------------- /doc/man3/metalink_piece_hash_t.3: -------------------------------------------------------------------------------- 1 | .TH "METALINK_PIECE_HASH_T" "3" "10/28/2008" "libmetalink 0.0.3" "libmetalink Manual" 2 | .SH "NAME" 3 | metalink_piece_hash_t \- The structure that holds hash value of a piece. 4 | 5 | .SH "SYNOPSIS" 6 | .B #include 7 | 8 | .SH "DESCRIPTION" 9 | \fBmetalink_piece_hash_t\fP is a structure that holds a hash value of a piece. 10 | 11 | .SH "STRUCTURE MEMBERS" 12 | int piece; 13 | .br 14 | char *hash; 15 | 16 | .SS type 17 | Index of a piece starting 0. 18 | 19 | .SS hash 20 | Null terminated string of a hash value in ASCII hexadecimal notation. 21 | 22 | .SH "SEE ALSO" 23 | .BR metalink_parse_file (3), 24 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | if HAVE_CUNIT 2 | 3 | check_PROGRAMS = metalinktest 4 | metalinktest_SOURCES = \ 5 | main.c\ 6 | metalink_list_test.c metalink_list_test.h\ 7 | metalink_pctrl_test.c metalink_pctrl_test.h\ 8 | metalink_parser_test.c metalink_parser_test.h\ 9 | metalink_parser_test_v4.c metalink_parser_test_v4.h\ 10 | metalink_helper_test.c metalink_helper_test.h 11 | metalinktest_LDADD = ${top_builddir}/lib/libmetalink.la 12 | metalinktest_LDFLAGS = -static @CUNIT_LIBS@ 13 | 14 | AM_CPPFLAGS = -I${top_srcdir}/lib -I${top_srcdir}/lib/includes \ 15 | -I${top_builddir}/lib/includes \ 16 | $(WARNCFLAGS) $(ADDCFLAGS) \ 17 | -DLIBMETALINK_TEST_DIR=\"$(top_srcdir)/test/\" @CUNIT_CFLAGS@ 18 | TESTS = metalinktest 19 | 20 | EXTRA_DIST = test1.xml test2.xml 21 | 22 | endif # HAVE_CUNIT 23 | -------------------------------------------------------------------------------- /doc/man3/metalink_checksum_t.3: -------------------------------------------------------------------------------- 1 | .TH "METALINK_CHECKSUM_T" "3" "10/28/2008" "libmetalink 0.0.3" "libmetalink Manual" 2 | .SH "NAME" 3 | metalink_checksum_t \- The structure that holds a hash value of an entire 4 | resource. 5 | 6 | .SH "SYNOPSIS" 7 | .B #include 8 | 9 | .SH "DESCRIPTION" 10 | \fBmetalink_checksum_t\fP is a structure that holds a hash value of an entire 11 | resource. 12 | It contains a hash value of a resource and its message digest algorithm name. 13 | 14 | .SH "STRUCTURE MEMBERS" 15 | char *type; 16 | .br 17 | char *hash; 18 | 19 | .SS type 20 | Null terminated string of a message digest algorithm name used to calculate 21 | hash value for a resource. 22 | 23 | .SS hash 24 | Null terminated string of a hash value in ASCII hexadecimal notation. 25 | 26 | .SH "SEE ALSO" 27 | .BR metalink_parse_file (3) 28 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | libmetalink 0.1.3 2 | ================= 3 | 4 | Release Note 5 | ------------ 6 | 7 | This release fixes the bug that signature element in metalink v4 was 8 | not parsed correctly. 9 | 10 | 11 | 12 | libmetalink 0.1.2 13 | ================= 14 | 15 | Release Note 16 | ------------ 17 | 18 | This release fixes the bug that the library version was not updated in 19 | the previous release. 20 | 21 | 22 | 23 | libmetalink 0.1.1 24 | ================= 25 | 26 | Release Note 27 | ------------ 28 | 29 | This release adds dynamic attribute of the origin element in Metalink 30 | 4 and the origin and type attributes of the metalink element in 31 | Metalink 3. It fixes configure and compile errors on netbsd and OSX. 32 | 33 | 34 | 35 | libmetalink 0.1.0 36 | ================= 37 | 38 | Release Note 39 | ------------ 40 | 41 | This release adds RFC 5854 Metalink 4.0 support, thanks to Quentin 42 | Stievenart. It also adds the ability to filter out dangerous filename 43 | in Metalink files. Many portability patches contributed by Guenter 44 | Knauf were merged. 45 | -------------------------------------------------------------------------------- /doc/man3/metalink_resource_t.3: -------------------------------------------------------------------------------- 1 | .TH "METALINK_RESOURCE_T" "3" "10/28/2008" "libmetalink 0.0.3" "libmetalink Manual" 2 | .SH "NAME" 3 | metalink_resource_t \- The structure that holds an URL of a resource and its 4 | metadata. 5 | 6 | .SH "SYNOPSIS" 7 | .B #include 8 | 9 | .SH "DESCRIPTION" 10 | \fBmetalink_resource_t\fP is a structure that holds an URL of a resource and its 11 | metadata. 12 | 13 | .SH "STRUCTURE MEMBERS" 14 | char *url; 15 | .br 16 | char *type; 17 | .br 18 | char *location; 19 | .br 20 | int preference; 21 | .br 22 | int maxconnections; 23 | 24 | .SS url 25 | Null terminated string of URL. 26 | 27 | .SS type 28 | Null terminated string of protocol of URL, like "http", "ftp". 29 | 30 | .SS location 31 | Null terminated string of country code, like "JP", where the server in URL 32 | resides. 33 | 34 | .SS preference 35 | Preference of this resource. The higher value has bigger preference. 36 | 37 | .SS maxconnections 38 | Max connections that a client can establish to this resource simultaneously. 39 | 40 | .SH "SEE ALSO" 41 | .BR metalink_parse_file (3) 42 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2008 Tatsuhiro Tsujikawa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /doc/man3/metalink_t.3: -------------------------------------------------------------------------------- 1 | .TH "METALINK_T" "3" "10/25/2008" "libmetalink 0.0.3" "libmetalink Manual" 2 | .SH "NAME" 3 | metalink_t \- Metalink top level structure. 4 | .SH "SYNOPSIS" 5 | .B #include 6 | 7 | .SH "DESCRIPTION" 8 | \fBmetalink_t\fP is a top level structure that contains 9 | metadata for Metalink file and list of \fBmetalink_file_t\fP(3) structure. 10 | Typically \fBmetalink_t\fP is created by parser function such as 11 | \fBmetalink_parse_file\fP(3). 12 | 13 | .SH "STRUCTURE MEMBERS" 14 | metalink_file_t **files; 15 | .br 16 | char *identity; 17 | .br 18 | char *tags; 19 | 20 | .SS files 21 | Null terminated array of pointer of \fBmetalink_file_t\fP(3) structure. 22 | This corresponds to files tag in Metalink XML file. 23 | Each \fBmetalink_file_t\fP(3) structure corresponds to file element in 24 | Metalink XML file. 25 | 26 | .SS identity 27 | Null terminated string which corresponds to identity element in Metalink XML file. 28 | 29 | .SS tags 30 | Null terminated string which corresponds to tags element in Metalink XML file. 31 | 32 | .SH "SEE ALSO" 33 | .BR metalink_delete_t (3), 34 | .BR metalink_file_t (3), 35 | .BR metalink_parse_file (3) 36 | -------------------------------------------------------------------------------- /doc/man3/metalink_chunk_checksum_t.3: -------------------------------------------------------------------------------- 1 | .TH "METALINK_CHUNK_CHECKSUM_T" "3" "10/28/2008" "libmetalink 0.0.3" "libmetalink Manual" 2 | .SH "NAME" 3 | metalink_chunk_checksum_t \- The structure that holds piece hashes for a 4 | resource. 5 | 6 | .SH "SYNOPSIS" 7 | .B #include 8 | 9 | .SH "DESCRIPTION" 10 | \fBmetalink_chunk_checksum_t\fP is a structure that holds piece hashes for a 11 | resource. 12 | It contains length of piece and a message digest algorithm name and each hash value which is stored in \fBmetalink_piece_hash_t\fP(3). 13 | 14 | .SH "STRUCTURE MEMBERS" 15 | char *type; 16 | .br 17 | int length; 18 | .br 19 | metalink_piece_hash_t **piece_hashes; 20 | 21 | .SS type 22 | Null terminated string of a message digest algorithm name used to calculate 23 | hash value for a resource. 24 | 25 | .SS length 26 | Length of a piece in bytes. 27 | 28 | .SS piece_hashes 29 | Null terminated array of pointer of \fBmetalink_piece_hash_t\fP(3) structure. 30 | They are ordered so that a pointer to \fBmetalink_piece_hash_t\fP(3) of 31 | \fIi\fPth piece can be accessed by piece_hashes[\fIi\fP]. 32 | 33 | .SH "SEE ALSO" 34 | .BR metalink_parse_file (3), 35 | .BR metalink_piece_hash_t (3) 36 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Libmetalink 2 | =========== 3 | 4 | Libmetalink is a library to read Metalink XML download description 5 | format. It supports both `Metalink version 3 6 | `_ and `Metalink 7 | version 4 (RFC 5854) `_. 8 | 9 | Requirements 10 | ------------ 11 | 12 | The following packages are needed to build the library: 13 | 14 | * pkg-config >= 0.20 15 | * libexpat >= 2.1.0 or libxml2 >= 2.7.8 16 | 17 | To build and run the unit test programs, the following packages are 18 | needed: 19 | 20 | * cunit >= 2.1 21 | 22 | Building from git 23 | ----------------- 24 | 25 | To build from git, run following commands (you need autoconf):: 26 | 27 | $ ./buildconf 28 | $ ./configure 29 | $ make 30 | 31 | API 32 | --- 33 | 34 | Include header file for public APIs: 35 | 36 | .. code-block:: c 37 | 38 | #include 39 | 40 | Please note that ``metalink_*_set_*``, ``metalink_*_new`` and 41 | ``metalink_*_delete`` functions in will be 42 | hidden from public API in the future release. The newly written 43 | application should not use these functions. The existing applications 44 | are advised to stop using these functions. If you want to hold the 45 | modified data of Metalink, define application specific data structure, 46 | and make a copy of parsed object. 47 | -------------------------------------------------------------------------------- /test/metalink_list_test.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_LIST_TEST_H_ 27 | #define _D_METALINK_LIST_TEST_H_ 28 | 29 | void test_metalink_list(void); 30 | 31 | #endif /* _D_METALINK_LIST_TEST_H_ */ 32 | -------------------------------------------------------------------------------- /test/metalink_parser_test_v4.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_PARSER_TEST_V4_H_ 27 | #define _D_METALINK_PARSER_TEST_V4_H_ 28 | 29 | void test_metalink_parse_file_v4(void); 30 | 31 | #endif /* _D_METALINK_PARSER_TEST_V4_H_ */ 32 | -------------------------------------------------------------------------------- /test/metalink_helper_test.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_HELPER_TEST_H_ 27 | #define _D_METALINK_HELPER_TEST_H_ 28 | 29 | void test_metalink_check_safe_path(void); 30 | void test_metalink_get_version(void); 31 | 32 | #endif /* _D_METALINK_HELPER_TEST_H_ */ 33 | -------------------------------------------------------------------------------- /lib/strptime.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_STRPTIME_H 27 | #define _D_STRPTIME_H 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | char *strptime(const char *buf, const char *format, struct tm *timeptr); 34 | 35 | #endif /* not _D_STRPTIME_H */ 36 | -------------------------------------------------------------------------------- /lib/libmetalink.pc.in: -------------------------------------------------------------------------------- 1 | # libmetalink 2 | # 3 | # Copyright (c) 2012 Tatsuhiro Tsujikawa 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | prefix=@prefix@ 23 | exec_prefix=@exec_prefix@ 24 | libdir=@libdir@ 25 | includedir=@includedir@ 26 | 27 | Name: libmetalink 28 | Description: Metalink library 29 | URL: https://launchpad.net/libmetalink 30 | Version: @PACKAGE_VERSION@ 31 | Libs: -L${libdir} -lmetalink 32 | Libs.private: @XML_LIBS@ @EXPAT_LIBS@ 33 | Cflags: -I${includedir} 34 | -------------------------------------------------------------------------------- /lib/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = includes 2 | 3 | AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes \ 4 | $(WARNCFLAGS) $(ADDCFLAGS) \ 5 | @XML_CPPFLAGS@ @EXPAT_CFLAGS@ \ 6 | @DEFS@ 7 | 8 | pkgconfigdir = $(libdir)/pkgconfig 9 | pkgconfig_DATA = libmetalink.pc 10 | DISTCLEANFILES = $(pkgconfig_DATA) 11 | 12 | lib_LTLIBRARIES = libmetalink.la 13 | 14 | OBJECTS = \ 15 | metalink_types.c \ 16 | metalink_pstm.c \ 17 | metalink_pstate.c \ 18 | metalink_pstate_v3.c \ 19 | metalink_pstate_v4.c \ 20 | metalink_pctrl.c \ 21 | metalink_parser_common.c \ 22 | metalink_session_data.c \ 23 | metalink_stack.c \ 24 | metalink_list.c \ 25 | metalink_string_buffer.c \ 26 | metalink_helper.c 27 | 28 | HFILES = \ 29 | metalink_config.h\ 30 | metalink_pstm.h\ 31 | metalink_pstate.h\ 32 | metalink_pstate_v3.h\ 33 | metalink_pstate_v4.h\ 34 | metalink_pctrl.h\ 35 | metalink_parser_common.h\ 36 | metalink_session_data.h\ 37 | metalink_stack.h\ 38 | metalink_list.h\ 39 | metalink_string_buffer.h\ 40 | metalink_helper.h 41 | 42 | if !HAVE_STRPTIME 43 | OBJECTS += strptime.c 44 | HFILES += strptime.h 45 | endif 46 | 47 | if !HAVE_TIMEGM 48 | OBJECTS += timegm.c 49 | HFILES += timegm.h 50 | endif 51 | 52 | if ENABLE_LIBXML2 53 | OBJECTS += libxml2_metalink_parser.c 54 | endif 55 | 56 | if ENABLE_LIBEXPAT 57 | OBJECTS += libexpat_metalink_parser.c 58 | endif 59 | 60 | libmetalink_la_SOURCES = $(HFILES) $(OBJECTS) 61 | libmetalink_la_LDFLAGS = -no-undefined \ 62 | -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ 63 | @XML_LIBS@ @EXPAT_LIBS@ 64 | -------------------------------------------------------------------------------- /lib/timegm.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_TIMEGM_H_ 27 | #define _D_TIMEGM_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif /* __cplusplus */ 34 | 35 | #include 36 | 37 | #ifndef HAVE_TIMEGM 38 | 39 | time_t timegm(struct tm *tm); 40 | 41 | #endif /* HAVE_TIMEGM */ 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif /* __cplusplus */ 46 | 47 | #endif /* _D_TIMEGM_H_ */ 48 | -------------------------------------------------------------------------------- /test/metalink_parser_test.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_PARSER_TEST_H_ 27 | #define _D_METALINK_PARSER_TEST_H_ 28 | 29 | size_t count_array(void **array); 30 | 31 | void test_metalink_parse_file(void); 32 | 33 | void test_metalink_parse_fp(void); 34 | 35 | void test_metalink_parse_fd(void); 36 | 37 | void test_metalink_parse_memory(void); 38 | 39 | void test_metalink_parse_update(void); 40 | 41 | void test_metalink_parse_update_fail(void); 42 | 43 | #endif /* _D_METALINK_PARSER_TEST_H_ */ 44 | -------------------------------------------------------------------------------- /lib/metalink_helper.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_HELPER_H_ 27 | #define _D_METALINK_HELPER_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | /* 34 | * Returns nonzero if a given path is safe by checking directory 35 | * traversal and certain control characters in it. If path is NULL, 36 | * this function returns 0. 37 | */ 38 | int metalink_check_safe_path(const char *path); 39 | 40 | /* 41 | * Returns one of metalink_ns enum value corresponding to XML 42 | * namespace. 43 | */ 44 | int metalink_match_ns(const char *uri, size_t len); 45 | 46 | #endif /* _D_METALINK_HELPER_H_ */ 47 | -------------------------------------------------------------------------------- /test/metalink_pctrl_test.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_PCTRL_TEST_H_ 27 | #define _D_METALINK_PCTRL_TEST_H_ 28 | 29 | void test_metalink_pctrl_file_transaction(void); 30 | 31 | void test_metalink_pctrl_resource_transaction(void); 32 | 33 | void test_metalink_pctrl_checksum_transaction(void); 34 | 35 | void test_metalink_pctrl_chunk_checksum_transaction(void); 36 | 37 | void test_metalink_pctrl_piece_hash_transaction(void); 38 | 39 | void test_metalink_pctrl_signature_transaction(void); 40 | 41 | void test_metalink_pctrl_metalink_accumulate_files(void); 42 | 43 | void test_metalink_pctrl_detach_metalink(void); 44 | 45 | #endif /* _D_METALINK_PCTRL_TEST_H_ */ 46 | -------------------------------------------------------------------------------- /lib/metalink_session_data.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_SESSION_DATA_H_ 27 | #define _D_METALINK_SESSION_DATA_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | #include "metalink_pstm.h" 34 | #include "metalink_stack.h" 35 | 36 | typedef struct _metalink_session_data { 37 | metalink_pstm_t *stm; 38 | 39 | metalink_stack_t *characters_stack; 40 | 41 | int name; 42 | int ns_uri; 43 | } metalink_session_data_t; 44 | 45 | /* constructor */ 46 | metalink_session_data_t *metalink_session_data_new(void); 47 | 48 | /* destructor */ 49 | void metalink_session_data_delete(metalink_session_data_t *sd); 50 | 51 | #endif /* _D_METALINK_SESSION_DATA_H_ */ 52 | -------------------------------------------------------------------------------- /lib/metalink_config.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_CONFIG_H_ 27 | #define _D_METALINK_CONFIG_H_ 28 | 29 | #ifdef HAVE_CONFIG_H 30 | #include "config.h" 31 | #endif /* HAVE_CONFIG_H */ 32 | 33 | #ifndef _XOPEN_SOURCE 34 | #define _XOPEN_SOURCE /* avoid warning when using strptime */ 35 | #endif 36 | #ifndef _BSD_SOURCE 37 | #define _BSD_SOURCE /* avoid warning when using timegm */ 38 | #endif 39 | #ifndef _NETBSD_SOURCE 40 | #define _NETBSD_SOURCE /* avoid warning when using strtoll on netbsd */ 41 | #endif 42 | 43 | #ifdef GCC_VISIBILITY 44 | #define METALINK_PUBLIC __attribute__((visibility("default"))) 45 | #else /* !GCC_VISIBILITY */ 46 | #define METALINK_PUBLIC 47 | #endif /* !GCC_VISIBILITY */ 48 | 49 | #endif /* _D_METALINK_CONFIG_H_ */ 50 | -------------------------------------------------------------------------------- /lib/metalink_parser_common.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include "metalink_parser_common.h" 27 | #include "metalink_pctrl.h" 28 | 29 | metalink_error_t 30 | metalink_handle_parse_result(metalink_t **res, 31 | metalink_session_data_t *session_data, 32 | metalink_error_t parser_retval) { 33 | metalink_error_t retval; 34 | if (parser_retval == 0 && session_data->stm->ctrl->error == 0) { 35 | *res = metalink_pctrl_detach_metalink(session_data->stm->ctrl); 36 | } 37 | 38 | if (parser_retval != 0) { 39 | /* TODO more detailed error handling for parser is desired. */ 40 | retval = METALINK_ERR_PARSER_ERROR; 41 | } else { 42 | retval = metalink_pctrl_get_error(session_data->stm->ctrl); 43 | } 44 | return retval; 45 | } 46 | -------------------------------------------------------------------------------- /genlibattrtokenlookup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | TOKENS = [ 4 | "dynamic", 5 | "length", 6 | "location", 7 | "maxconnections", 8 | "mediatype", 9 | "name", 10 | "origin", 11 | "piece", 12 | "preference", 13 | "priority", 14 | "type", 15 | "url", 16 | ] 17 | 18 | def to_enum_hd(k): 19 | res = 'METALINK_ATTR_TOKEN_' 20 | for c in k.upper(): 21 | if c == ':' or c == '-': 22 | res += '_' 23 | continue 24 | res += c 25 | return res 26 | 27 | def build_header(headers): 28 | res = {} 29 | for k in headers: 30 | size = len(k) 31 | if size not in res: 32 | res[size] = {} 33 | ent = res[size] 34 | c = k[-1] 35 | if c not in ent: 36 | ent[c] = [] 37 | ent[c].append(k) 38 | 39 | return res 40 | 41 | def gen_enum(): 42 | name = '' 43 | print 'typedef enum {' 44 | for k in TOKENS: 45 | print ' {},'.format(to_enum_hd(k)) 46 | print ' METALINK_ATTR_TOKEN_MAX' 47 | print '} metalink_attr_token;' 48 | 49 | def gen_index_header(): 50 | print '''\ 51 | int metalink_lookup_attr_token(const char *name, size_t namelen) { 52 | switch (namelen) {''' 53 | b = build_header(TOKENS) 54 | for size in sorted(b.keys()): 55 | ents = b[size] 56 | print '''\ 57 | case {}:'''.format(size) 58 | print '''\ 59 | switch (name[{}]) {{'''.format(size - 1) 60 | for c in sorted(ents.keys()): 61 | headers = sorted(ents[c]) 62 | print '''\ 63 | case '{}':'''.format(c) 64 | for k in headers: 65 | print '''\ 66 | if (lstreq("{}", name, {})) {{ 67 | return {}; 68 | }}'''.format(k[:-1], size - 1, to_enum_hd(k)) 69 | print '''\ 70 | break;''' 71 | print '''\ 72 | } 73 | break;''' 74 | print '''\ 75 | } 76 | return -1; 77 | }''' 78 | 79 | if __name__ == '__main__': 80 | gen_enum() 81 | print '' 82 | gen_index_header() 83 | -------------------------------------------------------------------------------- /lib/includes/metalink/metalinkver.h.in: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINKVER_H_ 27 | #define _D_METALINKVER_H_ 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #define LIBMETALINK_COPYRIGHT "2008-2012 Tatsuhiro Tsujikawa" 34 | 35 | #define LIBMETALINK_VERSION "@PACKAGE_VERSION@" 36 | 37 | #define LIBMETALINK_VERSION_MAJOR @MAJOR_VERSION@ 38 | #define LIBMETALINK_VERSION_MINOR @MINOR_VERSION@ 39 | #define LIBMETALINK_VERSION_PATCH @PATCH_VERSION@ 40 | 41 | /* 42 | *Version concatenated in one integer. In this hexadecimal notation, 43 | * after first 0x prefix, each 2 digits group represents major, minor 44 | * and patch version in this order from most significant byte. 45 | */ 46 | #define LIBMETALINK_VERSION_NUMBER @NUMBER_VERSION@ 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | 52 | #endif /* _D_METALINKVER_H_ */ 53 | -------------------------------------------------------------------------------- /lib/metalink_stack.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_STACK_H_ 27 | #define _D_METALINK_STACK_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | typedef struct _metalink_stack_entry { 34 | void *data; 35 | struct _metalink_stack_entry *next; 36 | } metalink_stack_entry_t; 37 | 38 | typedef struct _metalink_stack { 39 | metalink_stack_entry_t *entry; 40 | } metalink_stack_t; 41 | 42 | metalink_stack_t *metalink_stack_new(void); 43 | 44 | void metalink_stack_delete(metalink_stack_t *stack); 45 | 46 | int metalink_stack_empty(const metalink_stack_t *stack); 47 | 48 | void *metalink_stack_top(metalink_stack_t *stack); 49 | 50 | /* returns data */ 51 | void *metalink_stack_pop(metalink_stack_t *stack); 52 | 53 | int metalink_stack_push(metalink_stack_t *stack, void *data); 54 | 55 | #endif /* _D_METALINK_STACK_H_ */ 56 | -------------------------------------------------------------------------------- /lib/includes/metalink/metalink.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_H_ 27 | #define _D_METALINK_H_ 28 | 29 | /* Convenient header file to include all libmetalink include files. */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | /** 41 | * Stores the major, minor and patch version of the libmetalink to the 42 | * variables pointed by |major|, |minor| and |patch| respectively. 43 | */ 44 | void metalink_get_version(int *major, int *minor, int *patch); 45 | 46 | /** 47 | * Returns the string error message describing the error code 48 | * |error_code|. The error code is defined in 49 | * metalink/metalink_error.h. 50 | */ 51 | const char *metalink_strerror(int error_code); 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | #endif /* _D_METALINK_H_ */ 58 | -------------------------------------------------------------------------------- /genlibtokenlookup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | TOKENS = [ 4 | "copyright", 5 | "description", 6 | "file", 7 | "files", 8 | "generator", 9 | "hash", 10 | "identity", 11 | "language", 12 | "logo", 13 | "metalink", 14 | "metaurl", 15 | "origin", 16 | "os", 17 | "pieces", 18 | "published", 19 | "publisher", 20 | "resources", 21 | "signature", 22 | "size", 23 | "tags", 24 | "updated", 25 | "url", 26 | "verification", 27 | "version", 28 | ] 29 | 30 | def to_enum_hd(k): 31 | res = 'METALINK_TOKEN_' 32 | for c in k.upper(): 33 | if c == ':' or c == '-': 34 | res += '_' 35 | continue 36 | res += c 37 | return res 38 | 39 | def build_header(headers): 40 | res = {} 41 | for k in headers: 42 | size = len(k) 43 | if size not in res: 44 | res[size] = {} 45 | ent = res[size] 46 | c = k[-1] 47 | if c not in ent: 48 | ent[c] = [] 49 | ent[c].append(k) 50 | 51 | return res 52 | 53 | def gen_enum(): 54 | name = '' 55 | print 'typedef enum {' 56 | for k in TOKENS: 57 | print ' {},'.format(to_enum_hd(k)) 58 | print '} metalink_token;' 59 | 60 | def gen_index_header(): 61 | print '''\ 62 | int metalink_lookup_token(const char *name, size_t namelen) { 63 | switch (namelen) {''' 64 | b = build_header(TOKENS) 65 | for size in sorted(b.keys()): 66 | ents = b[size] 67 | print '''\ 68 | case {}:'''.format(size) 69 | print '''\ 70 | switch (name[{}]) {{'''.format(size - 1) 71 | for c in sorted(ents.keys()): 72 | headers = sorted(ents[c]) 73 | print '''\ 74 | case '{}':'''.format(c) 75 | for k in headers: 76 | print '''\ 77 | if (lstreq("{}", name, {})) {{ 78 | return {}; 79 | }}'''.format(k[:-1], size - 1, to_enum_hd(k)) 80 | print '''\ 81 | break;''' 82 | print '''\ 83 | } 84 | break;''' 85 | print '''\ 86 | } 87 | return -1; 88 | }''' 89 | 90 | if __name__ == '__main__': 91 | gen_enum() 92 | print '' 93 | gen_index_header() 94 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: true 6 | AlignEscapedNewlinesLeft: false 7 | AlignOperands: true 8 | AlignTrailingComments: true 9 | AllowAllParametersOfDeclarationOnNextLine: true 10 | AllowShortBlocksOnASingleLine: false 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortIfStatementsOnASingleLine: false 13 | AllowShortLoopsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AlwaysBreakAfterDefinitionReturnType: false 16 | AlwaysBreakTemplateDeclarations: false 17 | AlwaysBreakBeforeMultilineStrings: false 18 | BreakBeforeBinaryOperators: None 19 | BreakBeforeTernaryOperators: true 20 | BreakConstructorInitializersBeforeComma: false 21 | BinPackParameters: true 22 | BinPackArguments: true 23 | ColumnLimit: 80 24 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 25 | ConstructorInitializerIndentWidth: 4 26 | DerivePointerAlignment: false 27 | ExperimentalAutoDetectBinPacking: false 28 | IndentCaseLabels: false 29 | IndentWrappedFunctionNames: false 30 | IndentFunctionDeclarationAfterType: false 31 | MaxEmptyLinesToKeep: 1 32 | KeepEmptyLinesAtTheStartOfBlocks: true 33 | NamespaceIndentation: None 34 | ObjCBlockIndentWidth: 2 35 | ObjCSpaceAfterProperty: false 36 | ObjCSpaceBeforeProtocolList: true 37 | PenaltyBreakBeforeFirstCallParameter: 19 38 | PenaltyBreakComment: 300 39 | PenaltyBreakString: 1000 40 | PenaltyBreakFirstLessLess: 120 41 | PenaltyExcessCharacter: 1000000 42 | PenaltyReturnTypeOnItsOwnLine: 60 43 | PointerAlignment: Right 44 | SpacesBeforeTrailingComments: 1 45 | Cpp11BracedListStyle: true 46 | Standard: Cpp11 47 | IndentWidth: 2 48 | TabWidth: 8 49 | UseTab: Never 50 | BreakBeforeBraces: Attach 51 | SpacesInParentheses: false 52 | SpacesInSquareBrackets: false 53 | SpacesInAngles: false 54 | SpaceInEmptyParentheses: false 55 | SpacesInCStyleCastParentheses: false 56 | SpaceAfterCStyleCast: false 57 | SpacesInContainerLiterals: true 58 | SpaceBeforeAssignmentOperators: true 59 | ContinuationIndentWidth: 4 60 | CommentPragmas: '^ IWYU pragma:' 61 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 62 | SpaceBeforeParens: ControlStatements 63 | DisableFormat: false 64 | ... 65 | 66 | -------------------------------------------------------------------------------- /lib/metalink_string_buffer.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_STRING_BUFFER_H_ 27 | #define _D_METALINK_STRING_BUFFER_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | #include 34 | 35 | typedef struct metalink_string_buffer_t { 36 | char *buffer; 37 | size_t length; 38 | size_t capacity; 39 | } metalink_string_buffer_t; 40 | 41 | metalink_string_buffer_t *metalink_string_buffer_new(size_t initial_capacity); 42 | 43 | void metalink_string_buffer_delete(metalink_string_buffer_t *str_buf); 44 | 45 | void metalink_string_buffer_append(metalink_string_buffer_t *str_buf, 46 | const char *str, size_t length); 47 | 48 | const char *metalink_string_buffer_str(const metalink_string_buffer_t *str_buf); 49 | 50 | size_t metalink_string_buffer_capacity(const metalink_string_buffer_t *str_buf); 51 | 52 | size_t metalink_string_buffer_strlen(const metalink_string_buffer_t *str_buf); 53 | 54 | #endif /* _D_METALINK_STRING_BUFFER_H_ */ 55 | -------------------------------------------------------------------------------- /lib/includes/metalink/metalink_error.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_ERROR_H_ 27 | #define _D_METALINK_ERROR_H_ 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | typedef enum metalink_error_e { 34 | /* 9xx: fatal error */ 35 | METALINK_ERR_BAD_ALLOC = 901, 36 | 37 | METALINK_ERR_CANNOT_OPEN_FILE = 902, 38 | 39 | /* 1xx: XML semantic error */ 40 | METALINK_ERR_MISSING_REQUIRED_ATTR = 101, 41 | 42 | METALINK_ERR_NAMESPACE_ERROR = 102, 43 | 44 | /* 2xx: parser error */ 45 | METALINK_ERR_PARSER_ERROR = 201, 46 | 47 | /* 3xx transaction error */ 48 | METALINK_ERR_NO_FILE_TRANSACTION = 301, 49 | 50 | METALINK_ERR_NO_RESOURCE_TRANSACTION = 302, 51 | 52 | METALINK_ERR_NO_CHECKSUM_TRANSACTION = 303, 53 | 54 | METALINK_ERR_NO_CHUNK_CHECKSUM_TRANSACTION = 304, 55 | 56 | METALINK_ERR_NO_PIECE_HASH_TRANSACTION = 305, 57 | 58 | METALINK_ERR_NO_SIGNATURE_TRANSACTION = 306 59 | } metalink_error_t; 60 | 61 | #ifdef __cplusplus 62 | } 63 | #endif 64 | 65 | #endif /* _D_METALINK_ERROR_H_ */ 66 | -------------------------------------------------------------------------------- /test/metalink_list_test.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include "metalink_list_test.h" 27 | 28 | #include 29 | 30 | #include "metalink_list.h" 31 | 32 | void test_metalink_list(void) { 33 | metalink_list_t *l; 34 | int a, b, c; 35 | int *int_ptr_array[3]; 36 | 37 | l = metalink_list_new(); 38 | CU_ASSERT_PTR_NOT_NULL(l); 39 | 40 | /* Add 3 ints. */ 41 | a = 1; 42 | b = 2; 43 | c = 4; 44 | metalink_list_append(l, &a); 45 | metalink_list_append(l, &b); 46 | metalink_list_append(l, &c); 47 | CU_ASSERT_EQUAL(3, metalink_list_length(l)); 48 | 49 | /* get 2nd(index = 1) element = (2) */ 50 | CU_ASSERT_EQUAL(2, *(int *)metalink_list_get_data(l, 1)); 51 | 52 | /* dump the contents of list to array */ 53 | metalink_list_to_array(l, (void **)int_ptr_array); 54 | CU_ASSERT_EQUAL(1, *int_ptr_array[0]); 55 | CU_ASSERT_EQUAL(2, *int_ptr_array[1]); 56 | CU_ASSERT_EQUAL(4, *int_ptr_array[2]); 57 | 58 | /* clear all data */ 59 | metalink_list_clear(l); 60 | CU_ASSERT_EQUAL(0, metalink_list_length(l)); 61 | 62 | /* delete list */ 63 | metalink_list_delete(l); 64 | } 65 | -------------------------------------------------------------------------------- /lib/metalink_parser_common.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_PARSER_COMMON_H_ 27 | #define _D_METALINK_PARSER_COMMON_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | #include "metalink_session_data.h" 34 | 35 | /* 36 | * See session_data and parser_retval which is a return value of parser object 37 | * and decide the actual return value of metalink_parse_* function and fills 38 | * res. 39 | * @param res If the function decided the parse operation is succeeded, then 40 | * res is filled with actual metalink_t pointer which is detached from 41 | * session_data. 42 | * @param session_data session_data used in parser operation. 43 | * @param parser_retval return value of parser object. 44 | * @return error code listed in metalink_error.h if error, otherwise 0 for 45 | * success. 46 | * 47 | */ 48 | metalink_error_t 49 | metalink_handle_parse_result(metalink_t **res, 50 | metalink_session_data_t *session_data, 51 | metalink_error_t parser_retval); 52 | 53 | #endif /* _D_METALINK_PARSER_COMMON_H_ */ 54 | -------------------------------------------------------------------------------- /lib/metalink_session_data.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include "metalink_session_data.h" 27 | #include "metalink_string_buffer.h" 28 | 29 | metalink_session_data_t *metalink_session_data_new(void) { 30 | metalink_session_data_t *sd; 31 | sd = malloc(sizeof(metalink_session_data_t)); 32 | if (!sd) { 33 | return NULL; 34 | } 35 | sd->name = -1; 36 | sd->ns_uri = METALINK_NS_NONE; 37 | sd->characters_stack = NULL; 38 | sd->stm = new_metalink_pstm(); 39 | if (!sd->stm) { 40 | goto NEW_SESSION_DATA_ERROR; 41 | } 42 | sd->characters_stack = metalink_stack_new(); 43 | if (!sd->characters_stack) { 44 | goto NEW_SESSION_DATA_ERROR; 45 | } 46 | return sd; 47 | NEW_SESSION_DATA_ERROR: 48 | metalink_session_data_delete(sd); 49 | return NULL; 50 | } 51 | 52 | void metalink_session_data_delete(metalink_session_data_t *sd) { 53 | if (!sd) { 54 | return; 55 | } 56 | delete_metalink_pstm(sd->stm); 57 | while (!metalink_stack_empty(sd->characters_stack)) { 58 | metalink_string_buffer_delete(metalink_stack_pop(sd->characters_stack)); 59 | } 60 | metalink_stack_delete(sd->characters_stack); 61 | free(sd); 62 | } 63 | -------------------------------------------------------------------------------- /doc/man3/metalink_file_t.3: -------------------------------------------------------------------------------- 1 | .TH "METALINK_FILE_T" "3" "10/25/2008" "libmetalink 0.0.3" "libmetalink Manual" 2 | .SH "NAME" 3 | metalink_file_t \- The structure that holds information of a single file. 4 | 5 | .SH "SYNOPSIS" 6 | .B #include 7 | 8 | .SH "DESCRIPTION" 9 | \fBmetalink_file_t\fP is a structure that holds information of a single file. 10 | It contains array of URLs(\fBmetalink_resource_t\fP(3)), checksums and metadata for a file. 11 | 12 | .SH "STRUCTURE MEMBERS" 13 | char *name; 14 | .br 15 | long long int size; 16 | .br 17 | char *version; 18 | .br 19 | char *language; 20 | .br 21 | char *os; 22 | .br 23 | metalink_resource_t **resources; 24 | .br 25 | int maxconnections; 26 | .br 27 | metalink_checksum_t **checksums; 28 | .br 29 | metalink_chunk_checksum_t *chunk_checksum; 30 | 31 | .SS name 32 | Null terminated file name of the resource which corresponds to name element in Metalink XML file. 33 | 34 | .SS size 35 | Length of the resource in bytes. 36 | 37 | .SS version 38 | Null terminated version string which corresponds to version element in Metalink XML file. 39 | 40 | .SS language 41 | Null terminated language string which corresponds to language element in Metalink XML file. 42 | 43 | .SS os 44 | Null terminated os string which corresponds to os element in Metalink XML file. 45 | 46 | .SS resources 47 | Null terminated array of pointer of \fBmetalink_resource_t\fP(3) structure. 48 | This corresponds to resources element in Metalink XML file. 49 | Each \fBmetalink_resource_t\fP(3) structure corresponds to url element in 50 | Metalink XML file. 51 | 52 | .SS maxconnections 53 | This is a value of maxconnections attribute of file element. 54 | This value is usually used for upper limit of concurrent connections for the 55 | resource. 56 | 57 | .SS checksums 58 | Null terminated array of pointer of \fBmetalink_checksum_t\fP(3) structure. 59 | This field is an array because in Metalink specification, 60 | verification element can contain multiple hash elements. 61 | Each \fBmetalink_checksum_t\fP(3) structure corresponds to hash element in 62 | Metalink XML file. 63 | 64 | .SS chunk_checksum 65 | The chunk checksum(aka piece hash) for the resource. This corresponds to 66 | pieces element under verification element in Metalink XML file. 67 | 68 | .SH "SEE ALSO" 69 | .BR metalink_checksum_t (3), 70 | .BR metalink_chunk_checksum_t (3), 71 | .BR metalink_resource_t (3), 72 | .BR metalink_parse_file (3) 73 | -------------------------------------------------------------------------------- /test/test2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | MetalinkEditor/2.0dev 4 | 2009-05-15T12:23:23+09:30 5 | http://example.org/foo.metalink 6 | 7 | 0.0.1 8 | en-US 9 | Linux-x86 10 | libmetalink 11 | 12 | a96cf3f0266b91d87d5124cf94326422800b627d 13 | 14 | notype 15 | fc4d834e89c18c99b2615d902750948c 16 | ftp://ftphost/libmetalink-0.0.1.tar.bz2 17 | 18 | http://httphost/libmetalink-0.0.1.tar.bz2 19 | 20 | 21 | 0.0.2a 22 | 4294967296 23 | 24 | 179463a88d79cbf0b1923991708aead914f26142 25 | fecf8bc9a1647505fe16746f94e97a477597dbf3 26 | 27 | ftp://ftphost/libmetalink-0.0.2a.tar.bz2 28 | 29 | http://httphost/libmetalink-0.0.2a.tar.bz2 30 | http://mirror1/libmetalink-0.0.2a.tar.bz2 31 | http://mirror1/libmetalink-0.0.2a.tar.bz2.torrent 32 | http://mirror2/libmetalink-0.0.2a.tar.bz2.torrent 33 | http://mirror3/libmetalink-0.0.2a.tar.bz2.torrent 34 | 35 | 36 | 37 | http://noname/file 38 | 39 | 40 | 41 | abc 42 | ftp://host/file 43 | 44 | 45 | 46 | ftp://host/file 47 | 48 | 49 | 50 | 51 | http://badpriority/ 52 | 53 | 54 | -------------------------------------------------------------------------------- /lib/metalink_list.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_LIST_H_ 27 | #define _D_METALINK_LIST_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | #include 34 | 35 | typedef struct _metalink_list_entry { 36 | void *data; 37 | struct _metalink_list_entry *next; 38 | } metalink_list_entry_t; 39 | 40 | typedef struct _metalink_list { 41 | metalink_list_entry_t *head; 42 | metalink_list_entry_t *tail; 43 | } metalink_list_t; 44 | 45 | metalink_list_t *metalink_list_new(void); 46 | 47 | void metalink_list_delete(metalink_list_t *list); 48 | 49 | void *metalink_list_get_data(metalink_list_t *list, size_t index); 50 | 51 | size_t metalink_list_length(metalink_list_t *list); 52 | 53 | void metalink_list_clear(metalink_list_t *list); 54 | 55 | void metalink_list_clear_data(metalink_list_t *list); 56 | 57 | void metalink_list_to_array(metalink_list_t *list, void **array); 58 | 59 | int metalink_list_append(metalink_list_t *list, void *data); 60 | 61 | void metalink_list_insert(metalink_list_t *list, size_t index); 62 | 63 | void metalink_list_remove(metalink_list_t *list, size_t index); 64 | 65 | void metalink_list_for_each(metalink_list_t *list, void (*fun)(void *data)); 66 | 67 | #endif /* _D_METALINK_LIST_H_ */ 68 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2008-10-16 Tatsuhiro Tsujikawa 2 | 3 | Fixed #define guard 4 | * lib/metalink/metalink_parser.h 5 | 6 | 2008-07-16 Tatsuhiro Tsujikawa 7 | 8 | Put -D_ISOC99_SOURCE to DEFS variable. 9 | * lib/metalink/Makefile.am 10 | * test/Makefile.am 11 | 12 | 2008-07-16 Tatsuhiro Tsujikawa 13 | 14 | Code leanup. 15 | * lib/metalink/metalink_parser_common.c 16 | 17 | 2008-07-16 Tatsuhiro Tsujikawa 18 | 19 | Fixed possible memory leak when parsing XML is aborted. 20 | * lib/metalink/session_data.c 21 | 22 | 2008-07-16 Tatsuhiro Tsujikawa 23 | 24 | Added metalink_parse_update, metalink_parse_final interface. 25 | * lib/metalink/libexpat_metalink_parser.c 26 | * lib/metalink/libxml2_metalink_parser.c 27 | * lib/metalink/metalink_parser.h 28 | * test/main.c 29 | * test/metalink_parser_test.c 30 | * test/metalink_parser_test.h 31 | 32 | 2008-07-16 Tatsuhiro Tsujikawa 33 | 34 | Renamed struct session_data_t as struct _session_data. 35 | * lib/metalink/session_data.h 36 | 37 | 2008-06-25 Tatsuhiro Tsujikawa 38 | 39 | Implemented metalink_parse_memory with libxml2. 40 | * lib/metalink/libxml2_metalink_parser.c 41 | 42 | 2008-06-25 Tatsuhiro Tsujikawa 43 | 44 | Added metalink_parse_memory function. Currently libexpat implementation 45 | only. libexpat_metalink_parser.c is refactored and setup_parser function 46 | added for creating parser object and setting handlers. 47 | The portion of code which handeles return value and detachment of 48 | metalink_t object is common for libexpat and libxml2, so it is now 49 | defined in metalink_parser_common.c. 50 | metalink_parser_test.c is refactord so that assertions are shared with 51 | both test_metalink_parse_file and test_metalink_parse_memory functions. 52 | * lib/metalink/Makefile.am 53 | * lib/metalink/Makefile.in 54 | * lib/metalink/libexpat_metalink_parser.c 55 | * lib/metalink/metalink_parser.h 56 | * lib/metalink/metalink_parser_common.c 57 | * lib/metalink/metalink_parser_common.h 58 | * test/main.c 59 | * test/metalink_parser_test.c 60 | * test/metalink_parser_test.h 61 | 62 | 2008-06-25 Tatsuhiro Tsujikawa 63 | 64 | Added extern "C" construct to make it easy to include them in C++ code. 65 | * lib/metalink/metalink_types.h 66 | * lib/metalink/metalink_parser.h 67 | 68 | 2008-06-13 Tatsuhiro Tsujikawa 69 | 70 | Release 0.0.2 71 | -------------------------------------------------------------------------------- /lib/metalink_stack.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include "metalink_stack.h" 27 | 28 | #include 29 | 30 | static void init_stack(metalink_stack_t *s) { s->entry = NULL; } 31 | 32 | metalink_stack_t *metalink_stack_new(void) { 33 | metalink_stack_t *s = malloc(sizeof(metalink_stack_t)); 34 | if (s) { 35 | init_stack(s); 36 | } 37 | return s; 38 | } 39 | 40 | void metalink_stack_delete(metalink_stack_t *stack) { 41 | metalink_stack_entry_t *e; 42 | metalink_stack_entry_t *next; 43 | 44 | e = stack->entry; 45 | while (e) { 46 | next = e->next; 47 | free(e); 48 | e = next; 49 | } 50 | free(stack); 51 | } 52 | 53 | int metalink_stack_empty(const metalink_stack_t *stack) { 54 | return stack->entry == NULL; 55 | } 56 | 57 | int metalink_stack_push(metalink_stack_t *stack, void *data) { 58 | metalink_stack_entry_t *new_entry; 59 | 60 | new_entry = malloc(sizeof(metalink_stack_entry_t)); 61 | if (!new_entry) { 62 | return 1; 63 | } 64 | new_entry->data = data; 65 | new_entry->next = stack->entry; 66 | stack->entry = new_entry; 67 | return 0; 68 | } 69 | 70 | void *metalink_stack_pop(metalink_stack_t *stack) { 71 | metalink_stack_entry_t *pop_entry; 72 | void *data; 73 | 74 | pop_entry = stack->entry; 75 | stack->entry = pop_entry->next; 76 | data = pop_entry->data; 77 | free(pop_entry); 78 | return data; 79 | } 80 | 81 | void *metalink_stack_top(metalink_stack_t *stack) { 82 | if (metalink_stack_empty(stack)) { 83 | return NULL; 84 | } else { 85 | return stack->entry->data; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /lib/timegm.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include "timegm.h" 27 | 28 | #ifndef HAVE_TIMEGM 29 | 30 | #include 31 | 32 | #ifndef INT32_MIN 33 | #define INT32_MIN ((int32_t)(1u << 31)) 34 | #endif /* INT32_MIN */ 35 | 36 | /* Counter the number of leap year in the range [0, y). The |y| is the 37 | year, including century (e.g., 2012) */ 38 | static int count_leap_year(int y) { 39 | y -= 1; 40 | return y / 4 - y / 100 + y / 400; 41 | } 42 | 43 | /* Returns nonzero if the |y| is the leap year. The |y| is the year, 44 | including century (e.g., 2012) */ 45 | static int is_leap_year(int y) { 46 | return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); 47 | } 48 | 49 | /* The number of days before ith month begins */ 50 | static int daysum[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; 51 | 52 | /* Based on the algorithm of Python 2.7 calendar.timegm. */ 53 | time_t timegm(struct tm *tm) { 54 | int days; 55 | int num_leap_year; 56 | int64_t t; 57 | if (tm->tm_mon > 11) { 58 | return -1; 59 | } 60 | num_leap_year = count_leap_year(tm->tm_year + 1900) - count_leap_year(1970); 61 | days = (tm->tm_year - 70) * 365 + num_leap_year + daysum[tm->tm_mon] + 62 | tm->tm_mday - 1; 63 | if (tm->tm_mon >= 2 && is_leap_year(tm->tm_year + 1900)) { 64 | ++days; 65 | } 66 | t = ((int64_t)days * 24 + tm->tm_hour) * 3600 + tm->tm_min * 60 + tm->tm_sec; 67 | if (sizeof(time_t) == 4) { 68 | if (t < INT32_MIN || t > INT32_MAX) { 69 | return -1; 70 | } 71 | } 72 | return t; 73 | } 74 | 75 | #endif /* !HAVE_TIMEGM */ 76 | -------------------------------------------------------------------------------- /test/test1.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | libmetalink 7 | http://libmetalink/ 8 | 9 | Metalink library for C 10 | libmetalink-0.0.1 11 | metalink,xml 12 | 13 | 14 | 15 | 0.0.1 16 | en-US 17 | Linux-x86 18 | 19 | a96cf3f0266b91d87d5124cf94326422800b627d 20 | 21 | notype 22 | fc4d834e89c18c99b2615d902750948c 23 | 24 | 25 | 26 | ftp://ftphost/libmetalink-0.0.1.tar.bz2 27 | 28 | http://httphost/libmetalink-0.0.1.tar.bz2 29 | 30 | 31 | 32 | 4294967296 33 | 0.0.2a 34 | ja-JP 35 | Linux-m68k 36 | 37 | 38 | 179463a88d79cbf0b1923991708aead914f26142 39 | 40 | 179463a88d79cbf0b1923991708aead914f26142 41 | fecf8bc9a1647505fe16746f94e97a477597dbf3 42 | 43 | 44 | 45 | 46 | ftp://ftphost/libmetalink-0.0.2a.tar.bz2 47 | 48 | http://httphost/libmetalink-0.0.2a.tar.bz2 49 | http://mirror1/libmetalink-0.0.2a.tar.bz2 50 | 51 | http://mirror2/libmetalink-0.0.2a.tar.bz2 52 | http://mirror2/libmetalink-0.0.2a.tar.bz2.torrent 53 | 54 | 55 | 56 | 57 | 58 | http://noname/file 59 | 60 | 61 | 62 | 63 | abc 64 | 65 | ftp://host/file 66 | 67 | 68 | 69 | 70 | 71 | ftp://host/file 72 | 73 | 74 | 75 | 76 | 77 | http://badpreference/ 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /lib/metalink_string_buffer.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include "metalink_string_buffer.h" 27 | 28 | #include 29 | #include 30 | 31 | metalink_string_buffer_t *metalink_string_buffer_new(size_t initial_capacity) { 32 | metalink_string_buffer_t *sbuf = malloc(sizeof(metalink_string_buffer_t)); 33 | if (!sbuf) { 34 | return NULL; 35 | } 36 | sbuf->buffer = calloc(sizeof(char), initial_capacity + 1); 37 | if (!sbuf->buffer) { 38 | free(sbuf); 39 | return NULL; 40 | } 41 | sbuf->length = 0; 42 | sbuf->buffer[sbuf->length] = '\0'; 43 | sbuf->capacity = initial_capacity; 44 | return sbuf; 45 | } 46 | 47 | void metalink_string_buffer_delete(metalink_string_buffer_t *str_buf) { 48 | if (str_buf) { 49 | free(str_buf->buffer); 50 | free(str_buf); 51 | } 52 | } 53 | 54 | static void metalink_string_buffer_resize(metalink_string_buffer_t *str_buf, 55 | size_t new_capacity) { 56 | char *new_buffer; 57 | 58 | new_buffer = realloc(str_buf->buffer, new_capacity + 1); 59 | 60 | str_buf->buffer = new_buffer; 61 | str_buf->capacity = new_capacity; 62 | if (str_buf->length > new_capacity) { 63 | str_buf->length = new_capacity; 64 | str_buf->buffer[str_buf->length] = '\0'; 65 | } 66 | } 67 | 68 | void metalink_string_buffer_append(metalink_string_buffer_t *str_buf, 69 | const char *str, size_t length) { 70 | if (str_buf->length + length > str_buf->capacity) { 71 | metalink_string_buffer_resize(str_buf, str_buf->length + length); 72 | } 73 | 74 | memcpy(str_buf->buffer + str_buf->length, str, length); 75 | str_buf->length += length; 76 | str_buf->buffer[str_buf->length] = '\0'; 77 | } 78 | 79 | const char * 80 | metalink_string_buffer_str(const metalink_string_buffer_t *str_buf) { 81 | return str_buf->buffer; 82 | } 83 | 84 | size_t 85 | metalink_string_buffer_capacity(const metalink_string_buffer_t *str_buf) { 86 | return str_buf->capacity; 87 | } 88 | 89 | size_t metalink_string_buffer_strlen(const metalink_string_buffer_t *str_buf) { 90 | return str_buf->length; 91 | } 92 | -------------------------------------------------------------------------------- /doc/examples/metalinkcat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Sample for libmetalink parser. This program prints the parsed 3 | * result of given Metalink files. 4 | * 5 | * To compile: 6 | * gcc -Wall -g -O2 -o sample sample.c -lmetalink 7 | * 8 | * Usage: metalinkcat ... 9 | */ 10 | #include 11 | #include 12 | #ifdef HAVE_INTTYPES_H 13 | #include 14 | #endif 15 | #include 16 | 17 | /* 18 | * Usually on most platforms one would just include inttypes.h, 19 | * but unfortunately some platforms either might lack this 20 | * header, or do not define the PRI* macros, so we do it here. 21 | */ 22 | #ifndef PRId64 23 | #ifdef _WIN32 24 | #define PRId64 "I64d" 25 | #else 26 | #define PRId64 "lld" 27 | #endif /* _WIN32 */ 28 | #endif /* PRId64 */ 29 | 30 | int main(int argc, char **argv) { 31 | int i; 32 | if (argc < 2) { 33 | printf("Usage: %s [...]\n", argv[0]); 34 | return EXIT_SUCCESS; 35 | } 36 | for (i = 1; i < argc; ++i) { 37 | metalink_error_t r; 38 | metalink_t *metalink; 39 | metalink_file_t *file; 40 | metalink_checksum_t **checksums; 41 | 42 | r = metalink_parse_file(argv[i], &metalink); 43 | 44 | if (r != 0) { 45 | fprintf(stderr, "ERROR (%d): %s\n", r, metalink_strerror(r)); 46 | exit(EXIT_FAILURE); 47 | } 48 | 49 | file = metalink->files[0]; 50 | printf("name: %s\n", file->name); 51 | printf("size: %" PRId64 "\n", (int64_t)file->size); 52 | if (file->os) { 53 | printf("os : %s\n", file->os); 54 | } 55 | 56 | if (file->checksums) { 57 | checksums = file->checksums; 58 | while (*checksums) { 59 | printf("hash: %s %s\n", (*checksums)->type, (*checksums)->hash); 60 | ++checksums; 61 | } 62 | } 63 | if (file->chunk_checksum) { 64 | size_t count = 0; 65 | metalink_piece_hash_t **piece_hashes; 66 | printf("chunk checksum: size=%d, type=%s\n", file->chunk_checksum->length, 67 | file->chunk_checksum->type); 68 | printf("first 5 piece hashes...\n"); 69 | piece_hashes = file->chunk_checksum->piece_hashes; 70 | while (*piece_hashes && count < 5) { 71 | printf("piece=%d, hash=%s\n", (*piece_hashes)->piece, 72 | (*piece_hashes)->hash); 73 | ++piece_hashes; 74 | ++count; 75 | } 76 | printf("...\n"); 77 | } 78 | if (file->resources) { 79 | size_t count = 0; 80 | metalink_resource_t **resources; 81 | printf("first 5 resources...\n"); 82 | resources = file->resources; 83 | while (*resources && count < 5) { 84 | printf("type=%s, location=%s, preference=%d, url=%s\n", 85 | (*resources)->type ? (*resources)->type : "", 86 | (*resources)->location ? (*resources)->location : "", 87 | (*resources)->preference, (*resources)->url); 88 | ++resources; 89 | ++count; 90 | } 91 | printf("...\n"); 92 | } 93 | 94 | if (file->signature) { 95 | metalink_signature_t *signature; 96 | signature = file->signature; 97 | printf("signature: mediatype=%s\n\t%s\n", signature->mediatype, 98 | signature->signature); 99 | } 100 | /* delete metalink_t */ 101 | metalink_delete(metalink); 102 | } 103 | return EXIT_SUCCESS; 104 | } 105 | -------------------------------------------------------------------------------- /test/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | /* include test cases' include files here */ 5 | #include "metalink_list_test.h" 6 | #include "metalink_pctrl_test.h" 7 | #include "metalink_parser_test.h" 8 | #include "metalink_parser_test_v4.h" 9 | #include "metalink_helper_test.h" 10 | 11 | static int init_suite1(void) { return 0; } 12 | 13 | static int clean_suite1(void) { return 0; } 14 | 15 | int main(void) { 16 | CU_pSuite pSuite = NULL; 17 | unsigned int num_tests_failed; 18 | 19 | /* initialize the CUnit test registry */ 20 | if (CUE_SUCCESS != CU_initialize_registry()) 21 | return CU_get_error(); 22 | 23 | /* add a suite to the registry */ 24 | pSuite = CU_add_suite("libmetalink_TestSuite", init_suite1, clean_suite1); 25 | if (NULL == pSuite) { 26 | CU_cleanup_registry(); 27 | return CU_get_error(); 28 | } 29 | 30 | /* add the tests to the suite */ 31 | if ((!CU_add_test(pSuite, "test of metalink_list", test_metalink_list)) || 32 | (!CU_add_test(pSuite, "test of metalink_pctrl_file_transaction", 33 | test_metalink_pctrl_file_transaction)) || 34 | (!CU_add_test(pSuite, "test of metalink_pctrl_resource_transaction", 35 | test_metalink_pctrl_resource_transaction)) || 36 | (!CU_add_test(pSuite, "test of metalink_pctrl_checksum_transaction", 37 | test_metalink_pctrl_checksum_transaction)) || 38 | (!CU_add_test(pSuite, "test of metalink_pctrl_piece_hash_transaction", 39 | test_metalink_pctrl_piece_hash_transaction)) || 40 | (!CU_add_test(pSuite, "test of metalink_pctrl_chunk_checksum_transaction", 41 | test_metalink_pctrl_chunk_checksum_transaction)) || 42 | (!CU_add_test(pSuite, "test of metalink_pctrl_signature_transaction", 43 | test_metalink_pctrl_signature_transaction)) || 44 | (!CU_add_test(pSuite, "test of metalink_parse_file", 45 | test_metalink_parse_file)) || 46 | (!CU_add_test(pSuite, "test of metalink_parse_fp", 47 | test_metalink_parse_fp)) || 48 | (!CU_add_test(pSuite, "test of metalink_parse_fd", 49 | test_metalink_parse_fd)) || 50 | (!CU_add_test(pSuite, "test of metalink_parse_memory", 51 | test_metalink_parse_memory)) || 52 | (!CU_add_test(pSuite, "test of metalink_parse_update", 53 | test_metalink_parse_update)) || 54 | (!CU_add_test(pSuite, "test of metalink_parser_update_fail", 55 | test_metalink_parse_update_fail)) || 56 | (!CU_add_test(pSuite, "test of metalink_check_safe_path", 57 | test_metalink_check_safe_path)) || 58 | (!CU_add_test(pSuite, "test of metalink_get_version", 59 | test_metalink_get_version)) || 60 | (!CU_add_test(pSuite, "test of metalink_parse_file_v4", 61 | test_metalink_parse_file_v4))) { 62 | CU_cleanup_registry(); 63 | return CU_get_error(); 64 | } 65 | 66 | /* Run all tests using the CUnit Basic interface */ 67 | CU_basic_set_mode(CU_BRM_VERBOSE); 68 | CU_basic_run_tests(); 69 | num_tests_failed = CU_get_number_of_tests_failed(); 70 | CU_cleanup_registry(); 71 | if (CU_get_error() == CUE_SUCCESS) { 72 | return num_tests_failed; 73 | } else { 74 | printf("CUnit Error: %s\n", CU_get_error_msg()); 75 | return CU_get_error(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /m4/ax_check_compile_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check whether the given FLAG works with the current language's compiler 12 | # or gives an error. (Warnings, however, are ignored) 13 | # 14 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on 15 | # success/failure. 16 | # 17 | # If EXTRA-FLAGS is defined, it is added to the current language's default 18 | # flags (e.g. CFLAGS) when the check is done. The check is thus made with 19 | # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to 20 | # force the compiler to issue an error when a bad flag is given. 21 | # 22 | # INPUT gives an alternative input source to AC_COMPILE_IFELSE. 23 | # 24 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this 25 | # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. 26 | # 27 | # LICENSE 28 | # 29 | # Copyright (c) 2008 Guido U. Draheim 30 | # Copyright (c) 2011 Maarten Bosmans 31 | # 32 | # This program is free software: you can redistribute it and/or modify it 33 | # under the terms of the GNU General Public License as published by the 34 | # Free Software Foundation, either version 3 of the License, or (at your 35 | # option) any later version. 36 | # 37 | # This program is distributed in the hope that it will be useful, but 38 | # WITHOUT ANY WARRANTY; without even the implied warranty of 39 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 40 | # Public License for more details. 41 | # 42 | # You should have received a copy of the GNU General Public License along 43 | # with this program. If not, see . 44 | # 45 | # As a special exception, the respective Autoconf Macro's copyright owner 46 | # gives unlimited permission to copy, distribute and modify the configure 47 | # scripts that are the output of Autoconf when processing the Macro. You 48 | # need not follow the terms of the GNU General Public License when using 49 | # or distributing such scripts, even though portions of the text of the 50 | # Macro appear in them. The GNU General Public License (GPL) does govern 51 | # all other use of the material that constitutes the Autoconf Macro. 52 | # 53 | # This special exception to the GPL applies to versions of the Autoconf 54 | # Macro released by the Autoconf Archive. When you make and distribute a 55 | # modified version of the Autoconf Macro, you may extend this special 56 | # exception to the GPL to apply to your modified version as well. 57 | 58 | #serial 3 59 | 60 | AC_DEFUN([AX_CHECK_COMPILE_FLAG], 61 | [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX 62 | AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl 63 | AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ 64 | ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS 65 | _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" 66 | AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], 67 | [AS_VAR_SET(CACHEVAR,[yes])], 68 | [AS_VAR_SET(CACHEVAR,[no])]) 69 | _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) 70 | AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], 71 | [m4_default([$2], :)], 72 | [m4_default([$3], :)]) 73 | AS_VAR_POPDEF([CACHEVAR])dnl 74 | ])dnl AX_CHECK_COMPILE_FLAGS 75 | -------------------------------------------------------------------------------- /lib/metalink_list.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include "metalink_list.h" 27 | 28 | metalink_list_t *metalink_list_new(void) { 29 | metalink_list_t *l = malloc(sizeof(metalink_list_t)); 30 | if (l) { 31 | l->head = NULL; 32 | l->tail = NULL; 33 | } 34 | return l; 35 | } 36 | 37 | void metalink_list_delete(metalink_list_t *list) { 38 | metalink_list_clear(list); 39 | free(list); 40 | } 41 | 42 | void metalink_list_clear(metalink_list_t *list) { 43 | metalink_list_entry_t *e = list->head; 44 | metalink_list_entry_t *next; 45 | while (e) { 46 | next = e->next; 47 | free(e); 48 | e = next; 49 | } 50 | list->head = NULL; 51 | list->tail = NULL; 52 | } 53 | 54 | void metalink_list_clear_data(metalink_list_t *list) { 55 | metalink_list_entry_t *e = list->head; 56 | metalink_list_entry_t *next; 57 | while (e) { 58 | next = e->next; 59 | free(e->data); 60 | free(e); 61 | e = next; 62 | } 63 | list->head = NULL; 64 | list->tail = NULL; 65 | } 66 | 67 | void *metalink_list_get_data(metalink_list_t *list, size_t index) { 68 | metalink_list_entry_t *e = list->head; 69 | while (index-- && e) { 70 | e = e->next; 71 | } 72 | if (e) { 73 | return e->data; 74 | } else { 75 | return 0; 76 | } 77 | } 78 | 79 | size_t metalink_list_length(metalink_list_t *list) { 80 | size_t length = 0; 81 | metalink_list_entry_t *e = list->head; 82 | while (e) { 83 | e = e->next; 84 | ++length; 85 | } 86 | return length; 87 | } 88 | 89 | int metalink_list_append(metalink_list_t *list, void *data) { 90 | metalink_list_entry_t *new_entry = malloc(sizeof(metalink_list_entry_t)); 91 | 92 | if (!new_entry) { 93 | return 1; 94 | } 95 | new_entry->data = data; 96 | new_entry->next = NULL; 97 | 98 | if (!list->head) { 99 | list->head = new_entry; 100 | } 101 | if (list->tail) { 102 | list->tail->next = new_entry; 103 | } 104 | list->tail = new_entry; 105 | return 0; 106 | } 107 | 108 | void metalink_list_to_array(metalink_list_t *list, void **array) { 109 | void **p = array; 110 | metalink_list_entry_t *e = list->head; 111 | while (e) { 112 | *p++ = e->data; 113 | e = e->next; 114 | } 115 | } 116 | 117 | void metalink_list_for_each(metalink_list_t *list, void (*fun)(void *data)) { 118 | metalink_list_entry_t *e = list->head; 119 | while (e) { 120 | fun(e->data); 121 | e = e->next; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /test/metalink_helper_test.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include "metalink_helper_test.h" 27 | 28 | #include 29 | 30 | #include 31 | 32 | #include "metalink_helper.h" 33 | 34 | void test_metalink_check_safe_path(void) { 35 | char ctrlchars[] = {0x1f, 0x7f, 0x00}; 36 | CU_ASSERT(!metalink_check_safe_path(NULL)); 37 | CU_ASSERT(!metalink_check_safe_path("")); 38 | CU_ASSERT(!metalink_check_safe_path(" ")); 39 | CU_ASSERT(!metalink_check_safe_path(" ")); 40 | CU_ASSERT(!metalink_check_safe_path(".")); 41 | CU_ASSERT(!metalink_check_safe_path("..")); 42 | CU_ASSERT(!metalink_check_safe_path("/foo")); 43 | CU_ASSERT(!metalink_check_safe_path("foo/")); 44 | CU_ASSERT(!metalink_check_safe_path("foo/")); 45 | CU_ASSERT(!metalink_check_safe_path(ctrlchars)); 46 | CU_ASSERT(!metalink_check_safe_path("./foo")); 47 | CU_ASSERT(!metalink_check_safe_path("../foo")); 48 | CU_ASSERT(!metalink_check_safe_path("foo/../bar")); 49 | CU_ASSERT(!metalink_check_safe_path("foo/./bar")); 50 | CU_ASSERT(!metalink_check_safe_path("foo/.")); 51 | CU_ASSERT(!metalink_check_safe_path("foo/..")); 52 | CU_ASSERT(!metalink_check_safe_path("A:")); 53 | CU_ASSERT(!metalink_check_safe_path("C:/foo")); 54 | CU_ASSERT(!metalink_check_safe_path("Z:/foo")); 55 | CU_ASSERT(!metalink_check_safe_path("a:/foo")); 56 | CU_ASSERT(!metalink_check_safe_path("c:/foo")); 57 | CU_ASSERT(!metalink_check_safe_path("z:/foo")); 58 | CU_ASSERT(!metalink_check_safe_path("C:\\foo")); 59 | CU_ASSERT(!metalink_check_safe_path("foo\\bar")); 60 | CU_ASSERT(!metalink_check_safe_path(" foo")); 61 | CU_ASSERT(!metalink_check_safe_path("foo ")); 62 | CU_ASSERT(!metalink_check_safe_path(".foo")); 63 | CU_ASSERT(!metalink_check_safe_path("..foo")); 64 | CU_ASSERT(!metalink_check_safe_path("~foo")); 65 | CU_ASSERT(!metalink_check_safe_path("|foo")); 66 | CU_ASSERT(!metalink_check_safe_path("foo/.bar")); 67 | CU_ASSERT(!metalink_check_safe_path("foo/~bar")); 68 | CU_ASSERT(!metalink_check_safe_path("foo/|bar")); 69 | CU_ASSERT(!metalink_check_safe_path("foo|bar")); 70 | CU_ASSERT(!metalink_check_safe_path("foo > /dev/null")); 71 | 72 | CU_ASSERT(metalink_check_safe_path("foo")); 73 | CU_ASSERT(metalink_check_safe_path("foo.")); 74 | CU_ASSERT(metalink_check_safe_path("foo~")); 75 | CU_ASSERT(metalink_check_safe_path("foo/bar")); 76 | CU_ASSERT(metalink_check_safe_path("foo/bar.baz")); 77 | } 78 | 79 | void test_metalink_get_version(void) { 80 | int major, minor, patch; 81 | major = minor = patch = -1; 82 | metalink_get_version(&major, &minor, &patch); 83 | CU_ASSERT_EQUAL(LIBMETALINK_VERSION_MAJOR, major); 84 | CU_ASSERT_EQUAL(LIBMETALINK_VERSION_MINOR, minor); 85 | CU_ASSERT_EQUAL(LIBMETALINK_VERSION_PATCH, patch); 86 | } 87 | -------------------------------------------------------------------------------- /lib/metalink_pstate_v3.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_PSTATE_V3_H_ 27 | #define _D_METALINK_PSTATE_V3_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | #include "metalink_pstate.h" 34 | 35 | /* metalink state */ 36 | void metalink_state_start_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 37 | const char **attrs); 38 | 39 | void metalink_state_end_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 40 | const char *characters); 41 | 42 | /* identity state */ 43 | void identity_state_start_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 44 | const char **attrs); 45 | 46 | void identity_state_end_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 47 | const char *characters); 48 | 49 | /* tags state */ 50 | void tags_state_start_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 51 | const char **attrs); 52 | 53 | void tags_state_end_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 54 | const char *characters); 55 | 56 | /* files state */ 57 | void files_state_start_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 58 | const char **attrs); 59 | 60 | void files_state_end_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 61 | const char *characters); 62 | 63 | /* file state */ 64 | void file_state_start_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 65 | const char **attrs); 66 | 67 | void file_state_end_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 68 | const char *characters); 69 | 70 | /* resources state */ 71 | void resources_state_start_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 72 | const char **attrs); 73 | 74 | void resources_state_end_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 75 | const char *characters); 76 | 77 | /* verification state */ 78 | void verification_state_start_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 79 | const char **attrs); 80 | 81 | void verification_state_end_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 82 | const char *characters); 83 | 84 | /* pieces state */ 85 | void pieces_state_start_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 86 | const char **attrs); 87 | 88 | void pieces_state_end_fun_v3(metalink_pstm_t *stm, int name, int ns_uri, 89 | const char *characters); 90 | 91 | #endif /* _D_METALINK_PARSER_STATE_V3_H_ */ 92 | -------------------------------------------------------------------------------- /doc/man3/metalink_parse_file.3: -------------------------------------------------------------------------------- 1 | .TH "METALINK_PARSE_FILE" "3" "July 2012" "libmetalink 0.1.0" "libmetalink Manual" 2 | .SH "NAME" 3 | metalink_parse_file, metalink_parse_fp, metalink_parse_fd, metalink_parse_memory \- Parse Metalink file and create metalink_t object. 4 | .SH "SYNOPSIS" 5 | .B #include 6 | .sp 7 | .BI "metalink_error_t metalink_parse_file(const char *" filename ", metalink_t **" res ); 8 | .br 9 | .BI "metalink_error_t metalink_parse_fp(FILE *" docfp ", metalink_t **" res ); 10 | .br 11 | .BI "metalink_error_t metalink_parse_fd(int " docfd ", metalink_t **" res ); 12 | .br 13 | .BI "metalink_error_t metalink_parse_memory(const char *" buf ", size_t " len ", metalink_t **" res ); 14 | 15 | .SH "DESCRIPTION" 16 | These functions parse Metalink file data and constructs metalink_t structure. 17 | You don't have to allocate memory for metalink_t structure. 18 | They take the pointer of metalink_t pointer and allocate memory for that pointer. 19 | 20 | \fBmetalink_parse_file\fP() parses Metalink file denoted by \fIfilename\fP and constructs 21 | metalink_t structure. 22 | 23 | \fBmetalink_parse_fp\fP() reads data from file stream \fIdocfp\fP and construtcts metalink_t structure. 24 | 25 | \fBmetalink_parse_fd\fP() reads data from file descriptor \fIdocfd\fP and constructs metalink_t structure. 26 | 27 | \fBmetalink_parse_memory\fP() parses \fIlen\fP bytes of \fIbuf\fP and constructs metalink_t structure. 28 | 29 | The caller must free the memory allocated for metalink_t structure using \fBmetalink_delete\fP(3) if it is no longer used. 30 | 31 | .SH "RETURN VALUE" 32 | All functions return 0 for success. When error occurred, non-zero value error code is returned and metalink_t structure is not allocated. The error codes are described in metalink_error.h. 33 | 34 | .SH "EXAMPLE" 35 | .nf 36 | #include 37 | #include 38 | #include 39 | 40 | int main(int argc, char** argv) 41 | { 42 | metalink_error_t r; 43 | metalink_t* metalink; 44 | metalink_file_t* file; 45 | metalink_checksum_t** checksums; 46 | 47 | r = metalink_parse_file("sample.metalink", &metalink); 48 | 49 | if(r != 0) { 50 | fprintf(stderr, "ERROR: code=%d\en", r); 51 | exit(EXIT_FAILURE); 52 | } 53 | 54 | file = metalink\->files[0]; 55 | printf("name: %s\en", file\->name); 56 | printf("size: %lld\en", file\->size); 57 | printf("os : %s\en", file\->os); 58 | 59 | if(file\->checksums) { 60 | checksums = file\->checksums; 61 | while(*checksums) { 62 | printf("hash: %s %s\en", (*checksums)\->type, (*checksums)\->hash); 63 | ++checksums; 64 | } 65 | } 66 | if(file\->chunk_checksum) { 67 | size_t count = 0; 68 | metalink_piece_hash_t** piece_hashes; 69 | printf("chunk checksum: size=%d, type=%s\en", 70 | file\->chunk_checksum\->length, 71 | file\->chunk_checksum\->type); 72 | printf("first 5 piece hashes...\en"); 73 | piece_hashes = file\->chunk_checksum\->piece_hashes; 74 | while(*piece_hashes && count < 5) { 75 | printf("piece=%d, hash=%s\en", (*piece_hashes)\->piece, 76 | (*piece_hashes)\->hash); 77 | ++piece_hashes; 78 | ++count; 79 | } 80 | printf("...\en"); 81 | } 82 | if(file\->resources) { 83 | size_t count = 0; 84 | metalink_resource_t** resources; 85 | printf("first 5 resources...\en"); 86 | resources = file\->resources; 87 | while(*resources && count < 5) { 88 | printf("type=%s, location=%s, preference=%d, url=%s\en", 89 | (*resources)\->type, (*resources)\->location, 90 | (*resources)\->preference, (*resources)\->url); 91 | ++resources; 92 | ++count; 93 | } 94 | printf("...\en"); 95 | } 96 | 97 | /* delete metalink_t */ 98 | metalink_delete(metalink); 99 | 100 | return EXIT_SUCCESS; 101 | } 102 | .fi 103 | 104 | .SH "SEE ALSO" 105 | .BR metalink_delete (3), 106 | .BR metalink_parse_update (3), 107 | .BR metalink_t (3) 108 | -------------------------------------------------------------------------------- /lib/metalink_pstm.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_PSTM_H_ 27 | #define _D_METALINK_PSTM_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | #include "metalink_pstate.h" 34 | #include "metalink_pstate_v3.h" 35 | #include "metalink_pstate_v4.h" 36 | #include "metalink_pctrl.h" 37 | 38 | /* parser state machine */ 39 | struct _metalink_pstm { 40 | metalink_pctrl_t *ctrl; 41 | metalink_pstate_t *state; 42 | } /* metalink_pstm_t */; 43 | 44 | /* constructor */ 45 | metalink_pstm_t *new_metalink_pstm(void); 46 | 47 | /* destructor */ 48 | void delete_metalink_pstm(metalink_pstm_t *stm); 49 | 50 | /* Setting callback functions for start element and end element */ 51 | void metalink_pstm_set_fun(metalink_pstm_t *stm, metalink_start_fun start_fun, 52 | metalink_end_fun end_fun); 53 | 54 | /** 55 | * Returns 1 if character buffering in XML parser is enabled, 56 | * otherwise returns 0. 57 | */ 58 | int metalink_pstm_character_buffering_enabled(const metalink_pstm_t *stm); 59 | 60 | /** 61 | * Enable character buffersing in XML parser. 62 | */ 63 | void metalink_pstm_enable_character_buffering(metalink_pstm_t *stm); 64 | 65 | /** 66 | * Disable character buffersing in XML parser. 67 | */ 68 | void metalink_pstm_disable_character_buffering(metalink_pstm_t *stm); 69 | 70 | /* functions for state transition */ 71 | void metalink_pstm_enter_null_state(metalink_pstm_t *stm); 72 | 73 | void metalink_pstm_enter_metalink_state(metalink_pstm_t *stm); 74 | 75 | void metalink_pstm_enter_metalink_state_v4(metalink_pstm_t *stm); 76 | 77 | void metalink_pstm_enter_identity_state(metalink_pstm_t *stm); 78 | 79 | void metalink_pstm_enter_tags_state(metalink_pstm_t *stm); 80 | 81 | void metalink_pstm_enter_files_state(metalink_pstm_t *stm); 82 | 83 | void metalink_pstm_enter_file_state(metalink_pstm_t *stm); 84 | 85 | void metalink_pstm_enter_size_state(metalink_pstm_t *stm); 86 | 87 | void metalink_pstm_enter_version_state(metalink_pstm_t *stm); 88 | 89 | void metalink_pstm_enter_language_state(metalink_pstm_t *stm); 90 | 91 | void metalink_pstm_enter_os_state(metalink_pstm_t *stm); 92 | 93 | void metalink_pstm_enter_resources_state(metalink_pstm_t *stm); 94 | 95 | void metalink_pstm_enter_url_state(metalink_pstm_t *stm); 96 | 97 | void metalink_pstm_enter_verification_state(metalink_pstm_t *stm); 98 | 99 | void metalink_pstm_enter_hash_state(metalink_pstm_t *stm); 100 | 101 | void metalink_pstm_enter_pieces_state(metalink_pstm_t *stm); 102 | 103 | void metalink_pstm_enter_piece_hash_state(metalink_pstm_t *stm); 104 | 105 | void metalink_pstm_enter_fin_state(metalink_pstm_t *stm); 106 | 107 | void metalink_pstm_enter_skip_state(metalink_pstm_t *stm); 108 | 109 | void metalink_pstm_exit_skip_state(metalink_pstm_t *stm); 110 | 111 | /* Metalink 4 states */ 112 | void metalink_pstm_enter_file_state_v4(metalink_pstm_t *stm); 113 | 114 | void metalink_pstm_enter_generator_state(metalink_pstm_t *stm); 115 | 116 | void metalink_pstm_enter_origin_state(metalink_pstm_t *stm); 117 | 118 | void metalink_pstm_enter_description_state_v4(metalink_pstm_t *stm); 119 | 120 | void metalink_pstm_enter_copyright_state_v4(metalink_pstm_t *stm); 121 | 122 | void metalink_pstm_enter_identity_state_v4(metalink_pstm_t *stm); 123 | 124 | void metalink_pstm_enter_logo_state_v4(metalink_pstm_t *stm); 125 | 126 | void metalink_pstm_enter_signature_state_v4(metalink_pstm_t *stm); 127 | 128 | void metalink_pstm_enter_pieces_state_v4(metalink_pstm_t *stm); 129 | 130 | void metalink_pstm_enter_metaurl_state_v4(metalink_pstm_t *stm); 131 | 132 | void metalink_pstm_enter_published_state_v4(metalink_pstm_t *stm); 133 | 134 | void metalink_pstm_enter_updated_state_v4(metalink_pstm_t *stm); 135 | 136 | #endif /* _D_METALINK_PSTM_H_ */ 137 | -------------------------------------------------------------------------------- /lib/includes/metalink/metalink_parser.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_PARSER_H_ 27 | #define _D_METALINK_PARSER_H_ 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | /* 39 | * Parses metalink XML file. 40 | * @param filename path to Metalink XML file to be parsed. 41 | * @param res a dynamically allocated metalink_t structure as a result of 42 | * parsing. 43 | * @return 0 for success, non-zero for error. See metalink_error.h for 44 | * the meaning of error code. 45 | */ 46 | metalink_error_t metalink_parse_file(const char *filename, metalink_t **res); 47 | 48 | /* 49 | * Parses metalink XML file. 50 | * @param docfp file stream for Metalink XML file to be parsed. 51 | * @param res a dynamically allocated metalink_t structure as a result of 52 | * parsing. 53 | * @return 0 for success, non-zero for error. See metalink_error.h for 54 | * the meaning of error code. 55 | */ 56 | metalink_error_t metalink_parse_fp(FILE *docfp, metalink_t **res); 57 | 58 | /* 59 | * Parses metalink XML from a file descriptor. 60 | * @param docfd file descriptor of Metalink XML file to be parsed. 61 | * @param res a dynamically allocated metalink_t structure as a result of 62 | * parsing. 63 | * @return 0 for success, non-zero for error. See metalink_error.h for 64 | * the meaning of error code. 65 | */ 66 | metalink_error_t metalink_parse_fd(int docfd, metalink_t **res); 67 | 68 | /* 69 | * Parses metalink XML stored in buf and its length is len. 70 | * @param buf a pointer to the XML data. 71 | * @param len length of XML data in byte. 72 | * @param res a dynamically allocated metalink_t structure as a result of 73 | * parsing. 74 | * @return 0 for success, non-zero for error. See metalink_error.h for 75 | * the meaning of error code. 76 | */ 77 | metalink_error_t metalink_parse_memory(const char *buf, size_t len, 78 | metalink_t **res); 79 | 80 | /** 81 | * a parser context to keep current progress of XML parser. 82 | */ 83 | typedef struct _metalink_parser_context metalink_parser_context_t; 84 | 85 | /* 86 | * Allocates, initializes and returns a parser context. 87 | * @return a parser context on success, otherwise NULL. 88 | */ 89 | metalink_parser_context_t *metalink_parser_context_new(void); 90 | 91 | /** 92 | * Deallocates a parser context ctx. 93 | * @param ctx a parser context to deallocate. If ctx is NULL, this function does 94 | * nothing. 95 | */ 96 | void metalink_parser_context_delete(metalink_parser_context_t *ctx); 97 | 98 | /** 99 | * Processes len bytes of data at buf. This function can be called several times 100 | * to parse entire XML data. 101 | * @param ctx a parser context. 102 | * @param buf a pointer to the XML data. 103 | * @param len length of XML data in bytes. 104 | * @return 0 on success, non-zero for error. See metalink_error.h for the 105 | * meaning of error code. 106 | */ 107 | metalink_error_t metalink_parse_update(metalink_parser_context_t *ctx, 108 | const char *buf, size_t len); 109 | 110 | /** 111 | * Processes len bytes of data at buf and places metalink_t to res. 112 | * Inside this function, ctx is cleaned up, so you don't need to call 113 | * delete_metalink_parser_context. len can be 0. 114 | * @param ctx a parser context. 115 | * @param buf a pointer to the XML data. 116 | * @param len length of XML data in bytes. 117 | * @param res a dynamically allocated metalink_t structure as a result of 118 | * parsing. 119 | * @return 0 on success, non-zero for error. See metalink_error_h for 120 | * the meaning of error code. 121 | */ 122 | metalink_error_t metalink_parse_final(metalink_parser_context_t *ctx, 123 | const char *buf, size_t len, 124 | metalink_t **res); 125 | 126 | #ifdef __cplusplus 127 | } 128 | #endif 129 | 130 | #endif /* _D_METALINK_PARSER_H_ */ 131 | -------------------------------------------------------------------------------- /lib/metalink_helper.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include "metalink_helper.h" 27 | 28 | #include 29 | #include 30 | 31 | #include "metalink_pstate.h" 32 | 33 | static int ends_with(const char *a, const char *b) { 34 | size_t alen = strlen(a); 35 | size_t blen = strlen(b); 36 | if (alen < blen) { 37 | return 0; 38 | } 39 | a += alen - blen; 40 | return strcmp(a, b) == 0; 41 | } 42 | 43 | int metalink_check_safe_path(const char *path) { 44 | /* See discussions of treating filename from the remote server in 45 | http://tools.ietf.org/html/rfc6266#section-4.3, 46 | http://tools.ietf.org/html/rfc2183#section-5 and 47 | http://tools.ietf.org/html/rfc5854.html#section-4.1.2.1 48 | */ 49 | size_t len, i; 50 | size_t filename_idx = 0; 51 | /* If path or filename (string following the final '/' in path) 52 | start with one of the characters in bad_prefix, we consider it as 53 | invalid. */ 54 | const char bad_prefix[] = " .~/"; 55 | /* If path ends with one of the characters in bad_suffix, we 56 | consider it as invalid. */ 57 | const char bad_suffix[] = " /"; 58 | if (!path || !path[0]) { 59 | return 0; 60 | } 61 | for (i = 0; path[i]; ++i) { 62 | unsigned char c = path[i]; 63 | if (c <= 0x1f || c == 0x7f || c == '\\' || c == '<' || c == '>' || 64 | c == '|') { 65 | return 0; 66 | } 67 | if (path[i] == '/') { 68 | filename_idx = i + 1; 69 | } 70 | } 71 | len = i; 72 | if (filename_idx == len) { 73 | return 0; 74 | } 75 | if (strchr(bad_prefix, path[0]) != NULL) { 76 | return 0; 77 | } 78 | if (filename_idx != 0) { 79 | if (strchr(bad_prefix, path[filename_idx]) != NULL) { 80 | return 0; 81 | } 82 | } 83 | if (strchr(bad_suffix, path[len - 1]) != NULL) { 84 | return 0; 85 | } 86 | /* Don't allow DOS drive letter (e.g., C:) */ 87 | if (len >= 2 && (('A' <= path[0] && path[0] <= 'Z') || 88 | ('a' <= path[0] && path[0] <= 'z')) && 89 | path[1] == ':') { 90 | return 0; 91 | } 92 | /* "." and ".." and prefix "./" and "../" are considered in 93 | bad_prefix */ 94 | if (strstr(path, "/./") != NULL || strstr(path, "/../") != NULL || 95 | ends_with(path, "/.") || ends_with(path, "/..")) { 96 | return 0; 97 | } 98 | return 1; 99 | } 100 | 101 | void metalink_get_version(int *major, int *minor, int *patch) { 102 | *major = LIBMETALINK_VERSION_MAJOR; 103 | *minor = LIBMETALINK_VERSION_MINOR; 104 | *patch = LIBMETALINK_VERSION_PATCH; 105 | } 106 | 107 | const char *metalink_strerror(int error_code) { 108 | switch (error_code) { 109 | case 0: 110 | return "success"; 111 | case METALINK_ERR_BAD_ALLOC: 112 | return "out of memory"; 113 | case METALINK_ERR_CANNOT_OPEN_FILE: 114 | return "could not open file"; 115 | case METALINK_ERR_MISSING_REQUIRED_ATTR: 116 | return "required attribute not found"; 117 | case METALINK_ERR_NAMESPACE_ERROR: 118 | return "unexpected namespace"; 119 | case METALINK_ERR_PARSER_ERROR: 120 | return "xml parser failure"; 121 | /* METALINK_ERR_NO_*_TRANSACTION error code should not be returned 122 | to the application code. If they are, it is a bug of 123 | libmetalink. In the future release, they will be removed and 124 | assert() will be used instead. */ 125 | case METALINK_ERR_NO_FILE_TRANSACTION: 126 | return "no file transaction"; 127 | case METALINK_ERR_NO_RESOURCE_TRANSACTION: 128 | return "no resource transaction"; 129 | case METALINK_ERR_NO_CHECKSUM_TRANSACTION: 130 | return "no checksum transaction"; 131 | case METALINK_ERR_NO_CHUNK_CHECKSUM_TRANSACTION: 132 | return "no chunk checksum transaction"; 133 | case METALINK_ERR_NO_PIECE_HASH_TRANSACTION: 134 | return "no piece hash transaction"; 135 | default: 136 | return "unknown error code"; 137 | } 138 | } 139 | 140 | int metalink_match_ns(const char *uri, size_t len) { 141 | switch (len) { 142 | case sizeof(METALINK_V3_NS_URI) - 1: 143 | if (memcmp(METALINK_V3_NS_URI, uri, len) == 0) { 144 | return METALINK_NS_V3; 145 | } 146 | break; 147 | case sizeof(METALINK_V4_NS_URI) - 1: 148 | if (memcmp(METALINK_V4_NS_URI, uri, len) == 0) { 149 | return METALINK_NS_V4; 150 | } 151 | break; 152 | } 153 | return METALINK_NS_NONE; 154 | } 155 | -------------------------------------------------------------------------------- /lib/metalink_pstate_v4.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_PSTATE_V4_H_ 27 | #define _D_METALINK_PSTATE_V4_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | #include "metalink_pstate.h" 34 | 35 | /* metalink state */ 36 | void metalink_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 37 | const char **attrs); 38 | 39 | void metalink_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 40 | const char *characters); 41 | 42 | /* generator state */ 43 | void generator_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 44 | const char **attrs); 45 | 46 | void generator_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 47 | const char *characters); 48 | 49 | /* origin state */ 50 | void origin_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 51 | const char **attrs); 52 | 53 | void origin_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 54 | const char *characters); 55 | 56 | /* file state */ 57 | void file_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 58 | const char **attrs); 59 | 60 | void file_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 61 | const char *characters); 62 | 63 | /* url state */ 64 | void url_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 65 | const char **attrs); 66 | 67 | void url_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 68 | const char *characters); 69 | 70 | /* description state */ 71 | void description_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 72 | const char **attrs); 73 | 74 | void description_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 75 | const char *characters); 76 | 77 | /* copyright state */ 78 | void copyright_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 79 | const char **attrs); 80 | 81 | void copyright_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 82 | const char *characters); 83 | 84 | /* identity state */ 85 | void identity_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 86 | const char **attrs); 87 | 88 | void identity_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 89 | const char *characters); 90 | 91 | /* logo state */ 92 | void logo_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 93 | const char **attrs); 94 | 95 | void logo_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 96 | const char *characters); 97 | 98 | /* signature state */ 99 | void signature_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 100 | const char **attrs); 101 | 102 | void signature_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 103 | const char *characters); 104 | 105 | /* pieces state */ 106 | void pieces_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 107 | const char **attrs); 108 | 109 | void pieces_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 110 | const char *characters); 111 | 112 | /* metaurl state */ 113 | void metaurl_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 114 | const char **attrs); 115 | 116 | void metaurl_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 117 | const char *characters); 118 | 119 | /* published state */ 120 | void published_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 121 | const char **attrs); 122 | 123 | void published_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 124 | const char *characters); 125 | 126 | /* updated state */ 127 | void updated_state_start_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 128 | const char **attrs); 129 | 130 | void updated_state_end_fun_v4(metalink_pstm_t *stm, int name, int ns_uri, 131 | const char *characters); 132 | 133 | #endif /* _D_METALINK_PARSER_STATE_V4_H_ */ 134 | -------------------------------------------------------------------------------- /doc/man3/metalink_parse_update.3: -------------------------------------------------------------------------------- 1 | .TH "METALINK_PARSE_UPDATE" "3" "July 2012" "libmetalink 0.1.0" "libmetalink Manual" 2 | .SH "NAME" 3 | metalink_parse_update, metalink_parse_final, 4 | metalink_parser_context_new, metalink_parser_context_delete \- Parse 5 | Metalink file and create metalink_t object. 6 | 7 | .SH "SYNOPSIS" 8 | .B #include 9 | .sp 10 | .BI "metalink_error_t metalink_parse_update(metalink_parser_context_t *" ctx , 11 | .BI " const char *" buf ", size_t " len ); 12 | .br 13 | .BI "metalink_error_t metalink_parse_final(metalink_parser_context_t *" ctx , 14 | .BI " const char *" buf ", size_t " len , 15 | .BI " metalink_t **" res ); 16 | .sp 17 | .BI "metalink_parser_context_t* metalink_parser_context_new();" 18 | .br 19 | .BI "void metalink_parser_context_delete(metalink_parser_context_t *" ctx ); 20 | 21 | .SH "DESCRIPTION" 22 | These functions provide a push interface for parsing Metalink XML 23 | files. 24 | 25 | Before calling \fBmetalink_parse_update\fP() and \fBmetalink_parse_final\fP(), 26 | \fBmetalink_parse_context_t\fP has to be created by 27 | \fBmetalink_parser_context_new\fP(). 28 | 29 | In each call of \fBmetalink_parse_update\fP(), \fIlen\fP bytes of \fIbuf\fP are 30 | processed. 31 | At the last piece of data, call \fBmetalink_parse_final\fP() to get 32 | \fBmetalink_t\fP(3) structure as a result. 33 | Giving 0 as \fIlen\fP is permitted. 34 | 35 | \fBmetalink_parse_final\fP() calls \fBmetalink_parser_context_delete\fP() 36 | internally to deallocate the memory for passed 37 | \fBmetalink_parser_context_t\fP. 38 | Therefore you don't have to call \fPmetlaink_parser_context_delete\fP() if you 39 | call \fBmetalink_parse_final\fP(). 40 | Otherwise call \fPmetalink_parser_context_delete\fP() to free the allocated 41 | resource. 42 | 43 | You don't have to allocate memory for \fBmetalink_t\fP(3) structure. 44 | \fBmetalink_parse_final\fP() takes the pointer of \fBmetalink_t\fP(3) 45 | pointer and allocates memory for that pointer. 46 | 47 | The caller must free the memory allocated for \fBmetalink_t\fP(3) structure 48 | using \fBmetalink_delete\fP(3) if it is no longer used. 49 | 50 | .SH "RETURN VALUE" 51 | \fBmetalink_parse_update\fP(), \fBmetalink_parse_final\fP() return 0 for 52 | success. When error occurred, non-zero value error code is returned. 53 | If error occurred, \fBmetalink_parse_final\fP() does not allocate memory for 54 | \fBmetalink_t\fP. The error codes are described in metalink_error.h. 55 | 56 | In case of success, \fBmetalink_parser_context_new\fP() allocates memory for 57 | \fBmetalink_parser_context_t\fP() and returns the pointer to it. 58 | In case of failure, \fBmetalink_parser_context_new\fP() returns NULL. 59 | 60 | \fBmetalink_parser_context_delete\fP() returns no value. 61 | 62 | .SH "EXAMPLE" 63 | .nf 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | 74 | int main(int argc, char** argv) 75 | { 76 | metalink_error_t r; 77 | metalink_t* metalink; 78 | metalink_file_t* file; 79 | metalink_checksum_t** checksums; 80 | metalink_parser_context_t* context; 81 | int fd; 82 | char buf[BUFSIZ]; 83 | ssize_t length; 84 | 85 | context = metalink_parser_context_new(); 86 | 87 | if(context == NULL) { 88 | fprintf(stderr, 89 | "ERROR: failed to create metalink_parser_context_t\en"); 90 | exit(EXIT_FAILURE); 91 | } 92 | 93 | fd = open("sample.metalink", O_RDONLY); 94 | if(fd == \-1) { 95 | fprintf(stderr, "ERROR: open():%s\en", strerror(errno)); 96 | exit(EXIT_FAILURE); 97 | } 98 | while((length = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)))) != 0){ 99 | r = metalink_parse_update(context, buf, length); 100 | if(r != 0) { 101 | fprintf(stderr, "ERROR: code=%d\en", r); 102 | metalink_parser_context_delete(context); 103 | exit(EXIT_FAILURE); 104 | } 105 | } 106 | if(length == \-1) { 107 | fprintf(stderr, "ERROR: read():%s\en", strerror(errno)); 108 | metalink_parser_context_delete(context); 109 | exit(EXIT_FAILURE); 110 | } 111 | 112 | r = metalink_parse_final(context, NULL, 0, &metalink); 113 | 114 | if(r != 0) { 115 | fprintf(stderr, "ERROR: code=%d\en", r); 116 | exit(EXIT_FAILURE); 117 | } 118 | 119 | TEMP_FAILURE_RETRY(close(fd)); 120 | 121 | file = metalink\->files[0]; 122 | printf("name: %s\en", file\->name); 123 | printf("size: %lld\en", file\->size); 124 | printf("os : %s\en", file\->os); 125 | 126 | if(file\->checksums) { 127 | checksums = file\->checksums; 128 | while(*checksums) { 129 | printf("hash: %s %s\en", (*checksums)\->type, (*checksums)\->hash); 130 | ++checksums; 131 | } 132 | } 133 | if(file\->chunk_checksum) { 134 | size_t count = 0; 135 | metalink_piece_hash_t** piece_hashes; 136 | printf("chunk checksum: size=%d, type=%s\en", 137 | file\->chunk_checksum\->length, 138 | file\->chunk_checksum\->type); 139 | printf("first 5 piece hashes...\en"); 140 | piece_hashes = file\->chunk_checksum\->piece_hashes; 141 | while(*piece_hashes && count < 5) { 142 | printf("piece=%d, hash=%s\en", (*piece_hashes)\->piece, 143 | (*piece_hashes)\->hash); 144 | ++piece_hashes; 145 | ++count; 146 | } 147 | printf("...\en"); 148 | } 149 | if(file\->resources) { 150 | size_t count = 0; 151 | metalink_resource_t** resources; 152 | printf("first 5 resources...\en"); 153 | resources = file\->resources; 154 | while(*resources && count < 5) { 155 | printf("type=%s, location=%s, preference=%d, url=%s\en", 156 | (*resources)\->type, (*resources)\->location, 157 | (*resources)\->preference, (*resources)\->url); 158 | ++resources; 159 | ++count; 160 | } 161 | printf("...\en"); 162 | } 163 | 164 | /* delete metalink_t */ 165 | metalink_delete(metalink); 166 | 167 | return EXIT_SUCCESS; 168 | } 169 | .fi 170 | 171 | .SH "SEE ALSO" 172 | .BR metalink_delete (3), 173 | .BR metalink_parse_file (3), 174 | .BR metalink_t (3) 175 | -------------------------------------------------------------------------------- /test/metalink_parser_test_v4.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "metalink_parser_test.h" 31 | #include "metalink_parser_test_v4.h" 32 | #include "metalink/metalink_parser.h" 33 | 34 | static void validate_result(metalink_t *metalink) { 35 | metalink_file_t *file; 36 | metalink_checksum_t *checksum; 37 | metalink_resource_t *resource; 38 | metalink_metaurl_t *metaurl; 39 | metalink_piece_hash_t *piece_hash; 40 | 41 | CU_ASSERT_STRING_EQUAL("MetalinkEditor/2.0dev", metalink->generator); 42 | /* UTC time */ 43 | CU_ASSERT_EQUAL(metalink->published, 1242356003); 44 | CU_ASSERT_EQUAL(metalink->version, METALINK_VERSION_4); 45 | 46 | CU_ASSERT_STRING_EQUAL("http://example.org/foo.metalink", metalink->origin); 47 | CU_ASSERT(metalink->origin_dynamic); 48 | 49 | /* count files */ 50 | CU_ASSERT_EQUAL_FATAL(4, count_array((void **)metalink->files)); 51 | 52 | /* check 1st file */ 53 | file = metalink->files[0]; 54 | CU_ASSERT_STRING_EQUAL("libmetalink-0.0.1.tar.bz2", file->name); 55 | CU_ASSERT_EQUAL(0, file->size); /* no size specified */ 56 | CU_ASSERT_STRING_EQUAL("0.0.1", file->version); 57 | CU_ASSERT_STRING_EQUAL("libmetalink", file->identity); 58 | 59 | CU_ASSERT_STRING_EQUAL("name", file->publisher_name); 60 | CU_ASSERT_STRING_EQUAL("url", file->publisher_url); 61 | 62 | CU_ASSERT_EQUAL(1, count_array((void **)file->languages)); 63 | CU_ASSERT_STRING_EQUAL("en-US", file->languages[0]); 64 | 65 | CU_ASSERT_EQUAL(1, count_array((void **)file->oses)); 66 | CU_ASSERT_STRING_EQUAL("Linux-x86", file->oses[0]); 67 | 68 | CU_ASSERT_EQUAL_FATAL(2, count_array((void **)file->checksums)); 69 | 70 | checksum = file->checksums[0]; 71 | CU_ASSERT_STRING_EQUAL("sha1", checksum->type); 72 | CU_ASSERT_STRING_EQUAL("a96cf3f0266b91d87d5124cf94326422800b627d", 73 | checksum->hash); 74 | checksum = file->checksums[1]; 75 | CU_ASSERT_STRING_EQUAL("md5", checksum->type); 76 | CU_ASSERT_STRING_EQUAL("fc4d834e89c18c99b2615d902750948c", checksum->hash); 77 | 78 | CU_ASSERT_PTR_NULL(file->chunk_checksum); /* no chunk checksum */ 79 | 80 | CU_ASSERT_EQUAL_FATAL(2, count_array((void **)file->resources)); 81 | 82 | /* file->resources were sorted by priority */ 83 | resource = file->resources[0]; 84 | CU_ASSERT_STRING_EQUAL("http://httphost/libmetalink-0.0.1.tar.bz2", 85 | resource->url); 86 | CU_ASSERT_PTR_NULL(resource->location); /* no location */ 87 | CU_ASSERT_EQUAL(99, resource->priority); 88 | 89 | resource = file->resources[1]; 90 | CU_ASSERT_STRING_EQUAL("ftp://ftphost/libmetalink-0.0.1.tar.bz2", 91 | resource->url); 92 | CU_ASSERT_STRING_EQUAL("jp", resource->location); 93 | CU_ASSERT_EQUAL(100, resource->priority); 94 | 95 | /* check 2nd file */ 96 | file = metalink->files[1]; 97 | CU_ASSERT_STRING_EQUAL("libmetalink-0.0.2a.tar.bz2", file->name); 98 | CU_ASSERT_EQUAL(4294967296LL, file->size); 99 | 100 | CU_ASSERT_PTR_NULL(file->checksums); /* no checksums */ 101 | 102 | CU_ASSERT_STRING_EQUAL("sha1", file->chunk_checksum->type); 103 | CU_ASSERT_EQUAL(262144, file->chunk_checksum->length); 104 | /* Check that the entry which doesn't have type attribute is skipped. */ 105 | CU_ASSERT_PTR_NOT_NULL_FATAL(file->chunk_checksum); 106 | CU_ASSERT_EQUAL(2, count_array((void **)file->chunk_checksum->piece_hashes)); 107 | 108 | piece_hash = file->chunk_checksum->piece_hashes[0]; 109 | CU_ASSERT_STRING_EQUAL("179463a88d79cbf0b1923991708aead914f26142", 110 | piece_hash->hash); 111 | 112 | piece_hash = file->chunk_checksum->piece_hashes[1]; 113 | CU_ASSERT_STRING_EQUAL("fecf8bc9a1647505fe16746f94e97a477597dbf3", 114 | piece_hash->hash); 115 | 116 | CU_ASSERT_EQUAL_FATAL(3, count_array((void **)file->resources)); 117 | 118 | resource = file->resources[0]; 119 | CU_ASSERT_STRING_EQUAL("ftp://ftphost/libmetalink-0.0.2a.tar.bz2", 120 | resource->url); 121 | 122 | resource = file->resources[1]; 123 | CU_ASSERT_STRING_EQUAL("http://mirror1/libmetalink-0.0.2a.tar.bz2", 124 | resource->url); 125 | 126 | resource = file->resources[2]; 127 | CU_ASSERT_STRING_EQUAL("http://httphost/libmetalink-0.0.2a.tar.bz2", 128 | resource->url); 129 | CU_ASSERT_EQUAL(999999, resource->priority); /* no priority */ 130 | 131 | CU_ASSERT_EQUAL_FATAL(3, count_array((void **)file->metaurls)); 132 | metaurl = file->metaurls[0]; 133 | CU_ASSERT_STRING_EQUAL("http://mirror3/libmetalink-0.0.2a.tar.bz2.torrent", 134 | metaurl->url); 135 | metaurl = file->metaurls[1]; 136 | CU_ASSERT_STRING_EQUAL("http://mirror1/libmetalink-0.0.2a.tar.bz2.torrent", 137 | metaurl->url); 138 | metaurl = file->metaurls[2]; 139 | CU_ASSERT_STRING_EQUAL("http://mirror2/libmetalink-0.0.2a.tar.bz2.torrent", 140 | metaurl->url); 141 | CU_ASSERT_EQUAL(999999, metaurl->priority); 142 | 143 | /* Check 3rd file */ 144 | file = metalink->files[2]; 145 | CU_ASSERT_STRING_EQUAL("NoVerificationHash", file->name); 146 | CU_ASSERT_EQUAL(0, file->size); /* bad size, fallback to 0 */ 147 | CU_ASSERT_PTR_NULL(file->checksums); 148 | CU_ASSERT_PTR_NULL(file->chunk_checksum); 149 | 150 | CU_ASSERT_EQUAL_FATAL(1, count_array((void **)file->resources)); 151 | resource = file->resources[0]; 152 | CU_ASSERT_STRING_EQUAL("ftp://host/file", resource->url); 153 | 154 | /* Check 4th file */ 155 | file = metalink->files[3]; 156 | CU_ASSERT_STRING_EQUAL("badpri", file->name); 157 | resource = file->resources[0]; 158 | CU_ASSERT_STRING_EQUAL("http://badpriority/", resource->url); 159 | /* bad priority, fallback to 999999. */ 160 | CU_ASSERT_EQUAL(999999, resource->priority); 161 | 162 | metalink_delete(metalink); 163 | } 164 | 165 | void test_metalink_parse_file_v4(void) { 166 | metalink_error_t r; 167 | metalink_t *metalink; 168 | 169 | r = metalink_parse_file(LIBMETALINK_TEST_DIR "test2.xml", &metalink); 170 | CU_ASSERT_EQUAL_FATAL(0, r); 171 | 172 | validate_result(metalink); 173 | } 174 | -------------------------------------------------------------------------------- /lib/metalink_pstate.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_PSTATE_H_ 27 | #define _D_METALINK_PSTATE_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | #define METALINK_V3_NS_URI "http://www.metalinker.org/" 34 | #define METALINK_V4_NS_URI "urn:ietf:params:xml:ns:metalink" 35 | 36 | typedef enum { METALINK_NS_NONE, METALINK_NS_V3, METALINK_NS_V4 } metalink_ns; 37 | 38 | typedef enum { 39 | METALINK_TOKEN_COPYRIGHT, 40 | METALINK_TOKEN_DESCRIPTION, 41 | METALINK_TOKEN_FILE, 42 | METALINK_TOKEN_FILES, 43 | METALINK_TOKEN_GENERATOR, 44 | METALINK_TOKEN_HASH, 45 | METALINK_TOKEN_IDENTITY, 46 | METALINK_TOKEN_LANGUAGE, 47 | METALINK_TOKEN_LOGO, 48 | METALINK_TOKEN_METALINK, 49 | METALINK_TOKEN_METAURL, 50 | METALINK_TOKEN_ORIGIN, 51 | METALINK_TOKEN_OS, 52 | METALINK_TOKEN_PIECES, 53 | METALINK_TOKEN_PUBLISHED, 54 | METALINK_TOKEN_PUBLISHER, 55 | METALINK_TOKEN_RESOURCES, 56 | METALINK_TOKEN_SIGNATURE, 57 | METALINK_TOKEN_SIZE, 58 | METALINK_TOKEN_TAGS, 59 | METALINK_TOKEN_UPDATED, 60 | METALINK_TOKEN_URL, 61 | METALINK_TOKEN_VERIFICATION, 62 | METALINK_TOKEN_VERSION 63 | } metalink_token; 64 | 65 | typedef enum { 66 | METALINK_ATTR_TOKEN_DYNAMIC, 67 | METALINK_ATTR_TOKEN_LENGTH, 68 | METALINK_ATTR_TOKEN_LOCATION, 69 | METALINK_ATTR_TOKEN_MAXCONNECTIONS, 70 | METALINK_ATTR_TOKEN_MEDIATYPE, 71 | METALINK_ATTR_TOKEN_NAME, 72 | METALINK_ATTR_TOKEN_ORIGIN, 73 | METALINK_ATTR_TOKEN_PIECE, 74 | METALINK_ATTR_TOKEN_PREFERENCE, 75 | METALINK_ATTR_TOKEN_PRIORITY, 76 | METALINK_ATTR_TOKEN_TYPE, 77 | METALINK_ATTR_TOKEN_URL, 78 | METALINK_ATTR_TOKEN_MAX 79 | } metalink_attr_token; 80 | 81 | int metalink_lookup_token(const char *name, size_t namelen); 82 | 83 | int metalink_lookup_attr_token(const char *name, size_t namelen); 84 | 85 | typedef struct _metalink_pstm metalink_pstm_t; 86 | 87 | typedef void (*metalink_start_fun)(metalink_pstm_t *stm, int name, int ns_uri, 88 | const char **attr); 89 | 90 | typedef void (*metalink_end_fun)(metalink_pstm_t *stm, int name, int ns_uri, 91 | const char *characters); 92 | 93 | typedef struct _metalink_pstate { 94 | metalink_start_fun start_fun; 95 | 96 | metalink_end_fun end_fun; 97 | 98 | int character_buffering; 99 | 100 | /** follow three elements are used in skip state **/ 101 | metalink_start_fun before_skip_state_start_fun; 102 | 103 | metalink_end_fun before_skip_state_end_fun; 104 | 105 | int before_skip_character_buffering; 106 | 107 | int skip_depth; 108 | 109 | } metalink_pstate_t; 110 | 111 | /* constructor */ 112 | metalink_pstate_t *new_metalink_pstate(void); 113 | 114 | /* destructor */ 115 | void delete_metalink_pstate(metalink_pstate_t *state); 116 | 117 | void error_handler(metalink_pstm_t *stm, metalink_error_t error); 118 | 119 | /* null handler doing nothing */ 120 | void null_state_start_fun(metalink_pstm_t *stm, int name, int ns_uri, 121 | const char **attrs); 122 | 123 | void null_state_end_fun(metalink_pstm_t *stm, int name, int ns_uri, 124 | const char *characters); 125 | 126 | /* initial state */ 127 | void initial_state_start_fun(metalink_pstm_t *stm, int name, int ns_uri, 128 | const char **attrs); 129 | 130 | void initial_state_end_fun(metalink_pstm_t *stm, int name, int ns_uri, 131 | const char *characters); 132 | 133 | /* skip state */ 134 | void skip_state_start_fun(metalink_pstm_t *stm, int name, int ns_uri, 135 | const char **attrs); 136 | 137 | void skip_state_end_fun(metalink_pstm_t *stm, int name, int ns_uri, 138 | const char *characters); 139 | 140 | /* size state */ 141 | void size_state_start_fun(metalink_pstm_t *stm, int name, int ns_uri, 142 | const char **attrs); 143 | 144 | void size_state_end_fun(metalink_pstm_t *stm, int name, int ns_uri, 145 | const char *characters); 146 | 147 | /* version state */ 148 | void version_state_start_fun(metalink_pstm_t *stm, int name, int ns_uri, 149 | const char **attrs); 150 | 151 | void version_state_end_fun(metalink_pstm_t *stm, int name, int ns_uri, 152 | const char *characters); 153 | 154 | /* language state */ 155 | void language_state_start_fun(metalink_pstm_t *stm, int name, int ns_uri, 156 | const char **attrs); 157 | 158 | void language_state_end_fun(metalink_pstm_t *stm, int name, int ns_uri, 159 | const char *characters); 160 | 161 | /* os state */ 162 | void os_state_start_fun(metalink_pstm_t *stm, int name, int ns_uri, 163 | const char **attrs); 164 | 165 | void os_state_end_fun(metalink_pstm_t *stm, int name, int ns_uri, 166 | const char *characters); 167 | 168 | /* url state */ 169 | void url_state_start_fun(metalink_pstm_t *stm, int name, int ns_uri, 170 | const char **attrs); 171 | 172 | void url_state_end_fun(metalink_pstm_t *stm, int name, int ns_uri, 173 | const char *characters); 174 | 175 | /* hash state */ 176 | void hash_state_start_fun(metalink_pstm_t *stm, int name, int ns_uri, 177 | const char **attrs); 178 | 179 | void hash_state_end_fun(metalink_pstm_t *stm, int name, int ns_uri, 180 | const char *characters); 181 | 182 | /* piece hash state inside of */ 183 | void piece_hash_state_start_fun(metalink_pstm_t *stm, int name, int ns_uri, 184 | const char **attrs); 185 | 186 | void piece_hash_state_end_fun(metalink_pstm_t *stm, int name, int ns_uri, 187 | const char *characters); 188 | 189 | /* fin state */ 190 | void fin_state_start_fun(metalink_pstm_t *stm, int name, int ns_uri, 191 | const char **attrs); 192 | 193 | void fin_state_end_fun(metalink_pstm_t *stm, int name, int ns_uri, 194 | const char *characters); 195 | 196 | #endif /* _D_METALINK_PARSER_STATE_H_ */ 197 | -------------------------------------------------------------------------------- /lib/libexpat_metalink_parser.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include 27 | 28 | #include "metalink_config.h" 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | #include "metalink_pstm.h" 38 | #include "metalink_pstate.h" 39 | #include "metalink_parser_common.h" 40 | #include "metalink_session_data.h" 41 | #include "metalink_stack.h" 42 | #include "metalink_string_buffer.h" 43 | #include "metalink_helper.h" 44 | 45 | #define NAMESPACE_SEPARATOR '\t' 46 | 47 | static int split_ns_name(const char **localname, const char *src) { 48 | const char *sep; 49 | 50 | sep = strchr(src, NAMESPACE_SEPARATOR); 51 | if (!sep) { 52 | *localname = src; 53 | return METALINK_NS_NONE; 54 | } 55 | 56 | *localname = sep + 1; 57 | return metalink_match_ns(src, sep - src); 58 | } 59 | 60 | static void start_element_handler(void *user_data, const char *name, 61 | const char **attrs) { 62 | const char *localname = NULL; 63 | const char *mattrs[METALINK_ATTR_TOKEN_MAX]; 64 | const char **p; 65 | 66 | metalink_session_data_t *session_data = (metalink_session_data_t *)user_data; 67 | 68 | session_data->ns_uri = split_ns_name(&localname, name); 69 | session_data->name = metalink_lookup_token(localname, strlen(localname)); 70 | 71 | memset(mattrs, 0, sizeof(mattrs)); 72 | 73 | for (p = attrs; *p; p += 2) { 74 | int key = metalink_lookup_attr_token(*p, strlen(*p)); 75 | if (key == -1) { 76 | continue; 77 | } 78 | mattrs[key] = *(p + 1); 79 | } 80 | 81 | session_data->stm->state->start_fun(session_data->stm, session_data->name, 82 | session_data->ns_uri, mattrs); 83 | 84 | if (metalink_pstm_character_buffering_enabled(session_data->stm)) { 85 | metalink_string_buffer_t *str_buf = metalink_string_buffer_new(128); 86 | /* TODO evaluate return value of stack_push; non-zero value is error. */ 87 | metalink_stack_push(session_data->characters_stack, str_buf); 88 | } 89 | } 90 | 91 | static void end_element_handler(void *user_data, const char *name) { 92 | metalink_session_data_t *session_data = (metalink_session_data_t *)user_data; 93 | metalink_string_buffer_t *str_buf = NULL; 94 | 95 | (void)name; 96 | 97 | if (metalink_pstm_character_buffering_enabled(session_data->stm)) { 98 | str_buf = metalink_stack_pop(session_data->characters_stack); 99 | } 100 | 101 | session_data->stm->state->end_fun( 102 | session_data->stm, session_data->name, session_data->ns_uri, 103 | str_buf ? metalink_string_buffer_str(str_buf) : ""); 104 | 105 | metalink_string_buffer_delete(str_buf); 106 | } 107 | 108 | static void characters_handler(void *user_data, const char *chars, int length) { 109 | metalink_session_data_t *session_data = (metalink_session_data_t *)user_data; 110 | metalink_string_buffer_t *str_buf; 111 | 112 | if (!metalink_pstm_character_buffering_enabled(session_data->stm)) { 113 | return; 114 | } 115 | 116 | str_buf = metalink_stack_top(session_data->characters_stack); 117 | 118 | metalink_string_buffer_append(str_buf, (const char *)chars, length); 119 | } 120 | 121 | static XML_Parser setup_parser(metalink_session_data_t *session_data) { 122 | XML_Parser parser; 123 | 124 | parser = XML_ParserCreateNS(NULL, NAMESPACE_SEPARATOR); 125 | 126 | XML_SetUserData(parser, session_data); 127 | XML_SetElementHandler(parser, &start_element_handler, &end_element_handler); 128 | XML_SetCharacterDataHandler(parser, &characters_handler); 129 | 130 | return parser; 131 | } 132 | 133 | metalink_error_t METALINK_PUBLIC 134 | metalink_parse_file(const char *filename, metalink_t **res) { 135 | metalink_error_t r; 136 | FILE *docfp = fopen(filename, "rb"); 137 | if (docfp == NULL) 138 | return METALINK_ERR_CANNOT_OPEN_FILE; 139 | r = metalink_parse_fp(docfp, res); 140 | fclose(docfp); 141 | return r; 142 | } 143 | 144 | metalink_error_t METALINK_PUBLIC 145 | metalink_parse_fp(FILE *docfp, metalink_t **res) { 146 | metalink_session_data_t *session_data; 147 | metalink_error_t r = 0, retval; 148 | XML_Parser parser; 149 | 150 | session_data = metalink_session_data_new(); 151 | 152 | parser = setup_parser(session_data); 153 | 154 | while (!feof(docfp)) { 155 | size_t num_read; 156 | void *buff = XML_GetBuffer(parser, BUFSIZ); 157 | if (buff == NULL) { 158 | r = METALINK_ERR_PARSER_ERROR; 159 | break; 160 | } 161 | num_read = fread(buff, 1, BUFSIZ, docfp); 162 | if (num_read == 0) { 163 | if (feof(docfp)) { 164 | break; 165 | } else if (ferror(docfp)) { 166 | r = METALINK_ERR_PARSER_ERROR; 167 | break; 168 | } else { 169 | assert(0); 170 | } 171 | } 172 | if (!XML_ParseBuffer(parser, (int)num_read, 0)) { 173 | r = METALINK_ERR_PARSER_ERROR; 174 | break; 175 | } 176 | } 177 | XML_ParserFree(parser); 178 | 179 | retval = metalink_handle_parse_result(res, session_data, r); 180 | 181 | metalink_session_data_delete(session_data); 182 | 183 | return retval; 184 | } 185 | 186 | metalink_error_t METALINK_PUBLIC metalink_parse_fd(int fd, metalink_t **res) { 187 | metalink_session_data_t *session_data; 188 | metalink_error_t r = 0; 189 | metalink_error_t retval; 190 | XML_Parser parser; 191 | 192 | session_data = metalink_session_data_new(); 193 | 194 | parser = setup_parser(session_data); 195 | 196 | while (1) { 197 | ssize_t num_read; 198 | void *buff = XML_GetBuffer(parser, BUFSIZ); 199 | if (buff == NULL) { 200 | r = METALINK_ERR_PARSER_ERROR; 201 | break; 202 | } 203 | while ((num_read = read(fd, buff, BUFSIZ)) == -1 && errno == EINTR) 204 | ; 205 | if (num_read == -1) { 206 | r = METALINK_ERR_PARSER_ERROR; 207 | break; 208 | } else if (num_read == 0) { 209 | break; 210 | } 211 | if (!XML_ParseBuffer(parser, (int)num_read, 0)) { 212 | r = METALINK_ERR_PARSER_ERROR; 213 | break; 214 | } 215 | } 216 | XML_ParserFree(parser); 217 | 218 | retval = metalink_handle_parse_result(res, session_data, r); 219 | 220 | metalink_session_data_delete(session_data); 221 | 222 | return retval; 223 | } 224 | 225 | metalink_error_t METALINK_PUBLIC 226 | metalink_parse_memory(const char *buf, size_t len, metalink_t **res) { 227 | metalink_session_data_t *session_data; 228 | metalink_error_t r = 0, retval; 229 | XML_Parser parser; 230 | 231 | session_data = metalink_session_data_new(); 232 | 233 | parser = setup_parser(session_data); 234 | 235 | if (!XML_Parse(parser, buf, (int)len, 1)) { 236 | r = METALINK_ERR_PARSER_ERROR; 237 | } 238 | 239 | XML_ParserFree(parser); 240 | 241 | retval = metalink_handle_parse_result(res, session_data, r); 242 | 243 | metalink_session_data_delete(session_data); 244 | 245 | return retval; 246 | } 247 | 248 | struct _metalink_parser_context { 249 | metalink_session_data_t *session_data; 250 | XML_Parser parser; 251 | metalink_t *res; 252 | }; 253 | 254 | metalink_parser_context_t METALINK_PUBLIC *metalink_parser_context_new(void) { 255 | metalink_parser_context_t *ctx; 256 | ctx = malloc(sizeof(metalink_parser_context_t)); 257 | if (ctx == NULL) { 258 | return NULL; 259 | } 260 | memset(ctx, 0, sizeof(metalink_parser_context_t)); 261 | 262 | ctx->session_data = metalink_session_data_new(); 263 | if (ctx->session_data == NULL) { 264 | metalink_parser_context_delete(ctx); 265 | return NULL; 266 | } 267 | 268 | ctx->parser = setup_parser(ctx->session_data); 269 | if (ctx->parser == NULL) { 270 | metalink_parser_context_delete(ctx); 271 | return NULL; 272 | } 273 | return ctx; 274 | } 275 | 276 | void METALINK_PUBLIC 277 | metalink_parser_context_delete(metalink_parser_context_t *ctx) { 278 | if (ctx == NULL) { 279 | return; 280 | } 281 | metalink_session_data_delete(ctx->session_data); 282 | XML_ParserFree(ctx->parser); 283 | free(ctx); 284 | } 285 | 286 | metalink_error_t METALINK_PUBLIC 287 | metalink_parse_update(metalink_parser_context_t *ctx, const char *buf, 288 | size_t len) { 289 | metalink_error_t r = 0; 290 | 291 | if (!XML_Parse(ctx->parser, buf, (int)len, 0)) { 292 | r = METALINK_ERR_PARSER_ERROR; 293 | } 294 | 295 | if (r == 0) { 296 | r = metalink_pctrl_get_error(ctx->session_data->stm->ctrl); 297 | } 298 | return r; 299 | } 300 | 301 | metalink_error_t METALINK_PUBLIC 302 | metalink_parse_final(metalink_parser_context_t *ctx, const char *buf, 303 | size_t len, metalink_t **res) { 304 | metalink_error_t r = 0, retval; 305 | 306 | if (!XML_Parse(ctx->parser, buf, (int)len, 1)) { 307 | r = METALINK_ERR_PARSER_ERROR; 308 | } 309 | 310 | retval = metalink_handle_parse_result(res, ctx->session_data, r); 311 | 312 | metalink_parser_context_delete(ctx); 313 | 314 | return retval; 315 | } 316 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # libmetalink 2 | # 3 | # Copyright (c) 2012 Tatsuhiro Tsujikawa 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | AC_PREREQ(2.61) 23 | AC_INIT([libmetalink], [0.1.3], [t-tujikawa@users.sourceforge.net]) 24 | 25 | LT_PREREQ([2.2.6]) 26 | LT_INIT() 27 | 28 | dnl See versioning rule: 29 | dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html 30 | AC_SUBST(LT_CURRENT, 4) 31 | AC_SUBST(LT_REVISION, 0) 32 | AC_SUBST(LT_AGE, 1) 33 | 34 | AC_CANONICAL_BUILD 35 | AC_CANONICAL_HOST 36 | AC_CANONICAL_TARGET 37 | 38 | AM_INIT_AUTOMAKE() 39 | 40 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 41 | 42 | AC_CONFIG_MACRO_DIR([m4]) 43 | 44 | # Special host-dependent stuff 45 | case ${host} in 46 | *android*|*mingw*) 47 | ac_cv_func_malloc_0_nonnull=yes 48 | ac_cv_func_realloc_0_nonnull=yes 49 | ;; 50 | *-*solaris*) 51 | ADDCFLAGS="-std=gnu99 -D_XOPEN_SOURCE=600" 52 | ;; 53 | *) 54 | ;; 55 | esac 56 | 57 | # Checks for arguments. 58 | AC_ARG_WITH([libexpat], [ --with-libexpat use libexpat library if installed. Default: yes], [with_libexpat=$withval], [with_libexpat=yes]) 59 | AC_ARG_WITH([libxml2], [ --with-libxml2 use libxml2 library if installed. Default: yes], [with_libxml2=$withval], [with_libxml2=yes]) 60 | 61 | AC_ARG_ENABLE([werror], 62 | [AS_HELP_STRING([--enable-werror], 63 | [Turn on strict compile time warnings])], 64 | [werror=$enableval], [werror=no]) 65 | 66 | AC_ARG_ENABLE([gcc-visibility], 67 | [AS_HELP_STRING([--enable-gcc-visibility], 68 | [Use gcc visibility attribute. This option may be removed in the future release.])], 69 | [gcc_visibility=$enableval], [gcc_visibility=no]) 70 | 71 | # Checks for programs 72 | AC_PROG_CC 73 | AC_PROG_INSTALL 74 | 75 | # Package version 76 | AC_SUBST([MAJOR_VERSION], 77 | [[`echo $PACKAGE_VERSION | sed 's/\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*.*/\1/'`]]) 78 | AC_SUBST([MINOR_VERSION], 79 | [[`echo $PACKAGE_VERSION | sed 's/[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*.*/\1/'`]]) 80 | AC_SUBST([PATCH_VERSION], 81 | [[`echo $PACKAGE_VERSION | sed 's/[0-9][0-9]*\.[0-9][0-9]*\.\([0-9][0-9]*\).*/\1/'`]]) 82 | AC_SUBST([NUMBER_VERSION], `printf "0x%02x%02x%02x" $MAJOR_VERSION $MINOR_VERSION $PATCH_VERSION`) 83 | 84 | # Checks for libraries. 85 | 86 | if test "x$with_libexpat" = "xyes"; then 87 | PKG_CHECK_MODULES([EXPAT], [expat >= 2.1.0], [have_libexpat=yes], [have_libexpat=no]) 88 | if test "x$have_libexpat" != "xyes"; then 89 | AC_MSG_WARN([$EXPAT_PKG_ERRORS]) 90 | AM_PATH_LIBEXPAT 91 | fi 92 | fi 93 | 94 | if test "x$with_libxml2" = "xyes" && test "x$have_libexpat" != "xyes"; then 95 | AM_PATH_XML2([2.6.24], [have_libxml2=yes]) 96 | if test "x$have_libxml2" = "xyes"; then 97 | AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have libxml2.]) 98 | fi 99 | fi 100 | 101 | if test "x$have_libexpat" != "xyes" && test "x$have_libxml2" != "xyes"; then 102 | AC_MSG_FAILURE([Neither expat nor libxml2 found. Please install one of \ 103 | them and run configure again.]) 104 | fi 105 | 106 | # cunit 107 | PKG_CHECK_MODULES([CUNIT], [cunit >= 2.1], [have_cunit=yes], [have_cunit=no]) 108 | # If pkg-config does not find cunit, check it using AC_CHECK_LIB. We 109 | # do this because Debian (Ubuntu) lacks pkg-config file for cunit. 110 | if test "x${have_cunit}" = "xno"; then 111 | AC_MSG_WARN([${CUNIT_PKG_ERRORS}]) 112 | AC_CHECK_LIB([cunit], [CU_initialize_registry], 113 | [have_cunit=yes], [have_cunit=no]) 114 | if test "x${have_cunit}" = "xyes"; then 115 | CUNIT_LIBS="-lcunit" 116 | CUNIT_CFLAGS="" 117 | AC_SUBST([CUNIT_LIBS]) 118 | AC_SUBST([CUNIT_CFLAGS]) 119 | fi 120 | fi 121 | 122 | AM_CONDITIONAL([ENABLE_LIBEXPAT], [test "x$have_libexpat" = "xyes"]) 123 | AM_CONDITIONAL([ENABLE_LIBXML2], [test "x$have_libxml2" = "xyes"]) 124 | AM_CONDITIONAL([HAVE_CUNIT], [ test "x${have_cunit}" = "xyes" ]) 125 | 126 | # Checks for header files. 127 | AC_HEADER_STDC 128 | AC_CHECK_HEADERS([limits.h stdlib.h string.h time64.h alloca.h]) 129 | 130 | AC_CHECK_HEADER([inttypes.h], [have_inttypes_h=yes], [have_inttypes_h=no]) 131 | 132 | if test "x$have_inttypes_h" = "xyes"; then 133 | AC_DEFINE([HAVE_INTTYPES_H], [1], 134 | [Define to 1 if you have header file.]) 135 | CPPFLAGS="-DHAVE_INTTYPES_H ${CPPFLAGS}" 136 | fi 137 | 138 | # Checks for typedefs, structures, and compiler characteristics. 139 | AC_C_CONST 140 | AC_TYPE_SIZE_T 141 | 142 | # Checks for library functions. 143 | AC_FUNC_MALLOC 144 | 145 | # _mkgmtime is available in Windows, behaves like timegm. 146 | # _mkgmtime is for mingw. mkgmtime is for NetWare. 147 | # Newer Android NDKs have timegm64 in the time64.h header. 148 | AC_CHECK_FUNCS([memset strtol strtoll timegm64 _mkgmtime mkgmtime]) 149 | AC_CHECK_FUNC([timegm], [have_timegm=yes], [have_timegm=no]) 150 | 151 | if test "x$have_timegm" = "xyes"; then 152 | AC_DEFINE([HAVE_TIMEGM], [1], 153 | [Define to 1 if you have timegm function.]) 154 | fi 155 | AM_CONDITIONAL([HAVE_TIMEGM], [ test "x$have_timegm" = "xyes" ]) 156 | 157 | 158 | AC_CHECK_FUNC([strptime], [have_strptime=yes], [have_strptime=no]) 159 | 160 | if test "x$have_strptime" = "xyes"; then 161 | AC_DEFINE([HAVE_STRPTIME], [1], 162 | [Define to 1 if you have strptime function.]) 163 | fi 164 | AM_CONDITIONAL([HAVE_STRPTIME], [ test "x$have_strptime" = "xyes" ]) 165 | 166 | ac_save_CFLAGS=$CFLAGS 167 | CFLAGS= 168 | 169 | if test "x$werror" != "xno"; then 170 | AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"]) 171 | AX_CHECK_COMPILE_FLAG([-Wextra], [CFLAGS="$CFLAGS -Wextra"]) 172 | AX_CHECK_COMPILE_FLAG([-Werror], [CFLAGS="$CFLAGS -Werror"]) 173 | AX_CHECK_COMPILE_FLAG([-Wmissing-prototypes], [CFLAGS="$CFLAGS -Wmissing-prototypes"]) 174 | AX_CHECK_COMPILE_FLAG([-Wstrict-prototypes], [CFLAGS="$CFLAGS -Wstrict-prototypes"]) 175 | AX_CHECK_COMPILE_FLAG([-Wmissing-declarations], [CFLAGS="$CFLAGS -Wmissing-declarations"]) 176 | AX_CHECK_COMPILE_FLAG([-Wpointer-arith], [CFLAGS="$CFLAGS -Wpointer-arith"]) 177 | AX_CHECK_COMPILE_FLAG([-Wdeclaration-after-statement], [CFLAGS="$CFLAGS -Wdeclaration-after-statement"]) 178 | AX_CHECK_COMPILE_FLAG([-Wformat-security], [CFLAGS="$CFLAGS -Wformat-security"]) 179 | AX_CHECK_COMPILE_FLAG([-Wwrite-strings], [CFLAGS="$CFLAGS -Wwrite-strings"]) 180 | AX_CHECK_COMPILE_FLAG([-Wshadow], [CFLAGS="$CFLAGS -Wshadow"]) 181 | AX_CHECK_COMPILE_FLAG([-Winline], [CFLAGS="$CFLAGS -Winline"]) 182 | AX_CHECK_COMPILE_FLAG([-Wnested-externs], [CFLAGS="$CFLAGS -Wnested-externs"]) 183 | AX_CHECK_COMPILE_FLAG([-Wfloat-equal], [CFLAGS="$CFLAGS -Wfloat-equal"]) 184 | AX_CHECK_COMPILE_FLAG([-Wundef], [CFLAGS="$CFLAGS -Wundef"]) 185 | AX_CHECK_COMPILE_FLAG([-Wendif-labels], [CFLAGS="$CFLAGS -Wendif-labels"]) 186 | AX_CHECK_COMPILE_FLAG([-Wempty-body], [CFLAGS="$CFLAGS -Wempty-body"]) 187 | AX_CHECK_COMPILE_FLAG([-Wcast-align], [CFLAGS="$CFLAGS -Wcast-align"]) 188 | AX_CHECK_COMPILE_FLAG([-Wclobbered], [CFLAGS="$CFLAGS -Wclobbered"]) 189 | AX_CHECK_COMPILE_FLAG([-Wvla], [CFLAGS="$CFLAGS -Wvla"]) 190 | AX_CHECK_COMPILE_FLAG([-Wpragmas], [CFLAGS="$CFLAGS -Wpragmas"]) 191 | AX_CHECK_COMPILE_FLAG([-Wunreachable-code], [CFLAGS="$CFLAGS -Wunreachable-code"]) 192 | AX_CHECK_COMPILE_FLAG([-Waddress], [CFLAGS="$CFLAGS -Waddress"]) 193 | AX_CHECK_COMPILE_FLAG([-Wattributes], [CFLAGS="$CFLAGS -Wattributes"]) 194 | AX_CHECK_COMPILE_FLAG([-Wdiv-by-zero], [CFLAGS="$CFLAGS -Wdiv-by-zero"]) 195 | AX_CHECK_COMPILE_FLAG([-Wshorten-64-to-32], [CFLAGS="$CFLAGS -Wshorten-64-to-32"]) 196 | 197 | # Only work with Clang for the moment 198 | AX_CHECK_COMPILE_FLAG([-Wheader-guard], [CFLAGS="$CFLAGS -Wheader-guard"]) 199 | fi 200 | 201 | WARNCFLAGS=$CFLAGS 202 | CFLAGS=$ac_save_CFLAGS 203 | 204 | AC_SUBST([WARNCFLAGS]) 205 | 206 | if test "x$gcc_visibility" != "xno"; then 207 | ADDCFLAGS="-fvisibility=hidden $ADDCFLAGS" 208 | AC_DEFINE([GCC_VISIBILITY], [1], [Define to 1 if you use gcc visibility attribute.]) 209 | fi 210 | 211 | AC_CONFIG_HEADERS([config.h]) 212 | AC_CONFIG_FILES([ 213 | Makefile 214 | lib/Makefile 215 | lib/libmetalink.pc 216 | lib/includes/metalink/metalinkver.h 217 | lib/includes/Makefile 218 | test/Makefile 219 | doc/Makefile 220 | doc/examples/Makefile 221 | doc/man3/Makefile 222 | m4/Makefile 223 | ]) 224 | AC_OUTPUT 225 | 226 | AC_MSG_NOTICE([summary of build options: 227 | 228 | Version: ${VERSION} (${MAJOR_VERSION}:${MINOR_VERSION}:${PATCH_VERSION}), shared $LT_CURRENT:$LT_REVISION:$LT_AGE 229 | Host type: ${host} 230 | Install prefix: ${prefix} 231 | C compiler: ${CC} 232 | CFLAGS: ${CFLAGS} 233 | ADDCFLAGS: ${ADDCFLAGS} 234 | WARNCFLAGS: ${WARNCFLAGS} 235 | LDFLAGS: ${LDFLAGS} 236 | LIBS: ${LIBS} 237 | CPPFLAGS: ${CPPFLAGS} 238 | C preprocessor: ${CPP} 239 | Library types: Shared=${enable_shared}, Static=${enable_static} 240 | Libexpat: ${have_libexpat} ${EXPAT_CFLAGS} ${EXPAT_LIBS} 241 | Libxml2: ${have_libxml2} ${XML_CPPFLAGS} ${XML_LIBS} 242 | CUnit: ${have_cunit} ${CUNIT_CFLAGS} ${CUNIT_LIBS} 243 | ]) 244 | -------------------------------------------------------------------------------- /test/metalink_pctrl_test.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include "metalink_pctrl_test.h" 27 | 28 | #include 29 | 30 | #include 31 | #include "metalink_pctrl.h" 32 | 33 | void test_metalink_pctrl_file_transaction(void) { 34 | metalink_pctrl_t *ctrl; 35 | metalink_file_t *file; 36 | 37 | ctrl = new_metalink_pctrl(); 38 | CU_ASSERT_PTR_NOT_NULL(ctrl); 39 | 40 | /* start new file transaction */ 41 | file = metalink_pctrl_new_file_transaction(ctrl); 42 | CU_ASSERT_PTR_NOT_NULL(file); 43 | 44 | /* Set values to file. */ 45 | CU_ASSERT_EQUAL(0, metalink_pctrl_file_set_name(ctrl, "libmetalink.tar.bz2")); 46 | metalink_pctrl_file_set_size(ctrl, 4294967296LL); 47 | CU_ASSERT_EQUAL(0, metalink_pctrl_file_set_version(ctrl, "1.0.0")); 48 | CU_ASSERT_EQUAL(0, metalink_pctrl_file_set_language(ctrl, "en_US")); 49 | CU_ASSERT_EQUAL(0, metalink_pctrl_file_set_os(ctrl, "linux")); 50 | metalink_pctrl_file_set_maxconnections(ctrl, 5); 51 | 52 | /* Commit */ 53 | CU_ASSERT_EQUAL(0, metalink_pctrl_commit_file_transaction(ctrl)); 54 | file = NULL; 55 | 56 | CU_ASSERT_PTR_NULL(ctrl->temp_file); 57 | CU_ASSERT_EQUAL(1, metalink_list_length(ctrl->files)); 58 | 59 | file = metalink_list_get_data(ctrl->files, 0); 60 | CU_ASSERT_STRING_EQUAL("libmetalink.tar.bz2", file->name); 61 | CU_ASSERT_EQUAL(4294967296LL, file->size); 62 | CU_ASSERT_STRING_EQUAL("1.0.0", file->version); 63 | CU_ASSERT_STRING_EQUAL("en_US", file->language); 64 | CU_ASSERT_STRING_EQUAL("linux", file->os); 65 | CU_ASSERT_EQUAL(5, file->maxconnections); 66 | 67 | delete_metalink_pctrl(ctrl); 68 | } 69 | 70 | void test_metalink_pctrl_resource_transaction(void) { 71 | metalink_pctrl_t *ctrl; 72 | metalink_resource_t *resource; 73 | 74 | ctrl = new_metalink_pctrl(); 75 | CU_ASSERT_PTR_NOT_NULL(ctrl); 76 | 77 | /* start new resource transaction */ 78 | resource = metalink_pctrl_new_resource_transaction(ctrl); 79 | CU_ASSERT_PTR_NOT_NULL(resource); 80 | 81 | /* Set several values to resource object. 82 | * These values are stored in ctrl->temp_resource, which is the return value 83 | * of metalink_pctrl_new_resource_transaction(), thus resource. 84 | */ 85 | metalink_pctrl_resource_set_type(ctrl, "http"); 86 | metalink_pctrl_resource_set_location(ctrl, "FI"); 87 | metalink_pctrl_resource_set_priority(ctrl, 100); 88 | metalink_pctrl_resource_set_maxconnections(ctrl, 4); 89 | metalink_pctrl_resource_set_url(ctrl, "http://host/dir/file"); 90 | 91 | /* Commit appends ctrl->temp_resource to ctrl->resources. */ 92 | metalink_pctrl_commit_resource_transaction(ctrl); 93 | /* at this point, resource is undefined. So set it to NULL */ 94 | resource = NULL; 95 | 96 | CU_ASSERT_PTR_NULL(ctrl->temp_resource); 97 | CU_ASSERT_EQUAL(1, metalink_list_length(ctrl->resources)); 98 | 99 | resource = metalink_list_get_data(ctrl->resources, 0); 100 | CU_ASSERT_STRING_EQUAL("http", resource->type); 101 | CU_ASSERT_STRING_EQUAL("FI", resource->location); 102 | CU_ASSERT_EQUAL(100, resource->priority); 103 | CU_ASSERT_EQUAL(4, resource->maxconnections); 104 | CU_ASSERT_STRING_EQUAL("http://host/dir/file", resource->url); 105 | 106 | delete_metalink_pctrl(ctrl); 107 | } 108 | 109 | void test_metalink_pctrl_checksum_transaction(void) { 110 | metalink_pctrl_t *ctrl; 111 | metalink_checksum_t *checksum; 112 | 113 | ctrl = new_metalink_pctrl(); 114 | CU_ASSERT_PTR_NOT_NULL(ctrl); 115 | 116 | /* start new checksum transaction */ 117 | checksum = metalink_pctrl_new_checksum_transaction(ctrl); 118 | CU_ASSERT_PTR_NOT_NULL(checksum); 119 | 120 | /* Set type, hash to checksum */ 121 | CU_ASSERT_EQUAL(0, metalink_pctrl_checksum_set_type(ctrl, "sha1")); 122 | CU_ASSERT_EQUAL(0, metalink_pctrl_checksum_set_hash( 123 | ctrl, "234f3611ad77aaf1241a0dc8ac708007935844d5")); 124 | 125 | CU_ASSERT_STRING_EQUAL("sha1", checksum->type); 126 | CU_ASSERT_STRING_EQUAL("234f3611ad77aaf1241a0dc8ac708007935844d5", 127 | checksum->hash); 128 | 129 | /* Commit appends ctrl->temp_checksum to ctrl->checksums. */ 130 | CU_ASSERT_EQUAL(0, metalink_pctrl_commit_checksum_transaction(ctrl)); 131 | checksum = NULL; 132 | 133 | CU_ASSERT_PTR_NULL(ctrl->temp_checksum); 134 | CU_ASSERT_EQUAL(1, metalink_list_length(ctrl->checksums)); 135 | 136 | checksum = metalink_list_get_data(ctrl->checksums, 0); 137 | CU_ASSERT_STRING_EQUAL("sha1", checksum->type); 138 | CU_ASSERT_STRING_EQUAL("234f3611ad77aaf1241a0dc8ac708007935844d5", 139 | checksum->hash); 140 | 141 | /* Try to commit while transaction is not started */ 142 | CU_ASSERT_EQUAL(METALINK_ERR_NO_CHECKSUM_TRANSACTION, 143 | metalink_pctrl_commit_checksum_transaction(ctrl)); 144 | 145 | delete_metalink_pctrl(ctrl); 146 | } 147 | 148 | void test_metalink_pctrl_chunk_checksum_transaction(void) { 149 | metalink_pctrl_t *ctrl; 150 | metalink_chunk_checksum_t *chunk_checksum; 151 | metalink_file_t *file; 152 | 153 | ctrl = new_metalink_pctrl(); 154 | CU_ASSERT_PTR_NOT_NULL(ctrl); 155 | 156 | /* start new file transaction, chunk checksum transaction needs this */ 157 | file = metalink_pctrl_new_file_transaction(ctrl); 158 | CU_ASSERT_PTR_NOT_NULL(file); 159 | 160 | /* start new chunk checksum transaction */ 161 | chunk_checksum = metalink_pctrl_new_chunk_checksum_transaction(ctrl); 162 | CU_ASSERT_PTR_NOT_NULL(chunk_checksum); 163 | 164 | /* Set type and length */ 165 | CU_ASSERT_EQUAL(0, metalink_pctrl_chunk_checksum_set_type(ctrl, "sha1")); 166 | metalink_pctrl_chunk_checksum_set_length(ctrl, 65536); 167 | 168 | /* Commit */ 169 | CU_ASSERT_EQUAL(0, metalink_pctrl_commit_chunk_checksum_transaction(ctrl)); 170 | chunk_checksum = NULL; 171 | 172 | CU_ASSERT_PTR_NULL(ctrl->temp_chunk_checksum); 173 | CU_ASSERT_PTR_NOT_NULL(ctrl->temp_file->chunk_checksum); 174 | 175 | chunk_checksum = ctrl->temp_file->chunk_checksum; 176 | CU_ASSERT_STRING_EQUAL("sha1", chunk_checksum->type); 177 | CU_ASSERT_EQUAL(65536, chunk_checksum->length); 178 | 179 | /* Try to commit while transaction is not started */ 180 | CU_ASSERT_EQUAL(METALINK_ERR_NO_CHUNK_CHECKSUM_TRANSACTION, 181 | metalink_pctrl_commit_chunk_checksum_transaction(ctrl)); 182 | 183 | delete_metalink_pctrl(ctrl); 184 | } 185 | 186 | void test_metalink_pctrl_piece_hash_transaction(void) { 187 | metalink_pctrl_t *ctrl; 188 | metalink_piece_hash_t *piece_hash; 189 | 190 | ctrl = new_metalink_pctrl(); 191 | CU_ASSERT_PTR_NOT_NULL(ctrl); 192 | 193 | /* start new piece hash transaction */ 194 | piece_hash = metalink_pctrl_new_piece_hash_transaction(ctrl); 195 | CU_ASSERT_PTR_NOT_NULL(piece_hash); 196 | 197 | /* Set piece and hash */ 198 | metalink_pctrl_piece_hash_set_piece(ctrl, 100); 199 | CU_ASSERT_EQUAL(0, metalink_pctrl_piece_hash_set_hash( 200 | ctrl, "234f3611ad77aaf1241a0dc8ac708007935844d5")); 201 | 202 | /* Commit */ 203 | CU_ASSERT_EQUAL(0, metalink_pctrl_commit_piece_hash_transaction(ctrl)); 204 | piece_hash = NULL; 205 | 206 | CU_ASSERT_PTR_NULL(ctrl->temp_piece_hash); 207 | CU_ASSERT_EQUAL(1, metalink_list_length(ctrl->piece_hashes)); 208 | 209 | piece_hash = metalink_list_get_data(ctrl->piece_hashes, 0); 210 | CU_ASSERT_EQUAL(100, piece_hash->piece); 211 | CU_ASSERT_STRING_EQUAL("234f3611ad77aaf1241a0dc8ac708007935844d5", 212 | piece_hash->hash); 213 | 214 | /* Try to commit while transaction is not started */ 215 | CU_ASSERT_EQUAL(METALINK_ERR_NO_PIECE_HASH_TRANSACTION, 216 | metalink_pctrl_commit_piece_hash_transaction(ctrl)); 217 | 218 | delete_metalink_pctrl(ctrl); 219 | } 220 | 221 | void test_metalink_pctrl_signature_transaction(void) { 222 | metalink_pctrl_t *ctrl; 223 | metalink_signature_t *signature; 224 | metalink_file_t *file; 225 | 226 | ctrl = new_metalink_pctrl(); 227 | CU_ASSERT_PTR_NOT_NULL(ctrl); 228 | 229 | /* start new file transaction, signature transaction needs this */ 230 | file = metalink_pctrl_new_file_transaction(ctrl); 231 | CU_ASSERT_PTR_NOT_NULL(file); 232 | 233 | /* start new signature transaction */ 234 | signature = metalink_pctrl_new_signature_transaction(ctrl); 235 | CU_ASSERT_PTR_NOT_NULL(signature); 236 | 237 | /* Set mediatype and signature */ 238 | metalink_signature_set_mediatype(signature, "application/pgp-signature"); 239 | CU_ASSERT_EQUAL( 240 | 0, metalink_pctrl_signature_set_signature(ctrl, "THIS IS SIGNATURE")); 241 | 242 | /* Commit */ 243 | CU_ASSERT_EQUAL(0, metalink_pctrl_commit_signature_transaction(ctrl)); 244 | signature = NULL; 245 | 246 | CU_ASSERT_PTR_NULL(ctrl->temp_signature); 247 | CU_ASSERT_PTR_NOT_NULL(ctrl->temp_file->signature); 248 | 249 | signature = ctrl->temp_file->signature; 250 | CU_ASSERT_STRING_EQUAL("application/pgp-signature", signature->mediatype); 251 | CU_ASSERT_STRING_EQUAL("THIS IS SIGNATURE", signature->signature); 252 | 253 | /* Try to commit while transaction is not started */ 254 | CU_ASSERT_EQUAL(METALINK_ERR_NO_SIGNATURE_TRANSACTION, 255 | metalink_pctrl_commit_signature_transaction(ctrl)); 256 | 257 | delete_metalink_pctrl(ctrl); 258 | } 259 | -------------------------------------------------------------------------------- /lib/metalink_pstm.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include "metalink_pstm.h" 27 | 28 | #include 29 | 30 | metalink_pstm_t *new_metalink_pstm(void) { 31 | metalink_pstm_t *stm; 32 | 33 | stm = malloc(sizeof(metalink_pstm_t)); 34 | if (!stm) { 35 | return NULL; 36 | } 37 | stm->state = NULL; 38 | stm->ctrl = new_metalink_pctrl(); 39 | if (!stm->ctrl) { 40 | goto NEW_METALINK_PSTM_ERROR; 41 | } 42 | stm->state = new_metalink_pstate(); 43 | if (!stm->state) { 44 | goto NEW_METALINK_PSTM_ERROR; 45 | } 46 | 47 | metalink_pstm_set_fun(stm, &initial_state_start_fun, &initial_state_end_fun); 48 | 49 | return stm; 50 | 51 | NEW_METALINK_PSTM_ERROR: 52 | delete_metalink_pstm(stm); 53 | return NULL; 54 | } 55 | 56 | void delete_metalink_pstm(metalink_pstm_t *stm) { 57 | if (!stm) { 58 | return; 59 | } 60 | delete_metalink_pctrl(stm->ctrl); 61 | delete_metalink_pstate(stm->state); 62 | free(stm); 63 | } 64 | 65 | int metalink_pstm_character_buffering_enabled(const metalink_pstm_t *stm) { 66 | return stm->state->character_buffering; 67 | } 68 | 69 | void metalink_pstm_enable_character_buffering(metalink_pstm_t *stm) { 70 | stm->state->character_buffering = 1; 71 | } 72 | 73 | void metalink_pstm_disable_character_buffering(metalink_pstm_t *stm) { 74 | stm->state->character_buffering = 0; 75 | } 76 | 77 | void metalink_pstm_set_fun(metalink_pstm_t *stm, metalink_start_fun start_fun, 78 | metalink_end_fun end_fun) { 79 | stm->state->start_fun = start_fun; 80 | stm->state->end_fun = end_fun; 81 | } 82 | 83 | void metalink_pstm_enter_null_state(metalink_pstm_t *stm) { 84 | metalink_pstm_set_fun(stm, &null_state_start_fun, &null_state_end_fun); 85 | metalink_pstm_disable_character_buffering(stm); 86 | } 87 | 88 | void metalink_pstm_enter_metalink_state(metalink_pstm_t *stm) { 89 | metalink_pstm_set_fun(stm, &metalink_state_start_fun_v3, 90 | &metalink_state_end_fun_v3); 91 | metalink_pstm_disable_character_buffering(stm); 92 | } 93 | 94 | void metalink_pstm_enter_metalink_state_v4(metalink_pstm_t *stm) { 95 | metalink_pstm_set_fun(stm, &metalink_state_start_fun_v4, 96 | &metalink_state_end_fun_v4); 97 | metalink_pstm_disable_character_buffering(stm); 98 | } 99 | 100 | void metalink_pstm_enter_identity_state(metalink_pstm_t *stm) { 101 | metalink_pstm_set_fun(stm, &identity_state_start_fun_v3, 102 | &identity_state_end_fun_v3); 103 | metalink_pstm_enable_character_buffering(stm); 104 | } 105 | 106 | void metalink_pstm_enter_tags_state(metalink_pstm_t *stm) { 107 | metalink_pstm_set_fun(stm, &tags_state_start_fun_v3, &tags_state_end_fun_v3); 108 | metalink_pstm_enable_character_buffering(stm); 109 | } 110 | 111 | void metalink_pstm_enter_files_state(metalink_pstm_t *stm) { 112 | metalink_pstm_set_fun(stm, &files_state_start_fun_v3, 113 | &files_state_end_fun_v3); 114 | metalink_pstm_disable_character_buffering(stm); 115 | } 116 | 117 | void metalink_pstm_enter_file_state(metalink_pstm_t *stm) { 118 | metalink_pstm_set_fun(stm, &file_state_start_fun_v3, &file_state_end_fun_v3); 119 | metalink_pstm_disable_character_buffering(stm); 120 | } 121 | 122 | void metalink_pstm_enter_size_state(metalink_pstm_t *stm) { 123 | metalink_pstm_set_fun(stm, &size_state_start_fun, &size_state_end_fun); 124 | metalink_pstm_enable_character_buffering(stm); 125 | } 126 | 127 | void metalink_pstm_enter_version_state(metalink_pstm_t *stm) { 128 | metalink_pstm_set_fun(stm, &version_state_start_fun, &version_state_end_fun); 129 | metalink_pstm_enable_character_buffering(stm); 130 | } 131 | 132 | void metalink_pstm_enter_language_state(metalink_pstm_t *stm) { 133 | metalink_pstm_set_fun(stm, &language_state_start_fun, 134 | &language_state_end_fun); 135 | metalink_pstm_enable_character_buffering(stm); 136 | } 137 | 138 | void metalink_pstm_enter_os_state(metalink_pstm_t *stm) { 139 | metalink_pstm_set_fun(stm, &os_state_start_fun, &os_state_end_fun); 140 | metalink_pstm_enable_character_buffering(stm); 141 | } 142 | 143 | void metalink_pstm_enter_resources_state(metalink_pstm_t *stm) { 144 | metalink_pstm_set_fun(stm, &resources_state_start_fun_v3, 145 | &resources_state_end_fun_v3); 146 | metalink_pstm_disable_character_buffering(stm); 147 | } 148 | 149 | void metalink_pstm_enter_url_state(metalink_pstm_t *stm) { 150 | metalink_pstm_set_fun(stm, &url_state_start_fun, &url_state_end_fun); 151 | metalink_pstm_enable_character_buffering(stm); 152 | } 153 | 154 | void metalink_pstm_enter_verification_state(metalink_pstm_t *stm) { 155 | metalink_pstm_set_fun(stm, &verification_state_start_fun_v3, 156 | &verification_state_end_fun_v3); 157 | metalink_pstm_disable_character_buffering(stm); 158 | } 159 | 160 | void metalink_pstm_enter_hash_state(metalink_pstm_t *stm) { 161 | metalink_pstm_set_fun(stm, &hash_state_start_fun, &hash_state_end_fun); 162 | metalink_pstm_enable_character_buffering(stm); 163 | } 164 | 165 | void metalink_pstm_enter_pieces_state(metalink_pstm_t *stm) { 166 | metalink_pstm_set_fun(stm, &pieces_state_start_fun_v3, 167 | &pieces_state_end_fun_v3); 168 | metalink_pstm_disable_character_buffering(stm); 169 | } 170 | 171 | void metalink_pstm_enter_piece_hash_state(metalink_pstm_t *stm) { 172 | metalink_pstm_set_fun(stm, &piece_hash_state_start_fun, 173 | &piece_hash_state_end_fun); 174 | metalink_pstm_enable_character_buffering(stm); 175 | } 176 | 177 | void metalink_pstm_enter_fin_state(metalink_pstm_t *stm) { 178 | metalink_pstm_set_fun(stm, &fin_state_start_fun, &fin_state_end_fun); 179 | metalink_pstm_disable_character_buffering(stm); 180 | } 181 | 182 | void metalink_pstm_enter_skip_state(metalink_pstm_t *stm) { 183 | stm->state->before_skip_state_start_fun = stm->state->start_fun; 184 | stm->state->before_skip_state_end_fun = stm->state->end_fun; 185 | 186 | metalink_pstm_set_fun(stm, &skip_state_start_fun, &skip_state_end_fun); 187 | 188 | metalink_pstm_disable_character_buffering(stm); 189 | stm->state->skip_depth = 1; 190 | } 191 | 192 | void metalink_pstm_exit_skip_state(metalink_pstm_t *stm) { 193 | metalink_pstm_set_fun(stm, stm->state->before_skip_state_start_fun, 194 | stm->state->before_skip_state_end_fun); 195 | 196 | if (stm->state->before_skip_character_buffering) { 197 | metalink_pstm_enable_character_buffering(stm); 198 | } else { 199 | metalink_pstm_disable_character_buffering(stm); 200 | } 201 | } 202 | 203 | /* Metalink 4 states */ 204 | void metalink_pstm_enter_file_state_v4(metalink_pstm_t *stm) { 205 | metalink_pstm_set_fun(stm, &file_state_start_fun_v4, &file_state_end_fun_v4); 206 | metalink_pstm_disable_character_buffering(stm); 207 | } 208 | 209 | void metalink_pstm_enter_generator_state(metalink_pstm_t *stm) { 210 | metalink_pstm_set_fun(stm, &generator_state_start_fun_v4, 211 | &generator_state_end_fun_v4); 212 | metalink_pstm_enable_character_buffering(stm); 213 | } 214 | 215 | void metalink_pstm_enter_origin_state(metalink_pstm_t *stm) { 216 | metalink_pstm_set_fun(stm, &origin_state_start_fun_v4, 217 | &origin_state_end_fun_v4); 218 | metalink_pstm_enable_character_buffering(stm); 219 | } 220 | 221 | void metalink_pstm_enter_description_state_v4(metalink_pstm_t *stm) { 222 | metalink_pstm_set_fun(stm, &description_state_start_fun_v4, 223 | &description_state_end_fun_v4); 224 | metalink_pstm_enable_character_buffering(stm); 225 | } 226 | 227 | void metalink_pstm_enter_copyright_state_v4(metalink_pstm_t *stm) { 228 | metalink_pstm_set_fun(stm, ©right_state_start_fun_v4, 229 | ©right_state_end_fun_v4); 230 | metalink_pstm_enable_character_buffering(stm); 231 | } 232 | 233 | void metalink_pstm_enter_identity_state_v4(metalink_pstm_t *stm) { 234 | metalink_pstm_set_fun(stm, &identity_state_start_fun_v4, 235 | &identity_state_end_fun_v4); 236 | metalink_pstm_enable_character_buffering(stm); 237 | } 238 | 239 | void metalink_pstm_enter_logo_state_v4(metalink_pstm_t *stm) { 240 | metalink_pstm_set_fun(stm, &logo_state_start_fun_v4, &logo_state_end_fun_v4); 241 | metalink_pstm_enable_character_buffering(stm); 242 | } 243 | 244 | void metalink_pstm_enter_signature_state_v4(metalink_pstm_t *stm) { 245 | metalink_pstm_set_fun(stm, &signature_state_start_fun_v4, 246 | &signature_state_end_fun_v4); 247 | metalink_pstm_enable_character_buffering(stm); 248 | } 249 | 250 | void metalink_pstm_enter_pieces_state_v4(metalink_pstm_t *stm) { 251 | metalink_pstm_set_fun(stm, &pieces_state_start_fun_v4, 252 | &pieces_state_end_fun_v4); 253 | metalink_pstm_disable_character_buffering(stm); 254 | } 255 | 256 | void metalink_pstm_enter_metaurl_state_v4(metalink_pstm_t *stm) { 257 | metalink_pstm_set_fun(stm, &metaurl_state_start_fun_v4, 258 | &metaurl_state_end_fun_v4); 259 | metalink_pstm_enable_character_buffering(stm); 260 | } 261 | 262 | void metalink_pstm_enter_published_state_v4(metalink_pstm_t *stm) { 263 | metalink_pstm_set_fun(stm, &published_state_start_fun_v4, 264 | &published_state_end_fun_v4); 265 | metalink_pstm_enable_character_buffering(stm); 266 | } 267 | 268 | void metalink_pstm_enter_updated_state_v4(metalink_pstm_t *stm) { 269 | metalink_pstm_set_fun(stm, &updated_state_start_fun_v4, 270 | &updated_state_end_fun_v4); 271 | metalink_pstm_enable_character_buffering(stm); 272 | } 273 | -------------------------------------------------------------------------------- /lib/metalink_pctrl.h: -------------------------------------------------------------------------------- 1 | /* */ 26 | #ifndef _D_METALINK_PCTRL_H_ 27 | #define _D_METALINK_PCTRL_H_ 28 | 29 | #include "metalink_config.h" 30 | 31 | #include 32 | 33 | #include "metalink_list.h" 34 | 35 | typedef struct metalink_pctrl_t { 36 | metalink_error_t error; 37 | 38 | metalink_t *metalink; 39 | 40 | metalink_list_t /* */ *files; 41 | 42 | metalink_file_t *temp_file; 43 | 44 | metalink_list_t /* */ *languages; 45 | 46 | metalink_list_t /* */ *oses; 47 | 48 | metalink_list_t /* */ *resources; 49 | 50 | metalink_resource_t *temp_resource; 51 | 52 | metalink_list_t /* */ *metaurls; 53 | 54 | metalink_metaurl_t *temp_metaurl; 55 | 56 | metalink_list_t /* */ *checksums; 57 | 58 | metalink_checksum_t *temp_checksum; 59 | 60 | metalink_chunk_checksum_t *temp_chunk_checksum; 61 | 62 | metalink_list_t /* */ *piece_hashes; 63 | 64 | metalink_piece_hash_t *temp_piece_hash; 65 | 66 | metalink_signature_t *temp_signature; 67 | } metalink_pctrl_t; 68 | 69 | metalink_pctrl_t *new_metalink_pctrl(void); 70 | 71 | void delete_metalink_pctrl(metalink_pctrl_t *ctrl); 72 | 73 | /** 74 | * detach metalink member: return ctrl->metalink and set NULL to 75 | * ctrl->metalink. 76 | */ 77 | metalink_t *metalink_pctrl_detach_metalink(metalink_pctrl_t *ctrl); 78 | 79 | /* Set error code */ 80 | void metalink_pctrl_set_error(metalink_pctrl_t *ctrl, metalink_error_t error); 81 | 82 | metalink_error_t metalink_pctrl_get_error(metalink_pctrl_t *ctrl); 83 | 84 | /* metalink manipulation functions */ 85 | metalink_error_t 86 | metalink_pctrl_metalink_accumulate_files(metalink_pctrl_t *ctrl); 87 | 88 | /* transaction functions */ 89 | metalink_file_t *metalink_pctrl_new_file_transaction(metalink_pctrl_t *ctrl); 90 | 91 | metalink_error_t metalink_pctrl_commit_file_transaction(metalink_pctrl_t *ctrl); 92 | 93 | metalink_resource_t * 94 | metalink_pctrl_new_resource_transaction(metalink_pctrl_t *ctrl); 95 | 96 | metalink_error_t 97 | metalink_pctrl_commit_resource_transaction(metalink_pctrl_t *ctrl); 98 | 99 | metalink_metaurl_t * 100 | metalink_pctrl_new_metaurl_transaction(metalink_pctrl_t *ctrl); 101 | 102 | metalink_error_t 103 | metalink_pctrl_commit_metaurl_transaction(metalink_pctrl_t *ctrl); 104 | 105 | metalink_checksum_t * 106 | metalink_pctrl_new_checksum_transaction(metalink_pctrl_t *ctrl); 107 | 108 | metalink_error_t 109 | metalink_pctrl_commit_checksum_transaction(metalink_pctrl_t *ctrl); 110 | 111 | metalink_chunk_checksum_t * 112 | metalink_pctrl_new_chunk_checksum_transaction(metalink_pctrl_t *ctrl); 113 | 114 | metalink_error_t 115 | metalink_pctrl_commit_chunk_checksum_transaction(metalink_pctrl_t *ctrl); 116 | 117 | metalink_piece_hash_t * 118 | metalink_pctrl_new_piece_hash_transaction(metalink_pctrl_t *ctrl); 119 | 120 | metalink_error_t 121 | metalink_pctrl_commit_piece_hash_transaction(metalink_pctrl_t *ctrl); 122 | 123 | metalink_signature_t * 124 | metalink_pctrl_new_signature_transaction(metalink_pctrl_t *ctrl); 125 | 126 | metalink_error_t 127 | metalink_pctrl_commit_signature_transaction(metalink_pctrl_t *ctrl); 128 | 129 | /* metalink manipulation functions */ 130 | void metalink_pctrl_set_version(metalink_pctrl_t *ctrl, 131 | metalink_version_t version); 132 | metalink_error_t metalink_pctrl_add_language(metalink_pctrl_t *ctrl, 133 | const char *language); 134 | metalink_error_t metalink_pctrl_add_os(metalink_pctrl_t *ctrl, const char *os); 135 | metalink_error_t metalink_pctrl_set_identity(metalink_pctrl_t *ctrl, 136 | const char *identity); 137 | metalink_error_t metalink_pctrl_set_tags(metalink_pctrl_t *ctrl, 138 | const char *tags); 139 | 140 | /* file manipulation functions */ 141 | metalink_error_t metalink_pctrl_file_set_language(metalink_pctrl_t *ctrl, 142 | const char *language); 143 | 144 | metalink_error_t metalink_pctrl_file_set_os(metalink_pctrl_t *ctrl, 145 | const char *os); 146 | 147 | metalink_error_t metalink_pctrl_file_set_name(metalink_pctrl_t *ctrl, 148 | const char *name); 149 | 150 | metalink_error_t metalink_pctrl_file_set_description(metalink_pctrl_t *ctrl, 151 | const char *description); 152 | 153 | metalink_error_t metalink_pctrl_file_set_copyright(metalink_pctrl_t *ctrl, 154 | const char *copyright); 155 | 156 | metalink_error_t metalink_pctrl_file_set_identity(metalink_pctrl_t *ctrl, 157 | const char *identity); 158 | 159 | metalink_error_t metalink_pctrl_file_set_logo(metalink_pctrl_t *ctrl, 160 | const char *logo); 161 | 162 | metalink_error_t metalink_pctrl_file_set_publisher_name(metalink_pctrl_t *ctrl, 163 | const char *name); 164 | 165 | metalink_error_t metalink_pctrl_file_set_publisher_url(metalink_pctrl_t *ctrl, 166 | const char *url); 167 | 168 | void metalink_pctrl_file_set_size(metalink_pctrl_t *ctrl, long long int size); 169 | 170 | metalink_error_t metalink_pctrl_file_set_version(metalink_pctrl_t *ctrl, 171 | const char *version); 172 | 173 | void metalink_pctrl_file_set_maxconnections(metalink_pctrl_t *ctrl, 174 | int maxconnections); 175 | 176 | /* resource manipulation functions */ 177 | metalink_error_t metalink_pctrl_resource_set_type(metalink_pctrl_t *ctrl, 178 | const char *type); 179 | 180 | metalink_error_t metalink_pctrl_resource_set_location(metalink_pctrl_t *ctrl, 181 | const char *location); 182 | 183 | void metalink_pctrl_resource_set_preference(metalink_pctrl_t *ctrl, 184 | int preference); 185 | 186 | void metalink_pctrl_resource_set_priority(metalink_pctrl_t *ctrl, int priority); 187 | 188 | void metalink_pctrl_resource_set_maxconnections(metalink_pctrl_t *ctrl, 189 | int maxconnections); 190 | 191 | metalink_error_t metalink_pctrl_resource_set_url(metalink_pctrl_t *ctrl, 192 | const char *url); 193 | 194 | /* metaurl manipulation functions */ 195 | metalink_error_t metalink_pctrl_metaurl_set_mediatype(metalink_pctrl_t *ctrl, 196 | const char *mediatype); 197 | 198 | metalink_error_t metalink_pctrl_metaurl_set_name(metalink_pctrl_t *ctrl, 199 | const char *name); 200 | 201 | void metalink_pctrl_metaurl_set_priority(metalink_pctrl_t *ctrl, int priority); 202 | 203 | metalink_error_t metalink_pctrl_metaurl_set_url(metalink_pctrl_t *ctrl, 204 | const char *url); 205 | 206 | /* checksum manipulation functions */ 207 | metalink_error_t metalink_pctrl_checksum_set_type(metalink_pctrl_t *ctrl, 208 | const char *type); 209 | 210 | metalink_error_t metalink_pctrl_checksum_set_hash(metalink_pctrl_t *ctrl, 211 | const char *hash); 212 | 213 | /* piece hash manipulation functions */ 214 | void metalink_pctrl_piece_hash_set_piece(metalink_pctrl_t *ctrl, int piece); 215 | 216 | metalink_error_t metalink_pctrl_piece_hash_set_hash(metalink_pctrl_t *ctrl, 217 | const char *hash); 218 | 219 | /* chunk checksum manipulation functions */ 220 | metalink_error_t metalink_pctrl_chunk_checksum_set_type(metalink_pctrl_t *ctrl, 221 | const char *type); 222 | 223 | void metalink_pctrl_chunk_checksum_set_length(metalink_pctrl_t *ctrl, 224 | int length); 225 | 226 | /* signature manipulation functions */ 227 | metalink_error_t metalink_pctrl_signature_set_signature(metalink_pctrl_t *ctrl, 228 | const char *signature); 229 | 230 | /* Unlike other mutator functions, this function doesn't create copy of 231 | piece_hashes. So don't free piece_hashes manually after this call.*/ 232 | void metalink_pctrl_chunk_checksum_set_piece_hashes( 233 | metalink_pctrl_t *ctrl, metalink_piece_hash_t **piece_hashes); 234 | 235 | /* information functions */ 236 | metalink_error_t metalink_pctrl_set_generator(metalink_pctrl_t *ctrl, 237 | const char *generator); 238 | 239 | metalink_error_t metalink_pctrl_set_origin(metalink_pctrl_t *ctrl, 240 | const char *origin); 241 | 242 | /* Sets the dynamic attribute of the origin element as per Metalink 243 | version 4. If it is "true", origin_dynamic must be 1. Otherwise, it 244 | must be 0. For Metalink version 3, origin_dynamic must be 1 if the 245 | type attribute of metalink element is "dynamic". Otherwise, it must 246 | be 0. 247 | */ 248 | void metalink_pctrl_set_origin_dynamic(metalink_pctrl_t *ctrl, 249 | int origin_dynamic); 250 | 251 | void metalink_pctrl_set_published(metalink_pctrl_t *ctrl, time_t published); 252 | 253 | void metalink_pctrl_set_updated(metalink_pctrl_t *ctrl, time_t updated); 254 | 255 | #endif /* _D_METALINK_PCTRL_H_ */ 256 | -------------------------------------------------------------------------------- /test/metalink_parser_test.c: -------------------------------------------------------------------------------- 1 | /* */ 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "metalink_parser_test.h" 31 | #include "metalink/metalink_parser.h" 32 | 33 | size_t count_array(void **array) { 34 | size_t count = 0; 35 | while (*array) { 36 | ++count; 37 | ++array; 38 | } 39 | return count; 40 | } 41 | 42 | static void validate_result(metalink_t *metalink) { 43 | metalink_file_t *file; 44 | metalink_checksum_t *checksum; 45 | metalink_resource_t *resource; 46 | metalink_piece_hash_t *piece_hash; 47 | 48 | CU_ASSERT_STRING_EQUAL("libmetalink-0.0.1", metalink->identity); 49 | CU_ASSERT_STRING_EQUAL("metalink,xml", metalink->tags); 50 | CU_ASSERT_EQUAL(metalink->version, METALINK_VERSION_3); 51 | CU_ASSERT_STRING_EQUAL("http://example.org/foo.metalink", metalink->origin); 52 | CU_ASSERT(metalink->origin_dynamic); 53 | 54 | /* count files */ 55 | CU_ASSERT_EQUAL_FATAL(4, count_array((void **)metalink->files)); 56 | 57 | /* check 1st file */ 58 | file = metalink->files[0]; 59 | CU_ASSERT_STRING_EQUAL("libmetalink-0.0.1.tar.bz2", file->name); 60 | CU_ASSERT_EQUAL(0, file->size); /* no size specified */ 61 | CU_ASSERT_STRING_EQUAL("0.0.1", file->version); 62 | 63 | CU_ASSERT_EQUAL(1, count_array((void **)file->languages)); 64 | CU_ASSERT_STRING_EQUAL("en-US", file->languages[0]); 65 | 66 | CU_ASSERT_EQUAL(1, count_array((void **)file->oses)); 67 | CU_ASSERT_STRING_EQUAL("Linux-x86", file->oses[0]); 68 | CU_ASSERT_EQUAL(1, file->maxconnections); 69 | 70 | /* There is one checksum which has no type specified. Let's see it is 71 | excluded. */ 72 | CU_ASSERT_EQUAL_FATAL(2, count_array((void **)file->checksums)); 73 | 74 | checksum = file->checksums[0]; 75 | CU_ASSERT_STRING_EQUAL("sha1", checksum->type); 76 | CU_ASSERT_STRING_EQUAL("a96cf3f0266b91d87d5124cf94326422800b627d", 77 | checksum->hash); 78 | checksum = file->checksums[1]; 79 | CU_ASSERT_STRING_EQUAL("md5", checksum->type); 80 | CU_ASSERT_STRING_EQUAL("fc4d834e89c18c99b2615d902750948c", checksum->hash); 81 | 82 | CU_ASSERT_PTR_NULL(file->chunk_checksum); /* no chunk checksum */ 83 | 84 | CU_ASSERT_EQUAL_FATAL(2, count_array((void **)file->resources)); 85 | 86 | resource = file->resources[0]; 87 | CU_ASSERT_STRING_EQUAL("ftp://ftphost/libmetalink-0.0.1.tar.bz2", 88 | resource->url); 89 | CU_ASSERT_STRING_EQUAL("ftp", resource->type); 90 | CU_ASSERT_STRING_EQUAL("jp", resource->location); 91 | CU_ASSERT_EQUAL(100, resource->preference); 92 | CU_ASSERT_EQUAL(1, resource->maxconnections); 93 | 94 | resource = file->resources[1]; 95 | CU_ASSERT_STRING_EQUAL("http://httphost/libmetalink-0.0.1.tar.bz2", 96 | resource->url); 97 | CU_ASSERT_STRING_EQUAL("http", resource->type); 98 | CU_ASSERT_PTR_NULL(resource->location); /* no location */ 99 | CU_ASSERT_EQUAL(99, resource->preference); 100 | CU_ASSERT_EQUAL( 101 | 0, resource->maxconnections); /* bad maxconnections, fallback to 0 */ 102 | 103 | /* check 2nd file */ 104 | file = metalink->files[1]; 105 | CU_ASSERT_STRING_EQUAL("libmetalink-0.0.2a.tar.bz2", file->name); 106 | CU_ASSERT_EQUAL(4294967296LL, file->size); 107 | CU_ASSERT_EQUAL(0, 108 | file->maxconnections) /* bad maxconnections, fallback to 0 */ 109 | 110 | CU_ASSERT_PTR_NULL(file->checksums); /* no checksums */ 111 | 112 | CU_ASSERT_STRING_EQUAL("sha1", file->chunk_checksum->type); 113 | CU_ASSERT_EQUAL(262144, file->chunk_checksum->length); 114 | /* Check that the entry which doesn't have type attribute is skipped. */ 115 | CU_ASSERT_PTR_NOT_NULL_FATAL(file->chunk_checksum); 116 | CU_ASSERT_EQUAL(2, count_array((void **)file->chunk_checksum->piece_hashes)); 117 | 118 | piece_hash = file->chunk_checksum->piece_hashes[0]; 119 | CU_ASSERT_EQUAL(0, piece_hash->piece); 120 | CU_ASSERT_STRING_EQUAL("179463a88d79cbf0b1923991708aead914f26142", 121 | piece_hash->hash); 122 | 123 | piece_hash = file->chunk_checksum->piece_hashes[1]; 124 | CU_ASSERT_EQUAL(1, piece_hash->piece); 125 | CU_ASSERT_STRING_EQUAL("fecf8bc9a1647505fe16746f94e97a477597dbf3", 126 | piece_hash->hash); 127 | 128 | /* Check that entry which doesn't have type attribute is skipped. */ 129 | CU_ASSERT_EQUAL_FATAL(4, count_array((void **)file->resources)); 130 | 131 | resource = file->resources[0]; 132 | CU_ASSERT_STRING_EQUAL("ftp://ftphost/libmetalink-0.0.2a.tar.bz2", 133 | resource->url); 134 | 135 | resource = file->resources[1]; 136 | CU_ASSERT_STRING_EQUAL("http://mirror1/libmetalink-0.0.2a.tar.bz2", 137 | resource->url); 138 | 139 | resource = file->resources[2]; 140 | CU_ASSERT_STRING_EQUAL("http://mirror2/libmetalink-0.0.2a.tar.bz2.torrent", 141 | resource->url); 142 | CU_ASSERT_STRING_EQUAL("bittorrent", resource->type); 143 | 144 | resource = file->resources[3]; 145 | CU_ASSERT_STRING_EQUAL("http://httphost/libmetalink-0.0.2a.tar.bz2", 146 | resource->url); 147 | CU_ASSERT_STRING_EQUAL("http", resource->type); 148 | CU_ASSERT_EQUAL(0, resource->preference); /* no preference */ 149 | 150 | /* Check 3rd file */ 151 | file = metalink->files[2]; 152 | CU_ASSERT_STRING_EQUAL("NoVerificationHash", file->name); 153 | CU_ASSERT_EQUAL(0, file->size); /* bad size, fallback to 0 */ 154 | CU_ASSERT_PTR_NULL(file->checksums); 155 | CU_ASSERT_PTR_NULL(file->chunk_checksum); 156 | 157 | CU_ASSERT_EQUAL_FATAL(1, count_array((void **)file->resources)); 158 | resource = file->resources[0]; 159 | CU_ASSERT_STRING_EQUAL("ftp://host/file", resource->url); 160 | 161 | /* Check 4th file */ 162 | file = metalink->files[3]; 163 | CU_ASSERT_STRING_EQUAL("badpref", file->name); 164 | CU_ASSERT_EQUAL_FATAL(1, count_array((void **)file->resources)); 165 | resource = file->resources[0]; 166 | CU_ASSERT_STRING_EQUAL("http://badpreference/", resource->url); 167 | CU_ASSERT_STRING_EQUAL("http", resource->type); 168 | CU_ASSERT_EQUAL(0, resource->preference); /* bad preference, fallback to 0. */ 169 | 170 | metalink_delete(metalink); 171 | } 172 | 173 | static int openfile(const char *filepath, int flags) { 174 | int fd = open(filepath, flags); 175 | if (fd == -1) { 176 | CU_FAIL_FATAL("opening file failed"); 177 | } 178 | return fd; 179 | } 180 | 181 | void test_metalink_parse_file(void) { 182 | metalink_error_t r; 183 | metalink_t *metalink; 184 | 185 | r = metalink_parse_file(LIBMETALINK_TEST_DIR "test1.xml", &metalink); 186 | CU_ASSERT_EQUAL(0, r); 187 | 188 | validate_result(metalink); 189 | } 190 | 191 | void test_metalink_parse_fp(void) { 192 | metalink_error_t r; 193 | metalink_t *metalink; 194 | FILE *fp; 195 | 196 | fp = fopen(LIBMETALINK_TEST_DIR "test1.xml", "rb"); 197 | if (fp == NULL) { 198 | CU_FAIL_FATAL("cannot open test1.xml"); 199 | } 200 | r = metalink_parse_fp(fp, &metalink); 201 | CU_ASSERT_EQUAL(0, r); 202 | fclose(fp); 203 | 204 | validate_result(metalink); 205 | } 206 | 207 | void test_metalink_parse_fd(void) { 208 | metalink_error_t r; 209 | metalink_t *metalink; 210 | int fd; 211 | 212 | fd = openfile(LIBMETALINK_TEST_DIR "test1.xml", O_RDONLY); 213 | r = metalink_parse_fd(fd, &metalink); 214 | CU_ASSERT_EQUAL(0, r); 215 | close(fd); 216 | validate_result(metalink); 217 | } 218 | 219 | void test_metalink_parse_memory(void) { 220 | metalink_error_t r; 221 | metalink_t *metalink; 222 | int fd; 223 | 224 | fd = openfile(LIBMETALINK_TEST_DIR "test1.xml", O_RDONLY); 225 | while (1) { 226 | char buf[4096]; 227 | ssize_t nread; 228 | while ((nread = read(fd, buf, sizeof(buf))) == -1 && errno == EINTR) 229 | ; 230 | CU_ASSERT_FATAL(nread != -1); 231 | if (nread == 0) { 232 | break; 233 | } 234 | r = metalink_parse_memory(buf, nread, &metalink); 235 | CU_ASSERT_EQUAL(0, r); 236 | } 237 | close(fd); 238 | validate_result(metalink); 239 | } 240 | 241 | void test_metalink_parse_update(void) { 242 | metalink_error_t r; 243 | metalink_t *metalink; 244 | int fd; 245 | metalink_parser_context_t *ctx; 246 | 247 | ctx = metalink_parser_context_new(); 248 | CU_ASSERT_FATAL(NULL != ctx); 249 | 250 | fd = openfile(LIBMETALINK_TEST_DIR "test1.xml", O_RDONLY); 251 | while (1) { 252 | char buf[4096]; 253 | ssize_t nread; 254 | while ((nread = read(fd, buf, sizeof(buf))) == -1 && errno == EINTR) 255 | ; 256 | CU_ASSERT_FATAL(nread != -1); 257 | if (nread == 0) { 258 | break; 259 | } 260 | r = metalink_parse_update(ctx, buf, nread); 261 | CU_ASSERT_EQUAL_FATAL(r, 0); 262 | } 263 | r = metalink_parse_final(ctx, 0, 0, &metalink); 264 | CU_ASSERT_EQUAL(r, 0); 265 | close(fd); 266 | validate_result(metalink); 267 | } 268 | 269 | void test_metalink_parse_update_fail(void) { 270 | metalink_error_t r; 271 | metalink_t *metalink; 272 | int fd; 273 | metalink_parser_context_t *ctx; 274 | 275 | /* Initialize ctx */ 276 | ctx = metalink_parser_context_new(); 277 | CU_ASSERT_FATAL(NULL != ctx); 278 | 279 | /* feed bad formed data */ 280 | r = metalink_parse_update(ctx, "", 10); 281 | CU_ASSERT(0 != r); 282 | 283 | metalink_parser_context_delete(ctx); 284 | 285 | /* Initialize ctx */ 286 | ctx = metalink_parser_context_new(); 287 | CU_ASSERT_FATAL(NULL != ctx); 288 | 289 | fd = openfile(LIBMETALINK_TEST_DIR "test1.xml", O_RDONLY); 290 | 291 | while (1) { 292 | char buf[128]; 293 | ssize_t nread; 294 | while ((nread = read(fd, buf, sizeof(buf))) == -1 && errno == EINTR) 295 | ; 296 | CU_ASSERT_FATAL(nread != -1); 297 | /* See when prematured XML data is supplied */ 298 | r = metalink_parse_final(ctx, buf, nread, &metalink); 299 | CU_ASSERT(0 != r); 300 | break; 301 | } 302 | 303 | close(fd); 304 | } 305 | --------------------------------------------------------------------------------