Index: .classpath
===================================================================
--- .classpath	(revision 2938)
+++ .classpath	(working copy)
@@ -7,5 +7,6 @@
 	<classpathentry kind="src" path="src/tests"/>
 	<classpathentry kind="var" path="JUNIT_HOME/junit.jar" sourcepath="ECLIPSE_HOME/plugins/org.eclipse.jdt.source_3.0.0/src/org.junit_3.8.1/junitsrc.zip"/>
 	<classpathentry kind="lib" path="lib/bsf.jar"/>
+	<classpathentry kind="lib" path="lib/ini4j.jar"/>
 	<classpathentry kind="output" path="eclipse-bin"/>
 </classpath>
Index: lib/ini4j.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib/ini4j.jar
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: sample/features/variables/IzPack Test Compilation.launch
===================================================================
--- sample/features/variables/IzPack Test Compilation.launch	(revision 0)
+++ sample/features/variables/IzPack Test Compilation.launch	(revision 0)
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/IzPack/src/lib/com/izforge/izpack/compiler/Compiler.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.izforge.izpack.compiler.Compiler"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="install.xml -b . -o install.jar"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="IzPack"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-DIZPACK_HOME=${workspace_loc:IzPack/sample/features/variables}"/>
+<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc:IzPack/sample/features/variables}"/>
+</launchConfiguration>
Index: sample/features/variables/IzPack Test Installation GUI.launch
===================================================================
--- sample/features/variables/IzPack Test Installation GUI.launch	(revision 0)
+++ sample/features/variables/IzPack Test Installation GUI.launch	(revision 0)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/IzPack/src/lib/com/izforge/izpack/installer/Installer.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot; javaProject=&quot;IzPack&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;IzPack&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/IzPack/sample/features/variables/install.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.izforge.izpack.installer.Installer"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="IzPack"/>
+<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc:IzPack/sample/features/variables}"/>
+</launchConfiguration>
Index: sample/features/variables/IzPack Test Installation.launch
===================================================================
--- sample/features/variables/IzPack Test Installation.launch	(revision 0)
+++ sample/features/variables/IzPack Test Installation.launch	(revision 0)
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/IzPack/src/lib/com/izforge/izpack/installer/Installer.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot; javaProject=&quot;IzPack&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;IzPack&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/IzPack/sample/features/variables/install.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.izforge.izpack.installer.Installer"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-console -options-system"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="IzPack"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-DINSTALL_PATH=/home/rkrell/src/izpack/izpack-src/trunk/sample/features/variables/new_installation"/>
+<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc:IzPack/sample/features/variables}"/>
+</launchConfiguration>
Index: sample/features/variables/install.xml
===================================================================
--- sample/features/variables/install.xml	(revision 0)
+++ sample/features/variables/install.xml	(revision 0)
@@ -0,0 +1,141 @@
+<installation version="1.0">
+
+  <info>
+    <appname>Test</appname>
+    <appversion>0</appversion>
+    <appsubpath>new_installation</appsubpath>
+    <javaversion>1.5</javaversion>
+    <uninstaller write="no"/>
+    <writeinstallationinformation>no</writeinstallationinformation>
+  </info>
+
+  <guiprefs width="640" height="480" resizable="no">
+    <modifier key="labelGap" value="2"/>
+    <modifier key="useHeadingPanel" value="yes"/>
+    <modifier key="useHeadingForSummary" value="yes"/>
+    <modifier key="headingLineCount" value="1"/>
+    <modifier key="headingFontSize" value="1.5"/>
+    <modifier key="headingBackgroundColor" value="0x00ffffff"/>
+    <modifier key="headingPanelCounter" value="text"/>
+    <modifier key="headingPanelCounterPos" value="inHeading"/>
+  </guiprefs>
+
+  <variables>
+    <variable name="PlainTest" value="Plain Text"/>
+    <variable name="PlainTest.Env" value="${ENV[PATH]}"/>
+  </variables>
+
+  <dynamicvariables>
+    <variable name="PlainTest.ResolveVar" value="Plain Text and ${PlainTest} and ${PlainTest.Env}"
+              ignorefailure="false"/>
+    <variable name="EnvTest.New" environment="PATH"/>
+    <variable name="RegExTest.Select" value="package.ABC.name" checkonce="true">
+      <regex regexp="package\.([^\.]*)\.name"
+             select="\1"
+             defaultValue="(unmatched)"
+             casesensitive="false"/>
+    </variable>
+    <variable name="RegExTest.ReplaceFirst" value="package.ABC.name" checkonce="true">
+      <regex regexp="(package)\.[^\.]*\.(name)"
+             replace="\1.DEF.\2"
+             defaultValue="(unmatched)"
+             casesensitive="false"
+             global="false"/>
+    </variable>
+    <variable name="RegExTest.ReplaceAll" value="a.b.abc.abc" checkonce="true">
+      <regex regexp="(\.)abc"
+             replace="\1def"
+             defaultValue="(unmatched)"
+             casesensitive="false"
+             global="true"/>
+    </variable>
+    <variable name="RegExTest.Select.Unix" value="${ENV[PATH]}" checkonce="true">
+      <regex regexp="([^\:]*)(.*)"
+             select="\1"
+             defaultValue="(unmatched)"
+             casesensitive="false"/>
+    </variable>
+    <variable name="RegExTest.ReplaceFirst.Unix" value="${ENV[PATH]}" checkonce="true">
+      <regex regexp="([^\:]*)"
+             replace="+++ \1 +++"
+             defaultValue="(unmatched)"
+             casesensitive="false"
+             global="false"/>
+    </variable>
+    <variable name="RegExTest.ReplaceAll.Unix" value="${ENV[PATH]}" checkonce="true">
+      <regex regexp="([^\:]*)"
+             replace="+++ \1 +++"
+             defaultValue="(unmatched)"
+             casesensitive="false"
+             global="true"/>
+    </variable>
+    <variable name="PropertiesReadTest.1" checkonce="true"
+              file="${INSTALL_PATH}/../old_installation/test.properties" type="properties"
+              key="first.setting"/>
+    <variable name="PropertiesReadTest.2" checkonce="true"
+              file="${INSTALL_PATH}/../old_installation/test.conf" type="properties"
+              key="work.dir"/>
+    <variable name="INIReadTest" checkonce="true"
+              file="${INSTALL_PATH}/../old_installation/test.ini" type="ini"
+              section="SSH server" key="SSHCMD"/>
+
+    <variable name="XMLReadTest.1" checkonce="true" ignorefailure="false"
+              file="${SYSTEM_INSTALL_PATH}/../old_installation/test.xml" type="xml"
+              key="/installations/installation[path='/usr/local']/title[@lang='en']/text()"/>
+    <variable name="XMLReadTest.2" checkonce="true" ignorefailure="false"
+              file="${SYSTEM_INSTALL_PATH}/../old_installation/test.xml" type="xml"
+              key="//title[@lang='en']/text()"/>
+
+    <!--
+    <variable name="RegistryReadTest" checkonce="true"
+              regkey="HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"
+              regvalue="Path"/>
+    <variable name="RegExTest.Select.Windows" checkonce="true"
+              regkey="HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"
+              regvalue="Path">
+      <regex regexp="([^;]*)(.*)"
+             select="\1"
+             defaultValue="(unmatched)"
+             casesensitive="false"/>
+    </variable>
+    <variable name="RegExTest.ReplaceFirst.Windows" checkonce="true"
+              regkey="HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"
+              regvalue="Path">
+      <regex regexp="([^;]*)"
+             replace="+++ \1 +++"
+             defaultValue="(unmatched)"
+             casesensitive="false"
+             global="false"/>
+    </variable>
+    <variable name="RegExTest.ReplaceAll.Windows" checkonce="true"
+              regkey="HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"
+              regvalue="Path">
+      <regex regexp="([^;]*)"
+             replace="+++ \1 +++"
+             defaultValue="(unmatched)"
+             casesensitive="false"
+             global="true"/>
+    </variable>
+      -->
+  </dynamicvariables>
+
+  <locale>
+    <langpack iso3="eng"/>
+  </locale>
+
+  <panels>
+    <panel classname="TargetPanel"/>
+    <panel classname="PacksPanel"/>
+    <panel classname="InstallPanel"/>
+    <panel classname="FinishPanel"/>
+  </panels>
+
+  <packs>
+    <pack name="Test Core" required="yes">
+      <description>The core files needed for the test</description>
+      <fileset dir="plain" targetdir="${INSTALL_PATH}" override="true"/>
+      <parsable targetfile="${INSTALL_PATH}/test.properties"/>
+    </pack>
+  </packs>
+
+</installation>

Property changes on: sample/features/variables/install.xml
___________________________________________________________________
Added: svn:executable
   + *

Index: sample/features/variables/old_installation/test.conf
===================================================================
--- sample/features/variables/old_installation/test.conf	(revision 0)
+++ sample/features/variables/old_installation/test.conf	(revision 0)
@@ -0,0 +1 @@
+work.dir: C:\Program Files\My Old Installation

Property changes on: sample/features/variables/old_installation/test.conf
___________________________________________________________________
Added: svn:executable
   + *

Index: sample/features/variables/old_installation/test.ini
===================================================================
--- sample/features/variables/old_installation/test.ini	(revision 0)
+++ sample/features/variables/old_installation/test.ini	(revision 0)
@@ -0,0 +1,54 @@
+[Telnet server]
+TelnetListenAddress=127.0.0.1
+TelnetListenPort=23
+TelnetMaxConnections=0
+TelnetTimeout=0
+TelnetBanner=
+TelnetCMD=C:\Windows\System32\logoff.exe
+TelnetRun=0
+TelnetNewConsole=0
+[SSH server]
+SSHListenAddress=0.0.0.0
+SSHListenPort=22
+SSHMaxConnections=0
+SSHTimeout=0
+SSHBanner=
+SSHCMD=C:\Windows\System32\cmd.exe /K cd "C:\Program Files\freesshd" && C:
+SSHRun=1
+SSHNewConsole=0
+SSHCiphers=0
+SSHMACs=65536
+SSHPasswordAuth=0
+SSHPublickeyAuth=0
+SSHPublickeyPath=$HOME\ssh_public_keys
+RSAKeyPath=C:\Program Files\freesshd\RSAKey.cfg
+DSAKeyPath=C:\Program Files\freesshd\DSAKey.cfg
+[SSH tunneling]
+SSHLocalTunnel=0
+SSHLocalTunnelOnly=0
+SSHRemoteTunnel=0
+SSHRemoteTunnelOnly=0
+[SFTP]
+SFTPHomePath=C:\Program Files\freesshd\
+[Access filtering]
+HostRestrictions=
+HostRestrictionsAllow=0
+[Logging]
+LogEvents=0
+LogFilePath=C:\Documents and Settings\myuser\log\freesshd.log
+LogResolveIP=0
+[Automatic updates]
+UpdateCheckOnStartup=0
+UpdateDontPrompt=0
+UpdateShowMessages=1
+UpdateLastMessageID=0
+[Users]
+UserCount=1
+[User0]
+Name=DefaultUserName
+Auth=0
+Password=000000000000000000000000000000000000000000
+Domain=
+Shell=1
+SFTP=1
+Tunnel=0

Property changes on: sample/features/variables/old_installation/test.ini
___________________________________________________________________
Added: svn:executable
   + *

Index: sample/features/variables/old_installation/test.properties
===================================================================
--- sample/features/variables/old_installation/test.properties	(revision 0)
+++ sample/features/variables/old_installation/test.properties	(revision 0)
@@ -0,0 +1,3 @@
+first.setting = first setting
+second.setting.1 = second setting
+second.setting.2 = ${first.setting}

Property changes on: sample/features/variables/old_installation/test.properties
___________________________________________________________________
Added: svn:executable
   + *

Index: sample/features/variables/old_installation/test.xml
===================================================================
--- sample/features/variables/old_installation/test.xml	(revision 0)
+++ sample/features/variables/old_installation/test.xml	(revision 0)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+
+<installations>
+
+<installation>
+  <title lang="en">Twinkle Phone - VOIP Telephony Application</title>
+  <title lang="de">Twinkle Phone - VOIP-Telefon</title>
+  <depends>QT3</depends>
+  <path>/usr</path>
+</installation>
+
+<installation>
+  <title lang="en">SFLPhone - VOIP Telephony Application</title>
+  <title lang="de">SFLPhone - VOIP-Telefon</title>
+  <depends>QT4</depends>
+  <path>/usr/local</path>
+</installation>
+
+</installations>
\ No newline at end of file

Property changes on: sample/features/variables/old_installation/test.xml
___________________________________________________________________
Added: svn:executable
   + *

Index: sample/features/variables/plain/test.properties
===================================================================
--- sample/features/variables/plain/test.properties	(revision 0)
+++ sample/features/variables/plain/test.properties	(revision 0)
@@ -0,0 +1,22 @@
+first.setting = first new setting
+second.setting.1 = second new setting
+second.setting.2 = ${first.setting}
+
+_INSTALL_PATH=${INSTALL_PATH}
+
+_PlainTest=${PlainTest}
+_PlainTest.ResolveVar=${PlainTest.ResolveVar}
+_EnvTest=${EnvTest}
+_EnvTest.New=${EnvTest.New}
+_RegExTest.Select.Unix=RegExTest.Select.Unix
+_RegExTest.ReplaceFirst.Unix=RegExTest.ReplaceFirst.Unix
+_RegExTest.ReplaceAll.Unix=RegExTest.ReplaceAll.Unix
+_PropertiesReadTest.1=${PropertiesReadTest.1}
+_PropertiesReadTest.2=${PropertiesReadTest.2}
+_INIReadTest=${INIReadTest}
+_RegistryReadTest=${RegistryReadTest}
+_RegExTest.Select=${RegExTest.Select}
+_RegExTest.ReplaceFirst=${RegExTest.ReplaceFirst}
+_RegExTest.ReplaceAll=${RegExTest.ReplaceAll}
+_XMLReadTest.1=${XMLReadTest.1}
+_XMLReadTest.2=${XMLReadTest.2}

Property changes on: sample/features/variables/plain/test.properties
___________________________________________________________________
Added: svn:executable
   + *

Index: src/build.xml
===================================================================
--- src/build.xml	(revision 2938)
+++ src/build.xml	(working copy)
@@ -130,25 +130,25 @@
         Clean, Regenerate installer and installer with reg support. Avoid use of bad jars during installation.
 
     18.07.2005: (by Julien Ponge)
-    	Enforce source / target compatibility, now 1.4 / 1.4.
+        Enforce source / target compatibility, now 1.4 / 1.4.
 
     02.09.2005: (by Klaus Bartz)
-    	Unicode support of ShellLink.
+        Unicode support of ShellLink.
 
     09.09.2005: (Marc.Eppelmann)
-		Added start.sh to the shipped files in bin-folder.
+        Added start.sh to the shipped files in bin-folder.
 
-	10.01.2006: (by Fabrice Mirabile)
-		Added the splashscreen to the cleandistreg target
+    10.01.2006: (by Fabrice Mirabile)
+        Added the splashscreen to the cleandistreg target
 
-	06.04.2006: (Marc Eppelmann)
-	    Inserted the fix.crlf target in the depends-list of target "all" to prevent encoding problems.
+    06.04.2006: (Marc Eppelmann)
+        Inserted the fix.crlf target in the depends-list of target "all" to prevent encoding problems.
 
-	26.06.2006: (Marc Eppelmann)
-	    Extracted / Reordered some dist related targets to prevent double copy actions.
+    26.06.2006: (Marc Eppelmann)
+        Extracted / Reordered some dist related targets to prevent double copy actions.
         Also fixed the fix.crlf basedir
 
-	27.08.2006: (Marc Eppelmann)
+    27.08.2006: (Marc Eppelmann)
       Embedd ShortcutPanel*.java
 
   14.09.2006: (Marc Eppelmann)
@@ -158,7 +158,7 @@
       Added DataCheckPanel
 
   10.10.2006: (Fabrice Mirabile)
-	  Fixed target src.tar.gz and clean.src.tar.gz
+    Fixed target src.tar.gz and clean.src.tar.gz
 
   11.02.2007: (Ari Voutilainen)
      Added 'preservelastmodified="true"' to all 'copy todir' commands to keep original file date
@@ -223,7 +223,7 @@
 
     <property name="build.subdir" value="_build"/>
     <property name="build.dir" value="${basedir}/${build.subdir}"/>
-                                          
+
     <property name="dist.subdir" value="_dist"/>
     <property name="dist.dir" value="${basedir}/${dist.subdir}"/>
     <property name="dist-files.dir" value="${basedir}/src/dist-files"/>
@@ -241,6 +241,10 @@
     <property name="uninstaller-ext.jar" value="${basedir}/lib/uninstaller-ext.jar"/>
     <property name="izevent.jar" value="${basedir}/lib/izevent.jar"/>
 
+    <property name="jakarta-regexp.jar" location="${basedir}/lib/jakarta-regexp-1.3.jar"/>
+    <property name="ini4j.jar" location="${basedir}/lib/ini4j.jar"/>
+    <property name="ant.jar" location="${ant.home}/lib/ant.jar"/>
+
     <!-- Compilation parameters -->
     <property name="debug" value="off"/>
     <property name="debuglevel" value=""/>
@@ -251,14 +255,14 @@
 
 
     <!-- paths -->
-    <path id="classpath">
-        <fileset id="ext.libs" dir="${basedir}/lib">
-            <!-- older ant jar, which izpack distributes and uses for fileset behavior -->
-            <include name="ant.jar"/>
-            <include name="jakarta-regexp-1.3.jar"/>
-        </fileset>
-        <!-- current ant jar, for compiling IzPackTask which uses modern ant features -->
-        <fileset dir="${ant.home}/lib" includes="ant.jar"/>
+    <!-- Libraries that will be included in the compiled IzPack jars -->
+    <fileset id="libs.regexp" file="${jakarta-regexp.jar}"/>
+    <fileset id="libs.ini4j" file="${ini4j.jar}"/>
+    <fileset id="libs.ant" file="${ant.jar}"/>
+    <path id="classpath.compile">
+        <fileset refid="libs.regexp"/>
+        <fileset refid="libs.ini4j"/>
+        <fileset refid="libs.ant"/>
     </path>
 
     <!-- Checking target -->
@@ -279,7 +283,7 @@
     <!-- Compiles the compiler src files -->
     <target name="compile.compiler" depends="prepare">
         <javac srcdir="${src.dir}"
-               classpath="${basedir}/lib/jakarta-regexp-1.3.jar"
+               classpathref="classpath.compile"
                destdir="${build.dir}"
                optimize="on"
                source="${compat.source}"
@@ -352,10 +356,12 @@
                 <attribute name="Class-Path" value="ant.jar"/>
                 <attribute name="Main-Class" value="${compiler.class}"/>
             </manifest>
-			<fileset dir="${build.dir}">
+            <fileset dir="${build.dir}">
                 <include name="**/*.class"/>
-			</fileset>
-            <zipfileset src="lib/ant.jar"/>
+            </fileset>
+            <zipfileset src="${ant.jar}"/>
+            <zipfileset src="${jakarta-regexp.jar}"/>
+            <zipfileset src="${ini4j.jar}"/>
             <fileset dir="${basedir}">
                 <include name="bin/langpacks/flags/*"/>
                 <include name="bin/langpacks/installer/*"/>
@@ -364,11 +370,11 @@
                 <include name="bin/panels/*Panel.jar"/>
                 <include name="bin/customActions/*.jar"/>
                 <include name="lib/*.jar"/>
-				<exclude name="lib/standalone-compiler.jar"/>
+                <exclude name="lib/standalone-compiler.jar"/>
             </fileset>
              <fileset dir="${src.dir}">
                 <include name="**/*"/>
-                <exclude name="**/*.java"/> 
+                <exclude name="**/*.java"/>
             </fileset>
         </jar>
     </target>
@@ -376,7 +382,7 @@
     <!-- Compiles the installer src files -->
     <target name="compile.installer" depends="prepare">
         <javac srcdir="${src.dir}"
-               classpath="${basedir}/lib/jakarta-regexp-1.3.jar"
+               classpathref="classpath.compile"
                destdir="${build.dir}"
                optimize="on"
                source="${compat.source}"
@@ -425,35 +431,39 @@
                 <include name="com/izforge/izpack/rules/*.class"/>
                 <include name="com/izforge/izpack/compiler/DynamicVariable.class"/>
                 <include name="com/izforge/izpack/compiler/CompilerException.class"/>
-				<include name="com/izforge/izpack/panels/Validator*.class"/>
+                <include name="com/izforge/izpack/panels/Validator*.class"/>
                 <!--<include name="net/n3/nanoxml/*.class"/>-->
-            	<include name="com/izforge/izpack/adaptator/**/*.class"/>
-            	<include name="com/izforge/izpack/adaptator/*.class"/>
+                <include name="com/izforge/izpack/adaptator/**/*.class"/>
+                <include name="com/izforge/izpack/adaptator/*.class"/>
                 <include name="com/izforge/izpack/panels/HelpWindow.class" />
                 <include name="com/izforge/izpack/panels/Processor.class"/>
                 <include name="com/izforge/izpack/panels/Validator.class"/>
             </fileset>
-            <zipfileset src="${basedir}/lib/jakarta-regexp-1.3.jar">
-                <include name="org/apache/regexp/*.class"/>
-            </zipfileset>
             <fileset dir="${src.dir}">
                 <include name="com/izforge/izpack/installer/*.xml"/>
                 <include name="com/izforge/izpack/installer/*.properties"/>
                 <include name="com/izforge/izpack/installer/run-with-privileges-on-osx"/>
                 <include name="com/izforge/izpack/installer/elevate.js"/>
-            	<include name="com/izforge/izpack/util/**/*.sh"/>
-            	<include name="com/izforge/izpack/adaptator/styleSheet.xsl"/>
+                <include name="com/izforge/izpack/util/**/*.sh"/>
+                <include name="com/izforge/izpack/adaptator/styleSheet.xsl"/>
             </fileset>
             <fileset dir="${img.dir}/installer"/>
             <zipfileset src="${izevent.jar}">
                 <include name="com/izforge/izpack/event/*InstallerListener.class"/>
             </zipfileset>
+            <zipfileset src="${basedir}/lib/jakarta-regexp-1.3.jar">
+                <include name="org/apache/regexp/*.class"/>
+            </zipfileset>
+            <zipfileset src="${ini4j.jar}">
+                <include name="org/ini4j/**/*.class"/>
+            </zipfileset>
         </jar>
     </target>
 
     <!-- Compiles the uninstaller src files -->
     <target name="compile.uninstaller" depends="prepare">
         <javac srcdir="${src.dir}"
+               classpathref="classpath.compile"
                destdir="${build.dir}"
                optimize="on"
                source="${compat.source}"
@@ -491,8 +501,8 @@
                 <include name="com/izforge/izpack/ExecutableFile.class"/>
                 <exclude name="com/izforge/izpack/gui/IzPackKMetalTheme.class"/>
                 <!--<include name="net/n3/nanoxml/*.class"/>-->
-            	<include name="com/izforge/izpack/adaptator/**/*.class"/>
-            	<include name="com/izforge/izpack/adaptator/*.class"/>
+                <include name="com/izforge/izpack/adaptator/**/*.class"/>
+                <include name="com/izforge/izpack/adaptator/*.class"/>
                 <include name="com/izforge/izpack/installer/PrivilegedRunner.class"/>
                 <include name="com/izforge/izpack/panels/Processor.class"/>
                 <include name="com/izforge/izpack/panels/Validator.class"/>
@@ -500,7 +510,7 @@
             <fileset dir="${src.dir}">
                 <include name="com/izforge/izpack/installer/run-with-privileges-on-osx"/>
                 <include name="com/izforge/izpack/installer/elevate.js"/>
-            	<include name="com/izforge/izpack/adaptator/styleSheet.xsl"/>
+                <include name="com/izforge/izpack/adaptator/styleSheet.xsl"/>
                 <include name="com/izforge/izpack/util/**/*.sh"/>
             </fileset>
             <fileset dir="${build.dir}">
@@ -518,6 +528,7 @@
     <!-- Compiles the extended uninstaller src files -->
     <target name="compile.uninstaller-ext" depends="prepare">
         <javac srcdir="${src.dir}"
+               classpathref="classpath.compile"
                destdir="${build.dir}"
                optimize="on"
                source="${compat.source}"
@@ -592,11 +603,11 @@
 
         <build-panel name="FinishPanel">
             <include name="com/izforge/izpack/panels/FinishPanel.java"/>
-        	<include name="com/izforge/izpack/panels/FinishPanelConsoleHelper.java" />
+            <include name="com/izforge/izpack/panels/FinishPanelConsoleHelper.java" />
         </build-panel>
         <build-panel name="HelloPanel">
             <include name="com/izforge/izpack/panels/HelloPanel.java"/>
-        	<include name="com/izforge/izpack/panels/HelloPanelConsoleHelper.java" />
+            <include name="com/izforge/izpack/panels/HelloPanelConsoleHelper.java" />
         </build-panel>
         <build-panel name="SelectPrinterPanel">
             <include name="com/izforge/izpack/panels/SelectPrinterPanel.java"/>
@@ -621,7 +632,7 @@
         <build-panel name="InstallPanel">
             <include name="com/izforge/izpack/panels/InstallPanel.java"/>
             <include name="com/izforge/izpack/panels/InstallPanelAutomationHelper.java"/>
-        	<include name="com/izforge/izpack/panels/InstallPanelConsoleHelper.java" />
+            <include name="com/izforge/izpack/panels/InstallPanelConsoleHelper.java" />
         </build-panel>
         <build-panel name="ExtendedInstallPanel">
             <include name="com/izforge/izpack/panels/ExtendedInstallPanel.java"/>
@@ -661,7 +672,7 @@
             <include name="com/izforge/izpack/panels/PathSelectionPanel.java"/>
             <include name="com/izforge/izpack/panels/TargetPanel.java"/>
             <include name="com/izforge/izpack/panels/TargetPanelAutomationHelper.java"/>
-        	<include name="com/izforge/izpack/panels/TargetPanelConsoleHelper.java" />
+            <include name="com/izforge/izpack/panels/TargetPanelConsoleHelper.java" />
         </build-panel>
         <build-panel name="DefaultTargetPanel">
             <include name="com/izforge/izpack/panels/PathInputPanel.java"/>
@@ -692,23 +703,23 @@
         <build-panel name="UserInputPanel">
             <include name="com/izforge/izpack/panels/PasswordGroup.java"/>
             <include name="com/izforge/izpack/panels/ProcessingClient.java"/>
-        	<include name="com/izforge/izpack/panels/StringInputProcessingClient.java"/>
+            <include name="com/izforge/izpack/panels/StringInputProcessingClient.java"/>
             <include name="com/izforge/izpack/panels/Processor.java"/>
             <include name="com/izforge/izpack/panels/RuleInputField.java"/>
             <include name="com/izforge/izpack/panels/RuleTextField.java"/>
             <include name="com/izforge/izpack/panels/TextInputField.java"/>
-        	<include name="com/izforge/izpack/panels/FileInputField.java"/>
-        	<include name="com/izforge/izpack/panels/DirInputField.java"/>
-        	<include name="com/izforge/izpack/panels/MultipleFileInputField.java"/>
+            <include name="com/izforge/izpack/panels/FileInputField.java"/>
+            <include name="com/izforge/izpack/panels/DirInputField.java"/>
+            <include name="com/izforge/izpack/panels/MultipleFileInputField.java"/>
             <include name="com/izforge/izpack/panels/UserInputPanel.java"/>
             <include name="com/izforge/izpack/panels/UserInputPanelAutomationHelper.java"/>
             <include name="com/izforge/izpack/panels/Validator.java"/>
             <include name="com/izforge/izpack/panels/ValidatorContainer.java"/>
-        	<include name="com/izforge/izpack/panels/UIElementType.java"/>
+            <include name="com/izforge/izpack/panels/UIElementType.java"/>
             <include name="com/izforge/izpack/panels/UIElement.java"/>
             <include name="com/izforge/izpack/panels/RadioButtonUIElement.java"/>
             <include name="com/izforge/izpack/panels/PasswordUIElement.java"/>
-        	<include name="com/izforge/izpack/panels/UserInputPanelConsoleHelper.java" />
+            <include name="com/izforge/izpack/panels/UserInputPanelConsoleHelper.java" />
         </build-panel>
         <build-panel name="UserPathPanel">
             <include name="com/izforge/izpack/panels/UserPathInputPanel.java"/>
@@ -720,19 +731,19 @@
             <include name="com/izforge/izpack/panels/ConditionalUserInputPanel.java"/>
             <include name="com/izforge/izpack/panels/PasswordGroup.java"/>
             <include name="com/izforge/izpack/panels/ProcessingClient.java"/>
-        	<include name="com/izforge/izpack/panels/StringInputProcessingClient.java"/>
+            <include name="com/izforge/izpack/panels/StringInputProcessingClient.java"/>
             <include name="com/izforge/izpack/panels/Processor.java"/>
             <include name="com/izforge/izpack/panels/RuleInputField.java"/>
             <include name="com/izforge/izpack/panels/RuleTextField.java"/>
-        	<include name="com/izforge/izpack/panels/FileInputField.java"/>
-        	<include name="com/izforge/izpack/panels/DirInputField.java"/>
-        	<include name="com/izforge/izpack/panels/MultipleFileInputField.java"/>
+            <include name="com/izforge/izpack/panels/FileInputField.java"/>
+            <include name="com/izforge/izpack/panels/DirInputField.java"/>
+            <include name="com/izforge/izpack/panels/MultipleFileInputField.java"/>
             <include name="com/izforge/izpack/panels/TextInputField.java"/>
             <include name="com/izforge/izpack/panels/UserInputPanel.java"/>
             <include name="com/izforge/izpack/panels/UserInputPanelAutomationHelper.java"/>
             <include name="com/izforge/izpack/panels/Validator.java"/>
             <include name="com/izforge/izpack/panels/ValidatorContainer.java"/>
-        	<include name="com/izforge/izpack/panels/UIElementType.java"/>
+            <include name="com/izforge/izpack/panels/UIElementType.java"/>
             <include name="com/izforge/izpack/panels/UIElement.java"/>
             <include name="com/izforge/izpack/panels/RadioButtonUIElement.java"/>
             <include name="com/izforge/izpack/panels/PasswordUIElement.java"/>
@@ -962,7 +973,7 @@
             <include name="com/izforge/izpack/event/BSFInstallerListener.java" />
             <include name="com/izforge/izpack/event/BSFAction.java" />
         </build-installer-listener>
-        
+
         <build-installer-listener name="ProgressBarInstallerListener">
             <include name="com/izforge/izpack/event/ProgressBarInstallerListener.java"/>
         </build-installer-listener>
@@ -1023,7 +1034,7 @@
     <!-- Builds the Javadoc -->
     <target name="build.javadoc" depends="prepare" description="Builds the javadoc">
         <mkdir dir="${build.dir}/javadoc"/>
-        <javadoc destdir="${build.dir}/javadoc" access="private" classpathref="classpath">
+        <javadoc destdir="${build.dir}/javadoc" access="private" classpathref="classpath.compile">
             <packageset dir="${src.dir}">
                 <exclude name="**/CVS"/>
             </packageset>
@@ -1108,11 +1119,11 @@
               verbose="true"
               overwrite="yes"
               preservelastmodified="true"/>
-      	<copy todir="${basedir}/bin/native/3rdparty"
-        	    file="${basedir}/src/native/COIOSHelper/src/lib/COIOSHelper_x64.dll"
-	            verbose="true"
-    	        overwrite="yes"
-        	    preservelastmodified="true"/>
+        <copy todir="${basedir}/bin/native/3rdparty"
+                file="${basedir}/src/native/COIOSHelper/src/lib/COIOSHelper_x64.dll"
+                verbose="true"
+                overwrite="yes"
+                preservelastmodified="true"/>
     </target>
 
 
@@ -1214,8 +1225,8 @@
     </target>
 
     <!-- =================================
-	   Creates a normal installer for IzPack
-	  ================================= -->
+    Creates a normal installer for IzPack
+    ================================= -->
     <target name="generate.installer" depends="prepare.install.dist">
         <antcall target="exec.izpack.compiler">
             <param name="installer.xmlfile" value="IzPack-install.xml"/>
@@ -1306,9 +1317,9 @@
             description="makes a complete installer and runs them"/>
 
     <!-- ** splashscreen **
-	  shows some ANT specific- and JAVA-
-	  but Platform and Project-independed Properties.
-	================================================================ -->
+    shows some ANT specific- and JAVA-
+    but Platform and Project-independed Properties.
+    ================================================================ -->
     <target name="splashscreen"
             depends="time"
             description="shows the used environment and project settings">
Index: src/lib/com/izforge/izpack/compiler/CompilerConfig.java
===================================================================
--- src/lib/com/izforge/izpack/compiler/CompilerConfig.java	(revision 2938)
+++ src/lib/com/izforge/izpack/compiler/CompilerConfig.java	(working copy)
@@ -45,6 +45,8 @@
 import com.izforge.izpack.util.Debug;
 import com.izforge.izpack.util.OsConstraint;
 import com.izforge.izpack.util.VariableSubstitutor;
+import com.izforge.izpack.util.variable.*;
+
 import org.apache.tools.ant.DirectoryScanner;
 
 import java.io.*;
@@ -911,7 +913,7 @@
                 IXMLElement f = iter.next();
                 String dir_attr = requireAttribute(f, "dir");
                 String targetdir = requireAttribute(f, "targetdir");
-                
+
                 File dir = new File(dir_attr);
                 if (!dir.isAbsolute())
                 {
@@ -1176,7 +1178,7 @@
         }
         return includedFiles.toArray(new String[]{});
     }
-    
+
     private IXMLElement readRefPackData(String refFileName, boolean isselfcontained)
             throws CompilerException {
         File refXMLFile = new File(refFileName);
@@ -2054,21 +2056,158 @@
         {
             IXMLElement var = iter.next();
             String name = requireAttribute(var, "name");
+
+            DynamicVariable dynamicVariable = new DynamicVariable();
+            dynamicVariable.setName(name);
+
+            // Check for plain value
             String value = var.getAttribute("value");
-            if (value==null){
+            if (value!=null) {
+                dynamicVariable.setValue(new PlainValue(value));
+            }
+            else {
                 IXMLElement valueElement = var.getFirstChildNamed("value");
                 if (valueElement != null){
                     value = valueElement.getContent();
                     if (value == null){
-                       parseError("A dynamic variable needs either a value attribute or a value element.");
+                        parseError("Empty value element for dynamic variable "+name);
                     }
+                    dynamicVariable.setValue(new PlainValue(value));
                 }
+            }
+            // Check for environment variable value
+            value = var.getAttribute("environment");
+            if (value!=null) {
+                if (dynamicVariable.getValue()==null) {
+                    dynamicVariable.setValue(new EnvironmentValue(value));
+                    try { dynamicVariable.validate(); }
+                    catch (Exception e)
+                    {
+                        parseError("Error in definition of dynamic variable "+name+": "+e.getMessage());
+                    }
+                }
                 else {
-                    parseError("A dynamic variable needs either a value attribute or a value element. Variable name: " + name);
+                    parseError("Ambiguous environment value definition for dynamic variable "+name);
                 }
             }
-            String conditionid = var.getAttribute("condition");
+            // Check for registry value
+            value = var.getAttribute("regkey");
+            if (value!=null) {
+                String regroot = var.getAttribute("regroot");
+                String regvalue = var.getAttribute("regvalue");
+                if (dynamicVariable.getValue()==null) {
+                    dynamicVariable.setValue(
+                            new RegistryValue(regroot, value, regvalue));
+                    try { dynamicVariable.validate(); }
+                    catch (Exception e)
+                    {
+                        parseError("Error in definition of dynamic variable "+name+": "+e.getMessage());
+                    }
+                }
+                else {
+                    parseError("Ambiguous registry value definition for dynamic variable "+name);
+                }
+            }
+            // Check for config file value
+            value = var.getAttribute("file");
+            if (value!=null) {
+                String sfiletype = var.getAttribute("type");
+                String filesection = var.getAttribute("section");
+                String filekey = var.getAttribute("key");
+                if (dynamicVariable.getValue()==null) {
+                    int filetype = ConfigFileValue.CONFIGFILE_TYPE_PROPERTIES;
+                    if (sfiletype!=null)
+                    {
+                        if (sfiletype.equalsIgnoreCase("properties"))
+                            filetype = ConfigFileValue.CONFIGFILE_TYPE_PROPERTIES;
+                        else if (sfiletype.equalsIgnoreCase("xml"))
+                            filetype = ConfigFileValue.CONFIGFILE_TYPE_XML;
+                        else if (sfiletype.equalsIgnoreCase("ini"))
+                            filetype = ConfigFileValue.CONFIGFILE_TYPE_INI;
+                        else parseError("Error in definition of dynamic variable "+name+": Unknown file type "+sfiletype);
+                    }
+                    dynamicVariable.setValue(
+                            new ConfigFileValue(value, filetype, filesection, filekey));
+                    try { dynamicVariable.validate(); }
+                    catch (Exception e)
+                    {
+                        parseError("Error in definition of dynamic variable "+name+": "+e.getMessage());
+                    }
+                }
+                else {
+                    parseError("Ambiguous file value definition for dynamic variable "+name);
+                }
+            }
+            // Check for config file value
+            value = var.getAttribute("executable");
+            if (value!=null) {
+                if (dynamicVariable.getValue()==null) {
+                    String exectype = var.getAttribute("type");
 
+                    if (value.length() <= 0)
+                        parseError("No command given in definition of dynamic variable "+name);
+                    if (exectype.equalsIgnoreCase("process") || exectype == null)
+                        dynamicVariable.setValue(
+                                new ExecValue(new String[]{value}, false));
+                    else if (exectype.equalsIgnoreCase("shell"))
+                        dynamicVariable.setValue(
+                                new ExecValue(new String[]{value}, true));
+                    else
+                        parseError("Bad execution type "+exectype+" given for dynamic variable "+name);
+                    try { dynamicVariable.validate(); }
+                    catch (Exception e)
+                    {
+                        parseError("Error in definition of dynamic variable "+name+": "+e.getMessage());
+                    }
+                } else {
+                    parseError("Ambiguous execution output value definition for dynamic variable "+name);
+                }
+            }
+
+            if (dynamicVariable.getValue()==null) {
+                parseError("No value specified at all for dynamic variable "+name);
+            }
+
+            // Check whether dynamic variable has to be evaluated only once during installation
+            value = var.getAttribute("checkonce");
+            if (value != null) {
+                dynamicVariable.setCheckonce(Boolean.valueOf(value));
+            }
+
+            // Check whether evaluation failures of the dynamic variable should be ignored
+            value = var.getAttribute("ignorefailure");
+            if (value != null) {
+                dynamicVariable.setIgnoreFailure(Boolean.valueOf(value));
+            }
+
+            // Nested regular expression filter
+            IXMLElement regexElement = var.getFirstChildNamed("regex");
+            if (regexElement != null) {
+                String expression = regexElement.getAttribute("regexp");
+                String selectexpr = regexElement.getAttribute("select");
+                String replaceexpr = regexElement.getAttribute("replace");
+                String defaultvalue = regexElement.getAttribute("defaultvalue");
+                String scasesensitive = regexElement.getAttribute("casesensitive");
+                String sglobal = regexElement.getAttribute("global");
+                if (dynamicVariable.getRegularExpression()==null) {
+                    dynamicVariable.setRegularExpression(
+                            new RegularExpressionFilter( expression,
+                                    selectexpr,
+                                    replaceexpr,
+                                    defaultvalue,
+                                    Boolean.valueOf(scasesensitive!=null?scasesensitive:"true"),
+                                    Boolean.valueOf(sglobal!=null?sglobal:"false")));
+                    try { dynamicVariable.validate(); }
+                    catch (Exception e)
+                    {
+                        parseError("Error in definition of dynamic variable "+name+": "+e.getMessage());
+                    }
+                }
+                else {
+                    parseError("Ambiguous regular expression filter definition for dynamic variable "+name);
+                }
+            }
+
             List<DynamicVariable> dynamicValues = new ArrayList<DynamicVariable>();
             if (dynamicvariables.containsKey(name))
             {
@@ -2079,9 +2218,7 @@
                 dynamicvariables.put(name, dynamicValues);
             }
 
-            DynamicVariable dynamicVariable = new DynamicVariable();
-            dynamicVariable.setName(name);
-            dynamicVariable.setValue(value);
+            String conditionid = var.getAttribute("condition");
             dynamicVariable.setConditionid(conditionid);
             if (dynamicValues.remove(dynamicVariable))
             {
Index: src/lib/com/izforge/izpack/compiler/DynamicVariable.java
===================================================================
--- src/lib/com/izforge/izpack/compiler/DynamicVariable.java	(revision 2938)
+++ src/lib/com/izforge/izpack/compiler/DynamicVariable.java	(working copy)
@@ -22,9 +22,12 @@
  */
 package com.izforge.izpack.compiler;
 
-import java.io.Serializable;
+import java.io.*;
 
+import com.izforge.izpack.util.*;
+import com.izforge.izpack.util.variable.*;
 
+
 /**
  * @author Dennis Reil, <Dennis.Reil@reddot.de>
  * @version $Id: $
@@ -33,16 +36,58 @@
 {
     private static final long serialVersionUID = -7985397187206803090L;
     private String name;
-    private String value;
+    private Value value;
     private String conditionid;
+    private RegularExpressionFilter regexp;
+    private boolean checkonce = false;
+    private boolean ignorefailure = true;
 
+    private transient String currentValue;
+
     public DynamicVariable()
     {
-        name = "";
-        value = "";
-        conditionid = "";
+//        name = "";
+//        value = "";
+//        conditionid = "";
     }
 
+    public void validate() throws Exception
+    {
+        if (name == null)
+            throw new Exception("No dynamic variable name defined");
+
+        if (value == null)
+            throw new Exception("No dynamic variable value defined for variable "+name);
+
+        value.validate();
+
+        if (regexp != null)
+            regexp.validate();
+    }
+
+    public String evaluate(VariableSubstitutorBase substitutor) throws Exception
+    {
+        String newValue = this.currentValue;
+
+        if (this.value == null)
+            return null;
+
+        if (this.checkonce && this.currentValue != null)
+            return this.currentValue;
+
+        try {
+            newValue = value.resolve(substitutor, regexp);
+            if (this.checkonce)
+                this.currentValue = newValue;
+        }
+        catch (Exception e) {
+            if (!this.ignorefailure)
+                throw e;
+        }
+
+        return newValue;
+    }
+
     /**
      * @return the name
      */
@@ -65,7 +110,7 @@
     /**
      * @return the value
      */
-    public String getValue()
+    public Value getValue()
     {
         return this.value;
     }
@@ -73,7 +118,7 @@
     /**
      * @param value the value to set
      */
-    public void setValue(String value)
+    public void setValue(Value value)
     {
         if (value != null)
         {
@@ -82,6 +127,25 @@
     }
 
     /**
+     * @return the non-mandatory regular expression
+     */
+    public RegularExpressionFilter getRegularExpression()
+    {
+        return this.regexp;
+    }
+
+    /**
+     * @param expression the non-mandatory regular expression
+     */
+    public void setRegularExpression(RegularExpressionFilter expression)
+    {
+        if (expression != null)
+        {
+            this.regexp = expression;
+        }
+    }
+
+    /**
      * @return the conditionid
      */
     public String getConditionid()
@@ -100,6 +164,26 @@
         }
     }
 
+    public boolean isCheckonce()
+    {
+        return checkonce;
+    }
+
+    public void setCheckonce(boolean checkonce)
+    {
+        this.checkonce = checkonce;
+    }
+
+    public boolean isIgnoreFailure()
+    {
+        return ignorefailure;
+    }
+
+    public void setIgnoreFailure(boolean ignore)
+    {
+        this.ignorefailure = ignore;
+    }
+
     @Override
     public boolean equals(Object obj)
     {
@@ -117,5 +201,6 @@
         // TODO: check if this always correct
         return name.hashCode() ^ conditionid.hashCode();
     }
+
 }
 
Index: src/lib/com/izforge/izpack/compiler/Property.java
===================================================================
--- src/lib/com/izforge/izpack/compiler/Property.java	(revision 2938)
+++ src/lib/com/izforge/izpack/compiler/Property.java	(working copy)
@@ -1,17 +1,17 @@
 /*
  * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
- * 
+ *
  * http://izpack.org/
  * http://izpack.codehaus.org/
- * 
+ *
  * Copyright 2004 Chadwick McHenry
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *     http://www.apache.org/licenses/LICENSE-2.0
- *     
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -241,8 +241,8 @@
         Properties props = new Properties();
         config.getPackagerListener().packagerMsg("Loading Environment " + prefix,
                 PackagerListener.MSG_VERBOSE);
-        Vector osEnv = Execute.getProcEnvironment();
-        for (Enumeration e = osEnv.elements(); e.hasMoreElements();)
+        Vector<String> osEnv = Execute.getProcEnvironment();
+        for (Enumeration<String> e = osEnv.elements(); e.hasMoreElements();)
         {
             String entry = (String) e.nextElement();
             int pos = entry.indexOf('=');
@@ -278,7 +278,7 @@
     protected void addProperties(Properties props) throws CompilerException
     {
         resolveAllProperties(props);
-        Enumeration e = props.keys();
+        Enumeration<Object> e = props.keys();
         while (e.hasMoreElements())
         {
             String name = (String) e.nextElement();
@@ -303,9 +303,9 @@
         VariableSubstitutor subs = new VariableSubstitutor(props);
         subs.setBracesRequired(true);
 
-        for (Enumeration e = props.keys(); e.hasMoreElements();)
+        for (Enumeration<Object> en = props.keys(); en.hasMoreElements();)
         {
-            String name = (String) e.nextElement();
+            String name = (String) en.nextElement();
             String value = props.getProperty(name);
 
             int mods = -1;
@@ -327,6 +327,9 @@
                     config.parseError(xmlProp, "Faild to load file: " + file.getAbsolutePath(),
                             ex);
                 }
+                catch(Exception e) {
+                    throw new CompilerException(e.getMessage());
+                }
             }
             while (mods != 0);
         }
Index: src/lib/com/izforge/izpack/installer/AutomatedInstaller.java
===================================================================
--- src/lib/com/izforge/izpack/installer/AutomatedInstaller.java	(revision 2938)
+++ src/lib/com/izforge/izpack/installer/AutomatedInstaller.java	(working copy)
@@ -336,8 +336,8 @@
         System.out.println("[ Starting automated installation ]");
         Debug.log("[ Starting automated installation ]");
 
-        ConsolePanelAutomationHelper uihelper = new ConsolePanelAutomationHelper(); 
-        
+        ConsolePanelAutomationHelper uihelper = new ConsolePanelAutomationHelper();
+
         try
         {
             // assume that installation will succeed
Index: src/lib/com/izforge/izpack/installer/ConsoleInstaller.java
===================================================================
--- src/lib/com/izforge/izpack/installer/ConsoleInstaller.java	(revision 2938)
+++ src/lib/com/izforge/izpack/installer/ConsoleInstaller.java	(working copy)
@@ -124,10 +124,9 @@
                 PanelConsole consoleHelperInstance = null;
                 if (consoleHelperClass != null)
                 {
-                    try
-                    {
-                        Debug.log("Instantiate :" + consoleHelperClassName);
-                        refreshDynamicVariables(substitutor, installdata);
+                    refreshDynamicVariables(substitutor, installdata);
+                    Debug.log("Instantiate :" + consoleHelperClassName);
+                    try {
                         consoleHelperInstance = consoleHelperClass.newInstance();
                     }
                     catch (Exception e)
@@ -206,7 +205,7 @@
         catch (Exception e)
         {
             this.result = false;
-            System.err.println(e.toString());
+            System.err.println(e.getMessage());
             e.printStackTrace();
             System.out.println("[ Console installation FAILED! ]");
         }
@@ -223,10 +222,7 @@
         {
             throw e;
         }
-        finally
-        {
-            checkedReboot();
-        }
+        checkedReboot();
     }
 
    protected void doGeneratePropertiesFile(String strFile) throws Exception
@@ -266,8 +262,8 @@
         finally
         {
             in.close();
-            checkedReboot();
         }
+        checkedReboot();
     }
 
     protected void doInstallFromSystemProperties() throws Exception
@@ -281,10 +277,7 @@
         {
             throw e;
         }
-        finally
-        {
-            checkedReboot();
-        }
+        checkedReboot();
     }
 
     protected void doInstallFromSystemPropertiesMerge(String strFile) throws Exception
@@ -304,8 +297,8 @@
         finally
         {
             in.close();
-            checkedReboot();
         }
+        checkedReboot();
     }
 
     /**
Index: src/lib/com/izforge/izpack/installer/GUIInstaller.java
===================================================================
--- src/lib/com/izforge/izpack/installer/GUIInstaller.java	(revision 2938)
+++ src/lib/com/izforge/izpack/installer/GUIInstaller.java	(working copy)
@@ -1,16 +1,16 @@
 /*
  * $Id$
  * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
- * 
+ *
  * http://izpack.org/
  * http://izpack.codehaus.org/
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *     http://www.apache.org/licenses/LICENSE-2.0
- *     
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -77,7 +77,7 @@
      * holds language to ISO-3 language code translation
      */
     private static HashMap isoTable;
-    
+
     /**
      * The constructor.
      *
@@ -87,15 +87,15 @@
     {
         try {
             init();
-        } catch (Exception e) { 
+        } catch (Exception e) {
             showFatalError(e);
             throw e;
-        } catch (Error e) { 
+        } catch (Error e) {
             showFatalError(e);
             throw e;
         }
     }
-    
+
     private void showFatalError(Throwable e)
     {
         try {
@@ -104,15 +104,15 @@
             e2.printStackTrace();
         }
     }
-    
+
     private void init() throws Exception
     {
-    
-        this.installdata = new InstallData();                
-        
+
+        this.installdata = new InstallData();
+
         // Loads the installation data
         loadInstallData(installdata);
-        
+
         // add the GUI install data
         loadGUIInstallData();
 
@@ -125,7 +125,7 @@
 
         // Check for already running instance
         checkLockFile();
-        
+
 //      Loads the suitable langpack
         SwingUtilities.invokeAndWait(new Runnable()
         {
@@ -142,19 +142,19 @@
                 }
             }
         });
-        
+
         // create the resource manager (after the language selection!)
         ResourceManager.create(this.installdata);
-        
+
 //      load conditions
         loadConditions(installdata);
-        
+
         // loads installer conditions
         loadInstallerRequirements();
 
         // load dynamic variables
         loadDynamicVariables();
-        
+
         // check installer conditions
         if (!checkInstallerRequirements(installdata))
         {
@@ -183,7 +183,7 @@
             }
         });
     }
-    
+
     public void showMissingRequirementMessage(String message){
         JOptionPane.showMessageDialog(null, message);
     }
@@ -199,7 +199,7 @@
         ObjectInputStream objIn = new ObjectInputStream(in);
         this.installdata.guiPrefs = (GUIPrefs) objIn.readObject();
         objIn.close();
-    }    
+    }
 
     /**
      * Sets a lock file. Not using java.nio.channels.FileLock to prevent
Index: src/lib/com/izforge/izpack/installer/Installer.java
===================================================================
--- src/lib/com/izforge/izpack/installer/Installer.java	(revision 2938)
+++ src/lib/com/izforge/izpack/installer/Installer.java	(working copy)
@@ -74,24 +74,24 @@
                     }
                     else if ("-options-template".equalsIgnoreCase(arg))
                     {
-			type = INSTALLER_CONSOLE;
+            type = INSTALLER_CONSOLE;
                         consoleAction = CONSOLE_GEN_TEMPLATE;
                         path = args_it.next().trim();
                     }
                     else if ("-options".equalsIgnoreCase(arg))
                     {
-			type = INSTALLER_CONSOLE;
+            type = INSTALLER_CONSOLE;
                         consoleAction = CONSOLE_FROM_TEMPLATE;
                         path = args_it.next().trim();
                     }
                     else if ("-options-system".equalsIgnoreCase(arg))
                     {
-			type = INSTALLER_CONSOLE;
+            type = INSTALLER_CONSOLE;
                         consoleAction = CONSOLE_FROM_SYSTEMPROPERTIES;
                     }
                     else if ("-options-auto".equalsIgnoreCase(arg))
                     {
-			type = INSTALLER_CONSOLE;
+            type = INSTALLER_CONSOLE;
                         consoleAction = CONSOLE_FROM_SYSTEMPROPERTIESMERGE;
                         path = args_it.next().trim();
                     }
@@ -131,7 +131,7 @@
 
         } catch (Exception e) {
             System.err.println("- ERROR -");
-            System.err.println(e.toString());
+            System.err.println("+++"+e.getMessage());
             e.printStackTrace();
             System.exit(1);
         }
Index: src/lib/com/izforge/izpack/installer/InstallerBase.java
===================================================================
--- src/lib/com/izforge/izpack/installer/InstallerBase.java	(revision 2938)
+++ src/lib/com/izforge/izpack/installer/InstallerBase.java	(working copy)
@@ -63,7 +63,7 @@
      * with the name expanded by _ISO3.
      */
     protected static final String LANG_FILE_NAME = "CustomLangpack.xml";
-    
+
     /**
      * Returns an ArrayList of the available langpacks ISO3 codes.
      *
@@ -647,11 +647,14 @@
     /**
      * Refreshes Dynamic Variables.
      */
-    protected void refreshDynamicVariables(VariableSubstitutor substitutor, AutomatedInstallData installdata)
+    protected void refreshDynamicVariables(VariableSubstitutor substitutor,
+            AutomatedInstallData installdata) throws Exception
     {
-        Debug.log("refreshing dyamic variables.");
+        Debug.log("refreshing dynamic variables");
         if (dynamicvariables != null)
         {
+            DynamicVariableSubstitutor dynsubst = new DynamicVariableSubstitutor(dynamicvariables, rules);
+
             for (String dynvarname : dynamicvariables.keySet())
             {
                 Debug.log("Variable: " + dynvarname);
@@ -677,9 +680,13 @@
                     }
                     if (refresh)
                     {
-                        String newvalue = substitutor.substitute(dynvar.getValue(), null);
-                        Debug.log("newvalue: " + newvalue);
-                        installdata.variables.setProperty(dynvar.getName(), newvalue);
+                        String newValue = dynvar.evaluate(substitutor);
+                        if (newValue != null) {
+                            Debug.log("dynamic variable " + dynvar.getName() + ": " + newValue);
+                            installdata.variables.setProperty(dynvar.getName(), newValue);
+                        } else {
+                            Debug.log("dynamic variable " + dynvar.getName() + " unchanged" + dynvar.getValue());
+                        }
                     }
                 }
             }
Index: src/lib/com/izforge/izpack/installer/InstallerFrame.java
===================================================================
--- src/lib/com/izforge/izpack/installer/InstallerFrame.java	(revision 2938)
+++ src/lib/com/izforge/izpack/installer/InstallerFrame.java	(working copy)
@@ -720,8 +720,35 @@
      */
     protected void switchPanel(int last) {
         // refresh dynamic variables every time, a panel switch is done
-        this.parentInstaller.refreshDynamicVariables(substitutor, installdata);
         try {
+            this.parentInstaller.refreshDynamicVariables(substitutor, installdata);
+        }
+        catch(Exception e) {
+            Debug.trace("Refreshing dynamic variables failed, asking user whether to proceed.");
+            StringBuffer msg = new StringBuffer();
+            msg.append("<html>");
+            msg.append("The following error occured during refreshing panel contents:<br>");
+            msg.append("<i>"+e.getMessage()+"</i><br>");
+            msg.append("Are you sure you want to continue with this installation?");
+            msg.append("</html>");
+            JLabel label = new JLabel(msg.toString());
+            label.setFont(new Font("Sans Serif", Font.PLAIN, 12));
+            Object[] optionValues = {"Continue", "Exit"};
+            int selectedOption = JOptionPane.showOptionDialog(null, label, "Warning",
+                    JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, optionValues,
+                    optionValues[1]);
+            Debug.trace("Selected option: " + selectedOption);
+            if (selectedOption == 0)
+            {
+                Debug.trace("Continuing installation");
+            }
+            else
+            {
+                Debug.trace("Exiting");
+                System.exit(1);
+            }
+        }
+        try {
             if (installdata.curPanelNumber < last) {
                 isBack = true;
             }
Index: src/lib/com/izforge/izpack/util/DynamicVariableSubstitutor.java
===================================================================
--- src/lib/com/izforge/izpack/util/DynamicVariableSubstitutor.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/DynamicVariableSubstitutor.java	(revision 0)
@@ -0,0 +1,101 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util;
+
+import java.io.*;
+import java.util.*;
+
+import com.izforge.izpack.compiler.DynamicVariable;
+import com.izforge.izpack.rules.RulesEngine;
+import com.izforge.izpack.util.variable.Value;
+
+/**
+ * Substitutes variables occurring in an input stream or a string. This implementation supports a
+ * generic variable value mapping and escapes the possible special characters occurring in the
+ * substituted values. The file types specifically supported are plain text files (no escaping),
+ * Java properties files, and XML files. A valid variable name matches the regular expression
+ * [a-zA-Z][a-zA-Z0-9_]* and names are case sensitive. Variables are referenced either by $NAME or
+ * ${NAME} (the latter syntax being useful in situations like ${NAME}NOTPARTOFNAME). If a referenced
+ * variable is undefined then it is not substituted but the corresponding part of the stream is
+ * copied as is.
+ *
+ * @author Johannes Lehtinen <johannes.lehtinen@iki.fi>
+ * @author René Krell <rkrell@gmx.net>
+ */
+public class DynamicVariableSubstitutor extends VariableSubstitutorBase implements Serializable
+{
+    /**
+     *
+     */
+    private static final long serialVersionUID = 6585770687685394673L;
+
+    /**
+     * dynamic variables
+     */
+    protected transient Map<String, List<DynamicVariable>> dynamicvariables;
+
+    protected RulesEngine rules;
+
+    /**
+     * Constructs a new substitutor using the specified variable value mappings. The environment
+     * hashtable is copied by reference. Braces are not required by default
+     *
+     * @param variables the map with variable value mappings
+     */
+    public DynamicVariableSubstitutor(Map<String, List<DynamicVariable>> dynamicvariables,
+            RulesEngine rules)
+    {
+        this.dynamicvariables = dynamicvariables;
+        this.rules = rules;
+    }
+
+
+    @Override
+    public Value getValue(String name) {
+        if (dynamicvariables != null)
+        {
+            for (String dynvarname : dynamicvariables.keySet())
+            {
+                for (DynamicVariable dynvar : dynamicvariables.get(dynvarname))
+                {
+                    String conditionid = dynvar.getConditionid();
+                    if ((conditionid != null) && (conditionid.length() > 0))
+                    {
+                        if ((rules != null) && rules.isConditionTrue(conditionid))
+                        {
+                            Debug.log("refresh condition");
+                            // condition for this rule is true
+                            return dynvar.getValue();
+                        }
+                    }
+                    else
+                    {
+                        // empty condition
+                        return dynvar.getValue();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+}
+
Index: src/lib/com/izforge/izpack/util/IoHelper.java
===================================================================
--- src/lib/com/izforge/izpack/util/IoHelper.java	(revision 2938)
+++ src/lib/com/izforge/izpack/util/IoHelper.java	(working copy)
@@ -1,17 +1,17 @@
 /*
  * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
- * 
+ *
  * http://izpack.org/
  * http://izpack.codehaus.org/
- * 
+ *
  * Copyright 2004 Elmar Klaus Bartz
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *     http://www.apache.org/licenses/LICENSE-2.0
- *     
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -184,7 +184,14 @@
         {
             BufferedInputStream bin = new BufferedInputStream(in, 5120);
             BufferedOutputStream bout = new BufferedOutputStream(out, 5120);
-            vs.substitute(bin, bout, type, null);
+            try
+            {
+                vs.substitute(bin, bout, type, null);
+            }
+            catch (Exception e)
+            {
+                throw new IOException(e.getMessage());
+            }
             bin.close();
             bout.close();
         }
Index: src/lib/com/izforge/izpack/util/RegularExpressionProcessor.java
===================================================================
--- src/lib/com/izforge/izpack/util/RegularExpressionProcessor.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/RegularExpressionProcessor.java	(revision 0)
@@ -0,0 +1,163 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util;
+
+import java.util.Vector;
+
+import com.izforge.izpack.util.regex.*;
+
+/**
+ * Regular expression utility adapted from and inspired by the PropertyRegEx Ant task
+ * (project Ant Contrib)
+ *
+ * @see <a href='http://ant-contrib.sourceforge.net'>Ant Contrib project</a>
+ * @author René Krell - changes against the original implementation ant-contrib 1.0b3
+ */
+public class RegularExpressionProcessor
+{
+    private String input;
+
+    private RegularExpression regexp;
+    private String select;
+    private String replace;
+    private String defaultValue;
+
+    private boolean caseSensitive = true;
+    private boolean global = true;
+
+    public void setInput(String input)
+    {
+        this.input = input;
+    }
+
+    public void setDefaultValue(String defaultValue)
+    {
+        this.defaultValue = defaultValue;
+    }
+
+    public void setRegexp(String regex) throws RuntimeException
+    {
+        this.regexp = new RegularExpression();
+        this.regexp.setPattern(regex);
+    }
+
+
+    public void setReplace(String replace)
+    {
+        if (select != null)
+            throw new IllegalArgumentException("You cannot specify both a select and replace expression");
+        this.replace = replace;
+    }
+
+    public void setSelect(String select)
+    {
+        if (replace != null)
+            throw new IllegalArgumentException("You cannot specify both a select and replace expression");
+        this.select = select;
+    }
+
+    public void setCaseSensitive(boolean caseSensitive)
+    {
+        this.caseSensitive = caseSensitive;
+    }
+
+    public void setGlobal(boolean global)
+    {
+        this.global = global;
+    }
+
+    protected String doReplace () throws RuntimeException
+    {
+        if (replace == null)
+            throw new IllegalArgumentException("No replace expression specified.");
+
+        int options = 0;
+        if (! caseSensitive)
+            options |= Regexp.MATCH_CASE_INSENSITIVE;
+        if (global)
+            options |= Regexp.REPLACE_ALL;
+
+        Regexp sregex = regexp.getRegexp();
+
+        String output = null;
+
+        if (sregex.matches(input, options)) {
+            output = sregex.substitute(input,
+                                       replace,
+                                       options);
+        }
+
+        if (output == null)
+            output = defaultValue;
+
+        return output;
+    }
+
+    protected String doSelect() throws RuntimeException
+    {
+        if (select == null)
+            throw new IllegalArgumentException("No select expression specified.");
+
+        int options = 0;
+        if (! caseSensitive)
+            options |= Regexp.MATCH_CASE_INSENSITIVE;
+
+        Regexp sregex = regexp.getRegexp();
+
+        String output = select;
+        Vector<String> groups = sregex.getGroups(input, options);
+
+        if (groups != null && groups.size() > 0)
+        {
+            output = RegexUtil.select(select, groups);
+        }
+        else
+        {
+            output = null;
+        }
+
+        if (output == null)
+            output = defaultValue;
+
+        return output;
+    }
+
+
+    protected void validate()
+    {
+        if (regexp == null)
+            throw new IllegalArgumentException("No match expression specified.");
+        if (replace == null && select == null)
+            throw new IllegalArgumentException("You must specify either a replace or select expression");
+    }
+
+    public String execute()
+    {
+        validate();
+
+        if (replace != null)
+            return doReplace();
+        else
+            return doSelect();
+    }
+
+}
Index: src/lib/com/izforge/izpack/util/VariableSubstitutor.java
===================================================================
--- src/lib/com/izforge/izpack/util/VariableSubstitutor.java	(revision 2888)
+++ src/lib/com/izforge/izpack/util/VariableSubstitutor.java	(working copy)
@@ -1,17 +1,17 @@
 /*
  * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
- * 
+ *
  * http://izpack.org/
  * http://izpack.codehaus.org/
- * 
+ *
  * Copyright 2001 Johannes Lehtinen
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *     http://www.apache.org/licenses/LICENSE-2.0
- *     
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,10 +22,10 @@
 package com.izforge.izpack.util;
 
 import java.io.*;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Properties;
 
+import com.izforge.izpack.util.variable.*;
+
 /**
  * Substitutes variables occurring in an input stream or a string. This implementation supports a
  * generic variable value mapping and escapes the possible special characters occurring in the
@@ -37,13 +37,10 @@
  * copied as is.
  *
  * @author Johannes Lehtinen <johannes.lehtinen@iki.fi>
+ * @author René Krell <rkrell@gmx.net>
  */
-public class VariableSubstitutor implements Serializable
+public class VariableSubstitutor extends VariableSubstitutorBase implements Serializable
 {
-
-    /**
-     *
-     */
     private static final long serialVersionUID = 3907213762447685687L;
 
     /**
@@ -52,69 +49,6 @@
     protected transient Properties variables;
 
     /**
-     * Whether braces are required for substitution.
-     */
-    protected boolean bracesRequired = false;
-
-    /**
-     * A constant for file type. Plain file.
-     */
-    protected final static int TYPE_PLAIN = 0;
-
-    /**
-     * A constant for file type. Java properties file.
-     */
-    protected final static int TYPE_JAVA_PROPERTIES = 1;
-
-    /**
-     * A constant for file type. XML file.
-     */
-    protected final static int TYPE_XML = 2;
-
-    /**
-     * A constant for file type. Shell file.
-     */
-    protected final static int TYPE_SHELL = 3;
-
-    /**
-     * A constant for file type. Plain file with '@' start char.
-     */
-    protected final static int TYPE_AT = 4;
-
-    /**
-     * A constant for file type. Java file, where \ have to be escaped.
-     */
-    protected final static int TYPE_JAVA = 5;
-
-    /**
-     * A constant for file type. Plain file with ANT-like variable markers, ie @param@
-     */
-    protected final static int TYPE_ANT = 6;
-
-    /**
-     * PLAIN = "plain"
-     */
-    public final static String PLAIN = "plain";
-
-    /**
-     * A mapping of file type names to corresponding integer constants.
-     */
-    protected final static Map<String, Integer> typeNameToConstantMap;
-
-    // Initialize the file type map
-    static
-    {
-        typeNameToConstantMap = new HashMap<String, Integer>();
-        typeNameToConstantMap.put("plain", TYPE_PLAIN);
-        typeNameToConstantMap.put("javaprop", TYPE_JAVA_PROPERTIES);
-        typeNameToConstantMap.put("java", TYPE_JAVA);
-        typeNameToConstantMap.put("xml", TYPE_XML);
-        typeNameToConstantMap.put("shell", TYPE_SHELL);
-        typeNameToConstantMap.put("at", TYPE_AT);
-        typeNameToConstantMap.put("ant", TYPE_ANT);
-    }
-
-    /**
      * Constructs a new substitutor using the specified variable value mappings. The environment
      * hashtable is copied by reference. Braces are not required by default
      *
@@ -125,410 +59,9 @@
         this.variables = variables;
     }
 
-    /**
-     * Get whether this substitutor requires braces.
-     */
-    public boolean areBracesRequired()
-    {
-        return bracesRequired;
+    @Override
+    public Value getValue(String name) {
+        return new PlainValue(variables.getProperty(name));
     }
-
-    /**
-     * Specify whether this substitutor requires braces.
-     */
-    public void setBracesRequired(boolean braces)
-    {
-        bracesRequired = braces;
-    }
-
-    /**
-     * Substitutes the variables found in the specified string. Escapes special characters using
-     * file type specific escaping if necessary.
-     *
-     * @param str  the string to check for variables
-     * @param type the escaping type or null for plain
-     * @return the string with substituted variables
-     * @throws IllegalArgumentException if unknown escaping type specified
-     */
-    public String substitute(String str, String type) throws IllegalArgumentException
-    {
-        if (str == null)
-        {
-            return null;
-        }
-
-        // Create reader and write for the strings
-        StringReader reader = new StringReader(str);
-        StringWriter writer = new StringWriter();
-
-        // Substitute any variables
-        try
-        {
-            substitute(reader, writer, type);
-        }
-        catch (IOException e)
-        {
-            throw new Error("Unexpected I/O exception when reading/writing memory "
-                    + "buffer; nested exception is: " + e);
-        }
-
-        // Return the resulting string
-        return writer.getBuffer().toString();
-    }
-
-    /**
-     * Substitutes the variables found in the specified input stream. Escapes special characters
-     * using file type specific escaping if necessary.
-     *
-     * @param in       the input stream to read
-     * @param out      the output stream to write
-     * @param type     the file type or null for plain
-     * @param encoding the character encoding or null for default
-     * @return the number of substitutions made
-     * @throws IllegalArgumentException     if unknown file type specified
-     * @throws UnsupportedEncodingException if encoding not supported
-     * @throws IOException                  if an I/O error occurs
-     */
-    public int substitute(InputStream in, OutputStream out, String type, String encoding)
-            throws IllegalArgumentException, UnsupportedEncodingException, IOException
-    {
-        // Check if file type specific default encoding known
-        if (encoding == null)
-        {
-            int t = getTypeConstant(type);
-            switch (t)
-            {
-                case TYPE_JAVA_PROPERTIES:
-                    encoding = "ISO-8859-1";
-                    break;
-                case TYPE_XML:
-                    encoding = "UTF-8";
-                    break;
-            }
-        }
-
-        // Create the reader and write
-        InputStreamReader reader = (encoding != null ? new InputStreamReader(in, encoding)
-                : new InputStreamReader(in));
-        OutputStreamWriter writer = (encoding != null ? new OutputStreamWriter(out, encoding)
-                : new OutputStreamWriter(out));
-
-        // Copy the data and substitute variables
-        int subs = substitute(reader, writer, type);
-
-        // Flush the write so that everything gets written out
-        writer.flush();
-
-        return subs;
-    }
-
-    /**
-     * Substitute method Variant that gets An Input Stream and returns A String
-     *
-     * @param in   The Input Stream, with Placeholders
-     * @param type The used FormatType
-     * @return the substituted result as string
-     * @throws IllegalArgumentException     If a wrong input was given.
-     * @throws UnsupportedEncodingException If the file comes with a wrong Encoding
-     * @throws IOException                  If an I/O Error occurs.
-     */
-    public String substitute(InputStream in, String type
-    )
-            throws IllegalArgumentException, UnsupportedEncodingException,
-            IOException
-    {
-        // Check if file type specific default encoding known
-        String encoding = PLAIN;
-        {
-            int t = getTypeConstant(type);
-
-            switch (t)
-            {
-                case TYPE_JAVA_PROPERTIES:
-                    encoding = "ISO-8859-1";
-
-                    break;
-
-                case TYPE_XML:
-                    encoding = "UTF-8";
-
-                    break;
-            }
-        }
-
-        // Create the reader and write
-        InputStreamReader reader = ((encoding != null)
-                ? new InputStreamReader(in, encoding)
-                : new InputStreamReader(in));
-        StringWriter writer = new StringWriter();
-
-        // Copy the data and substitute variables
-        substitute(reader, writer, type);
-
-        // Flush the write so that everything gets written out
-        writer.flush();
-
-        return writer.getBuffer().toString();
-    }
-
-
-    /**
-     * Substitutes the variables found in the data read from the specified reader. Escapes special
-     * characters using file type specific escaping if necessary.
-     *
-     * @param reader the reader to read
-     * @param writer the writer used to write data out
-     * @param type   the file type or null for plain
-     * @return the number of substitutions made
-     * @throws IllegalArgumentException if unknown file type specified
-     * @throws IOException              if an I/O error occurs
-     */
-    public int substitute(Reader reader, Writer writer, String type)
-            throws IllegalArgumentException, IOException
-    {
-        // Check the file type
-        int t = getTypeConstant(type);
-
-        // determine character which starts (and ends) a variable
-        char variable_start = '$';
-        char variable_end = '\0';
-        if (t == TYPE_SHELL)
-        {
-            variable_start = '%';
-        }
-        else if (t == TYPE_AT)
-        {
-            variable_start = '@';
-        }
-        else if (t == TYPE_ANT)
-        {
-            variable_start = '@';
-            variable_end = '@';
-        }
-
-
-        int subs = 0;
-
-        // Copy data and substitute variables
-        int c = reader.read();
-
-        while (true)
-        {
-            // Find the next potential variable reference or EOF
-            while (c != -1 && c != variable_start)
-            {
-                writer.write(c);
-                c = reader.read();
-            }
-            if (c == -1)
-            {
-                return subs;
-            }
-
-            // Check if braces used or start char escaped
-            boolean braces = false;
-            c = reader.read();
-            if (c == '{')
-            {
-                braces = true;
-                c = reader.read();
-            }
-            else if (bracesRequired)
-            {
-                writer.write(variable_start);
-                continue;
-            }
-            else if (c == -1)
-            {
-                writer.write(variable_start);
-                return subs;
-            }
-
-            // Read the variable name
-            StringBuffer nameBuffer = new StringBuffer();
-            while (c != -1 && (braces && c != '}') || (c >= 'a' && c <= 'z')
-                    || (c >= 'A' && c <= 'Z') || (braces && ((c == '[') || (c == ']')))
-                    || (((c >= '0' && c <= '9') || c == '_' || c == '.' || c == '-') && nameBuffer.length() > 0))
-            {
-                nameBuffer.append((char) c);
-                c = reader.read();
-            }
-            String name = nameBuffer.toString();
-
-            // Check if a legal and defined variable found
-            String varvalue = null;
-
-            if (((!braces || c == '}') &&
-                    (!braces || variable_end == '\0' || variable_end == c)
-            ) && name.length() > 0)
-            {
-                // check for environment variables
-                if (braces && name.startsWith("ENV[")
-                        && (name.lastIndexOf(']') == name.length() - 1))
-                {
-                    varvalue = IoHelper.getenv(name.substring(4, name.length() - 1));
-                    if (varvalue == null)
-                        varvalue = "";
-                }
-                else
-                {
-                    varvalue = variables.getProperty(name);
-                }
-
-                subs++;
-            }
-
-            // Substitute the variable...
-            if (varvalue != null)
-            {
-                writer.write(escapeSpecialChars(varvalue, t));
-                if (braces || variable_end != '\0')
-                {
-                    c = reader.read();
-                }
-            }
-            // ...or ignore it
-            else
-            {
-                writer.write(variable_start);
-                if (braces)
-                {
-                    writer.write('{');
-                }
-                writer.write(name);
-            }
-        }
-    }
-
-    /**
-     * Returns the internal constant for the specified file type.
-     *
-     * @param type the type name or null for plain
-     * @return the file type constant
-     */
-    protected int getTypeConstant(String type)
-    {
-        if (type == null)
-        {
-            return TYPE_PLAIN;
-        }
-        Integer integer = typeNameToConstantMap.get(type);
-        if (integer == null)
-        {
-            throw new IllegalArgumentException("Unknown file type " + type);
-        }
-        else
-        {
-            return integer;
-        }
-    }
-
-    /**
-     * Escapes the special characters in the specified string using file type specific rules.
-     *
-     * @param str  the string to check for special characters
-     * @param type the target file type (one of TYPE_xxx)
-     * @return the string with the special characters properly escaped
-     */
-    protected String escapeSpecialChars(String str, int type)
-    {
-        StringBuffer buffer;
-        int len;
-        int i;
-        switch (type)
-        {
-            case TYPE_PLAIN:
-            case TYPE_AT:
-            case TYPE_ANT:
-                return str;
-            case TYPE_SHELL:
-                //apple mac has major problem with \r, make sure they are gone
-                return str.replace("\r","");
-            case TYPE_JAVA_PROPERTIES:
-            case TYPE_JAVA:
-                buffer = new StringBuffer(str);
-                len = str.length();
-                for (i = 0; i < len; i++)
-                {
-                    // Check for control characters
-                    char c = buffer.charAt(i);
-                    if (type == TYPE_JAVA_PROPERTIES)
-                    {
-                        if (c == '\t' || c == '\n' || c == '\r')
-                        {
-                            char tag;
-                            if (c == '\t')
-                            {
-                                tag = 't';
-                            }
-                            else if (c == '\n')
-                            {
-                                tag = 'n';
-                            }
-                            else
-                            {
-                                tag = 'r';
-                            }
-                            buffer.replace(i, i + 1, "\\" + tag);
-                            len++;
-                            i++;
-                        }
-
-                        // Check for special characters
-                        if (c == '\\' || c == '"' || c == '\'' || c == ' ')
-                        {
-                            buffer.insert(i, '\\');
-                            len++;
-                            i++;
-                        }
-                    }
-                    else
-                    {
-                        if (c == '\\')
-                        {
-                            buffer.replace(i, i + 1, "\\\\");
-                            len++;
-                            i++;
-                        }
-                    }
-                }
-                return buffer.toString();
-            case TYPE_XML:
-                buffer = new StringBuffer(str);
-                len = str.length();
-                for (i = 0; i < len; i++)
-                {
-                    String r = null;
-                    char c = buffer.charAt(i);
-                    switch (c)
-                    {
-                        case '<':
-                            r = "&lt;";
-                            break;
-                        case '>':
-                            r = "&gt;";
-                            break;
-                        case '&':
-                            r = "&amp;";
-                            break;
-                        case '\'':
-                            r = "&apos;";
-                            break;
-                        case '"':
-                            r = "&quot;";
-                            break;
-                    }
-                    if (r != null)
-                    {
-                        buffer.replace(i, i + 1, r);
-                        len = buffer.length();
-                        i += r.length() - 1;
-                    }
-                }
-                return buffer.toString();
-            default:
-                throw new Error("Unknown file type constant " + type);
-        }
-    }
 }
 
Index: src/lib/com/izforge/izpack/util/VariableSubstitutorBase.java
===================================================================
--- src/lib/com/izforge/izpack/util/VariableSubstitutorBase.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/VariableSubstitutorBase.java	(revision 0)
@@ -0,0 +1,512 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.izforge.izpack.util.variable.Value;
+
+/**
+ * Substitutes variables occurring in an input stream or a string. This implementation supports a
+ * generic variable value mapping and escapes the possible special characters occurring in the
+ * substituted values. The file types specifically supported are plain text files (no escaping),
+ * Java properties files, and XML files. A valid variable name matches the regular expression
+ * [a-zA-Z][a-zA-Z0-9_]* and names are case sensitive. Variables are referenced either by $NAME or
+ * ${NAME} (the latter syntax being useful in situations like ${NAME}NOTPARTOFNAME). If a referenced
+ * variable is undefined then it is not substituted but the corresponding part of the stream is
+ * copied as is.
+ *
+ * This is a abstract base type for all kinds of variables
+ *
+ * @author Johannes Lehtinen <johannes.lehtinen@iki.fi>
+ * @author René Krell <rkrell@gmx.net>
+ */
+public abstract class VariableSubstitutorBase
+{
+    /**
+     * Whether braces are required for substitution.
+     */
+    protected boolean bracesRequired = false;
+
+    /**
+     * A constant for file type. Plain file.
+     */
+    protected final static int TYPE_PLAIN = 0;
+
+    /**
+     * A constant for file type. Java properties file.
+     */
+    protected final static int TYPE_JAVA_PROPERTIES = 1;
+
+    /**
+     * A constant for file type. XML file.
+     */
+    protected final static int TYPE_XML = 2;
+
+    /**
+     * A constant for file type. Shell file.
+     */
+    protected final static int TYPE_SHELL = 3;
+
+    /**
+     * A constant for file type. Plain file with '@' start char.
+     */
+    protected final static int TYPE_AT = 4;
+
+    /**
+     * A constant for file type. Java file, where \ have to be escaped.
+     */
+    protected final static int TYPE_JAVA = 5;
+
+    /**
+     * A constant for file type. Plain file with ANT-like variable markers, ie @param@
+     */
+    protected final static int TYPE_ANT = 6;
+
+    /**
+     * PLAIN = "plain"
+     */
+    public final static String PLAIN = "plain";
+
+    /**
+     * A mapping of file type names to corresponding integer constants.
+     */
+    protected final static Map<String, Integer> typeNameToConstantMap;
+
+    // Initialize the file type map
+    static
+    {
+        typeNameToConstantMap = new HashMap<String, Integer>();
+        typeNameToConstantMap.put("plain", TYPE_PLAIN);
+        typeNameToConstantMap.put("javaprop", TYPE_JAVA_PROPERTIES);
+        typeNameToConstantMap.put("java", TYPE_JAVA);
+        typeNameToConstantMap.put("xml", TYPE_XML);
+        typeNameToConstantMap.put("shell", TYPE_SHELL);
+        typeNameToConstantMap.put("at", TYPE_AT);
+        typeNameToConstantMap.put("ant", TYPE_ANT);
+    }
+
+    protected abstract Value getValue(String name);
+
+    /**
+     * Get whether this substitutor requires braces.
+     */
+    public boolean isBracesRequired()
+    {
+        return bracesRequired;
+    }
+
+    /**
+     * Specify whether this substitutor requires braces.
+     */
+    public void setBracesRequired(boolean braces)
+    {
+        bracesRequired = braces;
+    }
+
+    /**
+     * Substitutes the variables found in the specified string. Escapes special characters using
+     * file type specific escaping if necessary.
+     *
+     * @param str  the string to check for variables
+     * @param type the escaping type or null for plain
+     * @return the string with substituted variables
+     * @throws IllegalArgumentException An error occured
+     */
+    public String substitute(String str, String type) throws IllegalArgumentException
+    {
+        if (str == null)
+        {
+            return null;
+        }
+
+        // Create reader and write for the strings
+        StringReader reader = new StringReader(str);
+        StringWriter writer = new StringWriter();
+
+        // Substitute any variables
+        try
+        {
+            substitute(reader, writer, type);
+        }
+        catch (Exception e)
+        {
+            throw new Error(e.getMessage());
+        }
+
+        // Return the resulting string
+        return writer.getBuffer().toString();
+    }
+
+    /**
+     * Substitutes the variables found in the specified input stream. Escapes special characters
+     * using file type specific escaping if necessary.
+     *
+     * @param in       the input stream to read
+     * @param out      the output stream to write
+     * @param type     the file type or null for plain
+     * @param encoding the character encoding or null for default
+     * @return the number of substitutions made
+     * @throws Exception An error occured
+     */
+    public int substitute(InputStream in, OutputStream out, String type, String encoding)
+            throws Exception
+    {
+        // Check if file type specific default encoding known
+        if (encoding == null)
+        {
+            int t = getTypeConstant(type);
+            switch (t)
+            {
+                case TYPE_JAVA_PROPERTIES:
+                    encoding = "ISO-8859-1";
+                    break;
+                case TYPE_XML:
+                    encoding = "UTF-8";
+                    break;
+            }
+        }
+
+        // Create the reader and write
+        InputStreamReader reader = (encoding != null ? new InputStreamReader(in, encoding)
+                : new InputStreamReader(in));
+        OutputStreamWriter writer = (encoding != null ? new OutputStreamWriter(out, encoding)
+                : new OutputStreamWriter(out));
+
+        // Copy the data and substitute variables
+        int subs = substitute(reader, writer, type);
+
+        // Flush the write so that everything gets written out
+        writer.flush();
+
+        return subs;
+    }
+
+    /**
+     * Substitute method Variant that gets An Input Stream and returns A String
+     *
+     * @param in   The Input Stream, with Placeholders
+     * @param type The used FormatType
+     * @return the substituted result as string
+     * @throws Exception An error occured
+     */
+    public String substitute(InputStream in, String type)
+    throws Exception
+    {
+        // Check if file type specific default encoding known
+        String encoding = PLAIN;
+        {
+            int t = getTypeConstant(type);
+
+            switch (t)
+            {
+                case TYPE_JAVA_PROPERTIES:
+                    encoding = "ISO-8859-1";
+
+                    break;
+
+                case TYPE_XML:
+                    encoding = "UTF-8";
+
+                    break;
+            }
+        }
+
+        // Create the reader and write
+        InputStreamReader reader = ((encoding != null)
+                ? new InputStreamReader(in, encoding)
+                : new InputStreamReader(in));
+        StringWriter writer = new StringWriter();
+
+        // Copy the data and substitute variables
+        substitute(reader, writer, type);
+
+        // Flush the write so that everything gets written out
+        writer.flush();
+
+        return writer.getBuffer().toString();
+    }
+
+
+    /**
+     * Substitutes the variables found in the data read from the specified reader. Escapes special
+     * characters using file type specific escaping if necessary.
+     *
+     * @param reader the reader to read
+     * @param writer the writer used to write data out
+     * @param type   the file type or null for plain
+     * @return the number of substitutions made
+     * @throws Exception An error occured
+     */
+    public int substitute(Reader reader, Writer writer, String type)
+    throws Exception
+    {
+        // Check the file type
+        int t = getTypeConstant(type);
+
+        // determine character which starts (and ends) a variable
+        char variable_start = '$';
+        char variable_end = '\0';
+        if (t == TYPE_SHELL)
+        {
+            variable_start = '%';
+        }
+        else if (t == TYPE_AT)
+        {
+            variable_start = '@';
+        }
+        else if (t == TYPE_ANT)
+        {
+            variable_start = '@';
+            variable_end = '@';
+        }
+
+
+        int subs = 0;
+
+        // Copy data and substitute variables
+        int c = reader.read();
+
+        while (true)
+        {
+            // Find the next potential variable reference or EOF
+            while (c != -1 && c != variable_start)
+            {
+                writer.write(c);
+                c = reader.read();
+            }
+            if (c == -1)
+            {
+                return subs;
+            }
+
+            // Check if braces used or start char escaped
+            boolean braces = false;
+            c = reader.read();
+            if (c == '{')
+            {
+                braces = true;
+                c = reader.read();
+            }
+            else if (bracesRequired)
+            {
+                writer.write(variable_start);
+                continue;
+            }
+            else if (c == -1)
+            {
+                writer.write(variable_start);
+                return subs;
+            }
+
+            // Read the variable name
+            StringBuffer nameBuffer = new StringBuffer();
+            while (c != -1 && (braces && c != '}') || (c >= 'a' && c <= 'z')
+                    || (c >= 'A' && c <= 'Z') || (braces && ((c == '[') || (c == ']')))
+                    || (((c >= '0' && c <= '9') || c == '_' || c == '.' || c == '-') && nameBuffer.length() > 0))
+            {
+                nameBuffer.append((char) c);
+                c = reader.read();
+            }
+            String name = nameBuffer.toString();
+
+            // Check if a legal and defined variable found
+            String varvalue = null;
+
+            if (((!braces || c == '}') &&
+                    (!braces || variable_end == '\0' || variable_end == c)
+            ) && name.length() > 0)
+            {
+                // check for environment variables
+                if (braces && name.startsWith("ENV[")
+                        && (name.lastIndexOf(']') == name.length() - 1))
+                {
+                    varvalue = IoHelper.getenv(name.substring(4, name.length() - 1));
+                    if (varvalue == null)
+                        varvalue = "";
+                }
+                else
+                {
+                    Value val = getValue(name);
+                    if (val != null)
+                        varvalue = val.resolve();
+                }
+
+                subs++;
+            }
+
+            // Substitute the variable...
+            if (varvalue != null)
+            {
+                writer.write(escapeSpecialChars(varvalue, t));
+                if (braces || variable_end != '\0')
+                {
+                    c = reader.read();
+                }
+            }
+            // ...or ignore it
+            else
+            {
+                writer.write(variable_start);
+                if (braces)
+                {
+                    writer.write('{');
+                }
+                writer.write(name);
+            }
+        }
+    }
+
+    /**
+     * Returns the internal constant for the specified file type.
+     *
+     * @param type the type name or null for plain
+     * @return the file type constant
+     */
+    protected int getTypeConstant(String type)
+    {
+        if (type == null)
+        {
+            return TYPE_PLAIN;
+        }
+        Integer integer = typeNameToConstantMap.get(type);
+        if (integer == null)
+        {
+            throw new IllegalArgumentException("Unknown file type " + type);
+        }
+        else
+        {
+            return integer;
+        }
+    }
+
+    /**
+     * Escapes the special characters in the specified string using file type specific rules.
+     *
+     * @param str  the string to check for special characters
+     * @param type the target file type (one of TYPE_xxx)
+     * @return the string with the special characters properly escaped
+     */
+    protected String escapeSpecialChars(String str, int type)
+    {
+        StringBuffer buffer;
+        int len;
+        int i;
+        switch (type)
+        {
+            case TYPE_PLAIN:
+            case TYPE_AT:
+            case TYPE_ANT:
+                return str;
+            case TYPE_SHELL:
+                //apple mac has major problem with \r, make sure they are gone
+                return str.replace("\r","");
+            case TYPE_JAVA_PROPERTIES:
+            case TYPE_JAVA:
+                buffer = new StringBuffer(str);
+                len = str.length();
+                for (i = 0; i < len; i++)
+                {
+                    // Check for control characters
+                    char c = buffer.charAt(i);
+                    if (type == TYPE_JAVA_PROPERTIES)
+                    {
+                        if (c == '\t' || c == '\n' || c == '\r')
+                        {
+                            char tag;
+                            if (c == '\t')
+                            {
+                                tag = 't';
+                            }
+                            else if (c == '\n')
+                            {
+                                tag = 'n';
+                            }
+                            else
+                            {
+                                tag = 'r';
+                            }
+                            buffer.replace(i, i + 1, "\\" + tag);
+                            len++;
+                            i++;
+                        }
+
+                        // Check for special characters
+                        if (c == '\\' || c == '"' || c == '\'' || c == ' ')
+                        {
+                            buffer.insert(i, '\\');
+                            len++;
+                            i++;
+                        }
+                    }
+                    else
+                    {
+                        if (c == '\\')
+                        {
+                            buffer.replace(i, i + 1, "\\\\");
+                            len++;
+                            i++;
+                        }
+                    }
+                }
+                return buffer.toString();
+            case TYPE_XML:
+                buffer = new StringBuffer(str);
+                len = str.length();
+                for (i = 0; i < len; i++)
+                {
+                    String r = null;
+                    char c = buffer.charAt(i);
+                    switch (c)
+                    {
+                        case '<':
+                            r = "&lt;";
+                            break;
+                        case '>':
+                            r = "&gt;";
+                            break;
+                        case '&':
+                            r = "&amp;";
+                            break;
+                        case '\'':
+                            r = "&apos;";
+                            break;
+                        case '"':
+                            r = "&quot;";
+                            break;
+                    }
+                    if (r != null)
+                    {
+                        buffer.replace(i, i + 1, r);
+                        len = buffer.length();
+                        i += r.length() - 1;
+                    }
+                }
+                return buffer.toString();
+            default:
+                throw new Error("Unknown file type constant " + type);
+        }
+    }
+}
+
Index: src/lib/com/izforge/izpack/util/regex/JavaRegexp.java
===================================================================
--- src/lib/com/izforge/izpack/util/regex/JavaRegexp.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/regex/JavaRegexp.java	(revision 0)
@@ -0,0 +1,110 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.regex;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/***
+ * Regular expression implementation using the JDK 1.4 regular expression package
+ *
+ * @see <a href='http://ant.apache.org'>Apache Ant</a>
+ * @author René Krell - changes against the original implementation in Apache Ant 1.6.5
+ */
+public class JavaRegexp extends JavaRegexpMatcher implements Regexp {
+
+    /** Constructor for Jdk14RegexpRegexp */
+    public JavaRegexp() {
+        super();
+    }
+
+    /**
+     * Convert ant regexp substitution option to jdk1.4 options.
+     *
+     * @param options the ant regexp options
+     * @return the jdk14 substition options
+     */
+    protected int getSubsOptions(int options) {
+        int subsOptions = REPLACE_FIRST;
+        if (RegexUtil.hasFlag(options, REPLACE_ALL)) {
+            subsOptions = REPLACE_ALL;
+        }
+        return subsOptions;
+    }
+
+    /**
+     * Perform a substitution on the regular expression.
+     * @param input The string to substitute on
+     * @param argument The string which defines the substitution
+     * @param options The list of options for the match and replace.
+     * @return the result of the operation
+     * @throws BuildException on error
+     */
+    public String substitute(String input, String argument, int options)
+    throws RuntimeException
+    {
+        // translate \1 to $(1) so that the Matcher will work
+        StringBuffer subst = new StringBuffer();
+        for (int i = 0; i < argument.length(); i++) {
+            char c = argument.charAt(i);
+            if (c == '$') {
+                subst.append('\\');
+                subst.append('$');
+            } else if (c == '\\') {
+                if (++i < argument.length()) {
+                    c = argument.charAt(i);
+                    int value = Character.digit(c, 10);
+                    if (value > -1) {
+                        subst.append("$").append(value);
+                    } else {
+                        subst.append(c);
+                    }
+                } else {
+                    // XXX - should throw an exception instead?
+                    subst.append('\\');
+                }
+            } else {
+                subst.append(c);
+            }
+        }
+        argument = subst.toString();
+
+        int sOptions = getSubsOptions(options);
+        Pattern p = getCompiledPattern(options);
+        StringBuffer sb = new StringBuffer();
+
+        Matcher m = p.matcher(input);
+        if (RegexUtil.hasFlag(sOptions, REPLACE_ALL)) {
+            sb.append(m.replaceAll(argument));
+        } else {
+            boolean res = m.find();
+            if (res) {
+                m.appendReplacement(sb, argument);
+                m.appendTail(sb);
+            } else {
+                sb.append(input);
+            }
+        }
+
+        return sb.toString();
+    }
+}
Index: src/lib/com/izforge/izpack/util/regex/JavaRegexpMatcher.java
===================================================================
--- src/lib/com/izforge/izpack/util/regex/JavaRegexpMatcher.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/regex/JavaRegexpMatcher.java	(revision 0)
@@ -0,0 +1,174 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.regex;
+
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+ * Implementation of RegexpMatcher for the built-in regexp matcher of
+ * JDK 1.4. UNIX_LINES option is enabled as a default.
+ *
+ * @see <a href='http://ant.apache.org'>Apache Ant</a>
+ * @author René Krell - changes against the original implementation in Apache Ant 1.6.5
+ */
+public class JavaRegexpMatcher implements RegexpMatcher {
+
+    private String pattern;
+
+    /** Constructor for JakartaOroRegexp */
+    public JavaRegexpMatcher() {
+    }
+
+    /**
+     * Set the regexp pattern from the String description.
+     * @param pattern the pattern to match
+     */
+    public void setPattern(String pattern) {
+        this.pattern = pattern;
+    }
+
+    /**
+     * Get a String representation of the regexp pattern
+     * @return the pattern
+     * @throws BuildException on error
+     */
+    public String getPattern() {
+        return pattern;
+    }
+
+    /**
+     * Get a compiled representation of the regexp pattern
+     * @param options the options
+     * @return the compiled pattern
+     * @throws BuildException on error
+     */
+    protected Pattern getCompiledPattern(int options)
+    throws RuntimeException
+    {
+        int cOptions = getCompilerOptions(options);
+        try {
+            Pattern p = Pattern.compile(this.pattern, cOptions);
+            return p;
+        } catch (PatternSyntaxException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Does the given argument match the pattern using default options?
+     * @param argument the string to match against
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    public boolean matches(String argument) throws RuntimeException {
+        return matches(argument, MATCH_DEFAULT);
+    }
+
+    /**
+     * Does the given argument match the pattern?
+     * @param input the string to match against
+     * @param options the regex options to use
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    public boolean matches(String input, int options)
+        throws RuntimeException {
+        try {
+            Pattern p = getCompiledPattern(options);
+            return p.matcher(input).find();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Returns a Vector of matched groups found in the argument
+     * using default options.
+     *
+     * <p>Group 0 will be the full match, the rest are the
+     * parenthesized subexpressions</p>.
+     *
+     * @param argument the string to match against
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    public Vector<String> getGroups(String argument) throws RuntimeException {
+        return getGroups(argument, MATCH_DEFAULT);
+    }
+
+    /**
+     * Returns a Vector of matched groups found in the argument.
+     *
+     * <p>Group 0 will be the full match, the rest are the
+     * parenthesized subexpressions</p>.
+     *
+     * @param input the string to match against
+     * @param options the regex options to use
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    public Vector<String> getGroups(String input, int options) throws RuntimeException
+    {
+        Pattern p = getCompiledPattern(options);
+        Matcher matcher = p.matcher(input);
+        if (!matcher.find()) {
+            return null;
+        }
+        Vector<String> v = new Vector<String>();
+        int cnt = matcher.groupCount();
+        for (int i = 0; i <= cnt; i++) {
+            String match = matcher.group(i);
+            // treat non-matching groups as empty matches
+            if (match == null) {
+                match = "";
+            }
+            v.addElement(match);
+        }
+        return v;
+    }
+
+    /**
+     * Convert the generic options to the regex compiler specific options.
+     * @param options the generic options
+     * @return the specific options
+     */
+    protected int getCompilerOptions(int options) {
+        // be strict about line separator
+        int cOptions = Pattern.UNIX_LINES;
+
+        if (RegexUtil.hasFlag(options, MATCH_CASE_INSENSITIVE)) {
+            cOptions |= Pattern.CASE_INSENSITIVE;
+        }
+        if (RegexUtil.hasFlag(options, MATCH_MULTILINE)) {
+            cOptions |= Pattern.MULTILINE;
+        }
+        if (RegexUtil.hasFlag(options, MATCH_SINGLELINE)) {
+            cOptions |= Pattern.DOTALL;
+        }
+
+        return cOptions;
+    }
+
+}
Index: src/lib/com/izforge/izpack/util/regex/RegexUtil.java
===================================================================
--- src/lib/com/izforge/izpack/util/regex/RegexUtil.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/regex/RegexUtil.java	(revision 0)
@@ -0,0 +1,194 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.regex;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+/****************************************************************************
+ * Regular Expression utilities
+ *
+ * @author <a href='mailto:mattinger@yahoo.com'>Matthew Inger</a> (original Ant Contrib implementation part)
+ * @see <a href='http://ant.apache.org'>Apache Ant</a>
+ * @see <a href='http://ant-contrib.sourceforge.net'>Ant Contrib project</a>
+ * @author René Krell - changes against the original implementation in Apache Ant 1.6.5 and ant-contrib 1.0b3
+ ****************************************************************************/
+
+public class RegexUtil
+{
+    /***
+     * An abritrary node in a select expression
+     */
+    private static interface SelectNode
+    {
+        /***
+         * Select the value based on the groups
+         * @param groups The groups found in the match
+         */
+        public String select(Vector<String> groups);
+    }
+
+    /***
+     * A group node in a select expression
+     */
+    private static class GroupSelectNode
+        implements SelectNode
+    {
+        private int groupNumber;
+
+        public GroupSelectNode(int groupNumber)
+        {
+            this.groupNumber = groupNumber;
+        }
+
+        public String select(Vector<String> groups)
+        {
+            if ( groupNumber < groups.size())
+                return (String)groups.elementAt(groupNumber);
+            else
+                return "\\" + groupNumber;
+        }
+
+        public String toString()
+        {
+            return "group: " + groupNumber;
+        }
+    }
+
+    /***
+     * An abritrary node in a select expression
+     */
+    private static class StringSelectNode
+        implements SelectNode
+    {
+        private String text;
+
+        public StringSelectNode(String text)
+        {
+            this.text = text;
+        }
+
+        public String select(Vector<String> groups)
+        {
+            return text;
+        }
+
+        public String toString()
+        {
+            return "string: " + text;
+        }
+    }
+
+    /***
+     * Parses a select string into a List of SelectNode objects.
+     * These objects can then be merged with a group list to produce
+     * an output string (using the "select" method)
+     * @param input The select string
+     * @return a List of SelectNode objects
+     */
+    private static Vector<SelectNode> parseSelectString(String input)
+    {
+        Vector<SelectNode> nodes = new Vector<SelectNode>();
+        StringBuffer buf = new StringBuffer();
+        char c[] = input.toCharArray();
+        for (int i=0;i<c.length;i++)
+        {
+            if (c[i] == '\\')
+            {
+                if (buf.length() > 0)
+                {
+                    nodes.addElement(new StringSelectNode(buf.toString()));
+                    buf.setLength(0);
+                }
+
+                while (i+1 < c.length && Character.isDigit(c[i+1]))
+                {
+                    buf.append(c[i+1]);
+                    i++;
+                }
+
+                int groupNum = Integer.parseInt(buf.toString());
+                buf.setLength(0);
+                nodes.addElement(new GroupSelectNode(groupNum));
+            }
+            else
+            {
+                buf.append(c[i]);
+            }
+        }
+
+
+        if (buf.length() > 0)
+        {
+            nodes.addElement(new StringSelectNode(buf.toString()));
+            buf.setLength(0);
+        }
+
+        return nodes;
+    }
+
+    /***
+     * Parse a select string, and merge it with a match groups
+     * vector to produce an output string.  Each group placeholder
+     * in the select string is replaced with the group at the
+     * corresponding index in the match groups vector
+     * @param select The select string
+     * @param groups The match groups
+     * @return The output string with the merged selection
+     */
+    public static String select(String select, Vector<String> groups)
+    {
+        Vector<SelectNode> nodes = parseSelectString(select);
+
+        StringBuffer buf = new StringBuffer();
+        Enumeration<SelectNode> e = nodes.elements();
+        SelectNode node = null;
+        while (e.hasMoreElements())
+        {
+            node = (SelectNode)e.nextElement();
+            buf.append(node.select(groups));
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Check the options has a particular flag set.
+     *
+     * @param options an <code>int</code> value
+     * @param flag an <code>int</code> value
+     * @return true if the flag is set
+     */
+    public static boolean hasFlag(int options, int flag) {
+        return ((options & flag) > 0);
+    }
+
+    /**
+     * Remove a particular flag from an int value contains the option flags.
+     *
+     * @param options an <code>int</code> value
+     * @param flag an <code>int</code> value
+     * @return the options with the flag unset
+     */
+    public static int removeFlag(int options, int flag) {
+        return (options & (0xFFFFFFFF - flag));
+    }
+}
Index: src/lib/com/izforge/izpack/util/regex/Regexp.java
===================================================================
--- src/lib/com/izforge/izpack/util/regex/Regexp.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/regex/Regexp.java	(revision 0)
@@ -0,0 +1,54 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.regex;
+
+/***
+ * Interface which represents a regular expression, and the operations
+ * that can be performed on it.
+ *
+ * @see <a href='http://ant.apache.org'>Apache Ant</a>
+ * @author René Krell - changes against the original implementation in Apache Ant 1.6.5
+ */
+public interface Regexp extends RegexpMatcher {
+
+    /**
+     * Replace only the first occurance of the regular expression
+     */
+    int REPLACE_FIRST          = 0x00000001;
+
+    /**
+     * Replace all occurances of the regular expression
+     */
+    int REPLACE_ALL            = 0x00000010;
+
+    /**
+     * Perform a substitution on the regular expression.
+     * @param input The string to substitute on
+     * @param argument The string which defines the substitution
+     * @param options The list of options for the match and replace. See the
+     *                MATCH_ and REPLACE_ constants above.
+     * @return the result of the operation
+     * @throws BuildException on error
+     */
+    String substitute(String input, String argument, int options)
+        throws RuntimeException;
+}
Index: src/lib/com/izforge/izpack/util/regex/RegexpFactory.java
===================================================================
--- src/lib/com/izforge/izpack/util/regex/RegexpFactory.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/regex/RegexpFactory.java	(revision 0)
@@ -0,0 +1,96 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.regex;
+
+/***
+ * Regular expression factory, which will create Regexp objects.  The
+ * actual implementation class depends on the System or Ant Property:
+ * <code>izpack.regexp.regexpimpl</code>.
+ *
+ * @see <a href='http://ant.apache.org'>Apache Ant</a>
+ * @author René Krell - changes against the original implementation in Apache Ant 1.6.5
+ */
+public class RegexpFactory extends RegexpMatcherFactory
+{
+    /***
+     * Create a new regular expression matcher instance.
+     *
+     * @return the matcher instance
+     * @throws BuildException on error
+     */
+    public Regexp newRegexp() throws RuntimeException
+    {
+        String systemDefault = System.getProperty("izpack.regexp.regexpimpl");
+        if (systemDefault != null) {
+            return createRegexpInstance(systemDefault);
+            // XXX     should we silently catch possible exceptions and try to
+            //         load a different implementation?
+        }
+
+        try {
+            testAvailability("java.util.regex.Matcher");
+            return createRegexpInstance("com.izforge.izpack.util.regex.JavaRegexp");
+        } catch (Exception be) {
+            // ignore
+        }
+
+        /*
+        try {
+            testAvailability("org.apache.oro.text.regex.Pattern");
+            return createRegexpInstance("com.izforge.izpack.util.regex.JakartaOroRegexp");
+        } catch (Exception be) {
+            // ignore
+        }
+        */
+
+        /*
+        try {
+            testAvailability("org.apache.regexp.RE");
+            return createRegexpInstance("com.izforge.izpack.util.regex.JakartaRegexpRegexp");
+        } catch (Exception be) {
+            // ignore
+        }
+        */
+
+        throw new RuntimeException("No supported regular expression matcher found");
+    }
+
+    /**
+     * Wrapper over RegexpMatcherFactory.createInstance that ensures that
+     * we are dealing with a Regexp implementation.
+     *
+     * @since 1.3
+     *
+     * @see RegexpMatcherFactory#createInstance(String)
+     */
+    protected Regexp createRegexpInstance(String classname)
+    throws RuntimeException
+    {
+        RegexpMatcher m = createInstance(classname);
+        if (m instanceof Regexp) {
+            return (Regexp) m;
+        } else {
+            throw new RuntimeException(classname + " doesn't implement the Regexp interface");
+        }
+    }
+
+}
Index: src/lib/com/izforge/izpack/util/regex/RegexpMatcher.java
===================================================================
--- src/lib/com/izforge/izpack/util/regex/RegexpMatcher.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/regex/RegexpMatcher.java	(revision 0)
@@ -0,0 +1,113 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.regex;
+
+import java.util.Vector;
+
+/**
+ * Interface describing a regular expression matcher.
+ *
+ * @see <a href='http://ant.apache.org'>Apache Ant</a>
+ * @author René Krell - changes against the original implementation in Apache Ant 1.6.5
+ */
+public interface RegexpMatcher {
+
+    /***
+     * Default Mask (case insensitive, neither multiline nor
+     * singleline specified).
+     */
+    int MATCH_DEFAULT          = 0x00000000;
+
+    /***
+     * Perform a case insenstive match
+     */
+    int MATCH_CASE_INSENSITIVE = 0x00000100;
+
+    /***
+     * Treat the input as a multiline input
+     */
+    int MATCH_MULTILINE        = 0x00001000;
+
+    /***
+     * Treat the input as singleline input ('.' matches newline)
+     */
+    int MATCH_SINGLELINE       = 0x00010000;
+
+
+    /**
+     * Set the regexp pattern from the String description.
+     * @param pattern the pattern to match
+     * @throws BuildException on error
+     */
+    void setPattern(String pattern) throws RuntimeException;
+
+    /**
+     * Get a String representation of the regexp pattern
+     * @return the pattern
+     * @throws BuildException on error
+     */
+    String getPattern() throws RuntimeException;
+
+    /**
+     * Does the given argument match the pattern?
+     * @param argument the string to match against
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    boolean matches(String argument) throws RuntimeException;
+
+    /**
+     * Returns a Vector of matched groups found in the argument
+     * using default options.
+     *
+     * <p>Group 0 will be the full match, the rest are the
+     * parenthesized subexpressions</p>.
+     *
+     * @param argument the string to match against
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    Vector<String> getGroups(String argument) throws RuntimeException;
+
+    /***
+     * Does this regular expression match the input, given
+     * certain options
+     * @param input The string to check for a match
+     * @param options The list of options for the match. See the
+     *                MATCH_ constants above.
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    boolean matches(String input, int options) throws RuntimeException;
+
+    /***
+     * Get the match groups from this regular expression.  The return
+     * type of the elements is always String.
+     * @param input The string to check for a match
+     * @param options The list of options for the match. See the
+     *                MATCH_ constants above.
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    Vector<String> getGroups(String input, int options) throws RuntimeException;
+
+}
Index: src/lib/com/izforge/izpack/util/regex/RegexpMatcherFactory.java
===================================================================
--- src/lib/com/izforge/izpack/util/regex/RegexpMatcherFactory.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/regex/RegexpMatcherFactory.java	(revision 0)
@@ -0,0 +1,105 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.regex;
+
+/**
+ * Simple Factory Class that produces an implementation of
+ * RegexpMatcher based on the system property
+ * <code>izpack.regexp.matcherimpl</code> and the classes
+ * available.
+ *
+ * <p>In a more general framework this class would be abstract and
+ * have a static newInstance method.</p>
+ *
+ * @see <a href='http://ant.apache.org'>Apache Ant</a>
+ * @author René Krell - changes against the original implementation in Apache Ant 1.6.5
+ */
+public class RegexpMatcherFactory
+{
+    /***
+     * Create a new regular expression instance.
+     *
+     * @return the matcher
+     * @throws BuildException on error
+     */
+    public RegexpMatcher newRegexpMatcher() throws Exception
+    {
+        String systemDefault = System.getProperty("izpack.regexp.matcherimpl");
+        if (systemDefault != null) {
+            return createInstance(systemDefault);
+        }
+
+        try {
+            testAvailability("java.util.regex.Matcher");
+            return createInstance("com.izforge.izpack.util.regex.JavaRegexpMatcher");
+        } catch (Exception be) {
+            // ignore
+        }
+
+/*        try {
+            testAvailability("org.apache.oro.text.regex.Pattern");
+            return createInstance("com.izforge.izpack.util.regex.JakartaOroMatcher");
+        } catch (Exception be) {
+            // ignore
+        }
+
+        try {
+            testAvailability("org.apache.regexp.RE");
+            return createInstance("com.izforge.izpack.util.regex.JakartaRegexpMatcher");
+        } catch (Exception be) {
+            // ignore
+        }
+*/
+        throw new Exception("No supported regular expression matcher found");
+   }
+
+    /**
+     * Create an instance of a matcher from a classname.
+     *
+     * @param className a <code>String</code> value
+     * @return a <code>RegexpMatcher</code> value
+     * @exception BuildException if an error occurs
+     */
+    protected RegexpMatcher createInstance(String className)
+        throws RuntimeException {
+        try {
+            Class<?> implClass = Class.forName(className);
+            return (RegexpMatcher) implClass.newInstance();
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+
+    /**
+     * Test if a particular class is available to be used.
+     *
+     * @param className a <code>String</code> value
+     * @exception BuildException if an error occurs
+     */
+    protected void testAvailability(String className) throws Exception {
+        try {
+            Class.forName(className);
+        } catch (Throwable t) {
+            throw new Exception(t);
+        }
+    }
+}
Index: src/lib/com/izforge/izpack/util/regex/RegularExpression.java
===================================================================
--- src/lib/com/izforge/izpack/util/regex/RegularExpression.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/regex/RegularExpression.java	(revision 0)
@@ -0,0 +1,116 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.regex;
+
+/***
+ * A regular expression datatype.  Keeps an instance of the
+ * compiled expression for speed purposes.  This compiled
+ * expression is lazily evaluated (it is compiled the first
+ * time it is needed).  The syntax is the dependent on which
+ * regular expression type you are using.  The system property
+ * "izpack.regexp.regexpimpl" will be the classname of the implementation
+ * that will be used.
+ *
+ * <pre>
+ * For jdk  &lt;= 1.3, there are two available implementations:
+ *   org.apache.tools.ant.util.regexp.JakartaOroRegexp (the default)
+ *        Based on the jakarta-oro package
+ *
+ *   org.apache.tools.ant.util.regexp.JakartaRegexpRegexp
+ *        Based on the jakarta-regexp package
+ *
+ * For jdk &gt;= 1.4 an additional implementation is available:
+ *   org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp
+ *        Based on the jdk 1.4 built in regular expression package.
+ * </pre>
+ *
+ * <pre>
+ *   &lt;regexp [ [id="id"] pattern="expression" | refid="id" ]
+ *   /&gt;
+ * </pre>
+ *
+ * @see org.apache.oro.text.regex.Perl5Compiler
+ * @see org.apache.regexp.RE
+ * @see java.util.regex.Pattern
+ *
+ * @see org.apache.tools.ant.util.regexp.Regexp
+ *
+ * @see <a href='http://ant.apache.org'>Apache Ant</a>
+ * @author René Krell - changes against the original implementation in Apache Ant 1.6.5
+ */
+public class RegularExpression {
+    private boolean alreadyInit = false;
+
+    // The regular expression factory
+    private static final RegexpFactory FACTORY = new RegexpFactory();
+
+    private Regexp regexp = null;
+    // temporary variable
+    private String myPattern;
+    private boolean setPatternPending = false;
+
+    private void init() {
+        if (!alreadyInit) {
+            this.regexp = FACTORY.newRegexp();
+            alreadyInit = true;
+        }
+    }
+    private void setPattern() {
+        if (setPatternPending) {
+            regexp.setPattern(myPattern);
+            setPatternPending = false;
+        }
+    }
+    /**
+     * sets the regular expression pattern
+     * @param pattern regular expression pattern
+     */
+    public void setPattern(String pattern) {
+        if (regexp == null) {
+            myPattern = pattern;
+            setPatternPending = true;
+        } else {
+            regexp.setPattern(pattern);
+        }
+    }
+
+    /***
+     * Gets the pattern string for this RegularExpression in the
+     * given project.
+     * @return pattern
+     */
+    public String getPattern() {
+        init();
+        setPattern();
+        return regexp.getPattern();
+    }
+
+    /**
+     * provides a reference to the Regexp contained in this
+     * @return   Regexp instance associated with this RegularExpression instance
+     */
+    public Regexp getRegexp() {
+        init();
+        setPattern();
+        return this.regexp;
+    }
+}
Index: src/lib/com/izforge/izpack/util/variable/ConfigFileValue.java
===================================================================
--- src/lib/com/izforge/izpack/util/variable/ConfigFileValue.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/variable/ConfigFileValue.java	(revision 0)
@@ -0,0 +1,181 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.variable;
+
+import java.io.*;
+
+import javax.xml.parsers.*;
+import javax.xml.xpath.*;
+
+import org.ini4j.*;
+import org.w3c.dom.*;
+import org.xml.sax.SAXException;
+
+import com.izforge.izpack.util.VariableSubstitutorBase;
+
+public class ConfigFileValue extends Value implements Serializable
+{
+    /**
+     *
+     */
+    private static final long serialVersionUID = 6082215731362372562L;
+
+    public final static int CONFIGFILE_TYPE_PROPERTIES = 0;
+    public final static int CONFIGFILE_TYPE_INI = 1;
+    public final static int CONFIGFILE_TYPE_XML = 2;
+
+    public String location; // mandatory
+    public int type = CONFIGFILE_TYPE_PROPERTIES; // optional, default: property file
+    public String section; // mandatory for type = "ini"
+    public String key; // mandatory
+    public ConfigFileValue(String location, int type, String section, String key)
+    {
+        super();
+        this.location = location;
+        this.type = type;
+        this.section = section;
+        this.key = key;
+    }
+
+    public String getLocation()
+    {
+        return location;
+    }
+
+    public void setLocation(String location)
+    {
+        this.location = location;
+    }
+
+    public int getType()
+    {
+        return type;
+    }
+
+    public void setType(int type)
+    {
+        this.type = type;
+    }
+
+    public String getSection()
+    {
+        return section;
+    }
+
+    public void setSection(String section)
+    {
+        this.section = section;
+    }
+
+    public String getKey()
+    {
+        return key;
+    }
+
+    public void setKey(String key)
+    {
+        this.key = key;
+    }
+
+    @Override
+    public void validate() throws Exception
+    {
+        if (this.location == null || this.location.length() <= 0)
+            throw new Exception("No or empty file path");
+        if (this.type == CONFIGFILE_TYPE_INI && (this.section == null || this.section.length() <= 0))
+            throw new Exception("No INI file section defined");
+        if (this.type != CONFIGFILE_TYPE_INI && this.section != null)
+            throw new Exception("No INI file section expected for non-INI file types");
+    }
+
+    @Override
+    public String resolve() throws Exception
+    {
+        switch (type)
+        {
+        case CONFIGFILE_TYPE_PROPERTIES:
+            Options opts;
+            opts = new Options(new FileReader(location));
+            return opts.get(key);
+        case CONFIGFILE_TYPE_INI:
+            Ini ini;
+            ini = new Ini(new FileReader(location));
+            return ini.get(section, key);
+        case CONFIGFILE_TYPE_XML:
+            return parseXPath(
+                    new FileInputStream(location), key,
+                    System.getProperty("line.separator"));
+        default:
+            throw new Exception("Invalid configuration file type "+type);
+        }
+    }
+
+    @Override
+    public String resolve(VariableSubstitutorBase substitutor)
+    throws Exception
+    {
+        switch (type)
+        {
+        case CONFIGFILE_TYPE_PROPERTIES:
+            Options opts;
+            opts = new Options(new FileReader(substitutor.substitute(location, null)));
+            return opts.get(substitutor.substitute(key, null));
+        case CONFIGFILE_TYPE_INI:
+            Ini ini;
+            ini = new Ini(new FileReader(substitutor.substitute(location, null)));
+            return ini.get(substitutor.substitute(section, null), substitutor.substitute(key, null));
+        case CONFIGFILE_TYPE_XML:
+            return parseXPath(
+                    new FileInputStream(substitutor.substitute(location, null)),
+                    substitutor.substitute(key, null),
+                    System.getProperty("line.separator"));
+        default:
+            throw new Exception("Invalid configuration file type "+type);
+        }
+    }
+
+    private static String parseXPath( InputStream in, String expression, String separator )
+    throws ParserConfigurationException, SAXException, IOException, XPathExpressionException
+    {
+        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
+        domFactory.setNamespaceAware(true);
+        DocumentBuilder builder;
+        builder = domFactory.newDocumentBuilder();
+        Document doc = builder.parse(in);
+        XPath xpath = XPathFactory.newInstance().newXPath();
+        // XPath Query for showing all nodes value
+        XPathExpression expr = xpath.compile(expression);
+        Object result = expr.evaluate(doc, XPathConstants.NODESET);
+        NodeList nodes = (NodeList) result;
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < nodes.getLength(); i++)
+        {
+            String value = nodes.item(i).getNodeValue();
+            if (value != null) {
+                if (sb.length()>0)
+                    sb.append(separator);
+                sb.append(value);
+            }
+        }
+        return sb.toString();
+    }
+}
Index: src/lib/com/izforge/izpack/util/variable/EnvironmentValue.java
===================================================================
--- src/lib/com/izforge/izpack/util/variable/EnvironmentValue.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/variable/EnvironmentValue.java	(revision 0)
@@ -0,0 +1,70 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.variable;
+
+import java.io.Serializable;
+
+import com.izforge.izpack.util.*;
+
+public class EnvironmentValue extends Value implements Serializable
+{
+    /**
+     *
+     */
+    private static final long serialVersionUID = -658114236595736672L;
+
+    public String variable; // mandatory
+    public EnvironmentValue(String variable)
+    {
+        super();
+        this.variable = variable;
+    }
+    public String getVariable()
+    {
+        return this.variable;
+    }
+
+    public void setVariable(String variable)
+    {
+        this.variable = variable;
+    }
+
+    @Override
+    public void validate() throws Exception
+    {
+        if (this.variable == null || this.variable.length() <= 0)
+            throw new Exception("No or empty environment variable name");
+    }
+
+    @Override
+    public String resolve()
+    {
+        return IoHelper.getenv(variable);
+    }
+
+    @Override
+    public String resolve(VariableSubstitutorBase substitutor)
+    {
+        return IoHelper.getenv( substitutor.substitute(variable, null) );
+    }
+
+}
Index: src/lib/com/izforge/izpack/util/variable/ExecValue.java
===================================================================
--- src/lib/com/izforge/izpack/util/variable/ExecValue.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/variable/ExecValue.java	(revision 0)
@@ -0,0 +1,97 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.variable;
+
+import java.io.Serializable;
+
+import com.izforge.izpack.util.*;
+
+
+public class ExecValue extends Value implements Serializable
+{
+    /**
+     *
+     */
+    private static final long serialVersionUID = -6438593229737421526L;
+
+    private String cmd[];
+    public ExecValue(String[] command, boolean isShellCommand)
+    {
+        super();
+        if (isShellCommand) {
+            if (OsVersion.IS_WINDOWS)
+            {
+                this.cmd = new String[command.length+2];
+                this.cmd[0] = "cmd";
+                this.cmd[1] = "/C";
+                for (int i = 2; i < this.cmd.length; i++)
+                {
+                    this.cmd[i] = command[i-2];
+                }
+            } else if (OsVersion.IS_UNIX)
+            {
+                this.cmd = new String[command.length+1];
+                this.cmd[0] = "sh";
+                for (int i = 1; i < this.cmd.length; i++)
+                {
+                    this.cmd[i] = command[i-1];
+                }
+            } else
+            {
+                this.cmd = command;
+            }
+        } else
+            this.cmd = command;
+    }
+    public String[] getCmd()
+    {
+        return cmd;
+    }
+
+    public void setCmd(String[] cmd)
+    {
+        this.cmd = cmd;
+    }
+
+    @Override
+    public void validate() throws Exception
+    {
+        if (this.cmd == null || this.cmd.length <= 0)
+            throw new IllegalArgumentException("Bad command line");
+    }
+
+    @Override
+    public String resolve()
+    {
+        return FileExecutor.getExecOutput(cmd);
+    }
+
+    @Override
+    public String resolve(VariableSubstitutorBase substitutor)
+    {
+        for (int i = 0; i < cmd.length; i++)
+        {
+            cmd[i]=substitutor.substitute(cmd[i], null);
+        }
+        return FileExecutor.getExecOutput(cmd);
+    }
+}
Index: src/lib/com/izforge/izpack/util/variable/PlainValue.java
===================================================================
--- src/lib/com/izforge/izpack/util/variable/PlainValue.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/variable/PlainValue.java	(revision 0)
@@ -0,0 +1,72 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.variable;
+
+import java.io.Serializable;
+
+import com.izforge.izpack.util.VariableSubstitutorBase;
+
+
+public class PlainValue extends Value implements Serializable
+{
+    /**
+     *
+     */
+    private static final long serialVersionUID = -8081979859867523421L;
+
+    public String value; // mandatory
+
+    public PlainValue(String value)
+    {
+        super();
+        this.value = value;
+    }
+
+    public String getValue()
+    {
+        return this.value;
+    }
+
+    public void setValue(String value)
+    {
+        this.value = value;
+    }
+
+    @Override
+    public void validate() throws Exception
+    {
+        if (this.value == null || this.value.length() <= 0)
+            throw new Exception("None or empty plain value");
+    }
+
+    @Override
+    public String resolve()
+    {
+        return value;
+    }
+
+    @Override
+    public String resolve(VariableSubstitutorBase substitutor)
+    {
+        return substitutor.substitute(value, null);
+    }
+}
Index: src/lib/com/izforge/izpack/util/variable/RegistryValue.java
===================================================================
--- src/lib/com/izforge/izpack/util/variable/RegistryValue.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/variable/RegistryValue.java	(revision 0)
@@ -0,0 +1,127 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.variable;
+
+import java.io.*;
+
+import org.ini4j.Reg;
+
+import com.izforge.izpack.util.*;
+
+
+public class RegistryValue extends Value implements Serializable
+{
+    /**
+     *
+     */
+    private static final long serialVersionUID = 97879516787269847L;
+
+    public String root; // optional
+    public String key; // mandatory
+    public String value; // optional; if null -> use default value
+    public RegistryValue(String root, String key, String value)
+    {
+        super();
+        this.root = root;
+        this.key = key;
+        this.value = value;
+    }
+
+    public String getRoot()
+    {
+        return root;
+    }
+
+    public void setRoot(String root)
+    {
+        this.root = root;
+    }
+
+    public String getKey()
+    {
+        return key;
+    }
+
+    public void setKey(String key)
+    {
+        this.key = key;
+    }
+
+    public String getValue()
+    {
+        return this.value;
+    }
+
+    public void setValue(String value)
+    {
+        this.value = value;
+    }
+
+    @Override
+    public void validate() throws Exception
+    {
+        if ((this.root == null && this.key == null) ||
+            ((this.root != null && this.root.length() <= 0) &&
+             (this.key != null && this.key.length() <= 0)))
+            throw new Exception("No or empty registry key path");
+    }
+
+    @Override
+    public String resolve() throws Exception
+    {
+        if (!OsVersion.IS_WINDOWS)
+            throw new Exception("Registry access allowed only on Windows OS");
+
+        Reg reg = null;
+        Reg.Key regkey = null;
+        if (root != null) reg = new Reg(root);
+        if (key != null)
+        {
+            if (reg == null) reg = new Reg();
+            regkey = reg.get(key);
+        }
+        if (regkey != null)
+            return regkey.get(value);
+
+        return null;
+    }
+
+    @Override
+    public String resolve(VariableSubstitutorBase substitutor) throws Exception
+    {
+        if (!OsVersion.IS_WINDOWS)
+            throw new Exception("Registry access allowed only on Windows OS");
+
+        Reg reg = null;
+        Reg.Key regkey = null;
+        if (root != null) reg = new Reg(root);
+        if (key != null)
+        {
+            if (reg == null) reg = new Reg();
+            regkey = reg.get(substitutor.substitute(key, null));
+        }
+        if (regkey != null)
+            return regkey.get(substitutor.substitute(value, null));
+
+        return null;
+    }
+}
Index: src/lib/com/izforge/izpack/util/variable/RegularExpressionFilter.java
===================================================================
--- src/lib/com/izforge/izpack/util/variable/RegularExpressionFilter.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/variable/RegularExpressionFilter.java	(revision 0)
@@ -0,0 +1,128 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.variable;
+
+import java.io.Serializable;
+
+public class RegularExpressionFilter implements Serializable
+{
+    /**
+     *
+     */
+    private static final long serialVersionUID = -1405213251817336962L;
+
+    public String regexp;
+    public String select, replace;
+    public String defaultValue;
+    public Boolean casesensitive;
+    public Boolean global;
+    public RegularExpressionFilter(String regexp, String select, String replace, String defaultValue,
+            Boolean casesensitive, Boolean global)
+    {
+        super();
+        this.regexp = regexp;
+        this.select = select;
+        this.replace = replace;
+        this.defaultValue = defaultValue;
+        this.casesensitive = casesensitive;
+        this.global = global;
+    }
+    public RegularExpressionFilter(String regexp, String select, String defaultValue,
+            Boolean casesensitive)
+    {
+        this(regexp, select, null, defaultValue, casesensitive, null);
+    }
+    public RegularExpressionFilter(String regexp, String replace, String defaultValue,
+            Boolean casesensitive, Boolean global)
+    {
+        this(regexp, null, replace, defaultValue, casesensitive, global);
+    }
+    public void validate() throws Exception
+    {
+        if (this.regexp == null || this.regexp.length() <= 0)
+            throw new Exception("No or empty regular expression defined");
+        if (this.select == null && this.replace == null)
+            throw new Exception("Exactly one of both select or replace expression required");
+        if (this.select != null && this.replace != null)
+            throw new Exception("Expected only one of both select or replace expression");
+    }
+
+    public String getRegexp()
+    {
+        return regexp;
+    }
+
+    public void setRegexp(String regexp)
+    {
+        this.regexp = regexp;
+    }
+
+    public String getSelect()
+    {
+        return select;
+    }
+
+    public void setSelect(String select)
+    {
+        this.select = select;
+    }
+
+    public String getReplace()
+    {
+        return replace;
+    }
+
+    public void setReplace(String replace)
+    {
+        this.replace = replace;
+    }
+
+    public String getDefaultValue()
+    {
+        return defaultValue;
+    }
+
+    public void setDefaultValue(String defaultValue)
+    {
+        this.defaultValue = defaultValue;
+    }
+
+    public Boolean getCasesensitive()
+    {
+        return casesensitive;
+    }
+
+    public void setCasesensitive(Boolean casesensitive)
+    {
+        this.casesensitive = casesensitive;
+    }
+
+    public Boolean getGlobal()
+    {
+        return global;
+    }
+
+    public void setGlobal(Boolean global)
+    {
+        this.global = global;
+    }
+}
Index: src/lib/com/izforge/izpack/util/variable/Value.java
===================================================================
--- src/lib/com/izforge/izpack/util/variable/Value.java	(revision 0)
+++ src/lib/com/izforge/izpack/util/variable/Value.java	(revision 0)
@@ -0,0 +1,57 @@
+/*
+ * IzPack - Copyright 2001-2010 Julien Ponge, All Rights Reserved.
+ *
+ * http://izpack.org/
+ * http://izpack.codehaus.org/
+ *
+ * Copyright 2010 Rene Krell
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.izforge.izpack.util.variable;
+
+import com.izforge.izpack.util.*;
+
+public abstract class Value
+{
+    public abstract void validate() throws Exception;
+    public abstract String resolve() throws Exception;
+    public abstract String resolve(VariableSubstitutorBase substitutor) throws Exception;
+
+    public String resolve(VariableSubstitutorBase substitutor, RegularExpressionFilter regexp)
+    throws Exception
+    {
+        String newValue = resolve(substitutor);
+
+        if (regexp != null) {
+            String replace = substitutor.substitute(regexp.getReplace(), null);
+            String select = substitutor.substitute(regexp.getSelect(), null);
+            RegularExpressionProcessor processor = new RegularExpressionProcessor();
+            processor.setInput(substitutor.substitute(newValue, null));
+            processor.setRegexp(substitutor.substitute(regexp.getRegexp(), null));
+            processor.setCaseSensitive(regexp.getCasesensitive());
+            if (select != null) {
+                processor.setSelect(select);
+            } else
+                if (replace != null) {
+                    processor.setReplace(replace);
+                    processor.setGlobal(regexp.getGlobal());
+                }
+            newValue = processor.execute();
+        }
+
+        return newValue;
+    }
+
+}
Index: src/tests/com/izforge/izpack/adaptator/XMLParserTest.java
===================================================================
--- src/tests/com/izforge/izpack/adaptator/XMLParserTest.java	(revision 2938)
+++ src/tests/com/izforge/izpack/adaptator/XMLParserTest.java	(working copy)
@@ -80,7 +80,7 @@
         assertEquals("shortcuts", spec.getName());
     }
 
-    public void testParseString() throws NoSuchMethodException, ResourceNotFoundException, IOException
+    public void testParseString() throws Exception
     {
         InputStream input = null;
         IXMLElement spec;

