diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2013-01-09 16:29:37 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2013-01-09 18:04:19 +0100 |
commit | 549146755c4a510dd3fd8db87724c3b573927d89 (patch) | |
tree | 90d6a74f84fcc0083a2f48978687fb5a1f296fcf | |
parent | 06c962631abee5d0fc59cdabf186f9cd003a461b (diff) | |
parent | b57de2196e111605812cc3aff4d6dcb53ec8965d (diff) | |
download | msitools-549146755c4a510dd3fd8db87724c3b573927d89.tar.gz msitools-549146755c4a510dd3fd8db87724c3b573927d89.tar.xz msitools-549146755c4a510dd3fd8db87724c3b573927d89.zip |
Merge remote-tracking branch 'wixl/master'
-rw-r--r-- | AUTHORS | 3 | ||||
-rw-r--r-- | LICENSE | 19 | ||||
-rw-r--r-- | Makefile.am | 6 | ||||
-rw-r--r-- | README | 22 | ||||
-rw-r--r-- | atlocal.in | 4 | ||||
-rwxr-xr-x | autogen.sh | 10 | ||||
-rw-r--r-- | configure.ac | 37 | ||||
-rw-r--r-- | po/LINGUAS | 0 | ||||
-rw-r--r-- | po/POTFILES.in | 3 | ||||
-rw-r--r-- | po/POTFILES.skip | 3 | ||||
-rw-r--r-- | tests/data/wixl/FoobarAppl10.exe | 1 | ||||
-rw-r--r-- | tests/data/wixl/Helper.dll | 1 | ||||
-rw-r--r-- | tests/data/wixl/Manual.pdf | 1 | ||||
-rwxr-xr-x | tests/data/wixl/Manual.wxs | 14 | ||||
-rw-r--r-- | tests/data/wixl/SampleFirst.wxs | 61 | ||||
-rwxr-xr-x | tests/data/wixl/SampleFragment.wxs | 61 | ||||
-rw-r--r-- | tests/data/wixl/test-arp.wxs | 45 | ||||
-rw-r--r-- | tests/testsuite.at | 2 | ||||
-rw-r--r-- | tests/wixl.at | 95 | ||||
-rw-r--r-- | vapi/libxml-2.0.vapi | 1863 | ||||
-rw-r--r-- | wixl/Makefile.am | 46 | ||||
-rw-r--r-- | wixl/builder.vala | 590 | ||||
-rw-r--r-- | wixl/config.vapi | 12 | ||||
-rw-r--r-- | wixl/msi.vala | 642 | ||||
-rw-r--r-- | wixl/preprocessor.vala | 131 | ||||
-rw-r--r-- | wixl/util.vala | 139 | ||||
-rw-r--r-- | wixl/wix.vala | 598 | ||||
-rw-r--r-- | wixl/wixl.vala | 92 |
28 files changed, 4492 insertions, 9 deletions
@@ -1,4 +1,5 @@ -msitools are maintained by Paolo Bonzini. <pbonzini@redhat.com> +msitools are maintained by Paolo Bonzini <pbonzini@redhat.com> and +Marc-Andre Lureau <marcandre.lureau@gmail.com>. libmsi is mostly based on Wine's implementation of Windows Installer, with the following copyright: @@ -0,0 +1,19 @@ +Format: http://www.debian.org/doc/copyright-format/1.0 +Upstream-Name: Wixl + +Files: * +Copyright: Copyright 2013 Red Hat, Inc. +License: LGPL-2+ + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + . + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/Makefile.am b/Makefile.am index a76d7df..623c479 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,10 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = libmsi tests . +if WIXL +SUBDIRS += po wixl +endif + dist_include_HEADERS = \ include/libmsi.h \ include/libmsi-database.h \ @@ -33,7 +37,7 @@ DISTCLEANFILES = atconfig atlocal CLEANFILES = testsuite.log check-local: $(srcdir)/tests/testsuite atconfig atlocal - $(SHELL) $(srcdir)/tests/testsuite AUTOTEST_PATH=. $(TESTSUITEFLAGS) + $(SHELL) $(srcdir)/tests/testsuite AUTOTEST_PATH=.:wixl $(TESTSUITEFLAGS) installcheck-local: $(srcdir)/tests/testsuite atconfig atlocal $(SHELL) $(srcdir)/tests/testsuite AUTOTEST_PATH=$(bindir) $(TESTSUITEFLAGS) @@ -6,11 +6,17 @@ implementation of the Windows Installer. msitools plans to be a solution for packaging and deployment of cross-compiled Windows applications. -While in a very early stage, it is already usable. Two tools are -provided, msiinfo and msibuild, respectively to inspect and create -MSI files. They are very low-level, but it should already be possible -to use these tools to take an existing .MSI file, and update it with -new build products (for example after a cross-compilation). +Provided tools include: + +- msiinfo, to inspect MSI files + +- msibuild, a low-level tool to create MSI files + +- wixl, a WiX-like tool, that builds Windows Installer (MSI) packages + from an XML document, and tries to share the same syntax as the WiX + toolset, http://wixtoolset.org/ + +While in a very early stage, it is already usable. msitools uses libgsf in order to read OLE Structured Storage files (which are the underlying format of .MSI files). As of December 7th, @@ -18,4 +24,8 @@ msitools uses libgsf in order to read OLE Structured Storage files found in any release. Fedora packages for a fixed libgsf can be found at http://bonzini.fedorapeople.org/. -For more information, contact me at pbonzini@redhat.com. +Wixl lacks many features compared to WiX. As always, contributions +are welcome! + +For more information, please contact us by email. Forking and sending +github pull requests is also welcome. @@ -22,3 +22,7 @@ _msiinfo() { _msibuild() { WINEDEBUG=-all msibuild$EXEEXT "$@" } + +_wixl() { + wixl$EXEEXT "$@" +} diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..2463bcb --- /dev/null +++ b/autogen.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +test -n "$srcdir" || srcdir=$(dirname "$0") +test -n "$srcdir" || srcdir=. +( + cd "$srcdir" && + mkdir -p m4 && + AUTOPOINT='intltoolize --automake --copy' autoreconf -fiv -Wall +) || exit +test -n "$NOCONFIGURE" || "$srcdir/configure" --enable-maintainer-mode "$@" diff --git a/configure.ac b/configure.ac index 1d5f81a..a28fc48 100644 --- a/configure.ac +++ b/configure.ac @@ -15,6 +15,8 @@ AC_USE_SYSTEM_EXTENSIONS AC_PROG_CC AC_PROG_YACC +IT_PROG_INTLTOOL([0.35]) + AM_PATH_GLIB_2_0([2.12.0]) PKG_CHECK_MODULES([GOBJECT], [gobject-2.0 gio-2.0 >= 2.14]) PKG_CHECK_MODULES([GSF], [libgsf-1]) @@ -28,11 +30,32 @@ LT_INIT([win32-dll disable-fast-install]) GOBJECT_INTROSPECTION_CHECK([0.9.4]) AM_CONDITIONAL([GIR], [test "x$INTROSPECTION_MAKEFILE" != x]) -AM_PROG_VALAC([0.14]) +AM_PROG_VALAC([0.16]) AC_PATH_PROG(VAPIGEN, vapigen, no) AC_SUBST(VAPIGEN) AM_CONDITIONAL([VAPI], [test "x$VAPIGEN" != xno]) +PKG_CHECK_MODULES([WIXL], [gio-2.0 >= 2.26.0 + libgcab-1.0 + uuid >= 1.41.3 + libxml-2.0 >= 2.9], + [wixl_ok=yes], [wixl_ok=no]) + +AC_ARG_ENABLE([wixl], + [AS_HELP_STRING([--disable-wixl], [do not build wixl (default=yes)])], + [wixl=$enableval], [wixl=yes]) + +AS_IF([test $wixl_ok = no && test $wixl != no], + [AC_MSG_ERROR([Wixl dependencies not found])]) + +AM_CONDITIONAL([WIXL], [test "x$wixl" != xno]) + +GETTEXT_PACKAGE=wixl +AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext Package]) +AC_SUBST(GETTEXT_PACKAGE) +AM_GNU_GETTEXT_VERSION([1.11]) +AM_GLIB_GNU_GETTEXT + m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) AM_MISSING_PROG([AUTOM4TE], [autom4te]) @@ -45,7 +68,19 @@ AC_CONFIG_FILES([tests/package.m4.tmp:tests/package.m4.in], AC_CONFIG_FILES([ Makefile libmsi-1.0.pc + po/Makefile.in libmsi/Makefile + wixl/Makefile tests/Makefile ]) AC_OUTPUT + +AC_MSG_NOTICE([ + msitools $VERSION + ================ + + prefix: ${prefix} + c compiler: ${CC} + uuid: ${uuid} + wixl: ${wixl} +]) diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/po/LINGUAS diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..7b68332 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,3 @@ +[encoding: UTF-8] +wixl/wixl.vala +wixl/builder.vala diff --git a/po/POTFILES.skip b/po/POTFILES.skip new file mode 100644 index 0000000..e828b78 --- /dev/null +++ b/po/POTFILES.skip @@ -0,0 +1,3 @@ +wixl/builder.c +wixl/wixl.c +libmsi/sql-parser.c diff --git a/tests/data/wixl/FoobarAppl10.exe b/tests/data/wixl/FoobarAppl10.exe new file mode 100644 index 0000000..c1b0730 --- /dev/null +++ b/tests/data/wixl/FoobarAppl10.exe @@ -0,0 +1 @@ +x
\ No newline at end of file diff --git a/tests/data/wixl/Helper.dll b/tests/data/wixl/Helper.dll new file mode 100644 index 0000000..c1b0730 --- /dev/null +++ b/tests/data/wixl/Helper.dll @@ -0,0 +1 @@ +x
\ No newline at end of file diff --git a/tests/data/wixl/Manual.pdf b/tests/data/wixl/Manual.pdf new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/tests/data/wixl/Manual.pdf @@ -0,0 +1 @@ +1
\ No newline at end of file diff --git a/tests/data/wixl/Manual.wxs b/tests/data/wixl/Manual.wxs new file mode 100755 index 0000000..e767d58 --- /dev/null +++ b/tests/data/wixl/Manual.wxs @@ -0,0 +1,14 @@ +<?xml version='1.0' encoding='windows-1252'?>
+<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
+ <Fragment Id='FragmentManual'>
+
+ <DirectoryRef Id='INSTALLDIR'>
+ <Component Id='Manual' Guid='ABCDDCBA-574D-4A9A-A266-5B5EC2C022A4'>
+ <File Id='Manual' Name='Manual.pdf' DiskId='1' Source='Manual.pdf' KeyPath='yes'>
+ <Shortcut Id="startmenuManual" Directory="ProgramMenuDir" Name="Instruction Manual" Advertise="yes" />
+ </File>
+ </Component>
+ </DirectoryRef>
+
+ </Fragment>
+</Wix>
diff --git a/tests/data/wixl/SampleFirst.wxs b/tests/data/wixl/SampleFirst.wxs new file mode 100644 index 0000000..604eb0b --- /dev/null +++ b/tests/data/wixl/SampleFirst.wxs @@ -0,0 +1,61 @@ +<?xml version='1.0' encoding='windows-1252'?>
+<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
+ <Product Name='Foobar 1.0' Id='ABCDDCBA-86C7-4D14-AEC0-86416A69ABDE' UpgradeCode='ABCDDCBA-7349-453F-94F6-BCB5110BA4FD'
+ Language='1033' Codepage='1252' Version='1.0.0' Manufacturer='Acme Ltd.'>
+
+ <Package Id='*' Keywords='Installer' Description="Acme's Foobar 1.0 Installer"
+ Comments='Foobar is a registered trademark of Acme Ltd.' Manufacturer='Acme Ltd.'
+ InstallerVersion='100' Languages='1033' Compressed='yes' SummaryCodepage='1252' />
+
+ <Media Id='1' Cabinet='Sample.cab' EmbedCab='yes' DiskPrompt="CD-ROM #1" />
+ <Property Id='DiskPrompt' Value="Acme's Foobar 1.0 Installation [1]" />
+
+ <Directory Id='TARGETDIR' Name='SourceDir'>
+ <Directory Id='ProgramFilesFolder' Name='PFiles'>
+ <Directory Id='Acme' Name='Acme'>
+ <Directory Id='INSTALLDIR' Name='Foobar 1.0'>
+
+ <Component Id='MainExecutable' Guid='ABCDDCBA-83F1-4F22-985B-FDB3C8ABD471'>
+ <File Id='FoobarEXE' Name='FoobarAppl10.exe' DiskId='1' Source='FoobarAppl10.exe' KeyPath='yes'>
+ <Shortcut Id="startmenuFoobar10" Directory="ProgramMenuDir" Name="Foobar 1.0" WorkingDirectory='INSTALLDIR' Icon="Foobar10.exe" IconIndex="0" Advertise="yes" />
+ <Shortcut Id="desktopFoobar10" Directory="DesktopFolder" Name="Foobar 1.0" WorkingDirectory='INSTALLDIR' Icon="Foobar10.exe" IconIndex="0" Advertise="yes" />
+ </File>
+ </Component>
+
+ <Component Id='HelperLibrary' Guid='ABCDDCBA-6BE3-460D-A14F-75658D16550B'>
+ <File Id='HelperDLL' Name='Helper.dll' DiskId='1' Source='Helper.dll' KeyPath='yes' />
+ </Component>
+
+ <Component Id='Manual' Guid='ABCDDCBA-574D-4A9A-A266-5B5EC2C022A4'>
+ <File Id='Manual' Name='Manual.pdf' DiskId='1' Source='Manual.pdf' KeyPath='yes'>
+ <Shortcut Id="startmenuManual" Directory="ProgramMenuDir" Name="Instruction Manual" Advertise="yes" />
+ </File>
+ </Component>
+
+ </Directory>
+ </Directory>
+ </Directory>
+
+ <Directory Id="ProgramMenuFolder" Name="Programs">
+ <Directory Id="ProgramMenuDir" Name="Foobar 1.0">
+ <Component Id="ProgramMenuDir" Guid="ABCDDCBA-7E98-44CE-B049-C477CC0A2B00">
+ <RemoveFolder Id='ProgramMenuDir' On='uninstall' />
+ <RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]' Type='string' Value='' KeyPath='yes' />
+ </Component>
+ </Directory>
+ </Directory>
+
+ <Directory Id="DesktopFolder" Name="Desktop" />
+ </Directory>
+
+ <Feature Id='Complete' Level='1'>
+ <ComponentRef Id='MainExecutable' />
+ <ComponentRef Id='HelperLibrary' />
+ <ComponentRef Id='Manual' />
+ <ComponentRef Id='ProgramMenuDir' />
+ </Feature>
+
+ <Icon Id="Foobar10.exe" SourceFile="FoobarAppl10.exe" />
+
+ </Product>
+</Wix>
diff --git a/tests/data/wixl/SampleFragment.wxs b/tests/data/wixl/SampleFragment.wxs new file mode 100755 index 0000000..42f1718 --- /dev/null +++ b/tests/data/wixl/SampleFragment.wxs @@ -0,0 +1,61 @@ +<?xml version='1.0' encoding='windows-1252'?>
+<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
+ <Product Name='Foobar 1.0' Id='ABCDDCBA-86C7-4D14-AEC0-86416A69ABDE' UpgradeCode='ABCDDCBA-7349-453F-94F6-BCB5110BA4FD'
+ Language='1033' Codepage='1252' Version='1.0.0' Manufacturer='Acme Ltd.'>
+
+ <Package Id='*' Keywords='Installer' Description="Acme's Foobar 1.0 Installer"
+ Comments='Foobar is a registered trademark of Acme Ltd.' Manufacturer='Acme Ltd.'
+ InstallerVersion='100' Languages='1033' Compressed='yes' SummaryCodepage='1252' />
+
+ <Media Id='1' Cabinet='Sample.cab' EmbedCab='yes' DiskPrompt="CD-ROM #1" />
+ <Property Id='DiskPrompt' Value="Acme's Foobar 1.0 Installation [1]" />
+
+ <Directory Id='TARGETDIR' Name='SourceDir'>
+ <Directory Id='ProgramFilesFolder' Name='PFiles'>
+ <Directory Id='Acme' Name='Acme'>
+ <Directory Id='INSTALLDIR' Name='Foobar 1.0'>
+
+ <Component Id='MainExecutable' Guid='ABCDDCBA-83F1-4F22-985B-FDB3C8ABD471'>
+ <File Id='FoobarEXE' Name='FoobarAppl10.exe' DiskId='1' Source='FoobarAppl10.exe' KeyPath='yes'>
+ <Shortcut Id="startmenuFoobar10" Directory="ProgramMenuDir" Name="Foobar 1.0" WorkingDirectory='INSTALLDIR' Icon="Foobar10.exe" IconIndex="0" Advertise="yes" />
+ <Shortcut Id="desktopFoobar10" Directory="DesktopFolder" Name="Foobar 1.0" WorkingDirectory='INSTALLDIR' Icon="Foobar10.exe" IconIndex="0" Advertise="yes" />
+ </File>
+ </Component>
+
+ <Component Id='HelperLibrary' Guid='ABCDDCBA-6BE3-460D-A14F-75658D16550B'>
+ <File Id='HelperDLL' Name='Helper.dll' DiskId='1' Source='Helper.dll' KeyPath='yes' />
+ </Component>
+
+ </Directory>
+ </Directory>
+ </Directory>
+
+ <Directory Id="ProgramMenuFolder" Name="Programs">
+ <Directory Id="ProgramMenuDir" Name="Foobar 1.0">
+ <Component Id="ProgramMenuDir" Guid="ABCDDCBA-7E98-44CE-B049-C477CC0A2B00">
+ <RemoveFolder Id='ProgramMenuDir' On='uninstall' />
+ <RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]' Type='string' Value='' KeyPath='yes' />
+ </Component>
+ </Directory>
+ </Directory>
+
+ <Directory Id="DesktopFolder" Name="Desktop" />
+ </Directory>
+
+ <Feature Id='Complete' Title='Foobar 1.0' Description='The complete package.'
+ Display='expand' Level='1' ConfigurableDirectory='INSTALLDIR'>
+ <Feature Id='MainProgram' Title='Program' Description='The main executable.' Level='1'>
+ <ComponentRef Id='MainExecutable' />
+ <ComponentRef Id='HelperLibrary' />
+ <ComponentRef Id='ProgramMenuDir' />
+ </Feature>
+
+ <Feature Id='Documentation' Title='Description' Description='The instruction manual.' Level='1'>
+ <ComponentRef Id='Manual' />
+ </Feature>
+ </Feature>
+
+ <Icon Id="Foobar10.exe" SourceFile="FoobarAppl10.exe" />
+
+ </Product>
+</Wix>
diff --git a/tests/data/wixl/test-arp.wxs b/tests/data/wixl/test-arp.wxs new file mode 100644 index 0000000..3e135ee --- /dev/null +++ b/tests/data/wixl/test-arp.wxs @@ -0,0 +1,45 @@ +<?xml version="1.0"?>
+<?define Version = "0.2.0"?>
+<?define UpgradeCode = "ABCDDCBA-8392-0202-1993-199374829923"?>
+<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
+
+ <Product Id="*" Name="name" Manufacturer="manufacturer"
+ Version="$(var.Version)" UpgradeCode="$(var.UpgradeCode)"
+ Language="1033">
+
+ <Package InstallerVersion="200" Compressed="yes" Comments="comments"/>
+ <Media Id="1" Cabinet="cabinet.cab" EmbedCab="yes"/>
+
+ <Property Id="ARPHELPLINK" Value="http://www.foobar.baz"/>
+ <Property Id="ARPNOMODIFY" Value="1"/>
+ <Property Id="ARPNOREPAIR" Value="1"/>
+ <Property Id="ARPPRODUCTICON" Value="FoobarAppl10.exe"/>
+ <Property Id="ARPURLINFOABOUT" Value="http://www.foobar.baz/info"/>
+ <Upgrade Id="$(var.UpgradeCode)">
+ <UpgradeVersion Minimum="$(var.Version)" OnlyDetect="yes" Property="NEWERVERSIONDETECTED"/>
+ <UpgradeVersion Minimum="0.0.0" Maximum="$(var.Version)" IncludeMinimum="yes" IncludeMaximum="no" Property="OLDERVERSIONBEINGUPGRADED"/>
+ </Upgrade>
+ <Condition Message="A newer version is already installed.">NOT NEWERVERSIONDETECTED</Condition>
+
+ <Directory Id="TARGETDIR" Name="SourceDir">
+ <Directory Id="ProgramFilesFolder">
+ <Directory Id="INSTALLDIR" Name="Example">
+ <Component Id="MainExecutable" Guid="ABCDDCBA-2034-1019-3233-949940039491">
+ <File Id="FoobarAppl10.exe" Source="FoobarAppl10.exe"/>
+ </Component>
+ </Directory>
+ </Directory>
+ </Directory>
+
+ <Feature Id="Complete" Level="1">
+ <ComponentRef Id="MainExecutable"/>
+ </Feature>
+
+ <InstallExecuteSequence>
+ <RemoveExistingProducts After="InstallValidate"/>
+ </InstallExecuteSequence>
+
+ <Icon Id="FoobarAppl10.exe" SourceFile="FoobarAppl10.exe"/>
+
+ </Product>
+</Wix>
diff --git a/tests/testsuite.at b/tests/testsuite.at index 01ac62b..c48c5d1 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -231,3 +231,5 @@ Application: Windows Installer XML (3.7.1119.0) Security: 2 (2) ]) AT_CLEANUP + +m4_include([wixl.at]) diff --git a/tests/wixl.at b/tests/wixl.at new file mode 100644 index 0000000..0191012 --- /dev/null +++ b/tests/wixl.at @@ -0,0 +1,95 @@ +AT_BANNER([wixl]) + +# AT_CHECK_... - add exeext automatically +m4_define([AT_CHECK_WIXL], [ +AT_CHECK([_wixl ]$@)]) + +# AT_WIXLDATA - copy data file from source tree +m4_define([AT_WIXLDATA], [ +dir=`dirname $1` +AS_MKDIR_P([$dir]) +AT_CHECK([cp $abs_srcdir/tests/data/wixl/$1 $1])]) + + +AT_SETUP([Invalid command line]) +AT_CHECK_WIXL([], [1], [ignore], [ignore]) +AT_CHECK_WIXL([out.msi foo.wxs], [1], [ignore], [ignore]) +AT_CHECK_WIXL([-o out.msi], [1], [ignore], [ignore]) +AT_CHECK_WIXL([-E], [1], [ignore], [ignore]) +AT_CHECK_WIXL([-D], [1], [ignore], [ignore]) +AT_CHECK_WIXL([-E -o out.msi], [1], [ignore], [ignore]) +AT_CHECK([test -f out.msi], [1]) +AT_CLEANUP + +AT_SETUP([WiX tutorial SampleFirst]) +AT_WIXLDATA([SampleFirst.wxs]) +AT_WIXLDATA([FoobarAppl10.exe]) +AT_WIXLDATA([Helper.dll]) +AT_WIXLDATA([Manual.pdf]) +AT_CHECK_WIXL([-o out.msi SampleFirst.wxs], [0], [ignore], [ignore]) +# FIXME: add tons of tests on out.msi +AT_CHECK([test -f out.msi], [0]) +AT_CLEANUP + +AT_SETUP([WiX tutorial SampleFragment]) +AT_WIXLDATA([SampleFragment.wxs]) +AT_WIXLDATA([Manual.wxs]) +AT_WIXLDATA([FoobarAppl10.exe]) +AT_WIXLDATA([Helper.dll]) +AT_WIXLDATA([Manual.pdf]) +AT_CHECK_WIXL([-o out.msi SampleFragment.wxs Manual.wxs], [0], [ignore], [ignore]) +# FIXME: add tons of tests on out.msi +AT_CHECK([test -f out.msi], [0]) +AT_CLEANUP + +AT_SETUP([Preprocessor variables]) +export MY_VAR="Hello!" +AT_DATA([variables.wxs], [<?xml version="1.0"?> +<?define Version = "0.2.0"?> +<?define UpgradeCode = "ABCDDCBA-8392-0202-1993-199374829923"?> +<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'> + <Property Id="Id0" Value="$(var.UpgradeCode)"/> + <Property Id="Id0.1" Value="$$(var.UpgradeCode)"/> + <Property Id="Id0.2" Value="$$$(var.UpgradeCode)"/> + <?define UpgradeCode = "ABCDDCBA-8392-0202-1993-199374829924"?> + <Property Id="Id2" Value="$(var.UpgradeCode)"/> + <Property Id="Id3" Value="$(var.Version)"/> + <?define A = "A"?><?define B = "B"?> + <Property Id="IdAB" Value="$(var.A)$(var.B)"/> + <Property Id="IdHello" Value="$(env.MY_VAR)"/> + <Property Id="IdSys" Value="($(sys.SOURCEFILEDIR))foo"/> +</Wix> +]) +AT_CHECK_WIXL([-E variables.wxs], [0], [<?xml version="1.0"?> +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> + <Property Id="Id0" Value="ABCDDCBA-8392-0202-1993-199374829923"/> + <Property Id="Id0.1" Value="$ABCDDCBA-8392-0202-1993-199374829923"/> + <Property Id="Id0.2" Value="$$ABCDDCBA-8392-0202-1993-199374829923"/> + <Property Id="Id2" Value="ABCDDCBA-8392-0202-1993-199374829924"/> + <Property Id="Id3" Value="0.2.0"/> + <Property Id="IdAB" Value="AB"/> + <Property Id="IdHello" Value="Hello!"/> + <Property Id="IdSys" Value="(variables.wxs)foo"/> +</Wix> +], [ignore]) +AT_DATA([variables.wxs], [<?xml version="1.0"?> +<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'> + <Property Id="Id$(var.Foo)" Value="$(var.Foo)"/> + <Property Id="Id$(var.Zig)" Value="$(var.Zig)"/> +</Wix> +]) +AT_CHECK_WIXL([-E variables.wxs -D Foo -D Zig=Zag], [0], [<?xml version="1.0"?> +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> + <Property Id="Id1" Value="1"/> + <Property Id="IdZag" Value="Zag"/> +</Wix> +], [ignore]) +AT_CLEANUP + +AT_SETUP([ARP example]) +AT_WIXLDATA([test-arp.wxs]) +AT_WIXLDATA([FoobarAppl10.exe]) +AT_CHECK_WIXL([-o out.msi test-arp.wxs], [0], [ignore], [ignore]) +# FIXME: add tons of tests on out.msi +AT_CHECK([test -f out.msi], [0]) +AT_CLEANUP diff --git a/vapi/libxml-2.0.vapi b/vapi/libxml-2.0.vapi new file mode 100644 index 0000000..b76cc54 --- /dev/null +++ b/vapi/libxml-2.0.vapi @@ -0,0 +1,1863 @@ +/* libxml2.vala + * + * Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini, Michael Lawrence + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: + * Jürg Billeter <j@bitron.ch> + * Raffaele Sandrini <rasa@gmx.ch> + * Michael Lawrence <lawremi@iastate.edu> + * Ondřej Jirman <megous@megous.com> + */ + +[CCode (gir_namespace = "libxml2", gir_version = "2.0")] +namespace Xml { + /* nanoftp - minimal FTP implementation */ + + [CCode (has_target = false, cname = "ftpDataCallback", cheader_filename = "libxml/nanoftp.h")] + public delegate void FtpDataCallback (void* userData, [CCode (array_length = false)] char[] data, int len); + + [CCode (has_target = false, cname = "ftpListCallback", cheader_filename = "libxml/nanoftp.h")] + public delegate void FtpListCallback (void* userData, string filename, string attrib, string owner, string group, ulong size, int links, int year, string month, int day, int hour, int minute); + + [Compact] + [CCode (cname = "void", free_function = "xmlNanoFTPFreeCtxt", cheader_filename = "libxml/nanoftp.h")] + public class NanoFTP { + [CCode (cname = "xmlNanoFTPCheckResponse")] + public int check_response (); + + [CCode (cname = "xmlNanoFTPCleanup")] + public static void cleanup (); + + [CCode (cname = "xmlNanoFTPClose")] + public int close (); + + [CCode (cname = "xmlNanoFTPCloseConnection")] + public int close_connection (); + + [CCode (cname = "xmlNanoFTPConnect")] + public int connect (); + + [CCode (cname = "xmlNanoFTPConnectTo")] + public static NanoFTP* connect_to (string server, int port); + + [CCode (cname = "xmlNanoFTPCwd")] + public int cwd (string directory); + + [CCode (cname = "xmlNanoFTPDele")] + public int dele (string file); + + [CCode (cname = "xmlNanoFTPGet")] + public int get (FtpDataCallback cb, void* user_data, string filename); + + [CCode (cname = "xmlNanoFTPGetConnection")] + public int get_connection (); + + [CCode (cname = "xmlNanoFTPGetResponse")] + public int get_response (); + + [CCode (cname = "xmlNanoFTPGetSocket")] + public int get_socket (string filename); + + [CCode (cname = "xmlNanoFTPInit")] + public static void init (); + + [CCode (cname = "xmlNanoFTPList")] + public int list (FtpListCallback cb, void* user_data, string filename); + + [CCode (cname = "xmlNanoFTPNewCtxt")] + public NanoFTP (string url); + + [CCode (cname = "xmlNanoFTPOpen")] + public static NanoFTP* open (string url); + + [CCode (cname = "xmlNanoFTPProxy")] + public static void proxy (string host, int port, string user, string passwd, int type); + + [CCode (cname = "xmlNanoFTPQuit")] + public int quit (); + + [CCode (cname = "xmlNanoFTPRead")] + public int read (void* dest, int len); + + [CCode (cname = "xmlNanoFTPScanProxy")] + public static void scan_proxy (string url); + + [CCode (cname = "xmlNanoFTPUpdateURL")] + public int update_url (string url); + } + + + /* nanohttp - minimal HTTP implementation */ + + [Compact] + [CCode (cname = "void", cheader_filename = "libxml/nanohttp.h")] + public class NanoHTTP { + [CCode (cname = "xmlNanoHTTPAuthHeader")] + public unowned string auth_header (); + + [CCode (cname = "xmlNanoHTTPCleanup")] + public static void cleanup (); + + [CCode (cname = "xmlNanoHTTPClose")] + public int close (); + + [CCode (cname = "xmlNanoHTTPContentLength")] + public int content_length (); + + [CCode (cname = "xmlNanoHTTPEncoding")] + public unowned string http_encoding (); + + [CCode (cname = "xmlNanoHTTPFetch")] + public static int fetch (string url, string filename, out string content_type); + + [CCode (cname = "xmlNanoHTTPInit")] + public static void init (); + + [CCode (cname = "xmlNanoHTTPMethod")] + public static NanoHTTP* method (string url, string method, string input, out string content_type, string headers, int ilen); + + [CCode (cname = "xmlNanoHTTPMethodRedir")] + public static NanoHTTP* method_redir (string url, string method, string input, out string content_type, out string redir, string headers, int ilen); + + [CCode (cname = "xmlNanoHTTPMimeType")] + public string mime_type (); + + [CCode (cname = "xmlNanoHTTPOpen")] + public static NanoHTTP* open (string url, out string content_type); + + [CCode (cname = "xmlNanoHTTPOpenRedir")] + public static NanoHTTP* open_redir (string url, out string content_type, out string redir); + + [CCode (cname = "xmlNanoHTTPRead")] + public int read (void* dest, int len); + + [CCode (cname = "xmlNanoHTTPRedir")] + public unowned string redir (); + + [CCode (cname = "xmlNanoHTTPReturnCode")] + public int return_code (); + + [CCode (cname = "xmlNanoHTTPSave")] + public int save (string filename); + + [CCode (cname = "xmlNanoHTTPScanProxy")] + public static void scan_proxy (string URL); + } + + + /* parser - the core parser module */ + + [CCode (cheader_filename = "libxml/parser.h")] + namespace Parser { + [CCode (cname = "xmlCleanupParser")] + public static void cleanup (); + + [CCode (cname = "xmlInitParser")] + public static void init (); + + [CCode (cname = "xmlParseDoc")] + public static Doc* parse_doc (string cur); + + [CCode (cname = "xmlParseFile")] + public static Doc* parse_file (string filename); + + [CCode (cname = "xmlParseMemory")] + public static Doc* parse_memory (string buffer, int size); + + [CCode (cname = "xmlReadDoc")] + public static Doc* read_doc (string cur, string? url = null, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReadFd")] + public static Doc* read_fd (int fd, string? base_url = null, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReadFile")] + public static Doc* read_file (string filename, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReadMemory")] + public static Doc* read_memory (string text, int len, string? url = null, string? encoding = null, int options = 0); + } + + [CCode (cname = "xmlParserOption", cprefix = "XML_PARSE_", cheader_filename = "libxml/parser.h", has_type_id = false)] + public enum ParserOption { + RECOVER, + NOENT, + DTDLOAD, + DTDATTR, + DTDVALID, + NOERROR, + NOWARNING, + PEDANTIC, + NOBLANKS, + SAX1, + XINCLUDE, + NONET, + NODICT, + NSCLEAN, + NOCDATA, + NOXINCNODE, + COMPACT, + } + + [CCode (cname = "xmlCharEncoding", cprefix = "XML_CHAR_ENCODING_", cheader_filename = "libxml/encoding.h", has_type_id = false)] + public enum CharEncoding { + ERROR, + NONE, + UTF8, + UTF16LE, + UTF16BE, + UCS4LE, + UCS4BE, + EBCDIC, + UCS4_2143, + UCS4_3412, + UCS2, + [CCode (cname = "XML_CHAR_ENCODING_8859_1")] + ISO_8859_1, + [CCode (cname = "XML_CHAR_ENCODING_8859_2")] + ISO_8859_2, + [CCode (cname = "XML_CHAR_ENCODING_8859_3")] + ISO_8859_3, + [CCode (cname = "XML_CHAR_ENCODING_8859_4")] + ISO_8859_4, + [CCode (cname = "XML_CHAR_ENCODING_8859_5")] + ISO_8859_5, + [CCode (cname = "XML_CHAR_ENCODING_8859_6")] + ISO_8859_6, + [CCode (cname = "XML_CHAR_ENCODING_8859_7")] + ISO_8859_7, + [CCode (cname = "XML_CHAR_ENCODING_8859_8")] + ISO_8859_8, + [CCode (cname = "XML_CHAR_ENCODING_8859_9")] + ISO_8859_9, + ISO_2022_JP, + SHIFT_JIS, + EUC_JP, + ASCII, + } + + /* tree - interfaces for tree manipulation */ + + [CCode (cheader_filename = "libxml/tree.h")] + namespace Tree { + [CCode (cname = "xmlGetCompressMode")] + public static int get_compress_mode (); + + [CCode (cname = "xmlIsXHTML")] + public static int is_xhtml (string system_id, string public_id); + + [CCode (cname = "xmlSetCompressMode")] + public static void set_compress_mode (int mode); + } + + [Compact] + [CCode (cname = "xmlAttr", free_function = "xmlFreeProp", cheader_filename = "libxml/tree.h")] + public class Attr { + public ElementType type; + public weak string name; + public Node* children; + public Node* last; + public Node* parent; + public Attr* next; + public Attr* prev; + public Doc* doc; + public Ns* ns; + public AttributeType atype; + + [CCode (cname = "xmlRemoveProp")] + public int remove(); + } + + [Compact] + [CCode (cname = "xmlAttribute", cheader_filename = "libxml/tree.h")] + public class Attribute { + public ElementType type; + public weak string name; + public Node* children; + public Node* last; + public Dtd* parent; + public Node* next; + public Node* prev; + public Doc* doc; + public Attribute* nexth; + public AttributeType atype; + public AttributeDefault def; + public weak string default_value; + public weak string prefix; + public weak string elem; + } + + [CCode (cname = "xmlAttributeDefault", cprefix = "XML_ATTRIBUTE_", cheader_filename = "libxml/tree.h", has_type_id = false)] + public enum AttributeDefault { + NONE, + REQUIRED, + IMPLIED, + FIXED + } + + [CCode (cname = "xmlAttributeType", cprefix = "XML_ATTRIBUTE_", cheader_filename = "libxml/tree.h", has_type_id = false)] + public enum AttributeType { + CDATA, + ID, + IDREF , + IDREFS, + ENTITY, + ENTITIES, + NMTOKEN, + NMTOKENS, + ENUMERATION, + NOTATION + } + + [Compact] + [CCode (cname = "xmlDoc", free_function = "xmlFreeDoc", cheader_filename = "libxml/tree.h,libxml/parser.h")] + public class Doc { + public ElementType type; + public string name; + public Node* children; + public Node* last; + public Node* parent; + public Node* next; + public Node* prev; + public Doc* doc; + public int compression; + public int standalone; + [CCode (cname = "intSubset")] + public Dtd* int_subset; + [CCode (cname = "extSubset")] + public Dtd* ext_subset; + [CCode (cname = "oldNs")] + public Ns* old_ns; + public weak string version; + public weak string encoding; + [CCode (cname = "URL")] + public weak string url; + public int charset; + + [CCode (cname = "xmlCopyDoc")] + public Doc* copy (int recursive); + + [CCode (cname = "xmlCreateIntSubset")] + public Dtd* create_int_subset (string name, string external_id, string system_id); + + [CCode (cname = "xmlDocDump", instance_pos = -1)] + public int dump (GLib.FileStream f); + + [CCode (cname = "xmlDocDumpFormatMemory")] + public void dump_memory_format (out string mem, out int len = null, bool format = true); + + [CCode (cname = "xmlDocDumpFormatMemoryEnc")] + public void dump_memory_enc_format (out string mem, out int len = null, string enc = "UTF-8", bool format = true); + + [CCode (cname = "xmlDocDumpMemory")] + public void dump_memory (out string mem, out int len = null); + + [CCode (cname = "xmlDocDumpMemoryEnc")] + public void dump_memory_enc (out string mem, out int len = null, string enc = "UTF-8"); + + [CCode (cname = "xmlDocFormatDump", instance_pos = 1.1)] + public int dump_format (GLib.FileStream f, bool format = true); + + [CCode (cname = "xmlDocGetRootElement")] + public Node* get_root_element(); + + [CCode (cname = "xmlDocSetRootElement")] + public Node* set_root_element(Node* root); + + [CCode (cname = "xmlElemDump", instance_pos = 1.1)] + public void elem_dump (GLib.FileStream f, Node* cur); + + [CCode (cname = "xmlGetDocCompressMode")] + public int get_compress_mode (); + + [CCode (cname = "xmlNewCDataBlock")] + public Node* new_cdata_block (string content, int len); + + [CCode (cname = "xmlNewCharRef")] + public Node* new_char_ref (string name); + + [CCode (cname = "xmlNewDoc")] + public Doc (string? version = null); + + [CCode (cname = "xmlNewDocComment")] + public Node* new_comment (string content); + + [CCode (cname = "xmlNewDocFragment")] + public Node* new_fragment (); + + [CCode (cname = "xmlNewDocNode")] + public Node* new_node (Ns* ns, string name, string? content = null); + + [CCode (cname = "xmlNewDocNodeEatName")] + public Node* new_node_eat_name (Ns* ns, owned string name, string? content = null); + + [CCode (cname = "xmlNewDocPI")] + public Node* new_pi (string name, string content); + + [CCode (cname = "xmlNewDocProp")] + public Attr* new_prop (string name, string value); + + [CCode (cname = "xmlNewDocRawNode")] + public Node* new_raw_node (Ns* ns, string name, string? content = null); + + [CCode (cname = "xmlNewDocText")] + public Node* new_text (string content); + + [CCode (cname = "xmlNewDocTextLen")] + public Node* new_text_len (string content, int len); + + [CCode (cname = "xmlNewReference")] + public Node* new_reference (string name); + + [CCode (cname = "xmlNodeListGetRawString")] + public string node_list_get_raw_string (Node* list, bool in_line); + + [CCode (cname = "xmlNodeListGetString")] + public string node_list_get_string (Node* list, bool in_line); + + [CCode (cname = "xmlSaveFile", instance_pos = -1)] + public int save_file (string filename); + + [CCode (cname = "xmlSaveFileEnc", instance_pos = 1.1)] + public void save_file_enc (string filename, string enc = "UTF-8"); + + [CCode (cname = "xmlSaveFormatFile", instance_pos = 1.1)] + public int save_format_file (string filename, int format); + + [CCode (cname = "xmlSaveFormatFileEnc", instance_pos = 1.1)] + public void save_format_file_enc (string filename, string enc = "UTf-8", bool format = true); + + [CCode (cname = "xmlSetDocCompressMode")] + public void set_compress_mode (int mode); + + [CCode (cname = "xmlStringGetNodeList")] + public Node* string_get_node_list (string str); + + [CCode (cname = "xmlStringLenGetNodeList")] + public Node* string_len_get_node_list (string str, int len); + } + + [Compact] + [CCode (cname = "xmlDtd", free_function="xmlFreeDtd", cheader_filename = "libxml/tree.h")] + public class Dtd { + public ElementType type; + public string name; + public Node* children; + public Node* last; + public Node* parent; + public Node* next; + public Node* prev; + public Doc* doc; + + public weak string external_id; + public weak string system_id; + + [CCode (cname = "xmlNewDtd")] + public Dtd (Doc* doc, string name, string external_id, string system_id); + + [CCode (cname = "xmlCopyDtd")] + public Dtd* copy(); + } + + [Compact] + [CCode (cname = "xmlElement", cheader_filename = "libxml/tree.h")] + public class Element { + public ElementType type; + public weak string name; + public Node* children; + public Node* last; + public Dtd* parent; + public Node* next; + public Node* prev; + public Doc* doc; + public Attribute* attributes; + public weak string prefix; + } + + [CCode (cname = "xmlElementType", cprefix = "XML_", cheader_filename = "libxml/tree.h", has_type_id = false)] + public enum ElementType { + ELEMENT_NODE, + ATTRIBUTE_NODE, + TEXT_NODE, + CDATA_SECTION_NODE, + ENTITY_REF_NODE, + ENTITY_NODE, + PI_NODE, + COMMENT_NODE, + DOCUMENT_NODE, + DOCUMENT_TYPE_NODE, + DOCUMENT_FRAG_NODE, + NOTATION_NODE, + HTML_DOCUMENT_NODE, + DTD_NODE, + ELEMENT_DECL, + ATTRIBUTE_DECL, + ENTITY_DECL, + NAMESPACE_DECL, + XINCLUDE_START, + XINCLUDE_END, + DOCB_DOCUMENT_NODE + } + + [Compact] + [CCode (cname = "xmlElementContent", free_function = "xmlFreeElementContent", cheader_filename = "libxml/tree.h")] + public class ElementContent { + [CCode (cname = "xmlNewElementContent")] + ElementContent (string name, ElementContentType type); + + public ElementContentType type; + public ElementContentOccur ocur; + public const string name; + public ElementContent c1; + public ElementContent c2; + public ElementContent parent; + public const string prefix; + } + + [CCode (cname = "xmlElementContentType", cprefix = "XML_ELEMENT_CONTENT_", cheader_filename = "libxml/tree.h", has_type_id = false)] + public enum ElementContentType { + PCDATA, + ELEMENT, + SEQ, + OR + } + + [CCode (cname = "xmlElementContentOccur", cprefix = "XML_ELEMENT_CONTENT_", cheader_filename = "libxml/tree.h", has_type_id = false)] + public enum ElementContentOccur { + ONCE, + OPT, + MULT, + PLUS + } + + [Compact] + [CCode (cname = "xmlEntity", cheader_filename = "libxml/tree.h")] + public struct Entity { + public void* private; + public ElementType type; + public const string name; + public Node* children; + public Node* last; + public Dtd* parent; + public Node* next; + public Node* prev; + public Doc* doc; + public string orig; + public string content; + public int length; + public EntityType etype; + [CCode (cname = "ExternalID")] + public const string external_id; + [CCode (cname = "SystemID")] + public const string system_id; + public Entity* nexte; + [CCode (cname = "URI")] + public const string uri; + public int owner; + public int checked; + } + + [CCode (cname = "xmlEntityType", cprefix = "XML_", cheader_filename = "libxml/tree.h", has_type_id = false)] + public enum EntityType { + INTERNAL_GENERAL_ENTITY, + EXTERNAL_GENERAL_PARSED_ENTITY, + EXTERNAL_GENERAL_UNPARSED_ENTITY, + INTERNAL_PARAMETER_ENTITY, + EXTERNAL_PARAMETER_ENTITY, + INTERNAL_PREDEFINED_ENTITY + } + + [Compact] + [CCode (cname = "xmlEnumeration", cheader_filename = "libxml/tree.h")] + public struct Enumeration { + public Enumeration* next; + public const string name; + } + + + [Compact] + [CCode (cname = "xmlNode", free_function = "xmlFreeNode", cheader_filename = "libxml/tree.h")] + public class Node { + public ElementType type; + public weak string name; + public Node* children; + public Node* last; + public Node* parent; + public Node* next; + public Node* prev; + public Doc* doc; + public Ns* ns; + public string content; + public Attr* properties; + [CCode (cname = "nsDef")] + public Ns* ns_def; + public ushort line; + public ushort extra; + + [CCode (cname = "xmlAddChild")] + public Node* add_child (Node* cur); + + [CCode (cname = "xmlAddChildList")] + public Node* add_child_list (Node* cur); + + [CCode (cname = "xmlAddNextSibling")] + public Node* add_next_sibling (Node* elem); + + [CCode (cname = "xmlAddPrevSibling")] + public Node* add_prev_sibling (Node* elem); + + [CCode (cname = "xmlAddSibling")] + public Node* add_sibling (Node* elem); + + [CCode (cname = "xmlCopyNode")] + public Node* copy (int extended); + + [CCode (cname = "xmlCopyNodeList")] + public Node copy_list(); + + [CCode (cname = "xmlDocCopyNode")] + public Node* doc_copy (Doc* doc, int extended); + + [CCode (cname = "xmlDocCopyNodeList")] + public Node* doc_copy_list (Doc* doc); + + [CCode (cname = "xmlFreeNodeList")] + public void free_list (); + + [CCode (cname = "xmlGetLastChild")] + public Node* get_last_child (); + + [CCode (cname = "xmlGetLineNo")] + public long get_line_no (); + + [CCode (cname = "xmlGetNoNsProp")] + public string? get_no_ns_prop (string name); + + [CCode (cname = "xmlGetNodePath")] + public string get_path (); + + [CCode (cname = "xmlGetNsProp")] + public string? get_ns_prop (string name, string ns); + + [CCode (cname = "xmlGetProp")] + public string? get_prop (string name); + + [CCode (cname = "xmlHasNsProp")] + public Attr* has_ns_prop (string name, string name_space); + + [CCode (cname = "xmlHasProp")] + public Attr* has_prop (string name); + + [CCode (cname = "xmlIsBlankNode")] + public int is_blank (); + + [CCode (cname = "xmlNewChild")] + public Node* new_child (Ns* ns, string name, string? content = null); + + [CCode (cname = "xmlNewNs")] + public Ns* new_ns (string href, string prefix); + + [CCode (cname = "xmlNewNsProp")] + public Attr* new_ns_prop (Ns* ns, string name, string value); + + [CCode (cname = "xmlNewProp")] + public Attr* new_prop (string name, string value); + + [CCode (cname = "xmlNewTextChild")] + public Node* new_text_child (Ns* ns, string name, string content); + + [CCode (cname = "xmlNodeAddContent")] + public void add_content (string content); + + [CCode (cname = "xmlNodeAddContentLen")] + public void add_content_len (string content, int len); + + [CCode (cname = "xmlNodeGetContent")] + public string get_content(); + + [CCode (cname = "xmlNodeGetLang")] + public string get_lang(); + + [CCode (cname = "xmlNodeGetSpacePreserve")] + public int get_space_preserve(); + + [CCode (cname = "xmlNodeIsText")] + public int is_text(); + + [CCode (cname = "xmlNodeSetContent")] + public void set_content (string content); + + [CCode (cname = "xmlNodeSetContentLen")] + public void set_content_len (string content, int len); + + [CCode (cname = "xmlNodeSetLang")] + public void set_lang (string val); + + [CCode (cname = "xmlNodeSetName")] + public void set_name (string name); + + [CCode (cname = "xmlNodeSetSpacePreserve")] + public void set_space_preserve (int val); + + [CCode (cname = "xmlReplaceNode")] + public Node* replace (Node* cur); + + [CCode (cname = "xmlNewComment")] + public Node.comment (string content); + + [CCode (cname = "xmlNewNode")] + public Node (Ns* ns, string name); + + [CCode (cname = "xmlNewNodeEatName")] + public Node.eat_name (Ns* ns, owned string name); + + [CCode (cname = "xmlNewText")] + public Node.text (string content); + + [CCode (cname = "xmlNewTextLen")] + public Node.text_len (string content, int len); + + [CCode (cname = "xmlNewPI")] + public Node.pi (string name, string content); + + [CCode (cname = "xmlSetListDoc")] + public void set_list_doc (Doc* doc); + + [CCode (cname = "xmlSetNsProp")] + public Attr* set_ns_prop (Ns* ns, string name, string value); + + [CCode (cname = "xmlSetProp")] + public Attr* set_prop (string name, string value); + + [CCode (cname = "xmlSetTreeDoc")] + public void set_tree_doc (Doc* doc); + + [CCode (cname = "xmlTextConcat")] + public int text_concat (string content, int len); + + [CCode (cname = "xmlTextMerge")] + public Node* text_merge (Node* second); + + [CCode (cname = "xmlUnlinkNode")] + public void unlink (); + + [CCode (cname = "xmlUnsetNsProp")] + public int unset_ns_prop (Ns* ns, string name); + + [CCode (cname = "xmlUnsetProp")] + public int unset_prop (string name); + + [CCode (cname = "xmlNextElementSibling")] + public Node* next_element_sibling (); + + [CCode (cname = "xmlFirstElementChild")] + public Node* first_element_child (); + + [CCode (cname = "xmlChildElementCount")] + public ulong child_element_count (); + } + + [Compact] + [CCode (cname = "xmlNs", free_function= "xmlFreeNs", cheader_filename = "libxml/tree.h")] + public class Ns { + [CCode (cname = "xmlNewNs")] + public Ns (Xml.Node* node, string href, string prefix); + public Ns* next; + public ElementType type; + public string href; + public string prefix; + public Doc* context; + } + + [Compact] + [CCode (cname = "xmlParserCtxt", free_function = "xmlFreeParserCtxt", cheader_filename = "libxml/parser.h")] + public class ParserCtxt { + public SAXHandler* sax; + [CCode (cname = "userData")] + public void* user_data; + + [CCode (cname = "xmlNewParserCtxt")] + public ParserCtxt (); + + [CCode (cname = "xmlCreatePushParserCtxt")] + public ParserCtxt.create_push (Xml.SAXHandler* sax, void* user_data, [CCode (array_length = false)] char[] data, int len, string? filename = null); + + [CCode (cname = "xmlCreateIOParserCtxt")] + public ParserCtxt.create_io (Xml.SAXHandler* sax, void* user_data, Xml.InputReadCallback ioread, Xml.InputCloseCallback ioclose, void* ioctx, string? encoding = null); + + [CCode (cname = "xmlCreateDocParserCtxt")] + public ParserCtxt.create_doc (string cur); + + [CCode (cname = "xmlParseChunk")] + public int parse_chunk ([CCode (array_length = false)] char[] data, int size, bool terminate); + + [CCode (cname = "xmlParseDocument")] + public int parse_document (); + + [CCode (cname = "xmlCtxtResetPush")] + public void reset_push ([CCode (array_length = false)] char[] data, int len, string? filename = null, string? encoding = null); + + [CCode (cname = "xmlCtxtReset")] + public void reset (); + + [CCode (cname = "xmlCtxtInit")] + public void init (); + + [CCode (cname = "xmlCtxtClear")] + public void clear (); + + [CCode (cname = "xmlCtxtUseOptions")] + public int use_options (int options); + + [CCode (cname = "xmlCtxtReadDoc")] + public Doc* read_doc (string cur, string url, string? encoding = null, int options = 0); + + [CCode (cname = "xmlCtxtReadFile")] + public Doc* read_file (string filename, string? encoding = null, int options = 0); + + [CCode (cname = "xmlCtxtReadMemory")] + public Doc* read_memory ([CCode (array_length = false)] char[] buffer, int size, string url, string? encoding = null, int options = 0); + + [CCode (cname = "xmlCtxtReadFd")] + public Doc* read_fd (int fd, string url, string? encoding = null, int options = 0); + + [CCode (cname = "xmlCtxtReadIO")] + public Doc* read_io (Xml.InputReadCallback ioread, Xml.InputCloseCallback ioclose, void* ioctx, string url, string? encoding = null, int options = 0); + } + + + /* uri - library of generic URI related routines */ + + [Compact] + [CCode (cname = "xmlURI", free_function = "xmlFreeURI", cheader_filename = "libxml/uri.h")] + public class URI { + [CCode (cname = "xmlBuildRelativeURI")] + public static string build_relative (string uri, string @base); + + [CCode (cname = "xmlBuildURI")] + public static string build (string URI, string @base); + + [CCode (cname = "xmlCanonicPath")] + public static string canonic_path (string path); + + [CCode (cname = "xmlCreateURI")] + public URI (); + + [CCode (cname = "xmlNormalizeURIPath")] + public static int normalize_uri_path (string path); + + [CCode (cname = "xmlParseURI")] + public static URI? parse (string str); + + [CCode (cname = "xmlParseURIRaw")] + public static URI? parse_raw (string str, bool raw); + + [CCode (cname = "xmlParseURIReference")] + public int parse_reference (string str); + + [CCode (cname = "xmlPathToURI")] + public static string path_to_uri (string path); + + [CCode (cname = "xmlPrintURI", instance_pos = -1)] + public void print (GLib.FileStream stream); + + [CCode (cname = "xmlSaveUri")] + public string save (); + + [CCode (cname = "xmlURIEscape")] + public static string escape (string str); + + [CCode (cname = "xmlURIEscapeStr")] + public static string escape_str (string str, string list); + + [CCode (cname = "xmlURIUnescapeString")] + public static string unescape_string (string str, int len, string? target); + + public string scheme; + public string opaque; + public string authority; + public string server; + public string user; + public int port; + public string path; + public string query; + public string fragment; + public int cleanup; + public string query_raw; + } + + + /* xmlIO - interface for the I/O interfaces used by the parser */ + + [CCode (has_target = false, cname = "xmlInputCloseCallback", cheader_filename = "libxml/xmlIO.h")] + public delegate int InputCloseCallback (void* context); + + [CCode (has_target = false, cname = "xmlInputReadCallback", cheader_filename = "libxml/xmlIO.h")] + public delegate int InputReadCallback (void* context, [CCode (array_length = false)] char[] buffer, int len); + + [CCode (has_target = false, cname = "xmlInputMatchCallback", cheader_filename = "libxml/xmlIO.h")] + public delegate int InputMatchCallback (string filename); + + [CCode (has_target = false, cname = "xmlInputOpenCallback", cheader_filename = "libxml/xmlIO.h")] + public delegate void* InputOpenCallback (string filename); + + [CCode (has_target = false, cname = "xmlOutputMatchCallback", cheader_filename = "libxml/xmlIO.h")] + public delegate int OutputMatchCallback (string filename); + + [CCode (has_target = false, cname = "xmlOutputOpenCallback", cheader_filename = "libxml/xmlIO.h")] + public delegate void* OutputOpenCallback (string filename); + + [CCode (has_target = false, cname = "xmlOutputWriteCallback", cheader_filename = "libxml/xmlIO.h")] + public delegate int OutputWriteCallback ([CCode (array_length = false)] char[] buffer, int len); + + [CCode (has_target = false, cname = "xmlOutputCloseCallback", cheader_filename = "libxml/xmlIO.h")] + public delegate int OutputCloseCallback (void * context); + + [CCode (cname = "xmlRegisterInputCallbacks", cheader_filename = "libxml/xmlIO.h")] + public int registerInputCallbacks (InputMatchCallback matchFunc, InputOpenCallback openFunc, InputReadCallback readFunc, InputCloseCallback closeFunc); + + [CCode (cname = "xmlRegisterOutputCallbacks", cheader_filename = "libxml/xmlIO.h")] + public int registerOutputCallbacks(OutputMatchCallback matchFunc, OutputOpenCallback openFunc, OutputWriteCallback writeFunc, OutputCloseCallback closeFunc); + + /* xmlschemas - incomplete XML Schemas structure implementation */ + + [Compact] + [CCode (cname = "xmlSchemaValidCtxt", cheader_filename = "libxml/xmlreader.h")] + public class SchemaValidCtxt { + } + + /* xmlsave */ + + [Compact] + [CCode (cname = "xmlSaveCtxt", free_function = "xmlSaveClose", cheader_filename = "libxml/xmlsave.h")] + public class SaveCtxt { + [CCode (cname = "xmlSaveToIO")] + public SaveCtxt.to_io (OutputWriteCallback iowrite, OutputCloseCallback ioclose, void * ioctx = null, string? encoding = null, int options = 0); + + [CCode (cname = "xmlSaveClose")] + public int close (); + [CCode (cname = "xmlSaveFlush")] + public int flush (); + [CCode (cname = "xmlSaveDoc")] + public int save_doc (Xml.Doc *doc); + [CCode (cname = "xmlSaveTree")] + public int save_tree (Xml.Node *node); + } + + /* xmlwriter - the XMLWriter implementation */ + + [Compact] + [CCode (cname = "xmlTextWriter", free_function = "xmlFreeTextWriter", cheader_filename = "libxml/xmlwriter.h")] + public class TextWriter { + [CCode (cname = "xmlNewTextWriterFilename")] + public TextWriter.filename (string uri, bool compression = false); + + [CCode (cname = "xmlNewTextWriterDoc")] + public TextWriter.doc (out Doc doc, bool compression = false); + + [CCode (cname = "xmlTextWriterFlush")] + public int flush (); + + [CCode (cname = "xmlTextWriterSetIndent")] + public int set_indent (bool indent); + + [CCode (cname = "xmlTextWriterSetIndentString")] + public int set_indent_string (string str); + + /* End */ + [CCode (cname = "xmlTextWriterEndCDATA")] + public int end_cdata (); + + [CCode (cname = "xmlTextWriterEndComment")] + public int end_comment (); + + [CCode (cname = "xmlTextWriterEndDocument")] + public int end_document (); + + [CCode (cname = "xmlTextWriterEndElement")] + public int end_element (); + + [CCode (cname = "xmlTextWriterEndAttribute")] + public int end_attribute (); + + /* Start */ + + [CCode (cname = "xmlTextWriterStartCDATA")] + public int start_cdata (); + + [CCode (cname = "xmlTextWriterStartComment")] + public int start_comment (); + + [CCode (cname = "xmlTextWriterStartDocument")] + public int start_document (string? version = null, string? encoding = null, string? standalone = null); + + [CCode (cname = "xmlTextWriterStartElement")] + public int start_element (string name); + + [CCode (cname = "xmlTextWriterStartElementNS")] + public int start_element_ns (string prefix, string name, string namespaceURI); + + [CCode (cname = "xmlTextWriterStartAttribute")] + public int start_attribute (string name); + + [CCode (cname = "xmlTextWriterStartAttributeNS")] + public int start_attribute_ns (string prefix, string name, string namespaceURI); + + /* write */ + + [CCode (cname = "xmlTextWriterWriteAttribute")] + public int write_attribute (string name, string content); + + [CCode (cname = "xmlTextWriterWriteAttributeNS")] + public int write_attribute_ns (string prefix, string name, string namespaceURI, string content); + + [CCode (cname = "xmlTextWriterWriteElement")] + public int write_element (string name, string content); + + [CCode (cname = "xmlTextWriterWriteElementNS")] + public int write_element_ns (string prefix, string name, string namespaceURI, string content); + + [CCode (cname = "xmlTextWriterWriteBase64")] + public int write_base64 (void* data, int start, int length); + + [CCode (cname = "xmlTextWriterWriteComment")] + public int write_comment (string content); + + [CCode (cname = "xmlTextWriterWriteString")] + public int write_string (string content); + + [CCode (cname = "xmlTextWriterWriteCDATA")] + public int write_cdata (string content); + + /* formatted */ + + [CCode (cname = "xmlTextWriterWriteFormatAttribute")] + public int format_attribute (string name, string format, ...); + + [CCode (cname = "xmlTextWriterWriteFormatAttributeNS")] + public int format_attribute_ns (string prefix, string name, string namespaceURI, string format, ...); + + [CCode (cname = "xmlTextWriterWriteFormatCDATA")] + public int format_cdata (string format, ...); + + [CCode (cname = "xmlTextWriterWriteFormatComment")] + public int format_comment (string format, ...); + + [CCode (cname = "xmlTextWriterWriteFormatElement")] + public int format_element (string name, string format, ...); + + [CCode (cname = "xmlTextWriterWriteFormatElementNS")] + public int format_element_ns (string prefix, string name, string namespaceURI, string format, ...); + + [CCode (cname = "xmlTextWriterWriteFormatString")] + public int format_string (string format, ...); + } + + /* xmlreader - the XMLReader implementation */ + + [CCode (cname = "xmlParserProperties", cprefix = "XML_PARSER_", cheader_filename = "libxml/xmlreader.h", has_type_id = false)] + public enum ParserProperties { + LOADDTD, + DEFAULTATTRS, + VALIDATE, + SUBST_ENTITIES + } + + [CCode (cname = "xmlParserSeverities", cprefix = "XML_PARSER_SEVERITY_", cheader_filename = "libxml/xmlreader.h", has_type_id = false)] + public enum ParserSeverities { + VALIDITY_WARNING, + VALIDITY_ERROR, + WARNING, + ERROR + } + + [CCode (cname = "xmlReaderTypes", cheader_filename = "libxml/xmlreader.h", has_type_id = false)] + public enum ReaderType { + NONE, + ELEMENT, + ATTRIBUTE, + TEXT, + CDATA, + ENTITY_REFERENCE, + ENTITY, + PROCESSING_INSTRUCTION, + COMMENT, + DOCUMENT, + DOCUMENT_TYPE, + DOCUMENT_FRAGMENT, + NOTATION, + WHITESPACE, + SIGNIFICANT_WHITESPACE, + END_ELEMENT, + END_ENTITY, + XML_DECLARATION + } + + [Compact] + [CCode (cname = "xmlTextReader", free_function = "xmlFreeTextReader", cheader_filename = "libxml/xmlreader.h")] + public class TextReader { + [CCode (cname = "xmlNewTextReaderFilename")] + public TextReader.filename (string uri); + + [CCode (cname = "xmlReaderForDoc")] + public TextReader.for_doc (string cur, string url, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReaderForFd")] + public TextReader.for_fd (int fd, string url, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReaderForFile")] + public TextReader.for_file (string filename, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReaderForIO")] + public TextReader.for_io (InputReadCallback ioread, InputCloseCallback ioclose, void* ioctx, string url, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReaderForMemory")] + public TextReader.for_memory ([CCode (array_length = false)] char[] buffer, int size, string url, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReaderNewDoc")] + public int new_doc (string cur, string url, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReaderNewFd")] + public int new_fd (int fd, string url, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReaderNewFile")] + public int new_file (string filename, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReaderNewIO")] + public int new_io (InputReadCallback ioread, InputCloseCallback ioclose, void* ioctx, string url, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReaderNewMemory")] + public int new_memory ([CCode (array_length = false)] char[] buffer, int size, string url, string? encoding = null, int options = 0); + + [CCode (cname = "xmlReaderNewWalker")] + public int new_walker (Doc* doc); + + [CCode (cname = "xmlReaderWalker")] + public TextReader.walker (Doc* doc); + + [CCode (cname = "xmlTextReaderAttributeCount")] + public int attribute_count (); + + [CCode (cname = "xmlTextReaderBaseUri")] + public string base_uri (); + + [CCode (cname = "xmlTextReaderByteConsumed")] + public long byte_consumed (); + + [CCode (cname = "xmlTextReaderClose")] + public int close (); + + [CCode (cname = "xmlTextReaderConstBaseUri")] + public unowned string const_base_uri (); + + [CCode (cname = "xmlTextReaderConstEncoding")] + public unowned string const_encoding (); + + [CCode (cname = "xmlTextReaderConstLocalName")] + public unowned string const_local_name (); + + [CCode (cname = "xmlTextReaderConstName")] + public unowned string const_name (); + + [CCode (cname = "xmlTextReaderConstNamespaceUri")] + public unowned string const_namespace_uri (); + + [CCode (cname = "xmlTextReaderConstPrefix")] + public unowned string const_prefix (); + + [CCode (cname = "xmlTextReaderConstString")] + public unowned string const_string (string str); + + [CCode (cname = "xmlTextReaderConstValue")] + public unowned string const_value (); + + [CCode (cname = "xmlTextReaderConstXmlLang")] + public unowned string const_xml_lang (); + + [CCode (cname = "xmlTextReaderConstXmlVersion")] + public unowned string const_xml_version (); + + [CCode (cname = "xmlTextReaderCurrentDoc")] + public Doc* current_doc (); + + [CCode (cname = "xmlTextReaderCurrentNode")] + public Node* current_node (); + + [CCode (cname = "xmlTextReaderDepth")] + public int depth (); + + [CCode (cname = "xmlTextReaderExpand")] + public Node* expand (); + + [CCode (cname = "xmlTextReaderGetAttribute")] + public string get_attribute (string name); + + [CCode (cname = "xmlTextReaderGetAttributeNo")] + public string get_attribute_no (int no); + + [CCode (cname = "xmlTextReaderGetAttributeNs")] + public string get_attribute_ns (string local_name, string namespace_uri); + + [CCode (cname = "xmlTextReaderGetErrorHandler")] + public void get_error_handler (out TextReaderErrorFunc f, void** arg); + + [CCode (cname = "xmlTextReaderGetParserColumnNumber")] + public int get_parser_column_number (); + + [CCode (cname = "xmlTextReaderGetParserLineNumber")] + public int get_parser_line_number (); + + [CCode (cname = "xmlTextReaderGetParserProp")] + public int get_parser_prop (int prop); + + [CCode (cname = "xmlTextReaderHasAttributes")] + public int has_attributes (); + + [CCode (cname = "xmlTextReaderHasValue")] + public int has_value (); + + [CCode (cname = "xmlTextReaderIsDefault")] + public int is_default (); + + [CCode (cname = "xmlTextReaderIsEmptyElement")] + public int is_empty_element (); + + [CCode (cname = "xmlTextReaderIsNamespaceDecl")] + public int is_namespace_decl (); + + [CCode (cname = "xmlTextReaderIsValid")] + public int is_valid (); + + [CCode (cname = "xmlTextReaderLocalName")] + public string local_name (); + + [CCode (cname = "xmlTextReaderLookupNamespace")] + public string lookup_namespace (string prefix); + + [CCode (cname = "xmlTextReaderMoveToAttribute")] + public int move_to_attribute (string name); + + [CCode (cname = "xmlTextReaderMoveToAttributeNo")] + public int move_to_attribute_no (int no); + + [CCode (cname = "xmlTextReaderMoveToAttributeNs")] + public int move_to_attribute_ns (string local_name, string namespace_uri); + + [CCode (cname = "xmlTextReaderMoveToElement")] + public int move_to_element (); + + [CCode (cname = "xmlTextReaderMoveToFirstAttribute")] + public int move_to_first_attribute (); + + [CCode (cname = "xmlTextReaderMoveToNextAttribute")] + public int move_to_next_attribute (); + + [CCode (cname = "xmlTextReaderName")] + public string name (); + + [CCode (cname = "xmlTextReaderNamespaceUri")] + public string namespace_uri (); + + [CCode (cname = "xmlTextReaderNext")] + public int next (); + + [CCode (cname = "xmlTextReaderNextSibling")] + public int next_sibling (); + + [CCode (cname = "xmlTextReaderNodeType")] + public int node_type (); + + [CCode (cname = "xmlTextReaderNormalization")] + public int normalization (); + + [CCode (cname = "xmlTextReaderPrefix")] + public string prefix (); + + [CCode (cname = "xmlTextReaderPreserve")] + public Node* preserve (); + + [CCode (cname = "xmlTextReaderPreservePattern")] + public int preserve_pattern (string pattern, [CCode (array_length = false)] string[] namespaces); + + [CCode (cname = "xmlTextReaderQuoteChar")] + public int quote_char (); + + [CCode (cname = "xmlTextReaderRead")] + public int read (); + + [CCode (cname = "xmlTextReaderReadAttributeValue")] + public int read_attribute_value (); + + [CCode (cname = "xmlTextReaderReadInnerXml")] + public string read_inner_xml (); + + [CCode (cname = "xmlTextReaderReadOuterXml")] + public string read_outer_xml (); + + [CCode (cname = "xmlTextReaderReadState")] + public int read_state (); + + [CCode (cname = "xmlTextReaderReadString")] + public string read_string (); + + [CCode (cname = "xmlTextReaderSchemaValidate")] + public int schema_validate (string xsd); + + [CCode (cname = "xmlTextReaderSchemaValidateCtxt")] + public int schema_validate_ctxt (SchemaValidCtxt* ctxt, int options); + + [CCode (cname = "xmlTextReaderSetErrorHandler")] + public void set_error_handler (TextReaderErrorFunc f, void* arg); + + [CCode (cname = "xmlTextReaderSetParserProp")] + public int set_parser_prop (SchemaValidCtxt* ctxt, int options); + + [CCode (cname = "xmlTextReaderStandalone")] + public int standalone (); + + [CCode (cname = "xmlTextReaderValue")] + public string value (); + + [CCode (cname = "xmlTextReaderXmlLang")] + public string xml_lang (); + } + + [Compact] + [CCode (cname = "void", cheader_filename = "libxml/xmlreader.h")] + public class TextReaderLocator { + } + + [CCode (cname = "xmlTextReaderMode", cprefix = "XML_TEXTREADER_MODE_", cheader_filename = "libxml/xmlreader.h", has_type_id = false)] + public enum TextReaderMode { + INITIAL, + INTERACTIVE, + ERROR, + EOF, + CLOSED, + READING + } + + [CCode (has_target = false)] + public delegate void TextReaderErrorFunc (void* arg, string msg, ParserSeverities severity, TextReaderLocator* locator); + + + /* xpath - XML Path Language implementation */ + + [CCode (cheader_filename = "libxml/xpath.h")] + namespace XPath { + [CCode (cname = "xmlXPathOrderDocElems")] + public static long order_doc_elements (Doc* doc); + + [Compact] + [CCode (cname = "xmlNodeSet", free_function="xmlXPathFreeNodeSet", cheader_filename = "libxml/xpath.h")] + public class NodeSet { + [CCode (cname = "xmlXPathNodeSetGetLength")] + public int length (); + + [CCode (cname = "xmlXPathNodeSetIsEmpty")] + public bool is_empty (); + + [CCode (cname = "xmlXPathNodeSetItem")] + public Node* item (int index); + } + + [Compact] + [CCode (cname = "xmlXPathContext", free_function = "xmlXPathFreeContext", cheader_filename = "libxml/xpath.h")] + public class Context { + public Doc* doc; + public Node* node; + + [CCode (cname = "xmlXPathContextSetCache")] + public int set_cache (int active, int value, int options); + + [CCode (cname = "xmlXPathEval", instance_pos = -1)] + public Object* eval (string str); + + [CCode (cname = "xmlXPathEvalExpression", instance_pos = -1)] + public Object* eval_expression (string str); + + [CCode (cname = "xmlXPathRegisterNs")] + public int register_ns (string prefix, string ns_uri); + + [CCode (cname = "xmlXPathNewContext")] + public Context (Doc* doc); + } + + [CCode (cname = "xmlXPathError", cprefix = "XPATH_", cheader_filename = "libxml/xpath.h", has_type_id = false)] + public enum Error { + EXPRESSION_OK, + NUMBER_ERROR, + UNFINISHED_LITERAL_ERROR, + START_LITERAL_ERROR, + VARIABLE_REF_ERROR, + UNDEF_VARIABLE_ERROR, + INVALID_PREDICATE_ERROR, + EXPR_ERROR, + UNCLOSED_ERROR, + UNKNOWN_FUNC_ERROR, + INVALID_OPERAND, + INVALID_TYPE, + INVALID_ARITY, + INVALID_CTXT_SIZE, + INVALID_CTXT_POSITION, + MEMORY_ERROR, + [CCode (cname = "XPTR_SYNTAX_ERROR")] + XPTR_SYNTAX_ERROR, + [CCode (cname = "XPTR_RESOURCE_ERROR")] + XPTR_RESOURCE_ERROR, + [CCode (cname = "XPTR_SUB_RESOURCE_ERROR")] + XPTR_SUB_RESOURCE_ERROR, + UNDEF_PREFIX_ERROR, + ENCODING_ERROR, + INVALID_CHAR_ERROR, + INVALID_CTXT + } + + [Compact] + [CCode (cname = "xmlXPathObject", free_function="xmlXPathFreeObject", cheader_filename = "libxml/xpath.h")] + public class Object { + public ObjectType type; + public NodeSet* nodesetval; + public int boolval; + public double floatval; + public string stringval; + public void* user; + public int index; + public void* user2; + public int index2; + } + + [CCode (cname = "xmlXPathObjectType", cprefix = "XPATH_", cheader_filename = "libxml/xpath.h", has_type_id = false)] + public enum ObjectType { + UNDEFINED, + NODESET, + BOOLEAN, + NUMBER, + STRING, + POINT, + RANGE, + LOCATIONSET, + USERS, + XSLT_TREE + } + } + + /* SAX CALLBACKS */ + + [CCode (cname = "attributeDeclSAXFunc", has_target = false)] + public delegate void attributeDeclSAXFunc (void* ctx, string elem, string fullname, int type, int def, string defaultValue, Enumeration* tree); + + [CCode (cname = "attributeSAXFunc", has_target = false)] + public delegate void attributeSAXFunc (void* ctx, string name, string value); + + [CCode (cname = "cdataBlockSAXFunc", has_target = false)] + public delegate void cdataBlockSAXFunc (void* ctx, string value, int len); + + [CCode (cname = "charactersSAXFunc", has_target = false)] + public delegate void charactersSAXFunc (void* ctx, string ch, int len); + + [CCode (cname = "commentsSAXFunc", has_target = false)] + public delegate void commentSAXFunc (void* ctx, string value); + + [CCode (cname = "elementDeclSAXFunc", has_target = false)] + public delegate void elementDeclSAXFunc (void* ctx, string name, int type, ElementContent content); + + [CCode (cname = "endDocumentSAXFunc", has_target = false)] + public delegate void endDocumentSAXFunc (void* ctx); + + [CCode (cname = "endElementNsSAX2Func", has_target = false)] + public delegate void endElementNsSAX2Func (void* ctx, string localname, string prefix, string URI); + + [CCode (cname = "endElementSAXFunc", has_target = false)] + public delegate void endElementSAXFunc (void* ctx, string name); + + [CCode (cname = "entityDeclSAXFunc", has_target = false)] + public delegate void entityDeclSAXFunc (void* ctx, string name, int type, string publicId, string systemId, string content); + + [CCode (cname = "errorSAXFunc", has_target = false)] + public delegate void errorSAXFunc (void* ctx, string msg, ...); + + [CCode (cname = "externalSubsetSAXFunc", has_target = false)] + public delegate void externalSubsetSAXFunc (void* ctx, string name, string ExternalID, string SystemID); + + [CCode (cname = "fatalErrorSAXFunc", has_target = false)] + public delegate void fatalErrorSAXFunc (void* ctx, string msg, ...); + + [CCode (cname = "getEntitySAXFunc", has_target = false)] + public delegate Entity* getEntitySAXFunc (void* ctx, string name); + + [CCode (cname = "getParameterEntitySAXFunc", has_target = false)] + public delegate Entity* getParameterEntitySAXFunc (void* ctx, string name); + + [CCode (cname = "hasExternalSubsetSAXFunc", has_target = false)] + public delegate int hasExternalSubsetSAXFunc (void* ctx); + + [CCode (cname = "hasInternalSubsetSAXFunc", has_target = false)] + public delegate int hasInternalSubsetSAXFunc (void* ctx); + + [CCode (cname = "ignorableWhitespaceSAXFunc", has_target = false)] + public delegate void ignorableWhitespaceSAXFunc (void* ctx, string ch, int len); + + [CCode (cname = "internalSubsetSAXFunc", has_target = false)] + public delegate void internalSubsetSAXFunc (void* ctx, string name, string ExternalID, string SystemID); + + [CCode (cname = "isStandaloneSAXFunc", has_target = false)] + public delegate int isStandaloneSAXFunc (void* ctx); + + [CCode (cname = "notationDeclSAXFunc", has_target = false)] + public delegate void notationDeclSAXFunc (void* ctx, string name, string publicId, string systemId); + + [CCode (cname = "processingInstructionSAXFunc", has_target = false)] + public delegate void processingInstructionSAXFunc (void* ctx, string target, string data); + + [CCode (cname = "referenceSAXFunc", has_target = false)] + public delegate void referenceSAXFunc (void* ctx, string name); + + // [CCode (cname = "resolveEntitySAXFunc", has_target = false)] + // public delegate ParserInput resolveEntitySAXFunc (void* ctx, string publicId, string systemId); + + // [CCode (cname = "setDocumentLocatorSAXFunc", has_target = false)] + // public delegate void setDocumentLocatorSAXFunc (void* ctx, SAXLocator loc); + + [CCode (cname = "startDocumentSAXFunc", has_target = false)] + public delegate void startDocumentSAXFunc (void* ctx); + + [CCode (cname = "startElementNsSAX2Func", has_target = false)] + public delegate void startElementNsSAX2Func (void* ctx, string localname, string prefix, string URI, int nb_namespaces, [CCode (array_length = false, array_null_terminated = true)] string[] namespaces, int nb_attributes, int nb_defaulted, [CCode (array_length = false)] string[] attributes); + + [CCode (cname = "startElementSAXFunc", has_target = false)] + public delegate void startElementSAXFunc (void* ctx, string name, [CCode (array_length = false, array_null_terminated = true)] string[] atts); + + [CCode (cname = "unparsedEntityDeclSAXFunc", has_target = false)] + public delegate void unparsedEntityDeclSAXFunc (void* ctx, string name, string publicId, string systemId, string notationName); + + [CCode (cname = "warningSAXFunc", has_target = false)] + public delegate void warningSAXFunc (void* ctx, string msg, ...); + + [CCode (cname ="xmlStructuredErrorFunc", has_target = false)] + public delegate void xmlStructuredErrorFunc (void* ctx, Error* error); + + [Compact] + [CCode (cname = "xmlSAXHandler", cheader_filename = "libxml/parser.h")] + public struct SAXHandler { + [CCode (cname = "internalSubset")] + public internalSubsetSAXFunc internalSubset; + [CCode (cname = "isStandalone")] + public isStandaloneSAXFunc is_standalone; + [CCode (cname = "hasInternalSubset")] + public hasInternalSubsetSAXFunc hasInternalSubset; + [CCode (cname = "hasExternalSubset")] + public hasExternalSubsetSAXFunc hasExternalSubset; + // public resolveEntitySAXFunc resolveEntity; + [CCode (cname = "getEntity")] + public getEntitySAXFunc getEntity; + [CCode (cname = "entityDecl")] + public entityDeclSAXFunc entityDecl; + [CCode (cname = "notationDecl")] + public notationDeclSAXFunc notationDecl; + [CCode (cname = "attributeDecl")] + public attributeDeclSAXFunc attributeDecl; + [CCode (cname = "elementDecl")] + public elementDeclSAXFunc elementDecl; + [CCode (cname = "unparsedEntityDecl")] + public unparsedEntityDeclSAXFunc unparsedEntityDecl; + // public setDocumentLocatorSAXFunc setDocumentLocator; + [CCode (cname = "startDocument")] + public startDocumentSAXFunc startDocument; + [CCode (cname = "endDocument")] + public endDocumentSAXFunc endDocument; + [CCode (cname = "startElement")] + public startElementSAXFunc startElement; + [CCode (cname = "endElement")] + public endElementSAXFunc endElement; + public referenceSAXFunc reference; + public charactersSAXFunc characters; + [CCode (cname = "ignorableWhitespace")] + public ignorableWhitespaceSAXFunc ignorableWhitespace; + [CCode (cname = "processingInstruction")] + public processingInstructionSAXFunc processingInstruction; + public commentSAXFunc comment; + public warningSAXFunc warning; + public errorSAXFunc error; + [CCode (cname = "fatalError")] + public fatalErrorSAXFunc fatalError; + [CCode (cname = "getParameterEntity")] + public getParameterEntitySAXFunc getParameterEntity; + [CCode (cname = "cdataBlock")] + public cdataBlockSAXFunc cdataBlock; + [CCode (cname = "externalSubset")] + public externalSubsetSAXFunc externalSubset; + public uint initialized; + [CCode (cname = "startElementNs")] + public startElementNsSAX2Func startElementNs; + [CCode (cname = "endElementNs")] + public endElementNsSAX2Func endElementNs; + public xmlStructuredErrorFunc serror; + + [CCode (cname = "xmlSAXUserParseMemory")] + public int user_parse_memory (void* user_data, string buffer, int size); + [CCode (cname = "xmlSAXUserParseFile")] + public int user_parse_file (void* user_data, string filename); + } + + + /* xmlerror - error handling */ + + [Compact] + [CCode (cname = "xmlError", cheader_filename = "libxml/xmlerror.h")] + public struct Error { + public int domain; + public int code; + public string message; + public ErrorLevel level; + public string file; + public int line; + public string str1; + public string str2; + public string str3; + public int int1; + public int int2; + public void* ctx; + public void* node; + } + + [CCode (cname = "xmlErrorLevel", cprefix = "XML_ERR_", cheader_filename = "libxml/xmlerror.h", has_type_id = false)] + public enum ErrorLevel { + NONE = 0, + WARNING = 1, + ERROR = 2, + FATAL = 3 + } + +} + +namespace Html { + [CCode (cname = "htmlIsBooleanAttr", cheader_filename = "libxml/HTMLtree.h")] + public static int is_boolean_attr (string name); + + [CCode (cname = "UTF8ToHtml", cheader_filename = "libxml/HTMLparser.h")] + public static int utf8_to_html ([CCode (array_length = false)] char[] outdata, out int outlen, [CCode (array_length = false)] char[] indata, out int inlen); + + [CCode (cname = "htmlEncodeEntities", cheader_filename = "libxml/HTMLparser.h")] + public static int encode_entities ([CCode (array_length = false)] char[] outdata, out int outlen, [CCode (array_length = false)] char[] indata, out int inlen, char quote_char = '\0'); + + [CCode (cname = "htmlIsScriptAttribute", cheader_filename = "libxml/HTMLparser.h")] + public static bool is_script_attribute (string name); + + [CCode (cname = "htmlHandleOmittedElem", cheader_filename = "libxml/HTMLparser.h")] + public static bool handle_omitted_elem (bool val); + + [CCode (cname = "htmlParserOption", cprefix = "HTML_PARSE_", cheader_filename = "libxml/HTMLparser.h", has_type_id = false)] + public enum ParserOption { + RECOVER, + NOERROR, + NOWARNING, + PEDANTIC, + NOBLANKS, + NONET, + COMPACT, + } + + [CCode (cname = "htmlStatus", cprefix = "HTML_", cheader_filename = "libxml/HTMLparser.h", has_type_id = false)] + public enum Status { + NA, + INVALID, + DEPRECATED, + VALID, + REQUIRED, + } + + [Compact] + [CCode (cname = "xmlNode", cheader_filename = "libxml/HTMLparser.h")] + public class Node : Xml.Node { + [CCode (cname = "htmlNodeStatus")] + public Status status (bool legacy); + } + + [Compact] + [CCode (cname = "xmlDoc", cheader_filename = "libxml/HTMLtree.h,libxml/HTMLparser.h")] + public class Doc : Xml.Doc { + [CCode (cname = "htmlNewDoc")] + public Doc (string? uri = null, string? external_id = null); + + [CCode (cname = "htmlNewNoDtD")] + public Doc.new_no_dtd (string? uri = null, string? external_id = null); + + [CCode (cname = "htmlSAXParseDoc")] + public static Doc* sax_parse_doc (string cur, string? encoding, Xml.SAXHandler* sax, void* user_data = null); + + [CCode (cname = "htmlSAXParseFile")] + public static Doc* sax_parse_file (string filename, string? encoding, Xml.SAXHandler* sax, void* user_data = null); + + [CCode (cname = "htmlParseFile")] + public static Doc* parse_file (string filename, string? encoding); + + [CCode (cname = "htmlReadDoc")] + public static Doc* read_doc (string cur, string url, string? encoding = null, int options = 0); + + [CCode (cname = "htmlReadMemory")] + public static Doc* read_memory ([CCode (array_length = false)] char[] buffer, int size, string url, string? encoding = null, int options = 0); + + [CCode (cname = "htmlReadFd")] + public static Doc* read_fd (int fd, string url, string? encoding = null, int options = 0); + + [CCode (cname = "htmlReadIO")] + public static Doc* read_io (Xml.InputReadCallback ioread, Xml.InputCloseCallback ioclose, void* ioctx, string url, string? encoding = null, int options = 0); + + [CCode (cname = "htmlGetMetaEncoding")] + public string get_meta_encoding (); + + [CCode (cname = "htmlSetMetaEncoding")] + public int set_meta_encoding (string encoding); + + [CCode (cname = "htmlDocDumpMemory")] + public void dump_memory (out string mem, out int len = null); + + [CCode (cname = "htmlDocDumpMemoryFormat")] + public void dump_memory_format (out string mem, out int len = null, bool format = true); + + [CCode (cname = "htmlDocDump", instance_pos = -1)] + public int dump (GLib.FileStream f); + + [CCode (cname = "htmlSaveFile", instance_pos = -1)] + public int save_file (string filename); + + [CCode (cname = "htmlNodeDumpFile", instance_pos = 1.1)] + public int node_dump_file (GLib.FileStream file, Xml.Node* node); + + [CCode (cname = "htmlNodeDumpFileFormat", instance_pos = 1.1)] + public int node_dump_file_format (GLib.FileStream file, string enc = "UTF-8", bool format = true); + + [CCode (cname = "htmlSaveFileEnc", instance_pos = 1.1)] + public int save_file_enc (string filename, string enc = "UTF-8"); + + [CCode (cname = "htmlSaveFileFormat", instance_pos = 1.1)] + public int save_file_format (string filename, string enc = "UTF-8", bool format = true); + + [CCode (cname = "htmlIsAutoClosed")] + public bool is_auto_closed (Node* elem); + + [CCode (cname = "htmlAutoCloseTag")] + public bool auto_close_tag (string name, Node* elem); + } + + [Compact] + [CCode (cname = "htmlElemDesc", cheader_filename = "libxml/HTMLparser.h")] + public class ElemDesc { + public weak string name; + [CCode (cname = "startTag")] + public bool start_tag; + [CCode (cname = "endTag")] + public bool end_tag; + [CCode (cname = "saveEndTag")] + public bool save_end_tag; + public bool empty; + public bool depr; + public char dtd; + public bool isinline; + public weak string desc; + public weak string[] subelts; + public weak string defaultsubelt; + public weak string[] attrs_opt; + public weak string[] attrs_depr; + public weak string[] attrs_req; + + [CCode (cname = "htmlTagLookup")] + public static ElemDesc* tag_lookup (string tag); + + [CCode (cname = "htmlAttrAllowed")] + public Status attr_allowed (string attr, bool legacy); + + [CCode (cname = "htmlElementAllowedHere")] + public bool allowed_here (string elt); + + [CCode (cname = "htmlElementAllowedHereDesc")] + public bool allowed_here_desc (ElemDesc* child); + + [CCode (cname = "htmlElementStatusHere")] + public Status status_here (ElemDesc* child); + + [Ccode (cname = "htmlDefaultSubelement")] + public unowned string default_subelement (); + + [Ccode (cname = "htmlRequiredAttrs")] + public unowned string[] required_attrs (); + } + + [Compact] + [CCode (cname = "htmlEntityDesc", cheader_filename = "libxml/HTMLParser.h")] + public class EntityDesc + { + public uint value; + public weak string name; + public weak string desc; + + [CCode (cname = "htmlEntityDesc")] + public static EntityDesc* lookup (string name); + + [CCode (cname = "htmlEntityValueDesc")] + public static EntityDesc* value_lookup (uint value); + } + + [Compact] + [CCode (cname = "htmlParserCtxt", free_function = "htmlFreeParserCtxt", cheader_filename = "libxml/HTMLparser.h")] + public class ParserCtxt : Xml.ParserCtxt { + [CCode (cname = "htmlNewParserCtxt")] + public ParserCtxt (); + + [CCode (cname = "htmlCreateMemoryParserCtxt")] + public ParserCtxt.create_memory ([CCode (array_length = false)] char[] buffer, int size); + + [CCode (cname = "htmlCreatePushParserCtxt")] + public ParserCtxt.create_push (Xml.SAXHandler* sax, void* user_data, [CCode (array_length = false)] char[] data, int len, string? filename = null, Xml.CharEncoding enc = Xml.CharEncoding.NONE); + + [CCode (cname = "htmlParseChunk")] + public int parse_chunk ([CCode (array_length = false)] char[] data, int size, bool terminate); + + [CCode (cname = "htmlParseEntityRef")] + public EntityDesc* parse_entity_ref (out string entity_name); + + [CCode (cname = "htmlParseCharRef")] + public int parse_char_ref (); + + [CCode (cname = "htmlParseElement")] + public void parse_element (); + + [CCode (cname = "htmlParseDocument")] + public int parse_document (); + + [CCode (cname = "htmlCtxtReset")] + public void reset (); + + [CCode (cname = "htmlCtxtUseOptions")] + public int use_options (int options); + + [CCode (cname = "htmlCtxtReadDoc")] + public Doc* read_doc (string cur, string url, string? encoding = null, int options = 0); + + [CCode (cname = "htmlCtxtReadFile")] + public Doc* read_file (string filename, string? encoding = null, int options = 0); + + [CCode (cname = "htmlCtxtReadMemory")] + public Doc* read_memory ([CCode (array_length = false)] char[] buffer, int size, string url, string? encoding = null, int options = 0); + + [CCode (cname = "htmlCtxtReadFd")] + public Doc* read_fd (int fd, string url, string? encoding = null, int options = 0); + + [CCode (cname = "htmlCtxtReadIO")] + public Doc* read_io (Xml.InputReadCallback ioread, Xml.InputCloseCallback ioclose, void* ioctx, string url, string? encoding = null, int options = 0); + } +} diff --git a/wixl/Makefile.am b/wixl/Makefile.am new file mode 100644 index 0000000..8e1bfa7 --- /dev/null +++ b/wixl/Makefile.am @@ -0,0 +1,46 @@ +NULL = +bin_PROGRAMS = wixl + +AM_CFLAGS = -w + +# --vapidir paths are relative to the source directory! + +AM_VALAFLAGS = \ + -H wixl.h --use-header \ + --vapidir=. \ + --vapidir=../vapi \ + --vapidir=$(abs_top_builddir)/libmsi \ + --pkg config \ + --enable-experimental \ + --pkg gio-2.0 \ + --pkg libmsi-1.0 \ + --pkg libgcab-1.0 \ + --pkg libxml-2.0 \ + --pkg posix \ + $(NULL) + +wixl_SOURCES = \ + builder.vala \ + msi.vala \ + preprocessor.vala \ + util.vala \ + wix.vala \ + wixl.vala \ + $(NULL) + +AM_CPPFLAGS = \ + -include config.h \ + -I $(top_srcdir)/include \ + $(WIXL_CFLAGS) \ + -DG_LOG_DOMAIN=\""wixl"\" \ + -DLOCALEDIR=\""$(localedir)"\" \ + -DPKGDATADIR=\""$(pkgdatadir)"\" \ + -DPKGLIBDIR=\""$(pkglibdir)"\" \ + $(NULL) + +wixl_LDADD = \ + $(WIXL_LIBS) \ + ../libmsi/libmsi.la \ + $(NULL) + +wixl_DEPENDENCIES = ../libmsi/libmsi.la diff --git a/wixl/builder.vala b/wixl/builder.vala new file mode 100644 index 0000000..80c2ff6 --- /dev/null +++ b/wixl/builder.vala @@ -0,0 +1,590 @@ +namespace Wixl { + + class WixBuilder: WixNodeVisitor { + + public WixBuilder () { + add_path ("."); + } + + WixRoot root; + MsiDatabase db; + HashTable<string, string> variables; + + construct { + variables = new HashTable<string, string> (str_hash, str_equal); + } + + public void define_variable (string name, string value) { + variables.insert (name, value); + } + + List<File> path; + public void add_path (string p) { + var file = File.new_for_path (p); + path.append (file); + } + + List<WixRoot> roots; + public void load_doc (Xml.Doc doc) throws GLib.Error { + for (var child = doc.children; child != null; child = child->next) { + switch (child->type) { + case Xml.ElementType.ELEMENT_NODE: + if (child->name != "Wix") + warning ("unhandled node %s", child->name); + var root = new WixRoot (); + root.load (child); + roots.append (root); + break; + } + } + } + + public void load_file (File file, bool preproc_only = false) throws GLib.Error { + string data; + FileUtils.get_contents (file.get_path (), out data); + + var p = new Preprocessor (variables); + var doc = p.preprocess (data, file); + if (preproc_only) { + doc.dump_format (FileStream.fdopen (1, "w")); + return; + } + + load_doc (doc); + } + + public G? find_element<G> (string Id) { + foreach (var r in roots) { + var e = r.find_element<G> (Id); + if (e != null) + return e; + } + + return null; + } + + public G[] get_elements<G> () { + G[] elems = {}; + foreach (var r in roots) + elems = r.add_elements<G> (elems); + + return elems; + } + + delegate void AddSequence (string action, int sequence) throws GLib.Error; + + private void sequence_actions () throws GLib.Error { + MsiTableSequence? table = null; + AddSequence add = (action, sequence) => { + var seq = table.get_action (action); + seq.sequence = sequence; + }; + + // AdminExecuteSequence + table = db.table_admin_execute_sequence; + add ("CostInitialize", 800); + add ("FileCost", 900); + add ("CostFinalize", 1000); + add ("InstallValidate", 1400); + add ("InstallInitialize", 1500); + add ("InstallAdminPackage", 3900); + add ("InstallFiles", 4000); + add ("InstallFinalize", 6600); + table.add_sorted_actions (); + + // AdminUISequence + table = db.table_admin_ui_sequence; + add ("CostInitialize", 800); + add ("FileCost", 900); + add ("CostFinalize", 1000); + add ("ExecuteAction", 1300); + table.add_sorted_actions (); + + table = db.table_advt_execute_sequence; + add ("CostInitialize", 800); + add ("CostFinalize", 1000); + add ("InstallValidate", 1400); + add ("InstallInitialize", 1500); + if (db.table_shortcut.records.length () > 0) + add ("CreateShortcuts", 4500); + add ("PublishFeatures", 6300); + add ("PublishProduct", 6400); + add ("InstallFinalize", 6600); + table.add_sorted_actions (); + + // InstallExecuteSequence + table = db.table_install_execute_sequence; + if (db.table_upgrade.records.length () > 0) + add ("FindRelatedProducts", 25); + if (db.table_launch_condition.records.length () > 0) + add ("LaunchConditions", 100); + add ("ValidateProductID", 700); + add ("CostInitialize", 800); + add ("FileCost", 900); + add ("CostFinalize", 1000); + add ("InstallValidate", 1400); + add ("InstallInitialize", 1500); + add ("ProcessComponents", 1600); + add ("UnpublishFeatures", 1800); + if (db.table_registry.records.length () > 0) + add ("RemoveRegistryValues", 2600); + if (db.table_shortcut.records.length () > 0) + add ("RemoveShortcuts", 3200); + if (db.table_file.records.length () > 0 || + db.table_remove_file.records.length () > 0) + add ("RemoveFiles", 3500); + if (db.table_file.records.length () > 0) + add ("InstallFiles", 4000); + if (db.table_shortcut.records.length () > 0) + add ("CreateShortcuts", 4500); + if (db.table_registry.records.length () > 0) + add ("WriteRegistryValues", 5000); + add ("RegisterUser", 6000); + add ("RegisterProduct", 6100); + add ("PublishFeatures", 6300); + add ("PublishProduct", 6400); + add ("InstallFinalize", 6600); + table.add_sorted_actions (); + + table = db.table_install_ui_sequence; + if (db.table_upgrade.records.length () > 0) + add ("FindRelatedProducts", 25); + if (db.table_launch_condition.records.length () > 0) + add ("LaunchConditions", 100); + add ("ValidateProductID", 700); + add ("CostInitialize", 800); + add ("FileCost", 900); + add ("CostFinalize", 1000); + add ("ExecuteAction", 1300); + table.add_sorted_actions (); + } + + private void build_cabinet () throws GLib.Error { + var sequence = 0; + var medias = get_elements<WixMedia> (); + var files = get_elements<WixFile> (); + + foreach (var m in medias) { + var folder = new GCab.Folder (GCab.Compression.MSZIP); + + foreach (var f in files) { + if (f.DiskId != m.Id) + continue; + + folder.add_file (new GCab.File.with_file (f.Id, f.file), false); + var rec = f.record; + sequence += 1; + MsiTableFile.set_sequence (rec, sequence); + } + + var cab = new GCab.Cabinet (); + cab.add_folder (folder); + var output = new MemoryOutputStream (null, realloc, free); + cab.write (output, null, null, null); + var input = new MemoryInputStream.from_data (output.get_data ()[0:output.data_size], null); + if (parse_yesno (m.EmbedCab)) + db.table_streams.add (m.Cabinet, input, output.data_size); + + db.table_media.set_last_sequence (m.record, sequence); + } + } + + private void shortcut_target () throws GLib.Error { + var shortcuts = get_elements<WixShortcut> (); + + foreach (var sc in shortcuts) { + var component = sc.get_component (); + var feature = component.in_feature.first ().data; + MsiTableShortcut.set_target (sc.record, feature.Id); + } + } + + string[] secureProperties; + + public void property_update () throws GLib.Error { + if (secureProperties.length != 0) { + var prop = string.joinv (";", secureProperties); + db.table_property.add ("SecureCustomProperties", prop); + } + } + + public MsiDatabase build () throws GLib.Error { + db = new MsiDatabase (); + + foreach (var r in roots) { + root = r; + root.accept (this); + } + root = null; + + property_update (); + shortcut_target (); + sequence_actions (); + build_cabinet (); + + return db; + } + + public override void visit_product (WixProduct product) throws GLib.Error { + if (product.Codepage != null) + db.info.set_codepage (int.parse (product.Codepage)); + + if (product.Name != null) + db.info.set_subject (product.Name); + + db.info.set_author (product.Manufacturer); + + db.table_property.add ("Manufacturer", product.Manufacturer); + db.table_property.add ("ProductLanguage", product.Language); + db.table_property.add ("ProductCode", get_uuid (product.Id)); + db.table_property.add ("ProductName", product.Name); + db.table_property.add ("ProductVersion", product.Version); + db.table_property.add ("UpgradeCode", add_braces (product.UpgradeCode)); + } + + public override void visit_package (WixPackage package) throws GLib.Error { + db.info.set_comments (package.Comments); + + if (package.Description != null) + db.info.set_subject (package.Description); + + if (package.Keywords != null) + db.info.set_keywords (package.Keywords); + + if (package.InstallerVersion != null) + db.info.set_property (Libmsi.Property.VERSION, int.parse (package.InstallerVersion)); + + } + + public override void visit_icon (WixIcon icon) throws GLib.Error { + FileInfo info; + + icon.file = find_file (icon.SourceFile, out info); + db.table_icon.add (icon.Id, icon.file.get_path ()); + } + + public override void visit_property (WixProperty prop) throws GLib.Error { + db.table_property.add (prop.Id, prop.Value); + } + + public override void visit_media (WixMedia media) throws GLib.Error { + var cabinet = media.Cabinet; + + if (parse_yesno (media.EmbedCab)) + cabinet = "#" + cabinet; + + var rec = db.table_media.add (media.Id, media.DiskPrompt, cabinet); + media.record = rec; + } + + public override void visit_directory (WixDirectory dir) throws GLib.Error { + var defaultdir = dir.Name ?? "."; + + if (dir.parent.get_type () == typeof (WixProduct)) { + if (dir.Id != "TARGETDIR") + throw new Wixl.Error.FAILED ("Invalid root directory"); + db.table_directory.add (dir.Id, null, defaultdir); + } else if (dir.parent.get_type () == typeof (WixDirectory)) { + var parent = dir.parent as WixDirectory; + db.table_directory.add (dir.Id, parent.Id, defaultdir); + } else + warning ("unhandled parent type %s", dir.parent.name); + } + + [Flags] + enum ComponentAttribute { + LOCAL_ONLY = 0, + SOURCE_ONLY, + OPTIONAL, + REGISTRY_KEY_PATH, + SHARED_DLL_REF_COUNT, + PERMANENT, + ODBC_DATA_SOURCE, + TRANSITIVE, + NEVER_OVERWRITE, + 64BIT, + REGISTRY_REFLECTION, + UNINSTALL_ON_SUPERSEDENCE, + SHARED, + } + + G? resolve<G> (WixElement element) throws GLib.Error { + if (element.get_type () == typeof (G)) + return element; + else if (element is WixElementRef) { + var ref = element as WixElementRef<G>; + if (ref.ref_type != typeof (G)) + return null; + if (ref.resolved != null) + return ref.resolved; + ref.resolved = find_element<G> (element.Id); + return ref.resolved; + } + + throw new Wixl.Error.FAILED ("couldn't resolve %s", element.Id); + } + + public override void visit_component (WixComponent comp) throws GLib.Error { + var attr = 0; + + if (comp.key is WixRegistryValue) + attr |= ComponentAttribute.REGISTRY_KEY_PATH; + + var parent = resolve<WixDirectory> (comp.parent); + db.table_component.add (comp.Id, add_braces (comp.Guid), parent.Id, attr, + comp.key != null ? comp.key.Id : null); + + } + + enum FeatureDisplay { + HIDDEN = 0, + EXPAND, + COLLAPSE + } + WixFeature? feature_root; + int feature_display; + + public override void visit_feature (WixFeature feature, VisitState state) throws GLib.Error { + if (state == VisitState.ENTER && feature_root == null) { + feature_display = 0; + feature_root = feature; + } else if (state == VisitState.LEAVE && feature_root == feature) { + feature_root = null; + } + + if (state != VisitState.ENTER) + return; + + int display = FeatureDisplay.COLLAPSE; + if (feature.Display != null) { + try { + display = enum_from_string (typeof (FeatureDisplay), feature.Display); + } catch (GLib.Error error) { + display = int.parse (feature.Display); + if (display != 0) + feature_display = display; + } + } + + switch (display) { + case FeatureDisplay.COLLAPSE: + display = feature_display = (feature_display | 1) + 1; + break; + case FeatureDisplay.EXPAND: + display = feature_display = (feature_display + 1) | 1; + break; + } + + string? parent = (feature.parent is WixFeature) ? feature.parent.Id : null; + + db.table_feature.add (feature.Id, display, int.parse (feature.Level), 0, parent, feature.Title, feature.Description, feature.ConfigurableDirectory); + + } + + public override void visit_component_ref (WixComponentRef ref) throws GLib.Error { + if (ref.parent is WixFeature) { + var feature = ref.parent as WixFeature; + + var component = resolve<WixComponent> (@ref); + component.in_feature.append (feature); + db.table_feature_components.add (feature.Id, @ref.Id); + } else + warning ("unhandled parent type %s", @ref.parent.name); + } + + enum RemoveFileInstallMode { + INSTALL = 1, + UNINSTALL, + BOTH + } + + public override void visit_remove_folder (WixRemoveFolder rm) throws GLib.Error { + var on = enum_from_string (typeof (RemoveFileInstallMode), rm.On); + var comp = rm.parent as WixComponent; + var dir = comp.parent as WixDirectory; + + db.table_remove_file.add (rm.Id, comp.Id, dir.Id, on); + } + + void visit_key_element (WixKeyElement key) throws GLib.Error { + var component = key.parent as WixComponent; + + if (component.key == null || parse_yesno (key.KeyPath)) + component.key = key; + } + + enum RegistryValueType { + STRING, + INTEGER, + BINARY, + EXPANDABLE, + MULTI_STRING + } + + enum RegistryRoot { + HKCR, + HKCU, + HKLM, + HKU, + HKMU + } + + public override void visit_registry_value (WixRegistryValue reg) throws GLib.Error { + var comp = reg.parent as WixComponent; + var value = reg.Value; + var t = enum_from_string (typeof (RegistryValueType), reg.Type); + var r = enum_from_string (typeof (RegistryRoot), reg.Root.down ()); + if (reg.Id == null) { + reg.Id = generate_id ("reg", 4, + comp.Id, + reg.Root, + reg.Key != null ? reg.Key.down () : null, + reg.Name != null ? reg.Name.down () : null); + } + + switch (t) { + case RegistryValueType.STRING: + value = value[0] == '#' ? "#" + value : value; + break; + } + + db.table_registry.add (reg.Id, r, reg.Key, comp.Id); + + visit_key_element (reg); + } + + [Flags] + enum FileAttribute { + READ_ONLY = 1 << 0, + HIDDEN = 1 << 1, + SYSTEM = 1 << 2, + VITAL = 1 << 9, + CHECKSUM = 1 << 10, + PATCH_ADDED = 1 << 11, + NON_COMPRESSED = 1 << 12, + COMPRESSED = 1 << 13 + } + + File? find_file (string name, out FileInfo info) throws GLib.Error { + info = null; + + foreach (var p in path) { + var file = p.get_child (name); + try { + info = file.query_info ("standard::*", 0, null); + if (info != null) + return file; + } catch (IOError error) { + if (error is IOError.NOT_FOUND) + continue; + throw error; + } + } + + throw new Wixl.Error.FAILED ("Couldn't find file %s", name); + } + + public override void visit_file (WixFile file) throws GLib.Error { + file.DiskId = file.DiskId ?? "1"; + return_if_fail (file.DiskId == "1"); + + var name = file.Id; + if (file.Name != null) + name = file.Name; + else if (file.Source != null) + name = Path.get_basename (file.Source); + + var comp = file.parent as WixComponent; + FileInfo info; + file.file = find_file (name, out info); + var attr = FileAttribute.VITAL; + + var rec = db.table_file.add (file.Id, comp.Id, name, (int)info.get_size (), attr); + file.record = rec; + + visit_key_element (file); + } + + public override void visit_shortcut (WixShortcut shortcut) throws GLib.Error { + if (!parse_yesno (shortcut.Advertise)) + throw new Wixl.Error.FIXME ("unimplemented"); + + var component = shortcut.get_component (); + var rec = db.table_shortcut.add (shortcut.Id, shortcut.Directory, shortcut.Name, component.Id); + shortcut.record = rec; + + if (shortcut.Icon != null) + MsiTableShortcut.set_icon (rec, shortcut.Icon, int.parse (shortcut.IconIndex)); + if (shortcut.WorkingDirectory != null) + MsiTableShortcut.set_working_dir (rec, shortcut.WorkingDirectory); + } + + public override void visit_sequence (WixSequence sequence) throws GLib.Error { + } + + public override void visit_condition (WixCondition condition) throws GLib.Error { + return_if_fail (condition.children.length () == 1); + var text = condition.children.first ().data as WixText; + + db.table_launch_condition.add (text.Text, condition.Message); + } + + [Flags] + enum UpgradeAttribute { + MIGRATE_FEATURES = 1 << 0, + ONLY_DETECT = 1 << 1, + IGNORE_REMOVE_FAILURE = 1 << 2, + VERSION_MIN_INCLUSIVE = 1 << 8, + VERSION_MAX_INCLUSIVE = 1 << 9, + LANGUAGES_EXCLUSIVE = 1 << 10 + } + + public override void visit_upgrade (WixUpgrade upgrade) throws GLib.Error { + } + + public override void visit_upgrade_version (WixUpgradeVersion version) throws GLib.Error { + var upgrade = version.parent as WixUpgrade; + UpgradeAttribute attributes = 0; + + if (parse_yesno (version.OnlyDetect)) + attributes |= UpgradeAttribute.ONLY_DETECT; + + if (parse_yesno (version.IncludeMinimum, true)) + attributes |= UpgradeAttribute.VERSION_MIN_INCLUSIVE; + + db.table_upgrade.add (get_uuid (upgrade.Id), version.Minimum, version.Maximum, attributes, version.Property); + + secureProperties += version.Property; + } + + public override void visit_action (WixAction action) throws GLib.Error { + var parent = action.parent as WixSequence; + var table = db.tables.lookup (parent.name) as MsiTableSequence; + + var node = table.get_action (action.name); + warn_if_fail (node.action == null); + node.action = action; + + if (action.After != null) + node.add_dep (table.get_action (action.After)); + + if (action.Before != null) { + var before = table.get_action (action.Before); + before.add_dep (node); + } + } + + public override void visit_create_folder (WixCreateFolder folder) throws GLib.Error { + } + + public override void visit_fragment (WixFragment fragment) throws GLib.Error { + } + + public override void visit_directory_ref (WixDirectoryRef ref) throws GLib.Error { + } + + public override void visit_text (WixText text) throws GLib.Error { + } + } + +} // Wixl diff --git a/wixl/config.vapi b/wixl/config.vapi new file mode 100644 index 0000000..96bf752 --- /dev/null +++ b/wixl/config.vapi @@ -0,0 +1,12 @@ +[CCode (prefix = "", lower_case_cprefix = "", cheader_filename = "config.h")] +namespace Config +{ + public const string PACKAGE_NAME; + public const string PACKAGE_STRING; + public const string PACKAGE_VERSION; + public const string GETTEXT_PACKAGE; + + public const string LOCALEDIR; + public const string PKGDATADIR; + public const string PKGLIBDIR; +} diff --git a/wixl/msi.vala b/wixl/msi.vala new file mode 100644 index 0000000..b8700b0 --- /dev/null +++ b/wixl/msi.vala @@ -0,0 +1,642 @@ +namespace Wixl { + + abstract class MsiTable: Object { + public class string name; + public List<Libmsi.Record> records; + + public class string sql_create; + public class string sql_insert; + + public virtual void create (Libmsi.Database db) throws GLib.Error { + var query = new Libmsi.Query (db, sql_create); + query.execute (null); + + if (sql_insert == null) + return; + + query = new Libmsi.Query (db, sql_insert); + foreach (var r in records) + query.execute (r); + } + } + + class MsiTableIcon: MsiTable { + static construct { + name = "Icon"; + sql_create = "CREATE TABLE `Icon` (`Name` CHAR(72) NOT NULL, `Data` OBJECT NOT NULL PRIMARY KEY `Name`)"; + sql_insert = "INSERT INTO `Icon` (`Name`, `Data`) VALUES (?, ?)"; + } + + public void add (string id, string filename) throws GLib.Error { + var rec = new Libmsi.Record (2); + + if (!rec.set_string (1, id) || + !rec.load_stream (2, filename)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + } + + abstract class MsiTableSequence: MsiTable { + private void add (string action, int sequence) throws GLib.Error { + var rec = new Libmsi.Record (2); + + if (!rec.set_string (1, action) || + !rec.set_int (2, sequence)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + + protected class void set_sequence_table_name (string table) { + name = table; + sql_create = "CREATE TABLE `%s` (`Action` CHAR(72) NOT NULL, `Condition` CHAR(255), `Sequence` INT PRIMARY KEY `Action`)".printf (table); + sql_insert = "INSERT INTO `%s` (`Action`, `Sequence`) VALUES (?, ?)".printf (table); + } + + public class Action { + public string name; + public int sequence = -1; + public WixAction? action; + + public bool visited = false; + public bool incoming_deps = false; + + // Use it as a set, so value is not refcounted please vala + public HashTable<Action, Action*> depends_on = new HashTable<Action, Action*> (direct_hash, direct_equal); + + public void add_dep (Action a) { + depends_on.add (a); + a.incoming_deps = true; + } + } + + HashTable<string, Action> actions = new HashTable<string, Action> (str_hash, str_equal); + + + void sort_topological_visit (Action action, ref List<Action> sorted) { + if (action.visited) + return; + + action.visited = true; + + Action dep; + var it = HashTableIter <Action, Action*> (action.depends_on); + while (it.next (null, out dep)) + sort_topological_visit (dep, ref sorted); + + sorted.append (action); + } + + List<Action> sort_topological () { + List<Action> sorted = null; + + Action action; + var it = HashTableIter <string, Action> (actions); + while (it.next (null, out action)) { + if (action.incoming_deps) + continue; + sort_topological_visit (action, ref sorted); + } + + return sorted; + } + + void add_implicit_deps () { + CompareFunc<Action> cmp = (a, b) => { + return a.sequence - b.sequence; + }; + var list = actions.get_values (); + list.sort (cmp); + + Action? prev = null; + foreach (var a in list) { + if (a.sequence == -1) + continue; + if (prev != null) + a.add_dep (prev); + prev = a; + } + } + + public void add_sorted_actions () throws GLib.Error { + add_implicit_deps (); + var sorted = sort_topological (); + + int sequence = 0; + foreach (var action in sorted) { + if (action.sequence == -1) + action.sequence = ++sequence; + + sequence = action.sequence; + add (action.name, action.sequence); + } + } + + public Action get_action (string name) { + var action = actions.lookup (name); + if (action != null) + return action; + + action = new Action (); + actions.insert (name, action); + action.name = name; + + return action; + } + } + + class MsiTableAdminExecuteSequence: MsiTableSequence { + static construct { + set_sequence_table_name ("AdminExecuteSequence"); + } + } + + class MsiTableAdminUISequence: MsiTableSequence { + static construct { + set_sequence_table_name ("AdminUISequence"); + } + } + + class MsiTableAdvtExecuteSequence: MsiTableSequence { + static construct { + set_sequence_table_name ("AdvtExecuteSequence"); + } + } + + class MsiTableInstallExecuteSequence: MsiTableSequence { + static construct { + set_sequence_table_name ("InstallExecuteSequence"); + } + } + + class MsiTableInstallUISequence: MsiTableSequence { + static construct { + set_sequence_table_name ("InstallUISequence"); + } + } + + class MsiTableError: MsiTable { + static construct { + name = "Error"; + sql_create = "CREATE TABLE `Error` (`Error` INT NOT NULL, `Message` CHAR(0) LOCALIZABLE PRIMARY KEY `Error`)"; + } + } + + class MsiTableFile: MsiTable { + static construct { + name = "File"; + sql_create = "CREATE TABLE `File` (`File` CHAR(72) NOT NULL, `Component_` CHAR(72) NOT NULL, `FileName` CHAR(255) NOT NULL LOCALIZABLE, `FileSize` LONG NOT NULL, `Version` CHAR(72), `Language` CHAR(20), `Attributes` INT, `Sequence` LONG NOT NULL PRIMARY KEY `File`)"; + sql_insert = "INSERT INTO `File` (`File`, `Component_`, `FileName`, `FileSize`, `Attributes`, `Sequence`) VALUES (?, ?, ?, ?, ?, ?)"; + } + + public Libmsi.Record add (string File, string Component, string FileName, int FileSize, int Attributes, int Sequence = 0) throws GLib.Error { + var rec = new Libmsi.Record (6); + + if (!rec.set_string (1, File) || + !rec.set_string (2, Component) || + !rec.set_string (3, FileName) || + !rec.set_int (4, FileSize) || + !rec.set_int (5, Attributes) || + !rec.set_int (6, Sequence)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + + return rec; + } + + public static bool set_sequence (Libmsi.Record rec, int Sequence) { + return rec.set_int (6, Sequence); + } + } + + class MsiTableMedia: MsiTable { + static construct { + name = "Media"; + sql_create = "CREATE TABLE `Media` (`DiskId` INT NOT NULL, `LastSequence` LONG NOT NULL, `DiskPrompt` CHAR(64) LOCALIZABLE, `Cabinet` CHAR(255), `VolumeLabel` CHAR(32), `Source` CHAR(72) PRIMARY KEY `DiskId`)"; + sql_insert = "INSERT INTO `Media` (`DiskId`, `LastSequence`, `DiskPrompt`, `Cabinet`) VALUES (?, ?, ?, ?)"; + } + + public bool set_last_sequence (Libmsi.Record rec, int last_sequence) { + return rec.set_int (2, last_sequence); + } + + public Libmsi.Record add (string DiskId, string? DiskPrompt, string Cabinet) throws GLib.Error { + var rec = new Libmsi.Record (4); + + if (!rec.set_int (1, int.parse (DiskId)) || + !rec.set_int (2, 0) || + (DiskPrompt != null && !rec.set_string (3, DiskPrompt)) || + !rec.set_string (4, Cabinet)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + return rec; + } + } + + class MsiTableUpgrade: MsiTable { + static construct { + name = "Upgrade"; + sql_create = "CREATE TABLE `Upgrade` (`UpgradeCode` CHAR(38) NOT NULL, `VersionMin` CHAR(20), `VersionMax` CHAR(20), `Language` CHAR(255), `Attributes` LONG NOT NULL, `Remove` CHAR(255), `ActionProperty` CHAR(72) NOT NULL PRIMARY KEY `UpgradeCode`, `VersionMin`, `VersionMax`, `Language`, `Attributes`)"; + sql_insert = "INSERT INTO `Upgrade` (`UpgradeCode`, `VersionMin`, `VersionMax`, `Attributes`, `ActionProperty`) VALUES (?, ?, ?, ?, ?)"; + } + + public void add (string UpgradeCode, string VersionMin, string? VersionMax, int Attributes, string ActionProperty) throws GLib.Error { + var rec = new Libmsi.Record (5); + + if (!rec.set_string (1, UpgradeCode) || + !rec.set_string (2, VersionMin) || + (VersionMax != null && !rec.set_string (3, VersionMax)) || + !rec.set_int (4, Attributes) || + !rec.set_string (5, ActionProperty)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + } + + class MsiTableLaunchCondition: MsiTable { + static construct { + name = "LaunchCondition"; + sql_create = "CREATE TABLE `LaunchCondition` (`Condition` CHAR(255) NOT NULL, `Description` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `Condition`)"; + sql_insert = "INSERT INTO `LaunchCondition` (`Condition`, `Description`) VALUES (?, ?)"; + } + + public void add (string condition, string description) throws GLib.Error { + var rec = new Libmsi.Record (2); + + if (!rec.set_string (1, condition) || + !rec.set_string (2, description)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + } + + class MsiTableProperty: MsiTable { + static construct { + name = "Property"; + sql_create = "CREATE TABLE `Property` (`Property` CHAR(72) NOT NULL, `Value` CHAR(0) NOT NULL LOCALIZABLE PRIMARY KEY `Property`)"; + sql_insert = "INSERT INTO `Property` (`Property`, `Value`) VALUES (?, ?)"; + } + + public void add (string prop, string value) throws GLib.Error { + var rec = new Libmsi.Record (2); + + if (!rec.set_string (1, prop) || + !rec.set_string (2, value)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + } + + class MsiTableDirectory: MsiTable { + static construct { + name = "Directory"; + sql_create = "CREATE TABLE `Directory` (`Directory` CHAR(72) NOT NULL, `Directory_Parent` CHAR(72), `DefaultDir` CHAR(255) NOT NULL LOCALIZABLE PRIMARY KEY `Directory`)"; + sql_insert = "INSERT INTO `Directory` (`Directory`, `Directory_Parent`, `DefaultDir`) VALUES (?, ?, ?)"; + } + + public void add (string Directory, string? Parent, string DefaultDir) throws GLib.Error { + var rec = new Libmsi.Record (3); + if (!rec.set_string (1, Directory) || + !rec.set_string (2, Parent) || + !rec.set_string (3, DefaultDir)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + } + + class MsiTableComponent: MsiTable { + static construct { + name = "Component"; + sql_create = "CREATE TABLE `Component` (`Component` CHAR(72) NOT NULL, `ComponentId` CHAR(38), `Directory_` CHAR(72) NOT NULL, `Attributes` INT NOT NULL, `Condition` CHAR(255), `KeyPath` CHAR(72) PRIMARY KEY `Component`)"; + sql_insert = "INSERT INTO `Component` (`Component`, `ComponentId`, `Directory_`, `Attributes`, `KeyPath`) VALUES (?, ?, ?, ?, ?)"; + } + + public void add (string Component, string ComponentId, string Directory, int Attributes, string? KeyPath = null) throws GLib.Error { + var rec = new Libmsi.Record (5); + if (!rec.set_string (1, Component) || + !rec.set_string (2, ComponentId) || + !rec.set_string (3, Directory) || + !rec.set_int (4, Attributes) || + !rec.set_string (5, KeyPath)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + } + + class MsiTableFeatureComponents: MsiTable { + static construct { + name = "FeatureComponents"; + sql_create = "CREATE TABLE `FeatureComponents` (`Feature_` CHAR(38) NOT NULL, `Component_` CHAR(72) NOT NULL PRIMARY KEY `Feature_`, `Component_`)"; + sql_insert = "INSERT INTO `FeatureComponents` (`Feature_`, `Component_`) VALUES (?, ?)"; + } + + public void add (string Feature, string Component) throws GLib.Error { + var rec = new Libmsi.Record (2); + if (!rec.set_string (1, Feature) || + !rec.set_string (2, Component)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + } + + class MsiTableRegistry: MsiTable { + static construct { + name = "Registry"; + sql_create = "CREATE TABLE `Registry` (`Registry` CHAR(72) NOT NULL, `Root` INT NOT NULL, `Key` CHAR(255) NOT NULL LOCALIZABLE, `Name` CHAR(255) LOCALIZABLE, `Value` CHAR(0) LOCALIZABLE, `Component_` CHAR(72) NOT NULL PRIMARY KEY `Registry`)"; + sql_insert = "INSERT INTO `Registry` (`Registry`, `Root`, `Key`, `Component_`) VALUES (?, ?, ?, ?)"; + } + + public void add (string Registry, int Root, string Key, string Component) throws GLib.Error { + var rec = new Libmsi.Record (4); + if (!rec.set_string (1, Registry) || + !rec.set_int (2, Root) || + !rec.set_string (3, Key) || + !rec.set_string (4, Component)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + } + + class MsiTableShortcut: MsiTable { + static construct { + name = "Shortcut"; + sql_create = "CREATE TABLE `Shortcut` (`Shortcut` CHAR(72) NOT NULL, `Directory_` CHAR(72) NOT NULL, `Name` CHAR(128) NOT NULL LOCALIZABLE, `Component_` CHAR(72) NOT NULL, `Target` CHAR(72) NOT NULL, `Arguments` CHAR(255), `Description` CHAR(255) LOCALIZABLE, `Hotkey` INT, `Icon_` CHAR(72), `IconIndex` INT, `ShowCmd` INT, `WkDir` CHAR(72), `DisplayResourceDLL` CHAR(255), `DisplayResourceId` INT, `DescriptionResourceDLL` CHAR(255), `DescriptionResourceId` INT PRIMARY KEY `Shortcut`)"; + sql_insert = "INSERT INTO `Shortcut` (`Shortcut`, `Directory_`, `Name`, `Component_`, `Target`, `Icon_`, `IconIndex`, `WkDir`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + } + + public Libmsi.Record add (string Shortcut, string Directory, string Name, string Component) throws GLib.Error { + var rec = new Libmsi.Record (8); + + if (!rec.set_string (1, Shortcut) || + !rec.set_string (2, Directory) || + !rec.set_string (3, Name) || + !rec.set_string (4, Component)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + + return rec; + } + + public static void set_target (Libmsi.Record rec, string Target) throws GLib.Error { + if (!rec.set_string (5, Target)) + throw new Wixl.Error.FAILED ("failed to set record"); + } + + public static void set_icon (Libmsi.Record rec, string Icon, int IconIndex) throws GLib.Error { + if (!rec.set_string (6, Icon) || + !rec.set_int (7, IconIndex)) + throw new Wixl.Error.FAILED ("failed to set record"); + } + + public static void set_working_dir (Libmsi.Record rec, string WkDir) throws GLib.Error { + if (!rec.set_string (8, WkDir)) + throw new Wixl.Error.FAILED ("failed to set record"); + } + } + + class MsiTableRemoveFile: MsiTable { + static construct { + name = "RemoveFile"; + sql_create = "CREATE TABLE `RemoveFile` (`FileKey` CHAR(72) NOT NULL, `Component_` CHAR(72) NOT NULL, `FileName` CHAR(255) LOCALIZABLE, `DirProperty` CHAR(72) NOT NULL, `InstallMode` INT NOT NULL PRIMARY KEY `FileKey`)"; + sql_insert = "INSERT INTO `RemoveFile` (`FileKey`, `Component_`, `DirProperty`, `InstallMode`) VALUES (?, ?, ?, ?)"; + } + + public void add (string FileKey, string Component, string DirProperty, int InstallMode) throws GLib.Error { + var rec = new Libmsi.Record (4); + if (!rec.set_string (1, FileKey) || + !rec.set_string (2, Component) || + !rec.set_string (3, DirProperty) || + !rec.set_int (4, InstallMode)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + } + + class MsiTableFeature: MsiTable { + static construct { + name = "Feature"; + sql_create = "CREATE TABLE `Feature` (`Feature` CHAR(38) NOT NULL, `Feature_Parent` CHAR(38), `Title` CHAR(64) LOCALIZABLE, `Description` CHAR(255) LOCALIZABLE, `Display` INT, `Level` INT NOT NULL, `Directory_` CHAR(72), `Attributes` INT NOT NULL PRIMARY KEY `Feature`)"; + sql_insert = "INSERT INTO `Feature` (`Feature`, `Display`, `Level`, `Attributes`, `Feature_Parent`, `Title`, `Description`, `Directory_`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + } + + public void add (string Feature, int Display, int Level, int Attributes, string? Parent = null, string? Title = null, string? Description = null, string? ConfigurableDirectory = null) throws GLib.Error { + var rec = new Libmsi.Record (8); + if (!rec.set_string (1, Feature) || + !rec.set_int (2, Display) || + !rec.set_int (3, Level) || + !rec.set_int (4, Attributes) || + (Parent != null && !rec.set_string (5, Parent)) || + (Title != null && !rec.set_string (6, Title)) || + (Description != null && !rec.set_string (7, Description)) || + (ConfigurableDirectory != null && !rec.set_string (8, ConfigurableDirectory))) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + } + + class MsiTableValidation: MsiTable { + static construct { + name = "_Validation"; + } + + public override void create (Libmsi.Database db) throws GLib.Error { + } + } + + class MsiTableStreams: MsiTable { + static construct { + name = "_Streams"; + } + + public void add (string name, GLib.InputStream input, size_t count) throws GLib.Error { + var rec = new Libmsi.Record (2); + if (!rec.set_string (1, name) || + !rec.set_stream (2, input, count)) + throw new Wixl.Error.FAILED ("failed to add record"); + + records.append (rec); + } + + public override void create (Libmsi.Database db) throws GLib.Error { + var query = new Libmsi.Query (db, "INSERT INTO `_Streams` (`Name`, `Data`) VALUES (?, ?)"); + foreach (var r in records) + query.execute (r); + } + } + + class MsiSummaryInfo: Object { + public Libmsi.SummaryInfo properties; + + construct { + try { + properties = new Libmsi.SummaryInfo (null, uint.MAX); + } catch (GLib.Error error) { + critical (error.message); + } + } + + public MsiSummaryInfo () { + } + + public new void set_property (Libmsi.Property prop, Value value) throws GLib.Error { + if (value.type () == typeof (string)) + properties.set_string (prop, (string) value); + else if (value.type () == typeof (int)) + properties.set_int (prop, (int) value); + else if (value.type () == typeof (uint64)) + properties.set_filetime (prop, (uint64) value); + else + critical ("Unhandled property type"); + } + + public void save (Libmsi.Database db) throws GLib.Error { + properties.save (db); + } + + public void set_codepage (int value) throws GLib.Error { + set_property (Libmsi.Property.CODEPAGE, value); + } + + public void set_author (string value) throws GLib.Error { + set_property (Libmsi.Property.AUTHOR, value); + } + + public void set_keywords (string value) throws GLib.Error { + set_property (Libmsi.Property.KEYWORDS, value); + } + + public void set_subject (string value) throws GLib.Error { + set_property (Libmsi.Property.SUBJECT, value); + } + + public void set_comments (string value) throws GLib.Error { + set_property (Libmsi.Property.COMMENTS, value); + } + } + + class MsiDatabase: Object { + public MsiSummaryInfo info; + public MsiTableProperty table_property; + public MsiTableIcon table_icon; + public MsiTableMedia table_media; + public MsiTableDirectory table_directory; + public MsiTableComponent table_component; + public MsiTableFeature table_feature; + public MsiTableFeatureComponents table_feature_components; + public MsiTableRemoveFile table_remove_file; + public MsiTableRegistry table_registry; + public MsiTableFile table_file; + public MsiTableAdminExecuteSequence table_admin_execute_sequence; + public MsiTableAdminUISequence table_admin_ui_sequence; + public MsiTableAdvtExecuteSequence table_advt_execute_sequence; + public MsiTableInstallExecuteSequence table_install_execute_sequence; + public MsiTableInstallUISequence table_install_ui_sequence; + public MsiTableStreams table_streams; + public MsiTableShortcut table_shortcut; + public MsiTableUpgrade table_upgrade; + public MsiTableLaunchCondition table_launch_condition; + + public HashTable<string, MsiTable> tables; + + construct { + info = new MsiSummaryInfo (); + try { + info.set_property (Libmsi.Property.TITLE, "Installation Database"); + info.set_property (Libmsi.Property.TEMPLATE, "Intel;1033"); + info.set_property (Libmsi.Property.KEYWORDS, "Installer"); + info.set_property (Libmsi.Property.CODEPAGE, 1252); + info.set_property (Libmsi.Property.UUID, get_uuid ("*")); + info.set_property (Libmsi.Property.CREATED_TM, + time_to_filetime (now ())); + info.set_property (Libmsi.Property.LASTSAVED_TM, + time_to_filetime (now ())); + info.set_property (Libmsi.Property.VERSION, 100); + info.set_property (Libmsi.Property.SOURCE, 2); + info.set_property (Libmsi.Property.APPNAME, Config.PACKAGE_STRING); + info.set_property (Libmsi.Property.SECURITY, 2); + } catch (GLib.Error error) { + critical (error.message); + } + + tables = new HashTable<string, MsiTable> (str_hash, str_equal); + table_property = new MsiTableProperty (); + table_icon = new MsiTableIcon (); + table_media = new MsiTableMedia (); + table_directory = new MsiTableDirectory (); + table_component = new MsiTableComponent (); + table_feature = new MsiTableFeature (); + table_feature_components = new MsiTableFeatureComponents (); + table_remove_file = new MsiTableRemoveFile (); + table_registry = new MsiTableRegistry (); + table_file = new MsiTableFile (); + table_admin_execute_sequence = new MsiTableAdminExecuteSequence (); + table_admin_ui_sequence = new MsiTableAdminUISequence (); + table_advt_execute_sequence = new MsiTableAdvtExecuteSequence (); + table_install_execute_sequence = new MsiTableInstallExecuteSequence (); + table_install_ui_sequence = new MsiTableInstallUISequence (); + table_streams = new MsiTableStreams (); + table_shortcut = new MsiTableShortcut (); + table_upgrade = new MsiTableUpgrade (); + table_launch_condition = new MsiTableLaunchCondition (); + + foreach (var t in new MsiTable[] { + table_admin_execute_sequence, + table_admin_ui_sequence, + table_advt_execute_sequence, + table_install_execute_sequence, + table_install_ui_sequence, + table_directory, + table_media, + table_property, + table_icon, + table_component, + table_feature, + table_feature_components, + table_remove_file, + table_registry, + table_file, + table_streams, + table_shortcut, + table_upgrade, + table_launch_condition, + new MsiTableError (), + new MsiTableValidation () + }) { + tables.insert (t.name, t); + } + } + + public MsiDatabase () { + // empty ctor + } + + public void build (string filename) throws GLib.Error { + string name; + MsiTable table; + + var db = new Libmsi.Database (filename, (string)2); + info.save (db); + + var it = HashTableIter <string, MsiTable> (tables); + while (it.next (out name, out table)) + table.create (db); + + db.commit (); + } + } + +} // Wixl
\ No newline at end of file diff --git a/wixl/preprocessor.vala b/wixl/preprocessor.vala new file mode 100644 index 0000000..feafb3b --- /dev/null +++ b/wixl/preprocessor.vala @@ -0,0 +1,131 @@ +namespace Wixl { + + class Preprocessor: Object { + + HashTable<string, string> globals; + HashTable<string, string> variables; + construct { + variables = new HashTable<string, string> (str_hash, str_equal); + } + + public Preprocessor (HashTable<string, string> globals) { + this.globals = globals; + } + + public void define_variable (string name, string value) { + variables.insert (name, value); + } + + public string? lookup_variable (string name) { + return variables.lookup (name) ?? globals.lookup (name); + } + + public string eval_variable (string str, File? file) throws GLib.Error { + var var = str.split (".", 2); + if (var.length != 2) + throw new Wixl.Error.FAILED ("invalid variable %s", str); + + switch (var[0]) { + case "var": + var val = lookup_variable (var[1]); + if (val == null) + throw new Wixl.Error.FAILED ("Undefined variable %s", var[1]); + return val; + case "env": + return Environment.get_variable (var[1]); + case "sys": + switch (var[1]) { + case "CURRENTDIR": + return Environment.get_current_dir (); + case "SOURCEFILEDIR": + return file.get_basename (); + case "SOURCEFILEPATH": + return file.get_path (); + } + break; + } + + throw new Wixl.Error.FIXME ("unhandled variable type %s", str); + } + + public string eval (string str, File? file) throws GLib.Error { + var result = ""; + int end = 0; + int pos = 0; + + while ((pos = str.index_of ("$", end)) != -1) { + if (end < pos) + result += str[end:pos]; + end = pos + 1; + var remainder = str[end:str.length]; + if (remainder.has_prefix ("$")) + result += "$"; + else if (remainder.has_prefix ("(")) { + var closing = find_closing_paren (remainder); + if (closing == -1) + throw new Wixl.Error.FAILED ("no matching closing parenthesis"); + var substring = remainder[1:closing]; + if (substring.index_of ("(") != -1) + throw new Wixl.Error.FIXME ("unsupported function"); + result += eval_variable (substring, file); + end += closing + 1; + } + } + + return result + str[end:str.length]; + } + + public Xml.Doc preprocess (string data, File? file) throws GLib.Error { + Xml.Doc doc; + var writer = new Xml.TextWriter.doc (out doc); + var reader = new Xml.TextReader.for_doc (data, ""); + + writer.start_document (); + while (reader.read () > 0) { + switch (reader.node_type ()) { + case Xml.ReaderType.PROCESSING_INSTRUCTION: + switch (reader.const_local_name ()) { + case "define": + MatchInfo info; + var r = /^\s*(?P<name>.+?)\s*=\s*(?P<value>.+?)\s*$/; + if (r.match (reader.const_value (), 0, out info)) { + var name = remove_prefix ("var.", info.fetch_named ("name")); + var value = unquote (info.fetch_named ("value")); + define_variable (name, value); + } else + throw new Wixl.Error.FAILED ("invalid define"); + break; + default: + warning ("unhandled preprocessor instruction %s", reader.const_local_name ()); + break; + } + break; + case Xml.ReaderType.ELEMENT: + var empty = reader.is_empty_element () > 0; + + writer.start_element (reader.const_name ()); + while (reader.move_to_next_attribute () > 0) { + var value = eval (reader.const_value (), file); + writer.write_attribute (reader.const_name (), value); + } + + if (empty) + writer.end_element (); + break; + case Xml.ReaderType.END_ELEMENT: + writer.end_element (); + break; + case Xml.ReaderType.TEXT: + writer.write_string (eval (reader.const_value(), file)); + break; + case Xml.ReaderType.CDATA: + writer.write_cdata (eval (reader.const_value(), file)); + break; + } + } + writer.end_document (); + + return doc; + } + } +}
\ No newline at end of file diff --git a/wixl/util.vala b/wixl/util.vala new file mode 100644 index 0000000..11f1588 --- /dev/null +++ b/wixl/util.vala @@ -0,0 +1,139 @@ +namespace Wixl { + + public errordomain Error { + FAILED, + FIXME, + } + + namespace UUID { + [CCode (cname = "uuid_generate", cheader_filename = "uuid/uuid.h")] + internal extern static void generate ([CCode (array_length = false)] uchar[] uuid); + [CCode (cname = "uuid_unparse", cheader_filename = "uuid/uuid.h")] + internal extern static void unparse ([CCode (array_length = false)] uchar[] uuid, + [CCode (array_length = false)] uchar[] output); + } + + string uuid_generate () { + var udn = new uchar[50]; + var id = new uchar[16]; + + UUID.generate (id); + UUID.unparse (id, udn); + + return (string) udn; + } + + int enum_from_string (Type t, string str) throws GLib.Error { + var k = (EnumClass)t.class_ref (); + var v = k.get_value_by_nick (str); + + if (v == null) + throw new Wixl.Error.FAILED ("Can't convert string to enum"); + return v.value; + } + + string add_braces (string str) { + if (str[0] == '{') + return str; + + return "{" + str + "}"; + } + + string get_uuid (owned string uuid) throws GLib.Error { + if (uuid == "*") + uuid = uuid_generate (); + uuid = add_braces (uuid); + uuid = uuid.up (); + // FIXME: validate + return uuid; + } + + long now () { + var tv = TimeVal (); + tv.get_current_time (); + return tv.tv_sec; + } + + uint64 time_to_filetime (long t) { + return (t + 134774ULL * 86400ULL) * 10000000ULL; + } + + string get_attribute_content (Xml.Attr *attr) { + if (attr->children == null) + return ""; + + return attr->children->content; + } + + public string indent (string space, string text) { + var indented = ""; + + foreach (var l in text.split ("\n")) { + if (indented.length != 0) + indented += "\n"; + + if (l.length != 0) + indented += space + l; + } + + return indented; + } + + public string generate_id (string prefix, uint n, ...) { + var l = va_list (); + var args = new string[n]; + + for (var i = 0; n > 0; n--) { + string? val = l.arg (); + if (val == null) + continue; + args[i] = val; // FIXME: misc vala bug when += + i += 1; + } + var data = string.joinv ("|", args); + var hash = Checksum.compute_for_string (ChecksumType.MD5, data); + var str = prefix + hash[0:32].up (); + + return str; + } + + bool parse_yesno (string? str, bool default = false) { + if (str == null) + return default; + + return (str[0] == 'Y' || str[0] == 'y'); + } + + string unquote (string str) { + if ((str[0] == '\'' && str[str.length-1] == '\'') || + (str[0] == '"' && str[str.length-1] == '"')) + return str[1:-1]; + + return str; + } + + string remove_prefix (string prefix, string str) { + if (str.has_prefix (prefix)) + return str[prefix.length:str.length]; + + return str; + } + + int find_closing_paren (string str) { + return_val_if_fail (str[0] == '(', -1); + + var open_count = 1; + var close_count = 0; + for (var pos = 1; pos < str.length; pos++) { + if (str[pos] == '(') + open_count++; + else if (str[pos] == ')') { + close_count++; + if (open_count == close_count) + return pos; + } + } + + return -1; + } +} // Wixl diff --git a/wixl/wix.vala b/wixl/wix.vala new file mode 100644 index 0000000..d3468c5 --- /dev/null +++ b/wixl/wix.vala @@ -0,0 +1,598 @@ +namespace Wixl { + + public enum VisitState { + ENTER, + INFIX, + LEAVE + } + + public abstract class WixNodeVisitor: Object { + public abstract void visit_product (WixProduct product) throws GLib.Error; + public abstract void visit_icon (WixIcon icon) throws GLib.Error; + public abstract void visit_package (WixPackage package) throws GLib.Error; + public abstract void visit_property (WixProperty prop) throws GLib.Error; + public abstract void visit_media (WixMedia media) throws GLib.Error; + public abstract void visit_directory (WixDirectory dir) throws GLib.Error; + public abstract void visit_component (WixComponent comp) throws GLib.Error; + public abstract void visit_feature (WixFeature feature, VisitState state) throws GLib.Error; + public abstract void visit_component_ref (WixComponentRef ref) throws GLib.Error; + public abstract void visit_remove_folder (WixRemoveFolder rm) throws GLib.Error; + public abstract void visit_registry_value (WixRegistryValue reg) throws GLib.Error; + public abstract void visit_file (WixFile reg) throws GLib.Error; + public abstract void visit_shortcut (WixShortcut shortcut) throws GLib.Error; + public abstract void visit_create_folder (WixCreateFolder folder) throws GLib.Error; + public abstract void visit_fragment (WixFragment fragment) throws GLib.Error; + public abstract void visit_directory_ref (WixDirectoryRef ref) throws GLib.Error; + public abstract void visit_sequence (WixSequence sequence) throws GLib.Error; + public abstract void visit_condition (WixCondition condition) throws GLib.Error; + public abstract void visit_upgrade (WixUpgrade upgrade) throws GLib.Error; + public abstract void visit_upgrade_version (WixUpgradeVersion version) throws GLib.Error; + public abstract void visit_action (WixAction action) throws GLib.Error; + public abstract void visit_text (WixText text) throws GLib.Error; + } + + public abstract class WixNode: Object { + public WixElement? parent; + + static construct { + Value.register_transform_func (typeof (WixNode), typeof (string), (ValueTransform)WixNode.value_to_string); + } + + public abstract string to_string (); + + public static void value_to_string (Value src, out Value dest) { + WixNode e = value_get_node (src); + + dest = e.to_string (); + } + + public static WixNode? value_get_node (Value value) { + if (! value.holds (typeof (WixNode))) + return null; + + return (WixNode)value.get_object (); + } + + public abstract void accept (WixNodeVisitor visitor) throws GLib.Error; + } + + public class WixText: WixNode { + public string Text; + + public WixText (string str) { + Text = str; + } + + public override string to_string () { + return Text; + } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_text (this); + } + } + + public abstract class WixElement: WixNode { + public class string name; + + public string Id { get; set; } + public List<WixNode> children; + + // FIXME: would be nice if vala always initialize class member to null + // GObject copy class init so other class hashtable will be unrefed...?? + protected class HashTable<string, Type> *child_types = null; + class construct { + child_types = new HashTable<string, Type> (str_hash, str_equal); + } + + public class void add_child_types (HashTable<string, Type> table, Type[] child_types) { + foreach (var t in child_types) { + var n = ((WixElement) Object.new (t)).name; + table.insert (n, t); + } + } + + public void add_child (WixNode e) { + e.parent = this; + children.append (e); + } + + public G[] add_elements<G> (owned G[] a) { + // jeez, vala, took me a while to workaround generics & array issues.. + var array = a; + var type = typeof (G); + + if (this.get_type ().is_a (type)) + array += this; + + foreach (var c in children) { + if (c is WixElement) + array = (c as WixElement).add_elements<G> (array); + else if (c.get_type ().is_a (type)) + array += c; + } + + return array; + } + + public G[] get_elements<G> () { + return add_elements<G> ({}); + } + + public G? find_element<G> (string Id) { + var type = typeof (G); + if (this.Id == Id && this.get_type () == type) + return this; + + foreach (var c in children) { + if (c is WixElement) { + var e = (c as WixElement).find_element<G> (Id); + if (e != null) + return e; + } + } + + return null; + } + + public virtual void load (Xml.Node *node) throws Wixl.Error { + if (node->name != name) + throw new Error.FAILED ("%s: invalid node %s".printf (name, node->name)); + + for (var prop = node->properties; prop != null; prop = prop->next) { + if (prop->type == Xml.ElementType.ATTRIBUTE_NODE) + set_property (prop->name, get_attribute_content (prop)); + } + + for (var child = node->children; child != null; child = child->next) { + switch (child->type) { + case Xml.ElementType.COMMENT_NODE: + continue; + case Xml.ElementType.TEXT_NODE: + add_child (new WixText (child->content)); + continue; + case Xml.ElementType.ELEMENT_NODE: + var t = child_types->lookup (child->name); + if (t != 0) { + var elem = Object.new (t) as WixElement; + elem.load (child); + add_child (elem); + continue; + } + break; + } + debug ("unhandled child %s node %s", name, child->name); + } + } + + public override string to_string () { + var type = get_type (); + var klass = (ObjectClass)type.class_ref (); + var str = "<" + name; + + var i = 0; + foreach (var p in klass.list_properties ()) { + if (!(ParamFlags.READABLE in p.flags)) + continue; + var value = Value (p.value_type); + get_property (p.name, ref value); + var valstr = value.holds (typeof (string)) ? + (string)value : value.strdup_contents (); + if (valstr != null) + str += " " + p.name + "=\"" + valstr + "\""; + i += 1; + } + + if (children.length () != 0) { + str += ">\n"; + + foreach (var child in children) { + str += child.to_string () + "\n"; + } + + return str + "</" + name + ">"; + } else + return str + "/>"; + } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + foreach (var child in children) + child.accept (visitor); + } + } + + public class WixFragment: WixElement { + static construct { + name = "Fragment"; + + add_child_types (child_types, { + typeof (WixDirectory), + typeof (WixDirectoryRef), + }); + } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + base.accept (visitor); + visitor.visit_fragment (this); + } + } + + public class WixProperty: WixElement { + static construct { + name = "Property"; + } + + public string Value { get; set; } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_property (this); + } + } + + public class WixPackage: WixElement { + static construct { + name = "Package"; + } + + public string Keywords { get; set; } + public string InstallerDescription { get; set; } + public string InstallerComments { get; set; } + public string Manufacturer { get; set; } + public string InstallerVersion { get; set; } + public string Languages { get; set; } + public string Compressed { get; set; } + public string SummaryCodepage { get; set; } + public string Comments { get; set; } + public string Description { get; set; } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + base.accept (visitor); + visitor.visit_package (this); + } + } + + public class WixCreateFolder: WixElement { + static construct { + name = "CreateFolder"; + } + + public string Directory { get; set; } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_create_folder (this); + } + } + + public class WixIcon: WixElement { + static construct { + name = "Icon"; + } + + public string SourceFile { get; set; } + + public File file; + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_icon (this); + } + } + + public class WixShortcut: WixElement { + static construct { + name = "Shortcut"; + } + + public string Directory { get; set; } + public string Name { get; set; } + public string IconIndex { get; set; } + public string WorkingDirectory { get; set; } + public string Icon { get; set; } + public string Advertise { get; set; } + + public Libmsi.Record record; + + public WixComponent? get_component () { + if (parent is WixFile || parent is WixCreateFolder) + return parent.parent as WixComponent; + else + return parent as WixComponent; + } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_shortcut (this); + } + } + + public abstract class WixKeyElement: WixElement { + public string KeyPath { get; set; } + } + + public class WixFile: WixKeyElement { + static construct { + name = "File"; + + add_child_types (child_types, { typeof (WixShortcut) }); + } + + public string DiskId { get; set; } + public string Source { get; set; } + public string Name { get; set; } + + public Libmsi.Record record; + public File file; + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + base.accept (visitor); + visitor.visit_file (this); + } + } + + public class WixRegistryValue: WixKeyElement { + static construct { + name = "RegistryValue"; + } + + public string Root { get; set; } + public string Key { get; set; } + public string Type { get; set; } + public string Value { get; set; } + public string Name { get; set; } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_registry_value (this); + } + } + + public class WixRemoveFolder: WixElement { + static construct { + name = "RemoveFolder"; + } + + public string On { get; set; } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_remove_folder (this); + } + } + + public class WixFeature: WixElement { + static construct { + name = "Feature"; + + add_child_types (child_types, { + typeof (WixComponentRef), + typeof (WixFeature), + }); + } + + public string Level { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public string Display { get; set; } + public string ConfigurableDirectory { get; set; } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_feature (this, VisitState.ENTER); + base.accept (visitor); + visitor.visit_feature (this, VisitState.LEAVE); + } + } + + public class WixComponentRef: WixElementRef<WixComponent> { + static construct { + name = "ComponentRef"; + ref_type = typeof (WixComponent); + } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_component_ref (this); + } + } + + public class WixCondition: WixElement { + static construct { + name = "Condition"; + } + + public string Message { get; set; } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_condition (this); + } + } + + public abstract class WixAction: WixElement { + public string After { get; set; } + public string Before { get; set; } + public string Overridable { get; set; } + public string Sequence { get; set; } + public string Suppress { get; set; } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_action (this); + } + } + + public class WixRemoveExistingProducts: WixAction { + static construct { + name = "RemoveExistingProducts"; + } + } + + public class WixSequence: WixElement { + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + base.accept (visitor); + visitor.visit_sequence (this); + } + } + + public class WixInstallExecuteSequence: WixSequence { + static construct { + name = "InstallExecuteSequence"; + + add_child_types (child_types, { + typeof (WixRemoveExistingProducts), + }); + } + } + + public class WixUpgrade: WixElement { + static construct { + name = "Upgrade"; + + add_child_types (child_types, { + typeof (WixUpgradeVersion), + }); + } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + base.accept (visitor); + visitor.visit_upgrade (this); + } + } + + public class WixUpgradeVersion: WixElement { + static construct { + name = "UpgradeVersion"; + } + + public string Minimum { get; set; } + public string Maximum { get; set; } + public string IncludeMinimum { get; set; } + public string IncludeMaximum { get; set; } + public string OnlyDetect { get; set; } + public string Property { get; set; } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_upgrade_version (this); + } + } + + public class WixProduct: WixElement { + static construct { + name = "Product"; + + add_child_types (child_types, { + typeof (WixCondition), + typeof (WixDirectory), + typeof (WixFeature), + typeof (WixIcon), + typeof (WixInstallExecuteSequence), + typeof (WixMedia), + typeof (WixPackage), + typeof (WixProperty), + typeof (WixUpgrade), + }); + } + + public string Name { get; set; } + public string UpgradeCode { get; set; } + public string Language { get; set; } + public string Codepage { get; set; } + public string Version { get; set; } + public string Manufacturer { get; set; } + + public WixProduct () { + } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + base.accept (visitor); + visitor.visit_product (this); + } + } + + public class WixMedia: WixElement { + static construct { + name = "Media"; + } + + public string Cabinet { get; set; } + public string EmbedCab { get; set; } + public string DiskPrompt { get; set; } + + public Libmsi.Record record; + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + visitor.visit_media (this); + } + } + + public class WixComponent: WixElement { + static construct { + name = "Component"; + + add_child_types (child_types, { + typeof (WixRemoveFolder), + typeof (WixRegistryValue), + typeof (WixFile) + }); + } + + public string Guid { get; set; } + public WixKeyElement? key; + + public List<WixFeature> in_feature; + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + base.accept (visitor); + visitor.visit_component (this); + } + } + + public class WixDirectory: WixElement { + static construct { + name = "Directory"; + + add_child_types (child_types, { + typeof (WixDirectory), + typeof (WixComponent), + }); + } + + public string Name { get; set; } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + base.accept (visitor); + visitor.visit_directory (this); + } + } + + public class WixElementRef<G>: WixElement { + public class Type ref_type; + public G? resolved; + + // protected WixElementRef () { + // // FIXME vala: class init/construct fails, construct fails... + // ref_type = typeof (G); + // } + } + + public class WixDirectoryRef: WixElementRef<WixDirectory> { + static construct { + name = "DirectoryRef"; + ref_type = typeof (WixDirectory); + + add_child_types (child_types, { + typeof (WixDirectory), + typeof (WixComponent), + }); + } + + public override void accept (WixNodeVisitor visitor) throws GLib.Error { + base.accept (visitor); + visitor.visit_directory_ref (this); + } + } + + class WixRoot: WixElement { + static construct { + name = "Wix"; + + add_child_types (child_types, { + typeof (WixProduct), + typeof (WixFragment), + }); + } + } + +} // Wixl diff --git a/wixl/wixl.vala b/wixl/wixl.vala new file mode 100644 index 0000000..057749d --- /dev/null +++ b/wixl/wixl.vala @@ -0,0 +1,92 @@ +using Posix; + +namespace Wixl { + + static bool version; + static bool verbose; + static bool preproc; + static string output; + [CCode (array_length = false, array_null_terminated = true)] + static string[] files; + [CCode (array_length = false, array_null_terminated = true)] + static string[] defines; + + private const OptionEntry[] options = { + { "version", 0, 0, OptionArg.NONE, ref version, N_("Display version number"), null }, + { "verbose", 'v', 0, OptionArg.NONE, ref verbose, N_("Verbose output"), null }, + { "output", 'o', 0, OptionArg.FILENAME, ref output, N_("Output file"), null }, + { "define", 'D', 0, OptionArg.STRING_ARRAY, ref defines, N_("Define variable"), null }, + { "only-preproc", 'E', 0, OptionArg.NONE, ref preproc, N_("Stop after the preprocessing stage"), null }, + { "", 0, 0, OptionArg.FILENAME_ARRAY, ref files, null, N_("INPUT_FILE...") }, + { null } + }; + + int main (string[] args) { + Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); + Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); + Intl.textdomain (Config.GETTEXT_PACKAGE); + GLib.Environment.set_application_name (Config.PACKAGE_NAME); + + var parameter_string = _("- a msi building tool"); + var opt_context = new OptionContext (parameter_string); + opt_context.set_help_enabled (true); + opt_context.add_main_entries (options, null); + + try { + opt_context.parse (ref args); + } catch (OptionError.BAD_VALUE err) { + GLib.stdout.printf (opt_context.get_help (true, null)); + exit (1); + } catch (OptionError error) { + warning (error.message); + } + + if (version) { + GLib.stdout.printf ("%s\n", Config.PACKAGE_VERSION); + exit (0); + } + + if (files.length < 1) { + GLib.stderr.printf (_("Please specify input files.\n")); + exit (1); + } + + if (output == null && !preproc) { + GLib.stderr.printf (_("Please specify the output file.\n")); + exit (1); + } + + try { + var builder = new WixBuilder (); + + foreach (var d in defines) { + var def = d.split ("=", 2); + var name = def[0]; + var value = def.length == 2 ? def[1] : "1"; + builder.define_variable (name, value); + } + + foreach (var arg in files) { + if (verbose) + print ("Loading %s...\n", arg); + var file = File.new_for_commandline_arg (arg); + builder.load_file (file, preproc); + builder.add_path (file.get_parent ().get_path ()); + } + + if (preproc) + return 0; + + if (verbose) + print ("Building %s...\n", output); + var msi = builder.build (); + msi.build (output); + } catch (GLib.Error error) { + printerr (error.message + "\n"); + return 1; + } + + return 0; + } + +} // Wixl |